Added some crazy AI generated ideas, as a brainstorming exercise.
This commit is contained in:
720
examples/integrated_defi_platform.rs
Normal file
720
examples/integrated_defi_platform.rs
Normal file
@@ -0,0 +1,720 @@
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::collections::{BTreeMap, HashMap, HashSet};
|
||||
use std::time::{Duration, SystemTime, UNIX_EPOCH};
|
||||
|
||||
/// This example demonstrates how multiple BFT-CRDT use cases can be combined
|
||||
/// into a comprehensive DeFi platform that operates without global consensus.
|
||||
|
||||
// ==== Identity Layer ====
|
||||
|
||||
#[derive(Debug, Clone, Hash, Eq, PartialEq, Serialize, Deserialize)]
|
||||
pub struct IdentityId(pub String);
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
pub struct Identity {
|
||||
pub id: IdentityId,
|
||||
pub public_key: Vec<u8>,
|
||||
pub attestations_received: HashSet<AttestationId>,
|
||||
pub attestations_given: HashSet<AttestationId>,
|
||||
pub reputation_score: f64,
|
||||
pub created_at: u64,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Hash, Eq, PartialEq, Serialize, Deserialize)]
|
||||
pub struct AttestationId(pub String);
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
pub struct Attestation {
|
||||
pub id: AttestationId,
|
||||
pub issuer: IdentityId,
|
||||
pub subject: IdentityId,
|
||||
pub claim: String,
|
||||
pub confidence: u8,
|
||||
pub timestamp: u64,
|
||||
pub expiry: Option<u64>,
|
||||
pub signature: Vec<u8>,
|
||||
}
|
||||
|
||||
// ==== Multi-Party State Channel ====
|
||||
|
||||
#[derive(Debug, Clone, Hash, Eq, PartialEq, Serialize, Deserialize)]
|
||||
pub struct ChannelId(pub String);
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
pub struct StateChannel {
|
||||
pub id: ChannelId,
|
||||
pub participants: Vec<IdentityId>,
|
||||
pub balances: HashMap<(IdentityId, String), u128>, // (user, token) -> balance
|
||||
pub orders: OrderBookCRDT,
|
||||
pub positions: HashMap<IdentityId, Vec<Position>>,
|
||||
pub nonce: u64,
|
||||
pub last_update: u64,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
pub struct Position {
|
||||
pub id: String,
|
||||
pub owner: IdentityId,
|
||||
pub market: String,
|
||||
pub size: i128,
|
||||
pub entry_price: u128,
|
||||
pub leverage: u8,
|
||||
pub margin: u128,
|
||||
pub unrealized_pnl: i128,
|
||||
}
|
||||
|
||||
// ==== Order Book CRDT ====
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
pub struct OrderBookCRDT {
|
||||
pub orders: HashMap<String, Order>,
|
||||
pub executions: HashMap<String, Execution>,
|
||||
pub cancellations: HashSet<String>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
pub struct Order {
|
||||
pub id: String,
|
||||
pub trader: IdentityId,
|
||||
pub side: OrderSide,
|
||||
pub price: u128,
|
||||
pub amount: u128,
|
||||
pub remaining: u128,
|
||||
pub timestamp: u64,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy, Serialize, Deserialize)]
|
||||
pub enum OrderSide {
|
||||
Buy,
|
||||
Sell,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
pub struct Execution {
|
||||
pub id: String,
|
||||
pub buy_order: String,
|
||||
pub sell_order: String,
|
||||
pub price: u128,
|
||||
pub amount: u128,
|
||||
pub timestamp: u64,
|
||||
}
|
||||
|
||||
// ==== Oracle Price Data ====
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
pub struct PriceSubmission {
|
||||
pub oracle: IdentityId,
|
||||
pub asset: String,
|
||||
pub price: u128,
|
||||
pub confidence: u8,
|
||||
pub timestamp: u64,
|
||||
pub sources: Vec<String>,
|
||||
pub signature: Vec<u8>,
|
||||
}
|
||||
|
||||
// ==== Cross-Chain Messages ====
|
||||
|
||||
#[derive(Debug, Clone, Hash, Eq, PartialEq, Serialize, Deserialize)]
|
||||
pub struct ChainId(pub String);
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
pub struct CrossChainMessage {
|
||||
pub id: String,
|
||||
pub source_chain: ChainId,
|
||||
pub dest_chain: ChainId,
|
||||
pub sender: IdentityId,
|
||||
pub action: CrossChainAction,
|
||||
pub timestamp: u64,
|
||||
pub signatures: Vec<Vec<u8>>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
pub enum CrossChainAction {
|
||||
Deposit { token: String, amount: u128 },
|
||||
Withdraw { token: String, amount: u128 },
|
||||
SyncPosition { position: Position },
|
||||
LiquidationAlert { position_id: String },
|
||||
}
|
||||
|
||||
// ==== Integrated DeFi Platform ====
|
||||
|
||||
pub struct IntegratedDeFiPlatform {
|
||||
// Identity layer
|
||||
pub identities: HashMap<IdentityId, Identity>,
|
||||
pub attestations: HashMap<AttestationId, Attestation>,
|
||||
|
||||
// State channels
|
||||
pub channels: HashMap<ChannelId, StateChannel>,
|
||||
|
||||
// Oracle data
|
||||
pub price_submissions: BTreeMap<(String, u64), Vec<PriceSubmission>>,
|
||||
|
||||
// Cross-chain messages
|
||||
pub cross_chain_messages: HashMap<String, CrossChainMessage>,
|
||||
|
||||
// Platform parameters
|
||||
pub min_reputation_score: f64,
|
||||
pub liquidation_threshold: f64,
|
||||
}
|
||||
|
||||
impl IntegratedDeFiPlatform {
|
||||
pub fn new() -> Self {
|
||||
Self {
|
||||
identities: HashMap::new(),
|
||||
attestations: HashMap::new(),
|
||||
channels: HashMap::new(),
|
||||
price_submissions: BTreeMap::new(),
|
||||
cross_chain_messages: HashMap::new(),
|
||||
min_reputation_score: 0.5,
|
||||
liquidation_threshold: 0.8,
|
||||
}
|
||||
}
|
||||
|
||||
// ==== Identity Functions ====
|
||||
|
||||
pub fn create_identity(&mut self, id: IdentityId, public_key: Vec<u8>) -> Result<(), String> {
|
||||
if self.identities.contains_key(&id) {
|
||||
return Err("Identity already exists".to_string());
|
||||
}
|
||||
|
||||
let identity = Identity {
|
||||
id: id.clone(),
|
||||
public_key,
|
||||
attestations_received: HashSet::new(),
|
||||
attestations_given: HashSet::new(),
|
||||
reputation_score: 0.0,
|
||||
created_at: Self::timestamp(),
|
||||
};
|
||||
|
||||
self.identities.insert(id, identity);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn create_attestation(
|
||||
&mut self,
|
||||
issuer: IdentityId,
|
||||
subject: IdentityId,
|
||||
claim: String,
|
||||
confidence: u8,
|
||||
) -> Result<AttestationId, String> {
|
||||
// Check issuer exists and has sufficient reputation
|
||||
let issuer_identity = self.identities.get(&issuer).ok_or("Issuer not found")?;
|
||||
|
||||
if issuer_identity.reputation_score < self.min_reputation_score {
|
||||
return Err("Insufficient reputation to issue attestations".to_string());
|
||||
}
|
||||
|
||||
let attestation_id = AttestationId(format!("att_{}", Self::timestamp()));
|
||||
let attestation = Attestation {
|
||||
id: attestation_id.clone(),
|
||||
issuer: issuer.clone(),
|
||||
subject: subject.clone(),
|
||||
claim,
|
||||
confidence,
|
||||
timestamp: Self::timestamp(),
|
||||
expiry: None,
|
||||
signature: vec![1, 2, 3], // Placeholder signature
|
||||
};
|
||||
|
||||
// Update both identities
|
||||
self.attestations
|
||||
.insert(attestation_id.clone(), attestation);
|
||||
|
||||
if let Some(issuer_identity) = self.identities.get_mut(&issuer) {
|
||||
issuer_identity
|
||||
.attestations_given
|
||||
.insert(attestation_id.clone());
|
||||
}
|
||||
|
||||
if let Some(subject_identity) = self.identities.get_mut(&subject) {
|
||||
subject_identity
|
||||
.attestations_received
|
||||
.insert(attestation_id.clone());
|
||||
// Simple reputation update
|
||||
subject_identity.reputation_score += (confidence as f64 / 100.0) * 0.1;
|
||||
}
|
||||
|
||||
Ok(attestation_id)
|
||||
}
|
||||
|
||||
// ==== State Channel Functions ====
|
||||
|
||||
pub fn create_channel(&mut self, participants: Vec<IdentityId>) -> Result<ChannelId, String> {
|
||||
// Verify all participants exist and have sufficient reputation
|
||||
for participant in &participants {
|
||||
let identity = self
|
||||
.identities
|
||||
.get(participant)
|
||||
.ok_or("Participant not found")?;
|
||||
|
||||
if identity.reputation_score < self.min_reputation_score {
|
||||
return Err(format!(
|
||||
"Participant {} has insufficient reputation",
|
||||
participant.0
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
let channel_id = ChannelId(format!("channel_{}", Self::timestamp()));
|
||||
let channel = StateChannel {
|
||||
id: channel_id.clone(),
|
||||
participants,
|
||||
balances: HashMap::new(),
|
||||
orders: OrderBookCRDT {
|
||||
orders: HashMap::new(),
|
||||
executions: HashMap::new(),
|
||||
cancellations: HashSet::new(),
|
||||
},
|
||||
positions: HashMap::new(),
|
||||
nonce: 0,
|
||||
last_update: Self::timestamp(),
|
||||
};
|
||||
|
||||
self.channels.insert(channel_id.clone(), channel);
|
||||
Ok(channel_id)
|
||||
}
|
||||
|
||||
pub fn place_order(
|
||||
&mut self,
|
||||
channel_id: &ChannelId,
|
||||
trader: &IdentityId,
|
||||
side: OrderSide,
|
||||
price: u128,
|
||||
amount: u128,
|
||||
) -> Result<String, String> {
|
||||
let channel = self
|
||||
.channels
|
||||
.get_mut(channel_id)
|
||||
.ok_or("Channel not found")?;
|
||||
|
||||
// Verify trader is participant
|
||||
if !channel.participants.contains(trader) {
|
||||
return Err("Trader not in channel".to_string());
|
||||
}
|
||||
|
||||
// Check balance for sells or margin for buys
|
||||
match side {
|
||||
OrderSide::Sell => {
|
||||
let balance = channel
|
||||
.balances
|
||||
.get(&(trader.clone(), "ETH".to_string()))
|
||||
.unwrap_or(&0);
|
||||
if *balance < amount {
|
||||
return Err("Insufficient balance".to_string());
|
||||
}
|
||||
}
|
||||
OrderSide::Buy => {
|
||||
let usdc_balance = channel
|
||||
.balances
|
||||
.get(&(trader.clone(), "USDC".to_string()))
|
||||
.unwrap_or(&0);
|
||||
let required = price * amount / 1_000_000; // Assuming 6 decimals
|
||||
if *usdc_balance < required {
|
||||
return Err("Insufficient USDC balance".to_string());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let order_id = format!("order_{}_{}", trader.0, Self::timestamp());
|
||||
let order = Order {
|
||||
id: order_id.clone(),
|
||||
trader: trader.clone(),
|
||||
side,
|
||||
price,
|
||||
amount,
|
||||
remaining: amount,
|
||||
timestamp: Self::timestamp(),
|
||||
};
|
||||
|
||||
channel.orders.orders.insert(order_id.clone(), order);
|
||||
channel.last_update = Self::timestamp();
|
||||
channel.nonce += 1;
|
||||
|
||||
// Try to match orders
|
||||
self.match_orders(channel_id)?;
|
||||
|
||||
Ok(order_id)
|
||||
}
|
||||
|
||||
fn match_orders(&mut self, channel_id: &ChannelId) -> Result<(), String> {
|
||||
let channel = self
|
||||
.channels
|
||||
.get_mut(channel_id)
|
||||
.ok_or("Channel not found")?;
|
||||
|
||||
let mut executions = Vec::new();
|
||||
|
||||
// Simple matching logic
|
||||
let mut buy_orders: Vec<_> = channel
|
||||
.orders
|
||||
.orders
|
||||
.values()
|
||||
.filter(|o| matches!(o.side, OrderSide::Buy) && o.remaining > 0)
|
||||
.collect();
|
||||
buy_orders.sort_by_key(|o| std::cmp::Reverse(o.price));
|
||||
|
||||
let mut sell_orders: Vec<_> = channel
|
||||
.orders
|
||||
.orders
|
||||
.values()
|
||||
.filter(|o| matches!(o.side, OrderSide::Sell) && o.remaining > 0)
|
||||
.collect();
|
||||
sell_orders.sort_by_key(|o| o.price);
|
||||
|
||||
for buy_order in buy_orders {
|
||||
for sell_order in &mut sell_orders {
|
||||
if buy_order.price >= sell_order.price
|
||||
&& buy_order.remaining > 0
|
||||
&& sell_order.remaining > 0
|
||||
{
|
||||
let amount = buy_order.remaining.min(sell_order.remaining);
|
||||
let execution = Execution {
|
||||
id: format!("exec_{}", Self::timestamp()),
|
||||
buy_order: buy_order.id.clone(),
|
||||
sell_order: sell_order.id.clone(),
|
||||
price: sell_order.price,
|
||||
amount,
|
||||
timestamp: Self::timestamp(),
|
||||
};
|
||||
executions.push(execution);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Apply executions
|
||||
for execution in executions {
|
||||
channel
|
||||
.orders
|
||||
.executions
|
||||
.insert(execution.id.clone(), execution.clone());
|
||||
|
||||
// Update order remaining amounts
|
||||
if let Some(buy_order) = channel.orders.orders.get_mut(&execution.buy_order) {
|
||||
buy_order.remaining -= execution.amount;
|
||||
}
|
||||
if let Some(sell_order) = channel.orders.orders.get_mut(&execution.sell_order) {
|
||||
sell_order.remaining -= execution.amount;
|
||||
}
|
||||
|
||||
// Update balances
|
||||
// This is simplified - real implementation would handle decimals properly
|
||||
let buyer = channel
|
||||
.orders
|
||||
.orders
|
||||
.get(&execution.buy_order)
|
||||
.unwrap()
|
||||
.trader
|
||||
.clone();
|
||||
let seller = channel
|
||||
.orders
|
||||
.orders
|
||||
.get(&execution.sell_order)
|
||||
.unwrap()
|
||||
.trader
|
||||
.clone();
|
||||
|
||||
*channel
|
||||
.balances
|
||||
.entry((buyer.clone(), "ETH".to_string()))
|
||||
.or_insert(0) += execution.amount;
|
||||
*channel
|
||||
.balances
|
||||
.entry((seller.clone(), "ETH".to_string()))
|
||||
.or_insert(0) -= execution.amount;
|
||||
|
||||
let usdc_amount = execution.price * execution.amount / 1_000_000;
|
||||
*channel
|
||||
.balances
|
||||
.entry((buyer, "USDC".to_string()))
|
||||
.or_insert(0) -= usdc_amount;
|
||||
*channel
|
||||
.balances
|
||||
.entry((seller, "USDC".to_string()))
|
||||
.or_insert(0) += usdc_amount;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
// ==== Oracle Functions ====
|
||||
|
||||
pub fn submit_price(
|
||||
&mut self,
|
||||
oracle: IdentityId,
|
||||
asset: String,
|
||||
price: u128,
|
||||
confidence: u8,
|
||||
) -> Result<(), String> {
|
||||
// Verify oracle has sufficient reputation
|
||||
let oracle_identity = self.identities.get(&oracle).ok_or("Oracle not found")?;
|
||||
|
||||
if oracle_identity.reputation_score < self.min_reputation_score * 2.0 {
|
||||
return Err("Insufficient reputation to submit prices".to_string());
|
||||
}
|
||||
|
||||
let submission = PriceSubmission {
|
||||
oracle,
|
||||
asset: asset.clone(),
|
||||
price,
|
||||
confidence,
|
||||
timestamp: Self::timestamp(),
|
||||
sources: vec!["binance".to_string(), "coinbase".to_string()],
|
||||
signature: vec![1, 2, 3],
|
||||
};
|
||||
|
||||
let key = (asset, submission.timestamp);
|
||||
self.price_submissions
|
||||
.entry(key)
|
||||
.or_insert_with(Vec::new)
|
||||
.push(submission);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn get_aggregate_price(&self, asset: &str, time_window: Duration) -> Option<u128> {
|
||||
let now = Self::timestamp();
|
||||
let start_time = now - time_window.as_secs();
|
||||
|
||||
let mut prices = Vec::new();
|
||||
|
||||
for ((price_asset, timestamp), submissions) in &self.price_submissions {
|
||||
if price_asset == asset && *timestamp >= start_time && *timestamp <= now {
|
||||
for submission in submissions {
|
||||
// Weight by confidence
|
||||
for _ in 0..submission.confidence {
|
||||
prices.push(submission.price);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if prices.is_empty() {
|
||||
return None;
|
||||
}
|
||||
|
||||
// Calculate weighted median
|
||||
prices.sort();
|
||||
Some(prices[prices.len() / 2])
|
||||
}
|
||||
|
||||
// ==== Cross-Chain Functions ====
|
||||
|
||||
pub fn send_cross_chain_message(
|
||||
&mut self,
|
||||
source_chain: ChainId,
|
||||
dest_chain: ChainId,
|
||||
sender: IdentityId,
|
||||
action: CrossChainAction,
|
||||
) -> Result<String, String> {
|
||||
let message_id = format!("msg_{}", Self::timestamp());
|
||||
let message = CrossChainMessage {
|
||||
id: message_id.clone(),
|
||||
source_chain,
|
||||
dest_chain,
|
||||
sender,
|
||||
action,
|
||||
timestamp: Self::timestamp(),
|
||||
signatures: vec![vec![1, 2, 3]], // Placeholder
|
||||
};
|
||||
|
||||
self.cross_chain_messages
|
||||
.insert(message_id.clone(), message);
|
||||
Ok(message_id)
|
||||
}
|
||||
|
||||
// ==== Liquidation Monitor ====
|
||||
|
||||
pub fn check_liquidations(&mut self, channel_id: &ChannelId) -> Result<Vec<String>, String> {
|
||||
let channel = self.channels.get(channel_id).ok_or("Channel not found")?;
|
||||
|
||||
let mut liquidations = Vec::new();
|
||||
|
||||
for (identity, positions) in &channel.positions {
|
||||
for position in positions {
|
||||
// Get current price
|
||||
let price = self
|
||||
.get_aggregate_price(&position.market, Duration::from_secs(300))
|
||||
.unwrap_or(position.entry_price);
|
||||
|
||||
// Calculate health
|
||||
let value = (position.size.abs() as u128) * price / 1_000_000;
|
||||
let health = position.margin as f64 / value as f64;
|
||||
|
||||
if health < self.liquidation_threshold {
|
||||
liquidations.push(position.id.clone());
|
||||
|
||||
// Send cross-chain alert
|
||||
self.send_cross_chain_message(
|
||||
ChainId("ethereum".to_string()),
|
||||
ChainId("arbitrum".to_string()),
|
||||
identity.clone(),
|
||||
CrossChainAction::LiquidationAlert {
|
||||
position_id: position.id.clone(),
|
||||
},
|
||||
)?;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Ok(liquidations)
|
||||
}
|
||||
|
||||
// ==== CRDT Merge Function ====
|
||||
|
||||
pub fn merge(&mut self, other: &Self) {
|
||||
// Merge identities
|
||||
for (id, identity) in &other.identities {
|
||||
self.identities
|
||||
.entry(id.clone())
|
||||
.or_insert_with(|| identity.clone());
|
||||
}
|
||||
|
||||
// Merge attestations
|
||||
for (id, attestation) in &other.attestations {
|
||||
self.attestations
|
||||
.entry(id.clone())
|
||||
.or_insert_with(|| attestation.clone());
|
||||
}
|
||||
|
||||
// Merge channels (simplified - real implementation would merge internal state)
|
||||
for (id, channel) in &other.channels {
|
||||
if let Some(our_channel) = self.channels.get_mut(id) {
|
||||
// Merge orders
|
||||
for (order_id, order) in &channel.orders.orders {
|
||||
our_channel
|
||||
.orders
|
||||
.orders
|
||||
.entry(order_id.clone())
|
||||
.or_insert_with(|| order.clone());
|
||||
}
|
||||
// Merge executions
|
||||
for (exec_id, execution) in &channel.orders.executions {
|
||||
our_channel
|
||||
.orders
|
||||
.executions
|
||||
.entry(exec_id.clone())
|
||||
.or_insert_with(|| execution.clone());
|
||||
}
|
||||
// Update nonce to max
|
||||
our_channel.nonce = our_channel.nonce.max(channel.nonce);
|
||||
} else {
|
||||
self.channels.insert(id.clone(), channel.clone());
|
||||
}
|
||||
}
|
||||
|
||||
// Merge price submissions
|
||||
for (key, submissions) in &other.price_submissions {
|
||||
self.price_submissions
|
||||
.entry(key.clone())
|
||||
.or_insert_with(Vec::new)
|
||||
.extend(submissions.clone());
|
||||
}
|
||||
|
||||
// Merge cross-chain messages
|
||||
for (id, message) in &other.cross_chain_messages {
|
||||
self.cross_chain_messages
|
||||
.entry(id.clone())
|
||||
.or_insert_with(|| message.clone());
|
||||
}
|
||||
}
|
||||
|
||||
fn timestamp() -> u64 {
|
||||
SystemTime::now()
|
||||
.duration_since(UNIX_EPOCH)
|
||||
.unwrap()
|
||||
.as_secs()
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn test_integrated_platform() {
|
||||
let mut platform = IntegratedDeFiPlatform::new();
|
||||
|
||||
// Create identities
|
||||
let alice = IdentityId("alice".to_string());
|
||||
let bob = IdentityId("bob".to_string());
|
||||
let oracle = IdentityId("oracle1".to_string());
|
||||
|
||||
platform
|
||||
.create_identity(alice.clone(), vec![1, 2, 3])
|
||||
.unwrap();
|
||||
platform
|
||||
.create_identity(bob.clone(), vec![4, 5, 6])
|
||||
.unwrap();
|
||||
platform
|
||||
.create_identity(oracle.clone(), vec![7, 8, 9])
|
||||
.unwrap();
|
||||
|
||||
// Build reputation through attestations
|
||||
platform
|
||||
.identities
|
||||
.get_mut(&alice)
|
||||
.unwrap()
|
||||
.reputation_score = 1.0;
|
||||
platform
|
||||
.create_attestation(alice.clone(), bob.clone(), "TrustedTrader".to_string(), 90)
|
||||
.unwrap();
|
||||
|
||||
platform
|
||||
.identities
|
||||
.get_mut(&oracle)
|
||||
.unwrap()
|
||||
.reputation_score = 2.0;
|
||||
|
||||
// Create trading channel
|
||||
let channel_id = platform
|
||||
.create_channel(vec![alice.clone(), bob.clone()])
|
||||
.unwrap();
|
||||
|
||||
// Add some balances
|
||||
let channel = platform.channels.get_mut(&channel_id).unwrap();
|
||||
channel
|
||||
.balances
|
||||
.insert((alice.clone(), "ETH".to_string()), 10_000_000);
|
||||
channel
|
||||
.balances
|
||||
.insert((bob.clone(), "USDC".to_string()), 25_000_000_000);
|
||||
|
||||
// Submit oracle prices
|
||||
platform
|
||||
.submit_price(oracle.clone(), "ETH".to_string(), 2500_000_000, 95)
|
||||
.unwrap();
|
||||
|
||||
// Place orders
|
||||
platform
|
||||
.place_order(
|
||||
&channel_id,
|
||||
&alice,
|
||||
OrderSide::Sell,
|
||||
2505_000_000,
|
||||
5_000_000,
|
||||
)
|
||||
.unwrap();
|
||||
platform
|
||||
.place_order(&channel_id, &bob, OrderSide::Buy, 2510_000_000, 3_000_000)
|
||||
.unwrap();
|
||||
|
||||
// Check that orders matched
|
||||
let channel = platform.channels.get(&channel_id).unwrap();
|
||||
assert!(!channel.orders.executions.is_empty());
|
||||
|
||||
// Check cross-chain functionality
|
||||
platform
|
||||
.send_cross_chain_message(
|
||||
ChainId("ethereum".to_string()),
|
||||
ChainId("polygon".to_string()),
|
||||
alice.clone(),
|
||||
CrossChainAction::Deposit {
|
||||
token: "USDC".to_string(),
|
||||
amount: 1000_000_000,
|
||||
},
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
assert!(!platform.cross_chain_messages.is_empty());
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user