use fuels::accounts::predicate::Predicate; use fuels::prelude::ViewOnlyAccount; use fuels::types::{Address, Bits256}; use spark_sdk::{ limit_orders_utils::{ limit_orders_interactions::{create_order, fulfill_order}, LimitOrderPredicateConfigurables, }, proxy_utils::{deploy_proxy_contract, ProxySendFundsToPredicateParams}, }; use src20_sdk::{token_abi_calls, TokenContract}; use crate::utils::local_tests_utils::{init_tokens, init_wallets}; use crate::utils::print_title; // Alice wants to exchange 1000 USDC for 200 UNI // Bob wants to exchange 200 UNI for 1000 USDC /* inputs ResourcePredicate { resource: Coin { amount: 1000000000, asset_id: USDC, owner: Predicate, status: Unspent }} ResourceSigned { resource: Coin { amount: 200000000000, asset_id: UNI, owner: Bob, status: Unspent }} outputs Coin { to: Alice, amount: 200000000000, asset_id: UNI } Change { to: Bob, amount: 0, asset_id: UNI } Coin { to: Bob, amount: 1000000000, asset_id: USDC } Change { to: Predicate, amount: 0, asset_id: USDC } */ #[tokio::test] async fn fulfill_order_test() { print_title("Fulfill Order Test"); //--------------- WALLETS --------------- let wallets = init_wallets().await; let admin = wallets[0].clone(); let alice = wallets[1].clone(); let alice_address = Address::from(alice.address()); let bob = wallets[2].clone(); let bob_address = Address::from(bob.address()); println!("admin_address = 0x{:?}", Address::from(admin.address())); println!("alice_address = 0x{:?}", alice_address); println!("bob_address = 0x{:?}\n", bob_address); //--------------- TOKENS --------------- let assets = init_tokens(&admin).await; let usdc = assets.get("USDC").unwrap(); let usdc_instance = TokenContract::new(usdc.contract_id.into(), admin.clone()); let uni = assets.get("UNI").unwrap(); let uni_instance = TokenContract::new(uni.contract_id.into(), admin.clone()); let amount0 = 1_000_000_000; //1000 USDC let amount1 = 200_000_000_000; // 200 UNI println!("USDC AssetId (asset0) = 0x{:?}", usdc.asset_id); println!("UNI AssetId (asset1) = 0x{:?}", uni.asset_id); println!("amount0 = {:?} USDC", amount0 / 1_000_000); println!("amount1 = {:?} UNI", amount1 / 1_000_000_000); let price_decimals = 9; let exp = (price_decimals + usdc.config.decimals - uni.config.decimals).into(); let price = amount1 * 10u64.pow(exp) / amount0; println!("Price = {:?} UNI/USDC", price); token_abi_calls::mint(&usdc_instance, amount0, alice_address) .await .unwrap(); token_abi_calls::mint(&uni_instance, amount1, bob_address) .await .unwrap(); println!("Alice minting {:?} USDC", amount0 / 1_000_000); println!("Bob minting {:?} UNI\n", amount1 / 1_000_000_000); //--------------- PREDICATE --------- let configurables = LimitOrderPredicateConfigurables::new() .set_ASSET0(Bits256::from_hex_str(&usdc.asset_id.to_string()).unwrap()) .set_ASSET1(Bits256::from_hex_str(&uni.asset_id.to_string()).unwrap()) .set_MAKER(Bits256::from_hex_str(&alice.address().hash().to_string()).unwrap()) .set_ASSET0_DECIMALS(usdc.config.decimals) .set_ASSET1_DECIMALS(uni.config.decimals) .set_PRICE(price) .set_MIN_FULFILL_AMOUNT0(amount0); let predicate: Predicate = Predicate::load_from("./limit-order-predicate/out/debug/limit-order-predicate.bin") .unwrap() .with_configurables(configurables) .with_provider(admin.provider().unwrap().clone()); println!("Predicate root = {:?}\n", predicate.address()); // ==================== ALICE CREATES THE ORDER (TRANSFER) ==================== // Alice transfer amount0 of usdc.asset_id to the predicate root assert!(alice.get_asset_balance(&usdc.asset_id).await.unwrap() == amount0); let params = ProxySendFundsToPredicateParams { predicate_root: predicate.address().into(), asset_0: usdc.contract_id.into(), asset_1: uni.contract_id.into(), maker: alice_address, min_fulfill_amount_0: 1, price, asset_0_decimals: 6, asset_1_decimals: 9, price_decimals: 9, }; let proxy = deploy_proxy_contract(&alice, "proxy-contract/out/debug/proxy-contract.bin").await; let proxy_address = format!("0x{}", proxy.contract_id().hash); println!("proxyAddress = {:?}", proxy_address); create_order(&alice, &proxy_address, params, amount0) .await .unwrap(); let initial_bob_usdc_balance = bob.get_asset_balance(&usdc.asset_id).await.unwrap(); let initial_bob_uni_balance = bob.get_asset_balance(&uni.asset_id).await.unwrap(); let initial_alice_uni_balance = alice.get_asset_balance(&uni.asset_id).await.unwrap(); // The predicate root has received the coin let predicate_usdc_balance = predicate.get_asset_balance(&usdc.asset_id).await.unwrap(); assert_eq!(predicate_usdc_balance, amount0); println!("Alice transfers 1000 USDC to predicate\n"); fulfill_order( &bob, &predicate, alice.address(), usdc.asset_id, amount0, uni.asset_id, amount1, ) .await .unwrap(); println!("Bob transfers 200 UNI to predicate, thus closing the order\n"); let predicate_balance = predicate.get_asset_balance(&usdc.asset_id).await.unwrap(); let bob_uni_balance = bob.get_asset_balance(&uni.asset_id).await.unwrap(); let bob_usdc_balance = bob.get_asset_balance(&usdc.asset_id).await.unwrap(); let alice_uni_balance = alice.get_asset_balance(&uni.asset_id).await.unwrap(); // The predicate root's coin has been spent assert_eq!(predicate_balance, 0); // Receiver has been paid `ask_amount` assert_eq!(alice_uni_balance, initial_alice_uni_balance + amount1); // Taker has sent `ask_amount` of the asked token and received `amount0` of the offered token in return assert_eq!(bob_uni_balance, initial_bob_uni_balance - amount1); assert_eq!(bob_usdc_balance, initial_bob_usdc_balance + amount0); println!("Alice balance 200 UNI"); println!("Bob balance 1000 USDC\n\n"); }