From 4d0253c0b40d5fe518b9a1d18400292d8323fd12 Mon Sep 17 00:00:00 2001 From: esteblock Date: Sat, 2 Nov 2024 14:02:37 -0300 Subject: [PATCH 1/7] add CometDEX submodule --- .gitmodules | 3 +++ README.md | 4 ++++ protocols/CometDEX | 1 + 3 files changed, 8 insertions(+) create mode 160000 protocols/CometDEX diff --git a/.gitmodules b/.gitmodules index d22cb665..a7d3125d 100644 --- a/.gitmodules +++ b/.gitmodules @@ -4,3 +4,6 @@ [submodule "protocols/phoenix-contracts"] path = protocols/phoenix-contracts url = https://github.com/Phoenix-Protocol-Group/phoenix-contracts/ +[submodule "protocols/CometDEX"] + path = protocols/CometDEX + url = https://github.com/mootz12/comet-contracts-v1/ diff --git a/README.md b/README.md index 019fb79c..7716327b 100644 --- a/README.md +++ b/README.md @@ -4,6 +4,10 @@ The Soroswap Aggregator Contract currently aggregates different Soroban based AM Check the documentation in https://docs.soroswap.finance/ and the [Security Audit Report](./audits/2024-08-31_Soroswap_Aggregator_Audit_by_RuntimeVerification.pdf) and the [Security Audit Findings Summary](audits/2024-08-31_Soroswap_Aggregator_Audit_Summary_by_RuntimeVerification.pdf) written by [Runtime Verification](https://runtimeverification.com). + +For Deployed address check the [`./public/mainnet.json`](./public/mainnet.json) + + # Setup and Deployment **For standalone development read #Development section** diff --git a/protocols/CometDEX b/protocols/CometDEX new file mode 160000 index 00000000..ef4cbfad --- /dev/null +++ b/protocols/CometDEX @@ -0,0 +1 @@ +Subproject commit ef4cbfad0a35202ad267c14d163d2f362995a8d3 From bff2f4526ef42300a387a1aa551d41ee849d8652 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rahim=20Klab=C3=A9r?= Date: Thu, 19 Dec 2024 11:41:25 +0100 Subject: [PATCH 2/7] Create comet adapter --- contracts/Cargo.lock | 8 + contracts/adapters/comet/Cargo.toml | 21 ++ contracts/adapters/comet/Makefile | 17 ++ .../comet/comet_contracts/comet_factory.wasm | Bin 0 -> 2502 bytes .../comet/comet_contracts/comet_pool.wasm | Bin 0 -> 29046 bytes contracts/adapters/comet/src/event.rs | 47 ++++ contracts/adapters/comet/src/lib.rs | 123 ++++++++++ .../adapters/comet/src/protocol_interface.rs | 54 +++++ contracts/adapters/comet/src/storage.rs | 51 +++++ contracts/adapters/comet/src/test.rs | 119 ++++++++++ .../adapters/comet/src/test/comet_setup.rs | 38 ++++ .../adapters/comet/src/test/initialize.rs | 75 +++++++ .../src/test/swap_exact_tokens_for_tokens.rs | 212 ++++++++++++++++++ .../src/test/swap_tokens_for_exact_tokens.rs | 197 ++++++++++++++++ contracts/aggregator/src/test.rs | 21 +- .../aggregator/src/test/budget_cpu_mem.rs | 4 +- contracts/aggregator/src/test/comet_setup.rs | 74 ++++++ contracts/aggregator/src/test/events.rs | 4 +- contracts/aggregator/src/test/get_adapters.rs | 4 +- contracts/aggregator/src/test/initialize.rs | 4 +- .../aggregator/src/test/remove_adapter.rs | 6 +- .../src/test/set_pause_get_paused.rs | 34 ++- .../src/test/swap_exact_tokens_for_tokens.rs | 193 ++++++++++++++++ .../src/test/swap_tokens_for_exact_tokens.rs | 205 +++++++++++++++++ .../aggregator/src/test/update_adapters.rs | 10 +- 25 files changed, 1502 insertions(+), 19 deletions(-) create mode 100644 contracts/adapters/comet/Cargo.toml create mode 100644 contracts/adapters/comet/Makefile create mode 100644 contracts/adapters/comet/comet_contracts/comet_factory.wasm create mode 100644 contracts/adapters/comet/comet_contracts/comet_pool.wasm create mode 100644 contracts/adapters/comet/src/event.rs create mode 100644 contracts/adapters/comet/src/lib.rs create mode 100644 contracts/adapters/comet/src/protocol_interface.rs create mode 100644 contracts/adapters/comet/src/storage.rs create mode 100644 contracts/adapters/comet/src/test.rs create mode 100644 contracts/adapters/comet/src/test/comet_setup.rs create mode 100644 contracts/adapters/comet/src/test/initialize.rs create mode 100644 contracts/adapters/comet/src/test/swap_exact_tokens_for_tokens.rs create mode 100644 contracts/adapters/comet/src/test/swap_tokens_for_exact_tokens.rs create mode 100644 contracts/aggregator/src/test/comet_setup.rs diff --git a/contracts/Cargo.lock b/contracts/Cargo.lock index b9887897..8eb9b988 100644 --- a/contracts/Cargo.lock +++ b/contracts/Cargo.lock @@ -151,6 +151,14 @@ dependencies = [ "windows-targets", ] +[[package]] +name = "comet-adapter" +version = "0.1.0" +dependencies = [ + "adapter-interface", + "soroban-sdk", +] + [[package]] name = "const-oid" version = "0.9.6" diff --git a/contracts/adapters/comet/Cargo.toml b/contracts/adapters/comet/Cargo.toml new file mode 100644 index 00000000..3b4e2453 --- /dev/null +++ b/contracts/adapters/comet/Cargo.toml @@ -0,0 +1,21 @@ +[package] +name = "comet-adapter" +version = "0.1.0" +edition = { workspace = true } +description = "Comet-Adapter is a smart contract on the Soroban platform, tailored for use with the Soroswap-Aggregator. It facilitates efficient transaction routing through the Comet protocol." +homepage = { workspace = true } +repository = { workspace = true } +authors = ["rahimklaber "] +readme = "README.md" +keywords = ["no_std", "wasm", "soroswap", "amm", "soroban"] +publish = true + +[lib] +crate-type = ["cdylib"] + +[dependencies] +soroban-sdk = { workspace = true } +adapter-interface = { workspace = true } + +[dev-dependencies] +soroban-sdk = { workspace = true, features = ["testutils"] } \ No newline at end of file diff --git a/contracts/adapters/comet/Makefile b/contracts/adapters/comet/Makefile new file mode 100644 index 00000000..dc20fa24 --- /dev/null +++ b/contracts/adapters/comet/Makefile @@ -0,0 +1,17 @@ +default: build + +all: test + +test: build + cargo test + +build: + cargo build --target wasm32-unknown-unknown --release + soroban contract optimize --wasm ../../target/wasm32-unknown-unknown/release/comet_adapter.wasm + @rm ../../target/wasm32-unknown-unknown/release/comet_adapter.wasm + +fmt: + cargo fmt --all --check + +clean: + cargo clean \ No newline at end of file diff --git a/contracts/adapters/comet/comet_contracts/comet_factory.wasm b/contracts/adapters/comet/comet_contracts/comet_factory.wasm new file mode 100644 index 0000000000000000000000000000000000000000..9db8020a75832879ce60472bcf1bf129d4c6cf62 GIT binary patch literal 2502 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 literal 0 HcmV?d00001 diff --git a/contracts/adapters/comet/src/event.rs b/contracts/adapters/comet/src/event.rs new file mode 100644 index 00000000..bd5f10bc --- /dev/null +++ b/contracts/adapters/comet/src/event.rs @@ -0,0 +1,47 @@ +//! Definition of the Events used in the contract +use soroban_sdk::{contracttype, symbol_short, Env, Address, Vec, String}; + +// INITIALIZED +#[contracttype] +#[derive(Clone, Debug, Eq, PartialEq)] +pub struct InitializedEvent { + pub state: bool, + pub protocol_id: String, + pub protocol_address: Address +} + +pub(crate) fn initialized(e: &Env, state: bool, protocol_id: String, protocol_address: Address) { + + let event: InitializedEvent = InitializedEvent { + state: state, + protocol_id, + protocol_address, + }; + e.events().publish(("SoroswapAggregatorAdapter", symbol_short!("init")), event); +} + +// SWAP EVENT +#[contracttype] +#[derive(Clone, Debug, Eq, PartialEq)] +pub struct SwapEvent { + pub amount_in: i128, + pub path: Vec
, + pub to: Address +} + +pub(crate) fn swap( + e: &Env, + amount_in: i128, + path: Vec
, + to: Address +) { + let event = SwapEvent { + amount_in, + path, + to, + }; + + e.events().publish(("SoroswapAggregatorAdapter", symbol_short!("swap")), event); +} + +// TODO IMPROVE EVENTS \ No newline at end of file diff --git a/contracts/adapters/comet/src/lib.rs b/contracts/adapters/comet/src/lib.rs new file mode 100644 index 00000000..ef0939ed --- /dev/null +++ b/contracts/adapters/comet/src/lib.rs @@ -0,0 +1,123 @@ +#![no_std] +use soroban_sdk::{contract, contractimpl, Address, Env, String, Vec}; + +mod event; +mod storage; +mod protocol_interface; +mod test; + +use storage::{ + extend_instance_ttl, + set_initialized, + is_initialized, + set_protocol_id, + get_protocol_id, + set_protocol_address, + get_protocol_address, +}; +use adapter_interface::{AdapterTrait, AdapterError}; +use protocol_interface::{protocol_swap_exact_tokens_for_tokens, + protocol_swap_tokens_for_exact_tokens}; + +fn check_initialized(e: &Env) -> Result<(), AdapterError> { + if is_initialized(e) { + Ok(()) + } else { + Err(AdapterError::NotInitialized) + } +} + +fn check_deadline(e: &Env, deadline: u64) -> Result<(), AdapterError> { + if e.ledger().timestamp() >= deadline{ + Err(AdapterError::DeadlineExpired) + }else{ + Ok(()) + } +} + +#[contract] +struct CometAggregatorAdapter; + +#[contractimpl] +impl AdapterTrait for CometAggregatorAdapter { + fn initialize( + e: Env, + protocol_id: String, + protocol_address: Address, + ) -> Result<(), AdapterError> { + if check_initialized(&e).is_ok() { + return Err(AdapterError::AlreadyInitialized); + } + + set_protocol_id(&e, protocol_id.clone()); + set_protocol_address(&e, protocol_address.clone()); + + set_initialized(&e); + event::initialized(&e, true, protocol_id, protocol_address); + extend_instance_ttl(&e); + Ok(()) + } + + fn swap_exact_tokens_for_tokens( + e: Env, + amount_in: i128, + amount_out_min: i128, + path: Vec
, + to: Address, + deadline: u64, + ) -> Result, AdapterError> { + check_initialized(&e)?; + extend_instance_ttl(&e); + check_deadline(&e, deadline)?; + to.require_auth(); + + let swap_result = protocol_swap_exact_tokens_for_tokens( + &e, + &amount_in, + &amount_out_min, + &path, + &to, + )?; + + event::swap(&e, amount_in, path, to); + Ok(swap_result) + } + + fn swap_tokens_for_exact_tokens( + e: Env, + amount_out: i128, + amount_in_max: i128, + path: Vec
, + to: Address, + deadline: u64, + ) -> Result, AdapterError> { + check_initialized(&e)?; + extend_instance_ttl(&e); + check_deadline(&e, deadline)?; + to.require_auth(); + + let swap_result = protocol_swap_tokens_for_exact_tokens( + &e, + &amount_out, + &amount_in_max, + &path, + &to, + )?; + + event::swap(&e, amount_in_max, path, to); + Ok(swap_result) + } + + /* *** Read only functions: *** */ + fn get_protocol_id(e: &Env) -> Result { + check_initialized(&e)?; + extend_instance_ttl(&e); + Ok(get_protocol_id(e)?) + } + + fn get_protocol_address(e: &Env) -> Result { + check_initialized(&e)?; + extend_instance_ttl(&e); + Ok(get_protocol_address(e)?) + } +} diff --git a/contracts/adapters/comet/src/protocol_interface.rs b/contracts/adapters/comet/src/protocol_interface.rs new file mode 100644 index 00000000..0272ddce --- /dev/null +++ b/contracts/adapters/comet/src/protocol_interface.rs @@ -0,0 +1,54 @@ +use soroban_sdk::{vec, Address, Env, Vec}; +use crate::storage::get_protocol_address; +use adapter_interface::AdapterError; + +soroban_sdk::contractimport!( + file = "./comet_contracts/comet_pool.wasm" +); +pub type CometPoolClient<'a> = Client<'a>; + +pub fn protocol_swap_exact_tokens_for_tokens( + e: &Env, + amount_in: &i128, + amount_out_min: &i128, + path: &Vec
, + to: &Address, +) -> Result, AdapterError> { + + let comet_pool_address = get_protocol_address(&e)?; + let comet_client = CometPoolClient::new(&e, &comet_pool_address); + + let (amount_out, _) = comet_client.swap_exact_amount_in( + &path.get(0).unwrap(), + amount_in, + &path.get(1).unwrap(), + amount_out_min, + &i128::MAX, + to + ); + + Ok(vec![e, *amount_in, amount_out]) +} + +pub fn protocol_swap_tokens_for_exact_tokens( + e: &Env, + amount_out: &i128, + amount_in_max: &i128, + path: &Vec
, + to: &Address, +) -> Result, AdapterError> { + + let comet_pool_address = get_protocol_address(&e)?; + let comet_client = CometPoolClient::new(&e, &comet_pool_address); + + let (amount_in, _) = comet_client.swap_exact_amount_out( + &path.get(0).unwrap(), + amount_in_max, + &path.get(1).unwrap(), + amount_out, + &i128::MAX, + to + ); + + Ok(vec![e, amount_in, *amount_out]) +} diff --git a/contracts/adapters/comet/src/storage.rs b/contracts/adapters/comet/src/storage.rs new file mode 100644 index 00000000..dee8a44a --- /dev/null +++ b/contracts/adapters/comet/src/storage.rs @@ -0,0 +1,51 @@ +use soroban_sdk::{contracttype, Env, Address, String}; +use adapter_interface::AdapterError; + +#[derive(Clone)] +#[contracttype] + +enum DataKey { + Initialized, + ProtocolId, + ProtocolAddress, +} + +const DAY_IN_LEDGERS: u32 = 17280; +const INSTANCE_BUMP_AMOUNT: u32 = 60 * DAY_IN_LEDGERS; +const INSTANCE_LIFETIME_THRESHOLD: u32 = INSTANCE_BUMP_AMOUNT - DAY_IN_LEDGERS; + +pub fn extend_instance_ttl(e: &Env) { + e.storage() + .instance() + .extend_ttl(INSTANCE_LIFETIME_THRESHOLD, INSTANCE_BUMP_AMOUNT); +} + +/* INITIALIZED */ +pub fn set_initialized(e: &Env) { + e.storage().instance().set(&DataKey::Initialized, &true); +} + +pub fn is_initialized(e: &Env) -> bool { + e.storage().instance().has(&DataKey::Initialized) +} + + +/* PROTOCOL ID - STRING */ +pub fn set_protocol_id(e: &Env, protocol_id: String) { + e.storage().instance().set(&DataKey::ProtocolId, &protocol_id); +} + +pub fn get_protocol_id(e: &Env) -> Result { + e.storage().instance().get(&DataKey::ProtocolId).ok_or(AdapterError::NotInitialized) +} + + +/* PROTOCOL ADDRESS */ +pub fn set_protocol_address(e: &Env, address: Address) { + e.storage().instance().set(&DataKey::ProtocolAddress, &address); +} + +pub fn get_protocol_address(e: &Env) -> Result { + e.storage().instance().get(&DataKey::ProtocolAddress).ok_or(AdapterError::NotInitialized) +} + diff --git a/contracts/adapters/comet/src/test.rs b/contracts/adapters/comet/src/test.rs new file mode 100644 index 00000000..1597b022 --- /dev/null +++ b/contracts/adapters/comet/src/test.rs @@ -0,0 +1,119 @@ +#![cfg(test)] +extern crate std; +pub mod comet_setup; + +use comet_adapter_contract::CometAggregatorAdapterClientFromWasm; +use comet_setup::{create_comet_factory, create_token_contract, pair::CometPairClient}; +use soroban_sdk::{ + testutils::Address as _, token::TokenClient, vec, Address, BytesN, Env, IntoVal, String, + Symbol, Val, Vec, +}; + +mod deployer_contract { + soroban_sdk::contractimport!(file = "../../target/wasm32-unknown-unknown/release/soroswap_aggregator_deployer.optimized.wasm"); + pub type DeployerClient<'a> = Client<'a>; +} +use deployer_contract::DeployerClient; + +use crate::{CometAggregatorAdapter, CometAggregatorAdapterClient}; + +fn create_deployer<'a>(e: &Env) -> DeployerClient<'a> { + let deployer_address = &e.register_contract_wasm(None, deployer_contract::WASM); + let deployer = DeployerClient::new(e, deployer_address); + deployer +} + +fn create_comet_aggregator_adapter<'a>(e: &Env) -> CometAggregatorAdapterClient<'a> { + CometAggregatorAdapterClient::new(e, &e.register_contract(None, CometAggregatorAdapter {})) +} + +pub mod comet_adapter_contract { + soroban_sdk::contractimport!( + file = "../../target/wasm32-unknown-unknown/release/comet_adapter.optimized.wasm" + ); + pub type CometAggregatorAdapterClientFromWasm<'a> = Client<'a>; +} + +pub struct CometAggregatorAdapterTest<'a> { + pub env: Env, + pub adapter_contract: CometAggregatorAdapterClientFromWasm<'a>, + pub adapter_contract_not_initialized: CometAggregatorAdapterClient<'a>, + pub comet_contract: CometPairClient<'a>, + // pub factory_contract: CometFactoryClient<'a>, + pub token_0: TokenClient<'a>, + pub token_1: TokenClient<'a>, + pub user: Address, + // pub admin: Address, +} + +impl<'a> CometAggregatorAdapterTest<'a> { + fn setup() -> Self { + let e = Env::default(); + e.mock_all_auths(); + + let admin = Address::generate(&e); + let user = Address::generate(&e); + + let (token_a, admin_token_a) = create_token_contract(&e, &admin); + let (token_b, admin_token_b) = create_token_contract(&e, &admin); + + admin_token_a.mint(&admin, &1000000_000_000_0); + admin_token_b.mint(&admin, &1000000_000_000_0); + + admin_token_a.mint(&user, &1000000_000_000_0); + admin_token_b.mint(&user, &1000000_000_000_0); + + let comet_factory_client = create_comet_factory(&e); + let comet_address = comet_factory_client.new_c_pool( + &BytesN::from_array(&e, &[0; 32]), + &admin, + &vec![&e, token_a.address.clone(), token_b.address.clone()], + &vec![&e, 8000000, 2000000], + &vec![&e, 800000000000, 200000000000], // these balances make the tokens have an equal value + &30000, + ); + let comet_client = CometPairClient::new(&e, &comet_address); + + let adapter_wasm_hash = e + .deployer() + .upload_contract_wasm(comet_adapter_contract::WASM); + let deployer_client = create_deployer(&e); + + let adapter_contract_not_initialized = create_comet_aggregator_adapter(&e); + + // Deploy contract using deployer, and include an init function to call. + let salt = BytesN::from_array(&e, &[0; 32]); + let init_fn = Symbol::new(&e, &("initialize")); + + let protocol_id = String::from_str(&e, "comet_blend"); + let protocol_address = comet_address.clone(); + + // Convert the arguments into a Vec + let init_fn_args: Vec = (protocol_id.clone(), protocol_address.clone()).into_val(&e); + + let (adapter_address, _init_result) = deployer_client.deploy( + &deployer_client.address, + &adapter_wasm_hash, + &salt, + &init_fn, + &init_fn_args, + ); + + let adapter_contract = CometAggregatorAdapterClientFromWasm::new(&e, &adapter_address); + + CometAggregatorAdapterTest { + env: e.clone(), + adapter_contract: adapter_contract, + adapter_contract_not_initialized: adapter_contract_not_initialized, + comet_contract: comet_client, + // factory_contract: comet_factory_client, + token_0: token_a, + token_1: token_b, + user: user, + } + } +} + +pub mod initialize; +pub mod swap_exact_tokens_for_tokens; +pub mod swap_tokens_for_exact_tokens; diff --git a/contracts/adapters/comet/src/test/comet_setup.rs b/contracts/adapters/comet/src/test/comet_setup.rs new file mode 100644 index 00000000..3317404c --- /dev/null +++ b/contracts/adapters/comet/src/test/comet_setup.rs @@ -0,0 +1,38 @@ +#![cfg(test)] +extern crate std; +use soroban_sdk::{ + token::{StellarAssetClient as TokenAdminClient, TokenClient}, Address, BytesN, Env +}; + + +pub mod pair{ + soroban_sdk::contractimport!(file = "./comet_contracts/comet_pool.wasm"); + pub type CometPairClient<'a> = Client<'a>; +} + +fn pair_contract_wasm(e: &Env) -> BytesN<32> { + e.deployer().upload_contract_wasm(pair::WASM) +} + +pub mod factory{ + soroban_sdk::contractimport!(file = "./comet_contracts/comet_factory.wasm"); + pub type CometFactoryClient<'a> = Client<'a>; +} +use factory::CometFactoryClient; + +pub fn create_comet_factory<'a>(e: &Env) -> CometFactoryClient{ + let pair_hash = pair_contract_wasm(e); + + let factory_address = e.register_contract_wasm(None, factory::WASM); + let factory_client = CometFactoryClient::new(&e.clone(), &factory_address); + + factory_client.init(&pair_hash); + + factory_client +} + +pub fn create_token_contract<'a>(e: &Env, admin: & Address) -> (TokenClient<'a>, TokenAdminClient<'a>) { + let address = e.register_stellar_asset_contract(admin.clone()); + + (TokenClient::new(&e, &address), TokenAdminClient::new(&e, &address)) +} \ No newline at end of file diff --git a/contracts/adapters/comet/src/test/initialize.rs b/contracts/adapters/comet/src/test/initialize.rs new file mode 100644 index 00000000..45a04110 --- /dev/null +++ b/contracts/adapters/comet/src/test/initialize.rs @@ -0,0 +1,75 @@ +use soroban_sdk::String; +use crate::test::CometAggregatorAdapterTest; +use adapter_interface::AdapterError; +use super::comet_adapter_contract::AdapterError as AdapterErrorDeployer; + +#[test] +fn test_initialize_and_get_values() { + let test = CometAggregatorAdapterTest::setup(); + + test.adapter_contract_not_initialized.initialize( + &String::from_str(&test.env, "comet_blend"), + &test.comet_contract.address); + + let protocol_id = test.adapter_contract_not_initialized.get_protocol_id(); + assert_eq!(protocol_id, String::from_str(&test.env, "comet_blend")); + + let protocol_address = test.adapter_contract_not_initialized.get_protocol_address(); + assert_eq!(protocol_address, test.comet_contract.address); +} + +#[test] +fn test_get_values() { + let test = CometAggregatorAdapterTest::setup(); + + let protocol_id = test.adapter_contract.get_protocol_id(); + assert_eq!(protocol_id, String::from_str(&test.env, "comet_blend")); + + let protocol_address = test.adapter_contract.get_protocol_address(); + assert_eq!(protocol_address, test.comet_contract.address); +} + +// test initialize twice +#[test] +fn test_initialize_twice() { + let test = CometAggregatorAdapterTest::setup(); + + test.adapter_contract_not_initialized.initialize( + &String::from_str(&test.env, "comet_blend"), + &test.comet_contract.address); + + let result = test.adapter_contract_not_initialized.try_initialize( + &String::from_str(&test.env, "comet_blend"), + &test.comet_contract.address); + + assert_eq!(result,Err(Ok(AdapterError::AlreadyInitialized))); +} + +#[test] +fn test_initialize_twice_deployer() { + let test = CometAggregatorAdapterTest::setup(); + + let result = test.adapter_contract.try_initialize( + &String::from_str(&test.env, "comet_blend"), + &test.comet_contract.address); + + assert_eq!(result,Err(Ok(AdapterErrorDeployer::AlreadyInitialized))); +} + +// test get protocol id not initialized +#[test] +fn test_get_protocol_id_not_initialized() { + let test = CometAggregatorAdapterTest::setup(); + + let result = test.adapter_contract_not_initialized.try_get_protocol_id(); + assert_eq!(result,Err(Ok(AdapterError::NotInitialized))); +} + +// test get protocol address not initialized +#[test] +fn test_get_protocol_address_not_initialized() { + let test = CometAggregatorAdapterTest::setup(); + + let result = test.adapter_contract_not_initialized.try_get_protocol_address(); + assert_eq!(result,Err(Ok(AdapterError::NotInitialized))); +} diff --git a/contracts/adapters/comet/src/test/swap_exact_tokens_for_tokens.rs b/contracts/adapters/comet/src/test/swap_exact_tokens_for_tokens.rs new file mode 100644 index 00000000..d831fd91 --- /dev/null +++ b/contracts/adapters/comet/src/test/swap_exact_tokens_for_tokens.rs @@ -0,0 +1,212 @@ +extern crate std; + +use soroban_sdk::{Address, vec, Vec}; +use crate::test::CometAggregatorAdapterTest; +use adapter_interface::AdapterError; + +#[test] +fn swap_exact_tokens_for_tokens_not_initialized() { + let test = CometAggregatorAdapterTest::setup(); + test.env.budget().reset_unlimited(); + let path: Vec
= Vec::new(&test.env); + + let result = test.adapter_contract_not_initialized.try_swap_exact_tokens_for_tokens( + &0, // amount_in + &0, // amount_out_min + &path, // path + &test.user, // to + &0, // deadline + ); + + assert_eq!(result,Err(Ok(AdapterError::NotInitialized))); + +} + +#[test] +#[should_panic(expected = "HostError: Error(Contract, #37)")] +fn swap_exact_tokens_for_tokens_amount_in_negative() { + let test = CometAggregatorAdapterTest::setup(); + test.env.budget().reset_unlimited(); + + let path: Vec
= vec![&test.env, test.token_0.address, test.token_1.address]; + + test.adapter_contract.swap_exact_tokens_for_tokens( + &-1, // amount_in + &0, // amount_out_min + &path, // path + &test.user, // to + &1, // deadline + ); +} + +#[test] +#[should_panic(expected = "HostError: Error(Contract, #37)")] +fn swap_exact_tokens_for_tokens_amount_out_min_negative() { + let test: CometAggregatorAdapterTest<'_> = CometAggregatorAdapterTest::setup(); + test.env.budget().reset_unlimited(); + + let path: Vec
= vec![&test.env, test.token_0.address, test.token_1.address]; + + test.adapter_contract.swap_exact_tokens_for_tokens( + &0, // amount_in + &-1, // amount_out_min + &path, // path + &test.user, // to + &1, // deadline + ); +} + +#[test] +#[should_panic(expected = "HostError: Error(Contract, #405)")] +fn swap_exact_tokens_for_tokens_expired() { + let test = CometAggregatorAdapterTest::setup(); + + let path: Vec
= vec![&test.env, test.token_0.address, test.token_1.address]; + + test.adapter_contract.swap_exact_tokens_for_tokens( + &10000, // amount_in + &1, // amount_out_min + &path, // path + &test.user, // to + &0, // deadline + ); +} + + + +#[test] +#[should_panic] // TODO: Test the imported error +fn try_swap_exact_tokens_for_tokens_invalid_path() { + let test = CometAggregatorAdapterTest::setup(); + + let deadline: u64 = test.env.ledger().timestamp() + 1000; + let path: Vec
= vec![&test.env, test.token_0.address.clone()]; + test.adapter_contract.swap_exact_tokens_for_tokens( + &0, // amount_in + &0, // amount_out_min + &path, // path + &test.user, // to + &deadline, // deadline + ); +} + + +#[test] +#[should_panic] // TODO: Test the imported error +fn try_swap_exact_tokens_for_tokens_insufficient_input_amount() { + let test = CometAggregatorAdapterTest::setup(); + + let deadline: u64 = test.env.ledger().timestamp() + 1000; + + let mut path: Vec
= Vec::new(&test.env); + path.push_back(test.token_0.address.clone()); + path.push_back(test.token_1.address.clone()); + + test.env.budget().reset_unlimited(); + + + let amount = 100_000; + + test.adapter_contract.swap_exact_tokens_for_tokens( + &amount, // amount_in + &amount, // amount_out_min + &path, // path + &test.user, // to + &deadline, // deadline + ); +} + + + +#[test] +#[should_panic(expected = "HostError: Error(Contract, #20)")] +fn swap_exact_tokens_for_tokens_insufficient_output_amount() { + let test = CometAggregatorAdapterTest::setup(); + + let deadline: u64 = test.env.ledger().timestamp() + 1000; + + let mut path: Vec
= Vec::new(&test.env); + path.push_back(test.token_0.address.clone()); + path.push_back(test.token_1.address.clone()); + + let amount_in = 1_000_000; + + let expected_amount_out = 996996; + + + // bone = 10**18 + // fee_ratio = (10**7 - 30000) * 10**11 => 997000000000000000 + // scaled_reserve_(out|in) = token_(out|in)_reserve * 10**7 + // adjusted_in = amount_in * fee_ratio / BONE + // base = (scaled_reserve_in * BONE) / (scaled_reserve_in) + adjusted_in) + // weight_ratio = in_token_weight * 10**18 / out_token_weight + // power = ((base / BONE) ** (weight_ratio / BONE)) * BONE // The code treats the numbers as 18 digit fixed point values. So code does it differently, but this is equivelant + // balance_ratio = BONE - power + // <= scaled_reserve_out * balance_ratio / BONE / 10**7 + + // scaled_reserve_in = 800000000000 * 10**7 => 8000000000000000000 + // scaled_reserve_out = 200000000000 * 10**7 => 2000000000000000000 + // adjusted_in = 1_000_000 * 997000000000000000 / BONE => 99700000000000000 + // base = (8000000000000000000 * BONE) / (8000000000000000000 + 99700000000000000) => 999998753751553137 + // weight_ratio = 8000000 * bone / 2000000 => 4000000000000000000 + // power = ((999998753751553137 / BONE) ** (4000000000000000000 / BONE)) * 10**18 => 999995015015531351 + // balance_ratio = BONE - 999995015015531351 => 4984984468649 + // 2000000000000000000 * 4984984468649 / BONE / 10**7 => 996996 + + test.env.budget().reset_unlimited(); + test.adapter_contract.swap_exact_tokens_for_tokens( + &amount_in, // amount_in + &(expected_amount_out + 1), // amount_out_min + &path, // path + &test.user, // to + &deadline, // deadline + ); +} + + + +#[test] +fn swap_exact_tokens_for_tokens_enough_output_amount() { + let test = CometAggregatorAdapterTest::setup(); + + let deadline: u64 = test.env.ledger().timestamp() + 1000; + + let mut path: Vec
= Vec::new(&test.env); + path.push_back(test.token_0.address.clone()); + path.push_back(test.token_1.address.clone()); + + let amount_in = 1_000_000; + + let expected_amount_out = 996996; + + // bone = 10**18 + // fee_ratio = (10**7 - 30000) * 10**11 => 997000000000000000 + // scaled_reserve_(out|in) = token_(out|in)_reserve * 10**7 + // adjusted_in = amount_in * fee_ratio / BONE + // base = (scaled_reserve_in * BONE) / (scaled_reserve_in) + adjusted_in) + // weight_ratio = in_token_weight * 10**18 / out_token_weight + // power = ((base / BONE) ** (weight_ratio / BONE)) * BONE // The code treats the numbers as 18 digit fixed point values. So code does it differently, but this is equivelant + // balance_ratio = BONE - power + // <= scaled_reserve_out * balance_ratio / BONE / 10**7 + + // scaled_reserve_in = 800000000000 * 10**7 => 8000000000000000000 + // scaled_reserve_out = 200000000000 * 10**7 => 2000000000000000000 + // adjusted_in = 1_000_000 * 997000000000000000 / BONE => 99700000000000000 + // base = (8000000000000000000 * BONE) / (8000000000000000000 + 99700000000000000) => 999998753751553137 + // weight_ratio = 8000000 * bone / 2000000 => 4000000000000000000 + // power = ((999998753751553137 / BONE) ** (4000000000000000000 / BONE)) * 10**18 => 999995015015531351 + // balance_ratio = BONE - 999995015015531351 => 4984984468649 + // 2000000000000000000 * 4984984468649 / BONE / 10**7 => 996996 + + test.env.budget().reset_unlimited(); + let executed_amounts = test.adapter_contract.swap_exact_tokens_for_tokens( + &amount_in, //amount_in + &(expected_amount_out), // amount_out_min + &path, // path + &test.user, // to + &deadline); // deadline + + assert_eq!(executed_amounts.get(0).unwrap(), amount_in); + assert_eq!(executed_amounts.get(1).unwrap(), expected_amount_out); + +} \ No newline at end of file diff --git a/contracts/adapters/comet/src/test/swap_tokens_for_exact_tokens.rs b/contracts/adapters/comet/src/test/swap_tokens_for_exact_tokens.rs new file mode 100644 index 00000000..8457ec52 --- /dev/null +++ b/contracts/adapters/comet/src/test/swap_tokens_for_exact_tokens.rs @@ -0,0 +1,197 @@ +extern crate std; + +use soroban_sdk::{Address, vec, Vec}; +use crate::test::CometAggregatorAdapterTest; +use adapter_interface::AdapterError; + +#[test] +fn swap_tokens_for_exact_tokens_not_initialized() { + let test = CometAggregatorAdapterTest::setup(); + test.env.budget().reset_unlimited(); + let path: Vec
= Vec::new(&test.env); + + let result = test.adapter_contract_not_initialized.try_swap_tokens_for_exact_tokens( + &0, // amount_out + &0, // amount_in_max + &path, // path + &test.user, // to + &0, // deadline + ); + + assert_eq!(result,Err(Ok(AdapterError::NotInitialized))); + +} + +#[test] +#[should_panic(expected = "HostError: Error(Contract, #37)")] +fn swap_tokens_for_exact_tokens_amount_out_negative() { + let test = CometAggregatorAdapterTest::setup(); + test.env.budget().reset_unlimited(); + + let path: Vec
= vec![&test.env, test.token_0.address, test.token_1.address]; + + test.adapter_contract.swap_tokens_for_exact_tokens( + &-1, // amount_out + &0, // amount_in_max + &path, // path + &test.user, // to + &1, // deadline + ); +} + +#[test] +#[should_panic(expected = "HostError: Error(Contract, #37)")] +fn swap_tokens_for_exact_tokens_amount_in_max_negative() { + let test = CometAggregatorAdapterTest::setup(); + test.env.budget().reset_unlimited(); + + let path: Vec
= vec![&test.env, test.token_0.address, test.token_1.address]; + + test.adapter_contract.swap_tokens_for_exact_tokens( + &1, // amount_out + &-1, // amount_in_max + &path, // path + &test.user, // to + &1, // deadline + ); +} + +#[test] +#[should_panic(expected = "HostError: Error(Contract, #405)")] +fn swap_tokens_for_exact_tokens_expired() { + let test = CometAggregatorAdapterTest::setup(); + + let path: Vec
= Vec::new(&test.env); + + test.adapter_contract.swap_tokens_for_exact_tokens( + &0, // amount_out + &0, // amount_in_max + &path, // path + &test.user, // to + &0, // deadline + ); +} + + +#[test] +#[should_panic] // TODO: Test the imported error +fn try_swap_tokens_for_exact_tokens_invalid_path() { + let test = CometAggregatorAdapterTest::setup(); + + let deadline: u64 = test.env.ledger().timestamp() + 1000; + + let path: Vec
= vec![&test.env, test.token_0.address.clone()]; + + test.adapter_contract.swap_tokens_for_exact_tokens( // add try_ to test the error + &0, // amount_out + &0, // amount_in_max + &path, // path + &test.user, // to + &deadline, // deadline + ); + + // assert_eq!(result, Err(Ok(CombinedRouterError::LibraryInvalidPath))); +} + + +#[test] +#[should_panic(expected = "HostError: Error(Contract, #19)")] +fn try_swap_tokens_for_exact_tokens_insufficient_input_amount() { + let test = CometAggregatorAdapterTest::setup(); + + let deadline: u64 = test.env.ledger().timestamp() + 1000; + + let mut path: Vec
= Vec::new(&test.env); + path.push_back(test.token_0.address.clone()); + path.push_back(test.token_1.address.clone()); + + + test.env.budget().reset_unlimited(); + + let amount_out = 1_000_000; + let expected_amount_in = 1_003_015; + + // bone = 10**18 + // fee_ratio = (10**7 - 30000) * 10**11 => 997000000000000000 + // scaled_reserve_(out|in) = token_(out|in)_reserve * 10**7 + // adjusted_out = amount_out * 10**7 + // base = (scaled_reserve_out * BONE) / (scaled_reserve_out) - adjusted_out) + // weight_ratio = out_token_weight * 10**18 / out_token_weight + // power = ((base / BONE) ** (weight_ratio / BONE)) * BONE // The code treats the numbers as 18 digit fixed point values. So code does it differently, but this is equivelant + // balance_ratio = power - BONE + // amount_in = scaled_reserve_in * balance_ratio / BONE + // adjusted_in = amount_in * BONE / fee_ratio + // <= adjusted_in / 10**7 + + // scaled_reserve_in = 800000000000 * 10**7 => 8000000000000000000 + // scaled_reserve_out = 200000000000 * 10**7 => 2000000000000000000 + // adjusted_out = 1_000_000 * 10**7 => 10000000000000 + // base = (2000000000000000000 * BONE) / (2000000000000000000 - 10000000000000) => 1000005000025000125 + // weight_ratio = 2000000 * BONE / 8000000 => 250000000000000000 + // power = ((1000005000025000125 / BONE) ** (250000000000000000 / BONE)) * 10**18 => 1250006250031 + // balance_ratio = 1000001250006250031 - BONE => 1250006250031 + // amount_in = 8000000000000000000 * 1250006250031 / BONE = 10000050000248 + // adjusted_in = 10000050000248 * BONE / fee_ratio => 10030140421512 + // 10030140421512 / 10**7 => 1003015 + + test.adapter_contract.swap_tokens_for_exact_tokens( + &amount_out, // amount_out + &(expected_amount_in - 1), // amount_in_max + &path, // path + &test.user, // to + &deadline, // deadline + ); +} + +#[test] +fn try_swap_tokens_for_exact_tokens_sufficient_input_amount() { + let test = CometAggregatorAdapterTest::setup(); + + let deadline: u64 = test.env.ledger().timestamp() + 1000; + + let mut path: Vec
= Vec::new(&test.env); + path.push_back(test.token_0.address.clone()); + path.push_back(test.token_1.address.clone()); + + + test.env.budget().reset_unlimited(); + + let amount_out = 1_000_000; + let expected_amount_in = 1_003_015; + + + // bone = 10**18 + // fee_ratio = (10**7 - 30000) * 10**11 => 997000000000000000 + // scaled_reserve_(out|in) = token_(out|in)_reserve * 10**7 + // adjusted_out = amount_out * 10**7 + // base = (scaled_reserve_out * BONE) / (scaled_reserve_out) - adjusted_out) + // weight_ratio = out_token_weight * 10**18 / out_token_weight + // power = ((base / BONE) ** (weight_ratio / BONE)) * BONE // The code treats the numbers as 18 digit fixed point values. So code does it differently, but this is equivelant + // balance_ratio = power - BONE + // amount_in = scaled_reserve_in * balance_ratio / BONE + // adjusted_in = amount_in * BONE / fee_ratio + // <= adjusted_in / 10**7 + + // scaled_reserve_in = 800000000000 * 10**7 => 8000000000000000000 + // scaled_reserve_out = 200000000000 * 10**7 => 2000000000000000000 + // adjusted_out = 1_000_000 * 10**7 => 10000000000000 + // base = (2000000000000000000 * BONE) / (2000000000000000000 - 10000000000000) => 1000005000025000125 + // weight_ratio = 2000000 * BONE / 8000000 => 250000000000000000 + // power = ((1000005000025000125 / BONE) ** (250000000000000000 / BONE)) * 10**18 => 1250006250031 + // balance_ratio = 1000001250006250031 - BONE => 1250006250031 + // amount_in = 8000000000000000000 * 1250006250031 / BONE = 10000050000248 + // adjusted_in = 10000050000248 * BONE / fee_ratio => 10030140421512 + // 10030140421512 / 10**7 => 1003015 + + + let executed_amounts = test.adapter_contract.swap_tokens_for_exact_tokens( + &amount_out, // amount_out + &expected_amount_in, // amount_in_max + &path, // path + &test.user, // to + &deadline, // deadline + ); + + assert_eq!(executed_amounts.get(0).unwrap(), expected_amount_in); + assert_eq!(executed_amounts.get(1).unwrap(), amount_out); +} \ No newline at end of file diff --git a/contracts/aggregator/src/test.rs b/contracts/aggregator/src/test.rs index 4fd629da..27a58a3f 100644 --- a/contracts/aggregator/src/test.rs +++ b/contracts/aggregator/src/test.rs @@ -2,6 +2,8 @@ extern crate std; use crate::models::Adapter; use crate::{SoroswapAggregator, SoroswapAggregatorClient}; +use comet_setup::comet_adapter::CometAdapterClient; +use comet_setup::{create_comet_adapter, create_comet_factory, deploy_and_init_comet_pool}; use soroban_sdk::{ testutils::{Address as _, Ledger}, vec, Address, BytesN, Env, String, Vec, Symbol, Val, IntoVal @@ -25,6 +27,8 @@ use phoenix_setup::{ SoroswapAggregatorAdapterForPhoenixClient }; +mod comet_setup; + mod deployer_contract { soroban_sdk::contractimport!(file = "../target/wasm32-unknown-unknown/release/soroswap_aggregator_deployer.optimized.wasm"); pub type DeployerClient<'a> = Client<'a>; @@ -95,7 +99,7 @@ pub fn create_protocols_addresses(test: &SoroswapAggregatorTest) -> Vec // ] // } -pub fn create_soroswap_phoenix_addresses_for_deployer(env: &Env, soroswap_adapter: Address, phoenix_adapter: Address) -> Vec { +pub fn create_soroswap_phoenix_comet_addresses_for_deployer(env: &Env, soroswap_adapter: Address, phoenix_adapter: Address, comet_adapter: Address) -> Vec { vec![ env, AdapterFromWasm { @@ -108,6 +112,11 @@ pub fn create_soroswap_phoenix_addresses_for_deployer(env: &Env, soroswap_adapte address: phoenix_adapter.clone(), paused: false, }, + AdapterFromWasm { + protocol_id: String::from_str(env, "comet"), + address: comet_adapter.clone(), + paused: false, + }, ] } @@ -165,6 +174,7 @@ pub struct SoroswapAggregatorTest<'a> { // soroswap_factory_contract: SoroswapFactoryClient<'a>, soroswap_adapter_contract: SoroswapAggregatorAdapterForSoroswapClient<'a>, phoenix_adapter_contract: SoroswapAggregatorAdapterForPhoenixClient<'a>, + comet_adapter_contract: CometAdapterClient<'a>, token_0: TokenClient<'a>, token_1: TokenClient<'a>, token_2: TokenClient<'a>, @@ -313,6 +323,10 @@ impl<'a> SoroswapAggregatorTest<'a> { admin.clone(), &phoenix_factory_client.address); + /* INITIALIZE COMET FACTORY AND LP */ + /************************************************/ + let comet_factory: comet_setup::factory::Client<'_> = create_comet_factory(&env); + let comet_pair = deploy_and_init_comet_pool(&env, &admin, &vec![&env, token_0.address.clone(), token_2.address.clone()], comet_factory); // SETTING UP DEPLOYER let deployer_client = create_deployer(&env); @@ -324,10 +338,12 @@ impl<'a> SoroswapAggregatorTest<'a> { let phoenix_adapter_contract = create_phoenix_adapter(&env, &deployer_client, phoenix_multihop_client.address.clone(), admin.clone()); + let comet_adapter_contract = create_comet_adapter(&env, &deployer_client, comet_pair.address.clone(), admin.clone()); + let wasm_hash = env.deployer().upload_contract_wasm(soroswap_aggregator_contract::WASM); // Deploy aggregator using deployer, and include an init function to call. - let initialize_aggregator_addresses = create_soroswap_phoenix_addresses_for_deployer(&env, soroswap_adapter_contract.address.clone(), phoenix_adapter_contract.address.clone()); + let initialize_aggregator_addresses = create_soroswap_phoenix_comet_addresses_for_deployer(&env, soroswap_adapter_contract.address.clone(), phoenix_adapter_contract.address.clone(), comet_adapter_contract.address.clone()); // Convert the arguments into a Vec let init_fn_args: Vec = (admin.clone(), initialize_aggregator_addresses).into_val(&env); @@ -350,6 +366,7 @@ impl<'a> SoroswapAggregatorTest<'a> { // soroswap_factory_contract, soroswap_adapter_contract, phoenix_adapter_contract, + comet_adapter_contract, token_0, token_1, token_2, diff --git a/contracts/aggregator/src/test/budget_cpu_mem.rs b/contracts/aggregator/src/test/budget_cpu_mem.rs index f256c807..e897d3e5 100644 --- a/contracts/aggregator/src/test/budget_cpu_mem.rs +++ b/contracts/aggregator/src/test/budget_cpu_mem.rs @@ -1,5 +1,5 @@ extern crate std; -use crate::test::{create_soroswap_phoenix_addresses_for_deployer, new_update_adapters_addresses_deployer, SoroswapAggregatorTest}; +use crate::test::{create_soroswap_phoenix_comet_addresses_for_deployer, new_update_adapters_addresses_deployer, SoroswapAggregatorTest}; use soroban_sdk::{String, Vec, Address, testutils::Address as _}; use super::soroswap_aggregator_contract::DexDistribution; @@ -61,7 +61,7 @@ fn budget() { //swap_exact_tokens_for_tokens TWO PROTOCOLS SOROSWAP AND PHOENIX- ONE HOP - let update_aggregator_addresses = create_soroswap_phoenix_addresses_for_deployer(&test.env, test.soroswap_adapter_contract.address.clone(), test.phoenix_adapter_contract.address.clone()); + let update_aggregator_addresses = create_soroswap_phoenix_comet_addresses_for_deployer(&test.env, test.soroswap_adapter_contract.address.clone(), test.phoenix_adapter_contract.address.clone(), test.comet_adapter_contract.address.clone()); test.aggregator_contract .update_adapters(&update_aggregator_addresses); diff --git a/contracts/aggregator/src/test/comet_setup.rs b/contracts/aggregator/src/test/comet_setup.rs new file mode 100644 index 00000000..a267b30c --- /dev/null +++ b/contracts/aggregator/src/test/comet_setup.rs @@ -0,0 +1,74 @@ +#![cfg(test)] +use comet_adapter::CometAdapterClient; +use pair::CometPairClient; +use soroban_sdk::{vec, Address, BytesN, Env, IntoVal, String, Symbol, Val, Vec}; +use super::{generate_salt, DeployerClient}; + +pub mod pair { + soroban_sdk::contractimport!(file = "../adapters/comet/comet_contracts/comet_pool.wasm"); + pub type CometPairClient<'a> = Client<'a>; +} + +fn pair_contract_wasm(e: &Env) -> BytesN<32> { + e.deployer().upload_contract_wasm(pair::WASM) +} + +pub mod factory { + soroban_sdk::contractimport!(file = "../adapters/comet/comet_contracts/comet_factory.wasm"); + pub type CometFactoryClient<'a> = Client<'a>; +} +use factory::CometFactoryClient; + +pub mod comet_adapter{ + soroban_sdk::contractimport!(file = "../target/wasm32-unknown-unknown/release/comet_adapter.optimized.wasm"); + pub type CometAdapterClient<'a> = Client<'a>; +} + +pub fn create_comet_factory<'a>(e: &Env) -> CometFactoryClient { + let pair_hash = pair_contract_wasm(e); + + let factory_address = e.register_contract_wasm(None, factory::WASM); + let factory_client = CometFactoryClient::new(&e.clone(), &factory_address); + + factory_client.init(&pair_hash); + + factory_client +} + +pub fn deploy_and_init_comet_pool<'a>(e: &Env, admin: &Address, tokens: &Vec
, factory_client: CometFactoryClient) -> CometPairClient<'a> { + let comet_address = factory_client.new_c_pool( + &BytesN::from_array(&e, &[0; 32]), + &admin, + tokens, + &vec![e, 8000000, 2000000], + &vec![e, 800000000000, 200000000000], // these balances make the tokens have an equal value + &30000, + ); + + CometPairClient::new(e, &comet_address) +} + +pub fn create_comet_adapter<'a>(e: &Env, deployer_client: &DeployerClient<'a>, pair_address: Address, admin: Address) -> CometAdapterClient<'a> { + let wasm_hash = e.deployer().upload_contract_wasm(comet_adapter::WASM); + + // Deploy contract using deployer, and include an init function to call + let salt = BytesN::from_array(&e, &generate_salt(3)); + let init_fn = Symbol::new(&e, &("initialize")); + + let protocol_id = String::from_str(&e, "comet"); + let protocol_address = pair_address.clone(); + + // Convert the arguments into a Vec + let init_fn_args: Vec = (protocol_id.clone(), protocol_address.clone()).into_val(e); + + let (contract_id, _init_result) = deployer_client.deploy( + &admin, + &wasm_hash, + &salt, + &init_fn, + &init_fn_args, + ); + + let adapter_contract = CometAdapterClient::new(e, &contract_id); + adapter_contract +} diff --git a/contracts/aggregator/src/test/events.rs b/contracts/aggregator/src/test/events.rs index 48c6dc45..964a772c 100644 --- a/contracts/aggregator/src/test/events.rs +++ b/contracts/aggregator/src/test/events.rs @@ -2,7 +2,7 @@ use soroban_sdk::{symbol_short, testutils::{Events, Address as _}, vec, Address, IntoVal, String, Vec}; use crate::test::{ - create_protocols_addresses, create_soroswap_phoenix_addresses_for_deployer, new_update_adapters_addresses_deployer, SoroswapAggregatorTest + create_protocols_addresses, create_soroswap_phoenix_comet_addresses_for_deployer, new_update_adapters_addresses_deployer, SoroswapAggregatorTest }; use crate::event::InitializedEvent; @@ -84,7 +84,7 @@ fn update_adapters_event() { let test = SoroswapAggregatorTest::setup(); //Initialize aggregator - let initialize_aggregator_addresses = create_soroswap_phoenix_addresses_for_deployer(&test.env, test.soroswap_adapter_contract.address.clone(), test.phoenix_adapter_contract.address.clone()); + let initialize_aggregator_addresses = create_soroswap_phoenix_comet_addresses_for_deployer(&test.env, test.soroswap_adapter_contract.address.clone(), test.phoenix_adapter_contract.address.clone(), test.comet_adapter_contract.address.clone()); // test.aggregator_contract // .initialize(&test.admin, &initialize_aggregator_addresses); diff --git a/contracts/aggregator/src/test/get_adapters.rs b/contracts/aggregator/src/test/get_adapters.rs index 754d0e0d..f381c335 100644 --- a/contracts/aggregator/src/test/get_adapters.rs +++ b/contracts/aggregator/src/test/get_adapters.rs @@ -1,13 +1,13 @@ extern crate std; use crate::error::AggregatorError; -use crate::test::{SoroswapAggregatorTest, create_soroswap_phoenix_addresses_for_deployer}; +use crate::test::{SoroswapAggregatorTest, create_soroswap_phoenix_comet_addresses_for_deployer}; #[test] fn test_get_adapters() { let test = SoroswapAggregatorTest::setup(); //Initialize aggregator - let initialize_aggregator_addresses = create_soroswap_phoenix_addresses_for_deployer(&test.env, test.soroswap_adapter_contract.address.clone(), test.phoenix_adapter_contract.address.clone()); + let initialize_aggregator_addresses = create_soroswap_phoenix_comet_addresses_for_deployer(&test.env, test.soroswap_adapter_contract.address.clone(), test.phoenix_adapter_contract.address.clone(), test.comet_adapter_contract.address.clone()); let result = test.aggregator_contract.get_adapters(); diff --git a/contracts/aggregator/src/test/initialize.rs b/contracts/aggregator/src/test/initialize.rs index 5c146c12..ca45af31 100644 --- a/contracts/aggregator/src/test/initialize.rs +++ b/contracts/aggregator/src/test/initialize.rs @@ -1,6 +1,6 @@ extern crate std; use crate::error::AggregatorError; -use crate::test::{create_protocols_addresses, create_soroswap_phoenix_addresses_for_deployer, SoroswapAggregatorTest}; +use crate::test::{create_protocols_addresses, create_soroswap_phoenix_comet_addresses_for_deployer, SoroswapAggregatorTest}; use super::soroswap_aggregator_contract::AggregatorError as AggregatorErrorDeployer; #[test] @@ -65,7 +65,7 @@ fn test_initialize_twice_deployer() { let test = SoroswapAggregatorTest::setup(); //Initialize aggregator - let initialize_aggregator_addresses = create_soroswap_phoenix_addresses_for_deployer(&test.env, test.soroswap_adapter_contract.address.clone(), test.phoenix_adapter_contract.address.clone()); + let initialize_aggregator_addresses = create_soroswap_phoenix_comet_addresses_for_deployer(&test.env, test.soroswap_adapter_contract.address.clone(), test.phoenix_adapter_contract.address.clone(),test.comet_adapter_contract.address.clone()); let result_second_init = test .aggregator_contract diff --git a/contracts/aggregator/src/test/remove_adapter.rs b/contracts/aggregator/src/test/remove_adapter.rs index 3cb8ba47..80509db3 100644 --- a/contracts/aggregator/src/test/remove_adapter.rs +++ b/contracts/aggregator/src/test/remove_adapter.rs @@ -1,7 +1,7 @@ extern crate std; use crate::error::AggregatorError as AggregatorErrorFromCrate; // use crate::models::Adapter; -use crate::test::{create_soroswap_phoenix_addresses_for_deployer, create_soroswap_router, SoroswapAggregatorTest}; +use crate::test::{create_soroswap_phoenix_comet_addresses_for_deployer, create_soroswap_router, SoroswapAggregatorTest}; use soroban_sdk::{ testutils::{AuthorizedFunction, AuthorizedInvocation, MockAuth, MockAuthInvoke}, IntoVal, Symbol, @@ -40,6 +40,8 @@ fn test_remove_adapter() { .remove_adapter(&String::from_str(&test.env, "soroswap")); test.aggregator_contract .remove_adapter(&String::from_str(&test.env, "phoenix")); + test.aggregator_contract + .remove_adapter(&String::from_str(&test.env, "comet")); let mut updated_protocols = test.aggregator_contract.get_adapters(); let expected_empty_vec = vec![&test.env]; @@ -102,7 +104,7 @@ fn test_update_adapters_with_mock_auth() { let test = SoroswapAggregatorTest::setup(); //Initialize aggregator - let initialize_aggregator_addresses = create_soroswap_phoenix_addresses_for_deployer(&test.env, test.soroswap_adapter_contract.address.clone(), test.phoenix_adapter_contract.address.clone()); + let initialize_aggregator_addresses = create_soroswap_phoenix_comet_addresses_for_deployer(&test.env, test.soroswap_adapter_contract.address.clone(), test.phoenix_adapter_contract.address.clone(), test.comet_adapter_contract.address.clone()); // test.aggregator_contract_not_initialized // .initialize(&test.admin, &initialize_aggregator_addresses); diff --git a/contracts/aggregator/src/test/set_pause_get_paused.rs b/contracts/aggregator/src/test/set_pause_get_paused.rs index 7d84b58d..e9af32e7 100644 --- a/contracts/aggregator/src/test/set_pause_get_paused.rs +++ b/contracts/aggregator/src/test/set_pause_get_paused.rs @@ -2,7 +2,7 @@ extern crate std; use crate::error::AggregatorError as AggregatorErrorFromCrate; // use crate::models::Adapter; -use crate::test::{create_soroswap_phoenix_addresses_for_deployer, create_soroswap_router, SoroswapAggregatorTest}; +use crate::test::{create_soroswap_phoenix_comet_addresses_for_deployer, create_soroswap_router, SoroswapAggregatorTest}; use soroban_sdk::{vec, String, Vec}; use super::soroswap_aggregator_contract::{Adapter, AggregatorError}; @@ -25,7 +25,7 @@ fn test_set_pause_true_false() { //Initialize aggregator // let initialize_aggregator_addresses = create_protocols_addresses(&test); - let initialize_aggregator_addresses = create_soroswap_phoenix_addresses_for_deployer(&test.env, test.soroswap_adapter_contract.address.clone(), test.phoenix_adapter_contract.address.clone()); + let initialize_aggregator_addresses = create_soroswap_phoenix_comet_addresses_for_deployer(&test.env, test.soroswap_adapter_contract.address.clone(), test.phoenix_adapter_contract.address.clone(), test.comet_adapter_contract.address.clone()); // test.aggregator_contract_not_initialized // .initialize(&test.admin, &initialize_aggregator_addresses); @@ -54,6 +54,11 @@ fn test_set_pause_true_false() { address: test.phoenix_adapter_contract.address.clone(), paused: false, }, + Adapter { + protocol_id: String::from_str(&test.env, "comet"), + address: test.comet_adapter_contract.address.clone(), + paused: false, + }, ]; assert_eq!(updated_protocols, expected_protocols_vec); @@ -80,6 +85,11 @@ fn test_set_pause_true_false() { address: initialize_aggregator_addresses.get(1).unwrap().address, paused: false, }, + Adapter { + protocol_id: initialize_aggregator_addresses.get(2).unwrap().protocol_id, + address: initialize_aggregator_addresses.get(2).unwrap().address, + paused: false, + }, new_protocol_0.get(0).unwrap(), ]; @@ -102,6 +112,11 @@ fn test_set_pause_true_false() { address: initialize_aggregator_addresses.get(1).unwrap().address, paused: false, }, + Adapter { + protocol_id: initialize_aggregator_addresses.get(2).unwrap().protocol_id, + address: initialize_aggregator_addresses.get(2).unwrap().address, + paused: false, + }, new_protocol_0.get(0).unwrap(), new_protocol_1.get(0).unwrap(), ]; @@ -125,6 +140,11 @@ fn test_set_pause_true_false() { address: initialize_aggregator_addresses.get(1).unwrap().address, paused: false, }, + Adapter { + protocol_id: initialize_aggregator_addresses.get(2).unwrap().protocol_id, + address: initialize_aggregator_addresses.get(2).unwrap().address, + paused: false, + }, new_protocol_0.get(0).unwrap(), Adapter { protocol_id: new_protocol_1.get(0).unwrap().protocol_id, @@ -168,6 +188,11 @@ fn test_set_pause_true_false() { address: initialize_aggregator_addresses.get(1).unwrap().address, paused: false, }, + Adapter { + protocol_id: initialize_aggregator_addresses.get(2).unwrap().protocol_id, + address: initialize_aggregator_addresses.get(2).unwrap().address, + paused: false, + }, new_protocol_0.get(0).unwrap(), Adapter { protocol_id: new_protocol_1.get(0).unwrap().protocol_id, @@ -211,6 +236,11 @@ fn test_set_pause_true_false() { address: initialize_aggregator_addresses.get(1).unwrap().address, paused: false, }, + Adapter { + protocol_id: initialize_aggregator_addresses.get(2).unwrap().protocol_id, + address: initialize_aggregator_addresses.get(2).unwrap().address, + paused: false, + }, new_protocol_0.get(0).unwrap(), Adapter { protocol_id: new_protocol_1.get(0).unwrap().protocol_id, diff --git a/contracts/aggregator/src/test/swap_exact_tokens_for_tokens.rs b/contracts/aggregator/src/test/swap_exact_tokens_for_tokens.rs index ee19d601..c33a4028 100644 --- a/contracts/aggregator/src/test/swap_exact_tokens_for_tokens.rs +++ b/contracts/aggregator/src/test/swap_exact_tokens_for_tokens.rs @@ -902,3 +902,196 @@ fn swap_exact_tokens_for_tokens_succeed_correctly_two_protocols() { assert_eq!(success_result, expected_result); } + + +#[test] +fn swap_exact_tokens_for_tokens_succeed_comet() { + let test = SoroswapAggregatorTest::setup(); + let deadline: u64 = test.env.ledger().timestamp() + 1000; + // call the function + let mut distribution_vec = Vec::new(&test.env); + // add one with part 1 and other with part 0 + let mut path: Vec
= Vec::new(&test.env); + path.push_back(test.token_0.address.clone()); + path.push_back(test.token_2.address.clone()); + + let distribution_0 = DexDistribution { + protocol_id: String::from_str(&test.env, "comet"), + path, + parts: 1, + }; + distribution_vec.push_back(distribution_0); + + let amount_in = 1_000_000; + // bone = 10**18 + // fee_ratio = (10**7 - 30000) * 10**11 => 997000000000000000 + // scaled_reserve_(out|in) = token_(out|in)_reserve * 10**7 + // adjusted_in = amount_in * fee_ratio / BONE + // base = (scaled_reserve_in * BONE) / (scaled_reserve_in) + adjusted_in) + // weight_ratio = in_token_weight * 10**18 / out_token_weight + // power = ((base / BONE) ** (weight_ratio / BONE)) * BONE // The code treats the numbers as 18 digit fixed point values. So code does it differently, but this is equivelant + // balance_ratio = BONE - power + // <= scaled_reserve_out * balance_ratio / BONE / 10**7 + + // scaled_reserve_in = 800000000000 * 10**7 => 8000000000000000000 + // scaled_reserve_out = 200000000000 * 10**7 => 2000000000000000000 + // adjusted_in = 1_000_000 * 997000000000000000 / BONE => 99700000000000000 + // base = (8000000000000000000 * BONE) / (8000000000000000000 + 99700000000000000) => 999998753751553137 + // weight_ratio = 8000000 * bone / 2000000 => 4000000000000000000 + // power = ((999998753751553137 / BONE) ** (4000000000000000000 / BONE)) * 10**18 => 999995015015531351 + // balance_ratio = BONE - 999995015015531351 => 4984984468649 + // 2000000000000000000 * 4984984468649 / BONE / 10**7 => 996996 + let expected_amount_out = 996996; + + // check initial user balance of both tokens + let user_balance_before_0 = test.token_0.balance(&test.user); + let user_balance_before_2 = test.token_2.balance(&test.user); + + let result = test + .aggregator_contract + .swap_exact_tokens_for_tokens( + &test.token_0.address.clone(), + &test.token_2.address.clone(), + &amount_in, + &(expected_amount_out), + &distribution_vec.clone(), + &test.user.clone(), + &deadline, + ); + + // check new user balances + let user_balance_after_0 = test.token_0.balance(&test.user); + let user_balance_after_2 = test.token_2.balance(&test.user); + // compare + assert_eq!(user_balance_after_0, user_balance_before_0 - amount_in); + assert_eq!( + user_balance_after_2, + user_balance_before_2 + expected_amount_out + ); + + // check the result vec + // the result vec in this case is a vec of 1 vec with two elements, the amount 0 and amount 1 + let mut expected_comet_result_vec: Vec = Vec::new(&test.env); + expected_comet_result_vec.push_back(amount_in); + expected_comet_result_vec.push_back(expected_amount_out); + + let mut expected_result = Vec::new(&test.env); + expected_result.push_back(expected_comet_result_vec); + + assert_eq!(result, expected_result); +} + +#[test] +fn swap_exact_tokens_for_tokens_succeed_comet_soroswap_two_hops() { + let test = SoroswapAggregatorTest::setup(); + let deadline: u64 = test.env.ledger().timestamp() + 1000; + + // call the function + let mut distribution_vec = Vec::new(&test.env); + + let mut path_soroswap: Vec
= Vec::new(&test.env); + path_soroswap.push_back(test.token_0.address.clone()); + path_soroswap.push_back(test.token_1.address.clone()); + path_soroswap.push_back(test.token_2.address.clone()); + + let distribution_0 = DexDistribution { + protocol_id: String::from_str(&test.env, "soroswap"), + path: path_soroswap, + parts: 1, + }; + + let mut path_comet: Vec
= Vec::new(&test.env); + path_comet.push_back(test.token_0.address.clone()); + path_comet.push_back(test.token_2.address.clone()); + + let distribution_1 = DexDistribution { + protocol_id: String::from_str(&test.env, "comet"), + path: path_comet, + parts: 1, + }; + + distribution_vec.push_back(distribution_0); + distribution_vec.push_back(distribution_1); + + // let initial_user_balance: i128 = 20_000_000_000_000_000_000; + // let amount_0: i128 = 1_000_000_000_000_000_000; + // let amount_1: i128 = 4_000_000_000_000_000_000; + // let amount_2: i128 = 8_000_000_000_000_000_000; + + let amount_in = 2_000_000; + + + let amount_in_soroswap = 1_000_000; + // fee = 1_000_000 * 3 /1000 = 3000 // USE CEILING + // amount_in less fee = 1_000_000 - 3000 = 997000 + // First out = (997000*4000000000000000000)/(1000000000000000000 + 997000) = 3987999.999996024 = 3987999 + let first_out = 3987999; + // fee = 3987999 * 3 /1000 = 11963.997 = 11964 // USE CEILING + // in less fee = 3987999 - 11964 = 3976035 + // Second out = (3976035*8000000000000000000)/(4000000000000000000 + 3976035) = 7952069.999992096 = 7952069 + let expected_amount_out_soroswap = 7952069; + + let amount_in_comet = 1_000_000; + // bone = 10**18 + // fee_ratio = (10**7 - 30000) * 10**11 => 997000000000000000 + // scaled_reserve_(out|in) = token_(out|in)_reserve * 10**7 + // adjusted_in = amount_in * fee_ratio / BONE + // base = (scaled_reserve_in * BONE) / (scaled_reserve_in) + adjusted_in) + // weight_ratio = in_token_weight * 10**18 / out_token_weight + // power = ((base / BONE) ** (weight_ratio / BONE)) * BONE // The code treats the numbers as 18 digit fixed point values. So code does it differently, but this is equivelant + // balance_ratio = BONE - power + // <= scaled_reserve_out * balance_ratio / BONE / 10**7 + + // scaled_reserve_in = 800000000000 * 10**7 => 8000000000000000000 + // scaled_reserve_out = 200000000000 * 10**7 => 2000000000000000000 + // adjusted_in = 1_000_000 * 997000000000000000 / BONE => 99700000000000000 + // base = (8000000000000000000 * BONE) / (8000000000000000000 + 99700000000000000) => 999998753751553137 + // weight_ratio = 8000000 * bone / 2000000 => 4000000000000000000 + // power = ((999998753751553137 / BONE) ** (4000000000000000000 / BONE)) * 10**18 => 999995015015531351 + // balance_ratio = BONE - 999995015015531351 => 4984984468649 + // 2000000000000000000 * 4984984468649 / BONE / 10**7 => 996996 + let expected_amount_out_comet = 996996; + + let expected_out = expected_amount_out_comet + expected_amount_out_soroswap; + + let user_balance_before_0 = test.token_0.balance(&test.user); + let user_balance_before_1 = test.token_1.balance(&test.user); + let user_balance_before_2 = test.token_2.balance(&test.user); + + let result = test.aggregator_contract.swap_exact_tokens_for_tokens( + &test.token_0.address.clone(), + &test.token_2.address.clone(), + &amount_in, + &(0), + &distribution_vec.clone(), + &test.user.clone(), + &deadline, + ); + + let user_balance_after_0 = test.token_0.balance(&test.user); + let user_balance_after_1 = test.token_1.balance(&test.user); + let user_balance_after_2 = test.token_2.balance(&test.user); + + // compare + assert_eq!(user_balance_after_0, user_balance_before_0 - amount_in); + assert_eq!(user_balance_after_1, user_balance_before_1); + assert_eq!( + user_balance_after_2, + user_balance_before_2 + expected_out + ); + + let mut expected_soroswap_result_vec: Vec = Vec::new(&test.env); + expected_soroswap_result_vec.push_back(amount_in_soroswap); + expected_soroswap_result_vec.push_back(first_out); + expected_soroswap_result_vec.push_back(expected_amount_out_soroswap); + + let mut expected_comet_result_vec: Vec = Vec::new(&test.env); + expected_comet_result_vec.push_back(amount_in_comet); + expected_comet_result_vec.push_back(expected_amount_out_comet); + + let mut expected_result = Vec::new(&test.env); + expected_result.push_back(expected_soroswap_result_vec); + expected_result.push_back(expected_comet_result_vec); + + assert_eq!(result, expected_result); +} \ No newline at end of file diff --git a/contracts/aggregator/src/test/swap_tokens_for_exact_tokens.rs b/contracts/aggregator/src/test/swap_tokens_for_exact_tokens.rs index d44d8034..f2087bf5 100644 --- a/contracts/aggregator/src/test/swap_tokens_for_exact_tokens.rs +++ b/contracts/aggregator/src/test/swap_tokens_for_exact_tokens.rs @@ -818,3 +818,208 @@ fn swap_tokens_for_exact_tokens_succeed_correctly_two_protocols() { assert_eq!(success_result, expected_result); } + +#[test] +fn swap_tokens_for_exact_tokens_succeed_comet() { + let test = SoroswapAggregatorTest::setup(); + let deadline: u64 = test.env.ledger().timestamp() + 1000; + // call the function + let mut distribution_vec = Vec::new(&test.env); + // add one with part 1 and other with part 0 + let mut path: Vec
= Vec::new(&test.env); + path.push_back(test.token_0.address.clone()); + path.push_back(test.token_2.address.clone()); + + let distribution_0 = DexDistribution { + protocol_id: String::from_str(&test.env, "comet"), + path, + parts: 1, + }; + distribution_vec.push_back(distribution_0); + + let amount_out = 1_000_000; + // bone = 10**18 + // fee_ratio = (10**7 - 30000) * 10**11 => 997000000000000000 + // scaled_reserve_(out|in) = token_(out|in)_reserve * 10**7 + // adjusted_out = amount_out * 10**7 + // base = (scaled_reserve_out * BONE) / (scaled_reserve_out) - adjusted_out) + // weight_ratio = out_token_weight * 10**18 / out_token_weight + // power = ((base / BONE) ** (weight_ratio / BONE)) * BONE // The code treats the numbers as 18 digit fixed point values. So code does it differently, but this is equivelant + // balance_ratio = power - BONE + // amount_in = scaled_reserve_in * balance_ratio / BONE + // adjusted_in = amount_in * BONE / fee_ratio + // <= adjusted_in / 10**7 + + // scaled_reserve_in = 800000000000 * 10**7 => 8000000000000000000 + // scaled_reserve_out = 200000000000 * 10**7 => 2000000000000000000 + // adjusted_out = 1_000_000 * 10**7 => 10000000000000 + // base = (2000000000000000000 * BONE) / (2000000000000000000 - 10000000000000) => 1000005000025000125 + // weight_ratio = 2000000 * BONE / 8000000 => 250000000000000000 + // power = ((1000005000025000125 / BONE) ** (250000000000000000 / BONE)) * 10**18 => 1250006250031 + // balance_ratio = 1000001250006250031 - BONE => 1250006250031 + // amount_in = 8000000000000000000 * 1250006250031 / BONE = 10000050000248 + // adjusted_in = 10000050000248 * BONE / fee_ratio => 10030140421512 + // 10030140421512 / 10**7 => 1003015 + let expected_amount_in = 1_003_015; + + // check initial user balance of both tokens + let user_balance_before_0 = test.token_0.balance(&test.user); + let user_balance_before_2 = test.token_2.balance(&test.user); + + let result = test + .aggregator_contract + .swap_tokens_for_exact_tokens( + &test.token_0.address.clone(), + &test.token_2.address.clone(), + &amount_out, + &expected_amount_in, + &distribution_vec.clone(), + &test.user.clone(), + &deadline, + ); + + // check new user balances + let user_balance_after_0 = test.token_0.balance(&test.user); + let user_balance_after_2 = test.token_2.balance(&test.user); + // compare + assert_eq!(user_balance_after_0, user_balance_before_0 - expected_amount_in); + assert_eq!( + user_balance_after_2, + user_balance_before_2 + amount_out + ); + + // check the result vec + // the result vec in this case is a vec of 1 vec with two elements, the amount 0 and amount 1 + let mut expected_comet_result_vec: Vec = Vec::new(&test.env); + expected_comet_result_vec.push_back(expected_amount_in); + expected_comet_result_vec.push_back(amount_out); + + let mut expected_result = Vec::new(&test.env); + expected_result.push_back(expected_comet_result_vec); + + assert_eq!(result, expected_result); +} + +#[test] +fn swap_tokens_for_exact_tokens_succeed_comet_soroswap_two_hops() { + let test = SoroswapAggregatorTest::setup(); + let deadline: u64 = test.env.ledger().timestamp() + 1000; + // call the function + let mut distribution_vec = Vec::new(&test.env); + // add one with part 1 and other with part 0 + + let mut path_soroswap: Vec
= Vec::new(&test.env); + path_soroswap.push_back(test.token_0.address.clone()); + path_soroswap.push_back(test.token_1.address.clone()); + path_soroswap.push_back(test.token_2.address.clone()); + + let distribution_0 = DexDistribution { + protocol_id: String::from_str(&test.env, "soroswap"), + path: path_soroswap, + parts: 1, + }; + distribution_vec.push_back(distribution_0); + + let mut path_comet: Vec
= Vec::new(&test.env); + path_comet.push_back(test.token_0.address.clone()); + path_comet.push_back(test.token_2.address.clone()); + + let distribution_1 = DexDistribution { + protocol_id: String::from_str(&test.env, "comet"), + path: path_comet, + parts: 1, + }; + distribution_vec.push_back(distribution_1); + + let amount_out = 2_000_000; + + + let amount_out_soroswap = 1_000_000; + // pair token_1, token_2 + // token_1 is r_in, token_2 is r_out + // (r_in*amount_out)*1000 / (r_out - amount_out)*997 + // (4_000_000_000_000_000_000*1_000_000)*1000 / ((8_000_000_000_000_000_000 - 1_000_000)*997) + 1 = + // 4000000000000000000000000000 / (7999999999999000000 * 997) +1 = + // 4000000000000000000000000000 / 7975999999999003000000 +1 = CEIL(501504.51354068454) +1 = 501505 +1 = 501506 + // + let middle_amount_in = 501506; + + // pair token_0, token_1 + // token_0 is r_in, token_1 is r_out + // first amount in = + // (1_000_000_000_000_000_000*501506)*1000 / ((4_000_000_000_000_000_000 - 501506)*997) + 1 = + // 501506000000000000000000000 / (3999999999999498494 * 997) + 1 = + // CEIL (501506000000000000000000000 / 3987999999999499998518) +1 = ceil(125753.76128386732) +1 = 125755 + + let expected_amount_in_soroswap = 125755; + + + let amount_out_comet = 1_000_000; + // bone = 10**18 + // fee_ratio = (10**7 - 30000) * 10**11 => 997000000000000000 + // scaled_reserve_(out|in) = token_(out|in)_reserve * 10**7 + // adjusted_out = amount_out * 10**7 + // base = (scaled_reserve_out * BONE) / (scaled_reserve_out) - adjusted_out) + // weight_ratio = out_token_weight * 10**18 / out_token_weight + // power = ((base / BONE) ** (weight_ratio / BONE)) * BONE // The code treats the numbers as 18 digit fixed point values. So code does it differently, but this is equivelant + // balance_ratio = power - BONE + // amount_in = scaled_reserve_in * balance_ratio / BONE + // adjusted_in = amount_in * BONE / fee_ratio + // <= adjusted_in / 10**7 + + // scaled_reserve_in = 800000000000 * 10**7 => 8000000000000000000 + // scaled_reserve_out = 200000000000 * 10**7 => 2000000000000000000 + // adjusted_out = 1_000_000 * 10**7 => 10000000000000 + // base = (2000000000000000000 * BONE) / (2000000000000000000 - 10000000000000) => 1000005000025000125 + // weight_ratio = 2000000 * BONE / 8000000 => 250000000000000000 + // power = ((1000005000025000125 / BONE) ** (250000000000000000 / BONE)) * 10**18 => 1250006250031 + // balance_ratio = 1000001250006250031 - BONE => 1250006250031 + // amount_in = 8000000000000000000 * 1250006250031 / BONE = 10000050000248 + // adjusted_in = 10000050000248 * BONE / fee_ratio => 10030140421512 + // 10030140421512 / 10**7 => 1003015 + let expected_amount_in_comet = 1_003_015; + + let expected_amount_in = expected_amount_in_comet + expected_amount_in_soroswap; + + // check initial user balance of both tokens + let user_balance_before_0 = test.token_0.balance(&test.user); + let user_balance_before_2 = test.token_2.balance(&test.user); + + let result = test + .aggregator_contract + .swap_tokens_for_exact_tokens( + &test.token_0.address.clone(), + &test.token_2.address.clone(), + &amount_out, + &expected_amount_in, + &distribution_vec.clone(), + &test.user.clone(), + &deadline, + ); + + // check new user balances + let user_balance_after_0 = test.token_0.balance(&test.user); + let user_balance_after_2 = test.token_2.balance(&test.user); + // compare + assert_eq!(user_balance_after_0, user_balance_before_0 - expected_amount_in); + assert_eq!( + user_balance_after_2, + user_balance_before_2 + amount_out + ); + + // check the result vec + let mut expected_soroswap_result_vec: Vec = Vec::new(&test.env); + expected_soroswap_result_vec.push_back(expected_amount_in_soroswap); + expected_soroswap_result_vec.push_back(middle_amount_in); + expected_soroswap_result_vec.push_back(amount_out_soroswap); + + let mut expected_comet_result_vec: Vec = Vec::new(&test.env); + expected_comet_result_vec.push_back(expected_amount_in_comet); + expected_comet_result_vec.push_back(amount_out_comet); + + let mut expected_result = Vec::new(&test.env); + expected_result.push_back(expected_soroswap_result_vec); + expected_result.push_back(expected_comet_result_vec); + + assert_eq!(result, expected_result); +} \ No newline at end of file diff --git a/contracts/aggregator/src/test/update_adapters.rs b/contracts/aggregator/src/test/update_adapters.rs index 00dde2c8..9832e7de 100644 --- a/contracts/aggregator/src/test/update_adapters.rs +++ b/contracts/aggregator/src/test/update_adapters.rs @@ -1,7 +1,7 @@ extern crate std; use crate::error::AggregatorError; use crate::test::{ - create_protocols_addresses, create_soroswap_phoenix_addresses_for_deployer, create_soroswap_router, new_update_adapters_addresses, new_update_adapters_addresses_deployer, SoroswapAggregatorTest + create_protocols_addresses, create_soroswap_phoenix_comet_addresses_for_deployer, create_soroswap_router, new_update_adapters_addresses, new_update_adapters_addresses_deployer, SoroswapAggregatorTest }; use soroban_sdk::{ testutils::{AuthorizedFunction, AuthorizedInvocation, MockAuth, MockAuthInvoke}, @@ -31,7 +31,7 @@ fn test_update_adapters_add_new() { let test = SoroswapAggregatorTest::setup(); //Initialize aggregator - let initialize_aggregator_addresses = create_soroswap_phoenix_addresses_for_deployer(&test.env, test.soroswap_adapter_contract.address.clone(), test.phoenix_adapter_contract.address.clone()); + let initialize_aggregator_addresses = create_soroswap_phoenix_comet_addresses_for_deployer(&test.env, test.soroswap_adapter_contract.address.clone(), test.phoenix_adapter_contract.address.clone(), test.comet_adapter_contract.address.clone()); // test.aggregator_contract_not_initialized // .initialize(&test.admin, &initialize_aggregator_addresses); @@ -49,7 +49,7 @@ fn test_update_adapters_add_new() { updated_protocols.get(0), initialize_aggregator_addresses.get(0) ); - assert_eq!(updated_protocols.get(2), update_aggregator_addresses.get(0)); + assert_eq!(updated_protocols.get(3), update_aggregator_addresses.get(0)); // test both are not paused for protocol_address in updated_protocols { let is_protocol_paused = test @@ -65,7 +65,7 @@ fn test_update_adapters_overwrite() { let test = SoroswapAggregatorTest::setup(); //Initialize aggregator - let initialize_aggregator_addresses = create_soroswap_phoenix_addresses_for_deployer(&test.env, test.soroswap_adapter_contract.address.clone(), test.phoenix_adapter_contract.address.clone()); + let initialize_aggregator_addresses = create_soroswap_phoenix_comet_addresses_for_deployer(&test.env, test.soroswap_adapter_contract.address.clone(), test.phoenix_adapter_contract.address.clone(), test.comet_adapter_contract.address.clone()); // test.aggregator_contract_not_initialized // .initialize(&test.admin, &initialize_aggregator_addresses); @@ -93,7 +93,7 @@ fn test_update_adapters_overwrite() { // but the other protocol is still the same let updated_protocols = test.aggregator_contract.get_adapters(); assert_eq!(updated_protocols.get(0), update_aggregator_addresses.get(0)); - assert_eq!(updated_protocols.get(2), new_aggregator_addresses.get(0)); + assert_eq!(updated_protocols.get(3), new_aggregator_addresses.get(0)); // test both are not paused for protocol_address in updated_protocols { From 6c32d4998b510b3672497d8e435c14eca6528941 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rahim=20Klab=C3=A9r?= Date: Thu, 19 Dec 2024 11:43:50 +0100 Subject: [PATCH 3/7] Test comet with manual tests --- package.json | 2 +- src/deploy.ts | 14 +- src/manual_testing/manual_tests.ts | 334 ++++++++++++++++++++++++++++- src/manual_testing/utils.ts | 129 +++++++++++ src/setup_comet.ts | 128 +++++++++++ src/test_comet_adapter.ts | 41 ++++ src/utils/contract.ts | 3 + src/utils/env_config.ts | 12 +- src/utils/tx.ts | 14 +- yarn.lock | 51 +++-- 10 files changed, 691 insertions(+), 37 deletions(-) create mode 100644 src/setup_comet.ts create mode 100644 src/test_comet_adapter.ts diff --git a/package.json b/package.json index 3584c0bc..8b52324d 100644 --- a/package.json +++ b/package.json @@ -28,7 +28,7 @@ "typescript": "^5.3.3" }, "dependencies": { - "@stellar/stellar-sdk": "^12.1.0", + "@stellar/stellar-sdk": "^13.0.0", "dotenv": "^16.4.5" } } diff --git a/src/deploy.ts b/src/deploy.ts index 4524e7d7..4cf85961 100644 --- a/src/deploy.ts +++ b/src/deploy.ts @@ -6,11 +6,13 @@ import { AddressBook } from './utils/address_book.js'; import { airdropAccount, deployContract, installContract, invokeContract } from './utils/contract.js'; import { config } from './utils/env_config.js'; import { TokensBook } from './utils/tokens_book.js'; +import { cometSetup } from './setup_comet.js'; export async function deployAndInitAggregator(addressBook: AddressBook) { // if(network == 'mainnet') throw new Error('Mainnet not yet supported') await airdropAccount(loadedConfig.admin); + console.log('-------------------------------------------------------'); console.log('Deploying Deployer'); console.log('-------------------------------------------------------'); @@ -51,6 +53,11 @@ export async function deployAndInitAggregator(addressBook: AddressBook) { // SAVE ADDRES IN ADDRESS BOOK addressBook.setContractId("soroswap_adapter", soroswapAdapterAddress) + console.log("** Comet Adapter"); + + await cometSetup(loadedConfig, addressBook) + + console.log('-------------------------------------------------------'); console.log('Deploying Aggregator'); console.log('-------------------------------------------------------'); @@ -63,6 +70,11 @@ export async function deployAndInitAggregator(addressBook: AddressBook) { address: new Address(addressBook.getContractId('soroswap_adapter')), paused: false }, + { + protocol_id: "comet_blend", + address: new Address(addressBook.getContractId('comet_adapter')), + paused: false + } ]; const adaptersVecScVal = xdr.ScVal.scvVec(adaptersVec.map((adapter) => { @@ -130,7 +142,7 @@ const soroswapAddressBook = AddressBook.loadFromFile( `../../protocols/soroswap/${soroswapDir}` ); const soroswapTokensBook = TokensBook.loadFromFile( - `./protocols/soroswap/${soroswapDir}` + `../../protocols/soroswap/${soroswapDir}` ); const loadedConfig = config(network); diff --git a/src/manual_testing/manual_tests.ts b/src/manual_testing/manual_tests.ts index 798ba8a0..059e746a 100644 --- a/src/manual_testing/manual_tests.ts +++ b/src/manual_testing/manual_tests.ts @@ -11,11 +11,12 @@ import { SwapMethod, getPhoenixBalanceForContract, SoroswapPool, - create_soroswap_liquidity_pool + create_soroswap_liquidity_pool, + createCometPool } from "./utils.js"; import { AddressBook } from '../utils/address_book.js'; import { config } from '../utils/env_config.js'; -import { Address, Asset, scValToNative, xdr } from "@stellar/stellar-sdk"; +import { Address, Asset, nativeToScVal, scValToNative, xdr } from "@stellar/stellar-sdk"; import { AxiosClient } from "@stellar/stellar-sdk/rpc"; const args = process.argv; @@ -37,7 +38,7 @@ switch(args.length){ const addressBook = AddressBook.loadFromFile(network); const loadedConfig = config(network); -const prepareTestEnvironment = async ()=>{ +const prepareTestEnvironment = async ()=>{ const networkPassphrase = loadedConfig.passphrase; const soroswapRouterAddress = await (await AxiosClient.get('https://api.soroswap.finance/api/testnet/router')).data.address; console.log("-------------------------------------------------------"); @@ -137,6 +138,31 @@ const prepareTestEnvironment = async ()=>{ await provide_phoenix_liquidity(phoenixAdmin, pairAddress, 100000000000000000, 100000000000000000); const phoenixPoolBalance = await invokeCustomContract(pairAddress, 'query_pool_info', [], phoenixAdmin, true); console.log('🔎 New Phoenix liquidity pool balances:',scValToNative(phoenixPoolBalance.result.retval)); + + console.log("-------------------------------------------------------"); + console.log("Creating Comet liquidity pool"); + console.log("-------------------------------------------------------"); + + let cometPool = await createCometPool( + { + asset_a: cID_A, + asset_b: cID_B, + user: testUser, + amount_a: 80000_0000000, + amount_b: 20000_0000000, + weight_a: 8000000, + weight_b: 2000000, + } + ) + + console.log('🟢 Comet pair address:', cometPool.address); + + const cometBalances = [ + await invokeCustomContract(cometPool.address, 'get_balance', [new Address(cID_A).toScVal()], testUser, true), + await invokeCustomContract(cometPool.address, 'get_balance', [new Address(cID_B).toScVal()], testUser, true), + ].map((value) => scValToNative(value.result.retval)); + console.log('🔎 comet pool balances:', cometBalances); + const result = { assetA: assetA, assetB: assetB, @@ -146,8 +172,11 @@ const prepareTestEnvironment = async ()=>{ phoenixAdmin: phoenixAdmin, soroswapPoolCID: soroswapPoolCID, pairAddress: pairAddress, + cometAddress: cometPool.address, + cometAdapterName: cometPool.adapter_name, soroswapPoolBalance: soroswapPoolBalance, phoenixPoolBalance: phoenixPoolBalance, + cometPoolBalance: cometBalances, } return result; } @@ -637,6 +666,294 @@ const swap_exact_tokens_for_tokens_one_protocol_two_hops = async ()=>{ } } + +const swapExactInputAggregatorCometTest = async ()=>{ + console.log("-------------------------------------------------------"); + console.log("Testing exact input swap for comet"); + console.log("-------------------------------------------------------"); + const { + assetA, + assetB, + cID_A, + cID_B, + testUser, + soroswapPoolCID, + soroswapPoolBalance, + cometPoolBalance, + cometAddress, + cometAdapterName, + } = await prepareTestEnvironment(); + + console.log('-------------------------------------------------------'); + console.log('Aggregator exact input swap comet test'); + console.log('-------------------------------------------------------'); + + const soroswapAdapter = addressBook.getContractId('soroswap_adapter'); + console.log('soroswapAdapter:', soroswapAdapter); + const comet_adapter = addressBook.getContractId('comet_adapter'); + console.log('cometAdapter:', comet_adapter); + + const dexDistributionRaw = [ + { + protocol_id: "soroswap", + path: [cID_A, cID_B], + parts: 1, + }, + { + protocol_id: cometAdapterName, + path: [cID_A, cID_B], + parts: 1, + }, + ]; + + const dexDistributionVec = await createDexDistribution(dexDistributionRaw); + + const asset_A_first_balance = await fetchAssetBalance(assetA, testUser); + const asset_B_first_balance = await fetchAssetBalance(assetB, testUser); + + console.log(' ------------ Test user balances --------------'); + console.log('🔎 Asset A:', asset_A_first_balance); + console.log('🔎 Asset B:', asset_B_first_balance); + + console.log(' ------------ Soroswap pool balances --------------'); + console.log('🔎 Soroswap pool balance [A,B]:', scValToNative(soroswapPoolBalance.result.retval)); + + console.log(' ------------ comet pool balances --------------') + console.log('🔎 Comet pool balance [A,B]:', cometPoolBalance); + + const swapExactIn = await callAggregatorSwap(cID_A, cID_B, 2_000_000, dexDistributionVec, testUser, SwapMethod.EXACT_INPUT); + console.log('🟡 Swap exact in:', swapExactIn); + + const asset_A_second_balance = await fetchAssetBalance(assetA, testUser); + const asset_B_second_balance = await fetchAssetBalance(assetB, testUser); + + console.log(' -------------- Test user balances after exact input swap -------------'); + console.log('🔎 Asset A:', asset_A_second_balance); + console.log('🔎 Asset B:', asset_B_second_balance); + + console.log(' -------------- Soroswap pool balances after exact input swap -------------'); + const soroswapPoolBalanceAfterExactIn = await invokeCustomContract(soroswapPoolCID, 'get_reserves', [], testUser, true); + console.log('🔎 Soroswap pool balance [A,B]:', scValToNative(soroswapPoolBalanceAfterExactIn.result.retval)) + + console.log(' -------------- Comet pool balances after exact input swap -------------'); + const cometPoolBalanceAfterExactIn = [ + await invokeCustomContract(cometAddress, 'get_balance', [new Address(cID_A).toScVal()], testUser, true), + await invokeCustomContract(cometAddress, 'get_balance', [new Address(cID_B).toScVal()], testUser, true), + ].map((value) => scValToNative(value.result.retval)); + console.log('🔎 Comet pool balance [A,B]:', cometPoolBalanceAfterExactIn); + + const comet_before_assets = cometPoolBalance; + const comet_after_assets = cometPoolBalanceAfterExactIn; + + console.log("-------------- Contract ID's -----------------") + console.table({ + 'Contract Asset A': cID_A, + 'Contract Asset B': cID_B, + 'Contract Soroswap': soroswapPoolCID, + 'Contract Comet': cometAddress, + }) + + // The comet amounts are the same as in the rust test + // see contracts\adapters\comet\src\test\swap_exact_tokens_for_tokens.rs for an explanation + const expectedAmountIn0 = 1000000n; + const expectedAmountIn1 = 1000000n; + const expectedAmountOut0 = 3987999n; + const expectedAmountOut1 = 996996n; + + console.log(' -------------- Asset balances table -------------') + console.table({ + 'Initial balance': { + 'User Asset A': asset_A_first_balance, + 'User Asset B': asset_B_first_balance, + 'Soroswap Asset A': scValToNative(soroswapPoolBalance.result.retval)[0], + 'Soroswap Asset B': scValToNative(soroswapPoolBalance.result.retval)[1], + 'Comet Asset A': comet_before_assets[0], + 'Comet Asset B': comet_before_assets[1], + }, + 'Balance after exact input swap': { + 'User Asset A': asset_A_second_balance, + 'User Asset B': asset_B_second_balance, + 'Soroswap Asset A': scValToNative(soroswapPoolBalanceAfterExactIn.result.retval)[0], + 'Soroswap Asset B': scValToNative(soroswapPoolBalanceAfterExactIn.result.retval)[1], + 'Comet Asset A': comet_after_assets[0], + 'Comet Asset B': comet_after_assets[1], + } + }) + console.log(' -------------- result table -------------') + console.table({ + + 'Expected amounts': { + 'Amount in asset A': expectedAmountIn0, + 'Amount out asset A': expectedAmountOut0, + 'Amount in asset B': expectedAmountIn1, + 'Amount out asset B': expectedAmountOut1, + }, + 'Swap result': { + 'Amount in asset A': swapExactIn[0][0], + 'Amount out asset A': swapExactIn[0][1], + 'Amount in asset B': swapExactIn[1][0], + 'Amount out asset B': swapExactIn[1][1], + } + }) + + if( + swapExactIn[0][0] === expectedAmountIn0 && + swapExactIn[0][1] === expectedAmountOut0 && + swapExactIn[1][0] === expectedAmountIn1 && + swapExactIn[1][1] === expectedAmountOut1 + ){ + console.log('🟢 Aggregator test swap exact input comet passed') + return true; + } else { + console.error('🔴 Aggregator test swap exact input comet failed') + return false; + } +} + +const swapExactOutputAggregatorCometTest = async ()=>{ + console.log("-------------------------------------------------------"); + console.log("Testing exact output comet swap"); + console.log("-------------------------------------------------------"); + const { + assetA, + assetB, + cID_A, + cID_B, + testUser, + soroswapPoolCID, + soroswapPoolBalance, + cometPoolBalance, + cometAddress, + cometAdapterName, + } = await prepareTestEnvironment(); + + console.log('-------------------------------------------------------'); + console.log('Aggregator exact output swap comet test'); + console.log('-------------------------------------------------------'); + + const soroswapAdapter = addressBook.getContractId('soroswap_adapter'); + console.log('soroswapAdapter:', soroswapAdapter); + const comet_adapter = addressBook.getContractId('comet_adapter'); + console.log('cometAdapter:', comet_adapter); + + const dexDistributionRaw = [ + { + protocol_id: "soroswap", + path: [cID_A, cID_B], + parts: 1, + }, + { + protocol_id: cometAdapterName, + path: [cID_A, cID_B], + parts: 1, + }, + ]; + + const dexDistributionVec = await createDexDistribution(dexDistributionRaw); + + const asset_A_first_balance = await fetchAssetBalance(assetA, testUser); + const asset_B_first_balance = await fetchAssetBalance(assetB, testUser); + + console.log(' ------------ Test user balances --------------'); + console.log('🔎 Asset A:', asset_A_first_balance); + console.log('🔎 Asset B:', asset_B_first_balance); + + console.log(' ------------ Soroswap pool balances --------------'); + console.log('🔎 Soroswap pool balance [A,B]:', scValToNative(soroswapPoolBalance.result.retval)); + + console.log(' ------------ comet pool balances --------------') + console.log('🔎 Comet pool balance [A,B]:', cometPoolBalance); + + const swapExactOut = await callAggregatorSwap(cID_A, cID_B, 2_000_000, dexDistributionVec, testUser, SwapMethod.EXACT_OUTPUT); + console.log('🟡 Swap exact out:', swapExactOut); + + const asset_A_second_balance = await fetchAssetBalance(assetA, testUser); + const asset_B_second_balance = await fetchAssetBalance(assetB, testUser); + + console.log(' -------------- Test user balances after exact output swap -------------'); + console.log('🔎 Asset A:', asset_A_second_balance); + console.log('🔎 Asset B:', asset_B_second_balance); + + console.log(' -------------- Soroswap pool balances after exact output swap -------------'); + const soroswapPoolBalanceAfterExactIn = await invokeCustomContract(soroswapPoolCID, 'get_reserves', [], testUser, true); + console.log('🔎 Soroswap pool balance [A,B]:', scValToNative(soroswapPoolBalanceAfterExactIn.result.retval)) + + console.log(' -------------- Comet pool balances after exact output swap -------------'); + const cometPoolBalanceAfterExactIn = [ + await invokeCustomContract(cometAddress, 'get_balance', [new Address(cID_A).toScVal()], testUser, true), + await invokeCustomContract(cometAddress, 'get_balance', [new Address(cID_B).toScVal()], testUser, true), + ].map((value) => scValToNative(value.result.retval)); + console.log('🔎 Comet pool balance [A,B]:', cometPoolBalanceAfterExactIn); + + const comet_before_assets = cometPoolBalance; + const comet_after_assets = cometPoolBalanceAfterExactIn; + + console.log("-------------- Contract ID's -----------------") + console.table({ + 'Contract Asset A': cID_A, + 'Contract Asset B': cID_B, + 'Contract Soroswap': soroswapPoolCID, + 'Contract Comet': cometAddress, + }) + + // The comet amounts are the same as in the rust test + // see contracts\adapters\comet\src\test\swap_tokens_for_exact_tokens.rs for an explanation + const expectedAmountIn0 = 250754n; + const expectedAmountIn1 = 1003015n; + const expectedAmountOut0 = 1000000n; + const expectedAmountOut1 = 1000000n; + + console.log(' -------------- Asset balances table -------------') + console.table({ + 'Initial balance': { + 'User Asset A': asset_A_first_balance, + 'User Asset B': asset_B_first_balance, + 'Soroswap Asset A': scValToNative(soroswapPoolBalance.result.retval)[0], + 'Soroswap Asset B': scValToNative(soroswapPoolBalance.result.retval)[1], + 'Comet Asset A': comet_before_assets[0], + 'Comet Asset B': comet_before_assets[1], + }, + 'Balance after exact input swap': { + 'User Asset A': asset_A_second_balance, + 'User Asset B': asset_B_second_balance, + 'Soroswap Asset A': scValToNative(soroswapPoolBalanceAfterExactIn.result.retval)[0], + 'Soroswap Asset B': scValToNative(soroswapPoolBalanceAfterExactIn.result.retval)[1], + 'Comet Asset A': comet_after_assets[0], + 'Comet Asset B': comet_after_assets[1], + } + }) + console.log(' -------------- result table -------------') + console.table({ + + 'Expected amounts': { + 'Amount in asset A': expectedAmountIn0, + 'Amount out asset A': expectedAmountOut0, + 'Amount in asset B': expectedAmountIn1, + 'Amount out asset B': expectedAmountOut1, + }, + 'Swap result': { + 'Amount in asset A': swapExactOut[0][0], + 'Amount out asset A': swapExactOut[0][1], + 'Amount in asset B': swapExactOut[1][0], + 'Amount out asset B': swapExactOut[1][1], + } + }) + + if( + swapExactOut[0][0] === expectedAmountIn0 && + swapExactOut[0][1] === expectedAmountOut0 && + swapExactOut[1][0] === expectedAmountIn1 && + swapExactOut[1][1] === expectedAmountOut1 + ){ + console.log('🟢 Aggregator test swap exact output comet passed') + return true; + } else { + console.error('🔴 Aggregator test swap exact output comet failed') + return false; + } +} + + const main = async ()=>{ console.log(test) console.log(network) @@ -688,9 +1005,12 @@ const main = async ()=>{ default: throw new Error('Invalid test name'); } */ + const exactInputResult = await swapExactInputAggregatorTest(); const exactOutputResult = await swapExactOutputAggregatorTest(); const exactInputOneProtocolTwoHops = await swap_exact_tokens_for_tokens_one_protocol_two_hops(); + const cometExactInput = await swapExactInputAggregatorCometTest(); + const cometExactOutput = await swapExactOutputAggregatorCometTest(); console.log("-------------------------------------------------------"); console.log("Test results"); console.log("-------------------------------------------------------"); @@ -703,7 +1023,13 @@ const main = async ()=>{ }, 'Exact input one protocol two hops': { 'Status': exactInputOneProtocolTwoHops ? '🟢 Passed' : '🔴 Failed', - } + }, + 'Comet exact input test': { + 'Status': cometExactInput ? '🟢 Passed' : '🔴 Failed', + }, + 'Comet exact output test': { + 'Status': cometExactOutput ? '🟢 Passed' : '🔴 Failed', + }, }) } diff --git a/src/manual_testing/utils.ts b/src/manual_testing/utils.ts index 0bef37ed..8788b3ca 100644 --- a/src/manual_testing/utils.ts +++ b/src/manual_testing/utils.ts @@ -19,6 +19,7 @@ import { getCurrentTimePlusOneHour, signWithKeypair } from "../utils/tx.js"; import * as PhoenixFactoryContract from '../protocols/phoenix/bindgins/factory_bindings.js'; import { AddressBook } from '../utils/address_book.js'; import { config } from "../utils/env_config.js"; +import { randomBytes } from "crypto"; const network = process.argv[2]; @@ -403,6 +404,134 @@ interface PhoenixPool { stake_address: string, } +export interface CometPoolParams{ + asset_a: string, + asset_b: string, + weight_a: number, + weight_b: number, + amount_a: number, + amount_b: number, + user: Keypair +} + +export interface CometPool { + address: string, + asset_0: string, + asset_0_balance: number, + asset_1: string, + asset_1_balance: number, + adapter_name: string, +} + +function generateAdapterIdForComet() { + const chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"; + let result = ""; + for (let i = 0; i < 10; i++) { + result += chars.charAt(Math.floor(Math.random() * chars.length)); + } + return result; +} + + +export async function createCometPool(params: CometPoolParams): Promise { + console.log('creating comet pair...'); + const createCometPairResponse = await invokeContract( + 'comet_factory', + addressBook, + 'new_c_pool', + [ + nativeToScVal(randomBytes(32)), + new Address(params.user.publicKey()).toScVal(), + nativeToScVal([new Address(params.asset_a).toScVal(), new Address(params.asset_b).toScVal()]), + nativeToScVal([ + nativeToScVal(params.weight_a, { type: 'i128' }), + nativeToScVal(params.weight_b, { type: 'i128' }), + ]), + nativeToScVal([ + nativeToScVal(params.amount_a, { type: 'i128' }), + nativeToScVal(params.amount_b, { type: 'i128' }), + ]), + nativeToScVal(30000, { type: 'i128' }), + ], + params.user + ); + const cometPairAddress = scValToNative(createCometPairResponse.returnValue) + + const initArgs = xdr.ScVal.scvVec([ + xdr.ScVal.scvString("comet"), + new Address(cometPairAddress).toScVal(), + ]); + + const cometAdapterDeployParams: xdr.ScVal[] = [ + new Address(loadedConfig.admin.publicKey()).toScVal(), + nativeToScVal(Buffer.from(addressBook.getWasmHash('comet_adapter'), 'hex')), + nativeToScVal(randomBytes(32)), + xdr.ScVal.scvSymbol('initialize'), + initArgs, + ]; + + const response = await invokeContract( + 'deployer', + addressBook, + 'deploy', + cometAdapterDeployParams, + loadedConfig.admin + ); + + const cometAdapterAddress = scValToNative(response.returnValue)[0]; + console.log('🚀 « comet adapter address:', cometAdapterAddress); + // SAVE ADDRES IN ADDRESS BOOK + addressBook.setContractId('comet_adapter', cometAdapterAddress); + + const adapter_name = generateAdapterIdForComet() + + const adaptersVec = [ + { + protocol_id: adapter_name, + address: new Address(cometAdapterAddress), + paused: false + } + ]; + + const adaptersVecScVal = xdr.ScVal.scvVec(adaptersVec.map((adapter) => { + return xdr.ScVal.scvMap([ + new xdr.ScMapEntry({ + key: xdr.ScVal.scvSymbol('address'), + val: adapter.address.toScVal(), + }), + new xdr.ScMapEntry({ + key: xdr.ScVal.scvSymbol('paused'), + val: nativeToScVal(adapter.paused), + }), + new xdr.ScMapEntry({ + key: xdr.ScVal.scvSymbol('protocol_id'), + val: xdr.ScVal.scvString(adapter.protocol_id), + }), + ]); + })); + + const aggregatorUpdateAdaptersParams: xdr.ScVal[] = [ + adaptersVecScVal, + ]; + + await invokeContract( + 'aggregator', + addressBook, + 'update_adapters', + aggregatorUpdateAdaptersParams, + loadedConfig.admin + ); + + return{ + address: cometPairAddress, + asset_0: params.asset_a, + asset_0_balance: params.amount_a, + asset_1: params.asset_b, + asset_1_balance: params.amount_b, + adapter_name + } +} + interface DexDistributionRaw { protocol_id: string, path: string[], diff --git a/src/setup_comet.ts b/src/setup_comet.ts new file mode 100644 index 00000000..647bf490 --- /dev/null +++ b/src/setup_comet.ts @@ -0,0 +1,128 @@ +import { Address, Asset, nativeToScVal, Networks, scValToNative, xdr } from '@stellar/stellar-sdk'; +import { AddressBook } from './utils/address_book.js'; +import { deployContract, installContract, invokeContract } from './utils/contract.js'; +import { EnvConfig } from './utils/env_config.js'; +import { randomBytes } from 'crypto'; +import { TokensBook } from './utils/tokens_book.js'; +import test from 'node:test'; +import { mintToken } from './mint_token.js'; +import { deployAndMint } from './manual_testing/utils.js'; + +async function initTokens(loadedConfig: EnvConfig, tokensBook: TokensBook) { + const tokens = tokensBook.getTokensByNetwork('testnet'); + + if (tokens != undefined && tokens.length > 1) { + return; + } + + tokensBook.addToken('testnet', { + name: 'xlm', + contract: 'CDLZFC3SYJYDZT7K67VZ75HPJVIEUVNIXF47ZG2FB2RMQQVU2HHGCYSC', + code: 'XLM', + decimals: 7, + }); + + let asset = new Asset('hi', loadedConfig.tokenAdmin.publicKey()) + + await deployAndMint(asset, loadedConfig.admin, "100000000000"); + + tokensBook.addToken('testnet', { + name: 'hi', + contract: asset.contractId(Networks.TESTNET), + code: 'hi', + decimals: 7, + }); + + tokensBook.writeToFile() +} + +export async function cometSetup(loadedConfig: EnvConfig, addressBook: AddressBook) { + const tokensBook = TokensBook.loadFromFile(`../../.soroban`); + + await initTokens(loadedConfig, tokensBook) + + const tokens = tokensBook.getTokensByNetwork("testnet") + + if (tokens == undefined) { + throw 'could not find tokens'; + } + + let tokenA = tokens[0]; // xlm + let tokenB = tokens[1]; + + await mintToken( + tokenB.contract, + 25000000000000, + loadedConfig.admin.publicKey(), + loadedConfig.tokenAdmin + ); + + console.log('uploading comet pair...'); + await installContract('comet_pool', addressBook, loadedConfig.admin); + + console.log('deploying comet factory...'); + await installContract('comet_factory', addressBook, loadedConfig.admin); + await deployContract('comet_factory', 'comet_factory', addressBook, loadedConfig.admin); + + await invokeContract( + 'comet_factory', + addressBook, + 'init', + [nativeToScVal(Buffer.from(addressBook.getWasmHash('comet_pool'), 'hex'))], + loadedConfig.admin + ); + + console.log('creating comet pair...'); + const createCometPairResponse = await invokeContract( + 'comet_factory', + addressBook, + 'new_c_pool', + [ + nativeToScVal(randomBytes(32)), + new Address(loadedConfig.admin.publicKey()).toScVal(), + nativeToScVal([new Address(tokenA.contract).toScVal(), new Address(tokenB.contract).toScVal()]), + nativeToScVal([ + nativeToScVal(8000000, { type: 'i128' }), + nativeToScVal(2000000, { type: 'i128' }), + ]), + nativeToScVal([ + nativeToScVal(800_0000000, { type: 'i128' }), + nativeToScVal(200_0000000, { type: 'i128' }), + ]), + nativeToScVal(30000, { type: 'i128' }), + ], + loadedConfig.admin + ); + const cometPairAddress = scValToNative(createCometPairResponse.returnValue) + + addressBook.setContractId("comet_pair", cometPairAddress) + console.log('🚀 « comet pair address:', cometPairAddress); + + await installContract('comet_adapter', addressBook, loadedConfig.admin); + + const initArgs = xdr.ScVal.scvVec([ + xdr.ScVal.scvString('comet_blend'), // protocol_id as ScVal string + new Address(cometPairAddress).toScVal(), // protocol_address as ScVal address + ]); + + const cometAdapterDeployParams: xdr.ScVal[] = [ + new Address(loadedConfig.admin.publicKey()).toScVal(), + nativeToScVal(Buffer.from(addressBook.getWasmHash('comet_adapter'), 'hex')), + nativeToScVal(randomBytes(32)), + xdr.ScVal.scvSymbol('initialize'), + initArgs, + ]; + + const response = await invokeContract( + 'deployer', + addressBook, + 'deploy', + cometAdapterDeployParams, + loadedConfig.admin + ); + + const cometAdapterAddress = scValToNative(response.returnValue)[0]; + console.log('🚀 « cometAdapterAddress:', cometAdapterAddress); + // SAVE ADDRES IN ADDRESS BOOK + addressBook.setContractId('comet_adapter', cometAdapterAddress); +} diff --git a/src/test_comet_adapter.ts b/src/test_comet_adapter.ts new file mode 100644 index 00000000..b2ef49f6 --- /dev/null +++ b/src/test_comet_adapter.ts @@ -0,0 +1,41 @@ +import { Address, nativeToScVal, xdr } from '@stellar/stellar-sdk'; +import { AddressBook } from './utils/address_book.js'; +import { invokeContract } from './utils/contract.js'; +import { config } from './utils/env_config.js'; +import { getCurrentTimePlusOneHour } from './utils/tx.js'; +import { TokensBook } from './utils/tokens_book.js'; +import { cometSetup } from './setup_comet.js'; + +export async function testCometAdapter(addressBook: AddressBook) { + console.log('-------------------------------------------------------'); + console.log('Testing Comet Adapter'); + console.log('-------------------------------------------------------'); + + const tokens = TokensBook.loadFromFile().getTokensByNetwork("testnet")!! + + const pathRaw = [tokens[0].contract, tokens[1].contract]; + + const aggregatorSwapParams: xdr.ScVal[] = [ + nativeToScVal(1_000_000_0, {type: "i128"}), + nativeToScVal(0, {type: "i128"}), + nativeToScVal(pathRaw.map((pathAddress) => new Address(pathAddress))), + new Address(loadedConfig.admin.publicKey()).toScVal(), //admin: Address, + nativeToScVal(getCurrentTimePlusOneHour()), //deadline + ]; + + await invokeContract( + 'comet_adapter', + addressBook, + 'swap_exact_tokens_for_tokens', + aggregatorSwapParams, + loadedConfig.admin + ); + +} + +const network = process.argv[2]; +const addressBook = AddressBook.loadFromFile(network); + +const loadedConfig = config(network); + +await testCometAdapter(addressBook); \ No newline at end of file diff --git a/src/utils/contract.ts b/src/utils/contract.ts index 761caf68..f6ba98bb 100644 --- a/src/utils/contract.ts +++ b/src/utils/contract.ts @@ -32,6 +32,9 @@ const CONTRACT_REL_PATH: object = { phoenix_pool: '../../contracts/adapters/phoenix/phoenix_contracts/phoenix_pool.wasm', phoenix_stake: '../../contracts/adapters/phoenix/phoenix_contracts/phoenix_stake.wasm', phoenix_stable: '../../contracts/adapters/phoenix/phoenix_contracts/phoenix_pool_stable.wasm', + comet_adapter: '../../contracts/target/wasm32-unknown-unknown/release/comet_adapter.optimized.wasm', + comet_factory: '../../contracts/adapters/comet/comet_contracts/comet_factory.wasm', + comet_pool: '../../contracts/adapters/comet/comet_contracts/comet_pool.wasm', }; const network = process.argv[2]; diff --git a/src/utils/env_config.ts b/src/utils/env_config.ts index 70a38f6d..0a438526 100644 --- a/src/utils/env_config.ts +++ b/src/utils/env_config.ts @@ -1,4 +1,4 @@ -import { Horizon, Keypair, SorobanRpc } from '@stellar/stellar-sdk'; +import { Horizon, Keypair, rpc } from '@stellar/stellar-sdk'; import dotenv from "dotenv"; import * as fs from "fs"; import path from "path"; @@ -22,8 +22,8 @@ interface Config { networkConfig: NetworkConfig[]; } -class EnvConfig { - rpc: SorobanRpc.Server; +export class EnvConfig { + rpc: rpc.Server; horizonRpc: Horizon.Server; passphrase: string; friendbot: string | undefined; @@ -33,7 +33,7 @@ class EnvConfig { testUser: Keypair; constructor( - rpc: SorobanRpc.Server, + rpc: rpc.Server, horizonRpc: Horizon.Server, passphrase: string, friendbot: string | undefined, @@ -106,8 +106,10 @@ class EnvConfig { const allowHttp = network === "standalone"; + console.log(admin) + return new EnvConfig( - new SorobanRpc.Server(rpc_url, { allowHttp }), + new rpc.Server(rpc_url, { allowHttp }), new Horizon.Server(horizon_rpc_url, {allowHttp}), passphrase, friendbot_url, diff --git a/src/utils/tx.ts b/src/utils/tx.ts index 601b0e5a..0d845484 100644 --- a/src/utils/tx.ts +++ b/src/utils/tx.ts @@ -1,8 +1,8 @@ -import { Account, Keypair, SorobanRpc, Transaction, TransactionBuilder, xdr } from '@stellar/stellar-sdk'; +import { Account, Keypair, rpc, Transaction, TransactionBuilder, xdr } from '@stellar/stellar-sdk'; import { config } from './env_config.js'; -type txResponse = SorobanRpc.Api.SendTransactionResponse | SorobanRpc.Api.GetTransactionResponse; -type txStatus = SorobanRpc.Api.SendTransactionStatus | SorobanRpc.Api.GetTransactionStatus; +type txResponse = rpc.Api.SendTransactionResponse | rpc.Api.GetTransactionResponse; +type txStatus = rpc.Api.SendTransactionStatus | rpc.Api.GetTransactionStatus; const network = process.argv[2]; const loadedConfig = config(network); @@ -11,10 +11,10 @@ export async function signWithKeypair( txXdr: string, passphrase: string, source: Keypair -): Promise { +): Promise<{signedTxXdr: string}> { const tx = new Transaction(txXdr, passphrase); tx.sign(source); - return tx.toXDR(); + return {signedTxXdr: tx.toXDR()}; } export async function invoke( @@ -36,7 +36,7 @@ export async function invoke( export async function invokeTransaction(tx: Transaction, source: Keypair, sim: boolean) { // simulate the TX const simulation_resp = await loadedConfig.rpc.simulateTransaction(tx); - if (SorobanRpc.Api.isSimulationError(simulation_resp)) { + if (rpc.Api.isSimulationError(simulation_resp)) { // No resource estimation available from a simulation error. Allow the response formatter // to fetch the error. if(simulation_resp.error.includes("ExistingValue")) {throw new Error("ExistingValue")} @@ -58,7 +58,7 @@ export async function invokeTransaction(tx: Transaction, source: Keypair, sim: b txResources.writeBytes() ) .build(); - const assemble_tx = SorobanRpc.assembleTransaction(tx, simulation_resp); + const assemble_tx = rpc.assembleTransaction(tx, simulation_resp); sim_tx_data.resourceFee( xdr.Int64.fromString((Number(sim_tx_data.resourceFee().toString()) + 100000).toString()) ); diff --git a/yarn.lock b/yarn.lock index 32886ff4..fc4e9c28 100644 --- a/yarn.lock +++ b/yarn.lock @@ -89,10 +89,10 @@ resolved "https://registry.yarnpkg.com/@stellar/js-xdr/-/js-xdr-3.1.2.tgz#db7611135cf21e989602fd72f513c3bed621bc74" integrity sha512-VVolPL5goVEIsvuGqDc5uiKxV03lzfWdvYg1KikvwheDmTBO68CKDji3bAZ/kppZrx5iTA8z3Ld5yuytcvhvOQ== -"@stellar/stellar-base@^12.1.0": - version "12.1.0" - resolved "https://registry.yarnpkg.com/@stellar/stellar-base/-/stellar-base-12.1.0.tgz#45b55a38738ed267e0d55a1fee3c4153c82d0fa6" - integrity sha512-pWwn+XWP5NotmIteZNuJzHeNn9DYSqH3lsYbtFUoSYy1QegzZdi9D8dK6fJ2fpBAnf/rcDjHgHOw3gtHaQFVbg== +"@stellar/stellar-base@^13.0.1": + version "13.0.1" + resolved "https://registry.yarnpkg.com/@stellar/stellar-base/-/stellar-base-13.0.1.tgz#0897f77349ded61e838c0d55519f36f720efe3c9" + integrity sha512-Xbd12mc9Oj/130Tv0URmm3wXG77XMshZtZ2yNCjqX5ZbMD5IYpbBs3DVCteLU/4SLj/Fnmhh1dzhrQXnk4r+pQ== dependencies: "@stellar/js-xdr" "^3.1.2" base32.js "^0.1.0" @@ -101,17 +101,18 @@ sha.js "^2.3.6" tweetnacl "^1.0.3" optionalDependencies: - sodium-native "^4.1.1" + sodium-native "^4.3.0" -"@stellar/stellar-sdk@^12.1.0": - version "12.2.0" - resolved "https://registry.yarnpkg.com/@stellar/stellar-sdk/-/stellar-sdk-12.2.0.tgz#c449bc52be282c7706aabbd257acbc5aec3345b3" - integrity sha512-Wy5sDOqb5JvAC76f4sQIV6Pe3JNyZb0PuyVNjwt3/uWsjtxRkFk6s2yTHTefBLWoR+mKxDjO7QfzhycF1v8FXQ== +"@stellar/stellar-sdk@^13.0.0": + version "13.0.0" + resolved "https://registry.yarnpkg.com/@stellar/stellar-sdk/-/stellar-sdk-13.0.0.tgz#293f0bf6964b384e489b0ad75174d39cd22a3a69" + integrity sha512-+wvmKi+XWwu27nLYTM17EgBdpbKohEkOfCIK4XKfsI4WpMXAqvnqSm98i9h5dAblNB+w8BJqzGs1JY0PtTGm4A== dependencies: - "@stellar/stellar-base" "^12.1.0" - axios "^1.7.2" + "@stellar/stellar-base" "^13.0.1" + axios "^1.7.7" bignumber.js "^9.1.2" eventsource "^2.0.2" + feaxios "^0.0.20" randombytes "^2.1.0" toml "^3.0.0" urijs "^1.19.1" @@ -276,10 +277,10 @@ asynckit@^0.4.0: resolved "https://registry.yarnpkg.com/asynckit/-/asynckit-0.4.0.tgz#c79ed97f7f34cb8f2ba1bc9790bcc366474b4b79" integrity sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q== -axios@^1.7.2: - version "1.7.2" - resolved "https://registry.yarnpkg.com/axios/-/axios-1.7.2.tgz#b625db8a7051fbea61c35a3cbb3a1daa7b9c7621" - integrity sha512-2A8QhOMrbomlDuiLeK9XibIBzuHeRcqqNOHp0Cyp5EoJ1IFDh+XZH3A6BkXtv0K4gFGCI0Y4BM7B1wOEi0Rmgw== +axios@^1.7.7: + version "1.7.8" + resolved "https://registry.yarnpkg.com/axios/-/axios-1.7.8.tgz#1997b1496b394c21953e68c14aaa51b7b5de3d6e" + integrity sha512-Uu0wb7KNqK2t5K+YQyVCLM76prD5sRFjKHbJYCP1J7JFGEQ6nN7HWn9+04LAeiJ3ji54lgS/gZCH1oxyrf1SPw== dependencies: follow-redirects "^1.15.6" form-data "^4.0.0" @@ -568,6 +569,13 @@ fastq@^1.6.0: dependencies: reusify "^1.0.4" +feaxios@^0.0.20: + version "0.0.20" + resolved "https://registry.yarnpkg.com/feaxios/-/feaxios-0.0.20.tgz#04e976beb7345401fedeba764f0e9e1c4d01afd4" + integrity sha512-g3hm2YDNffNxA3Re3Hd8ahbpmDee9Fv1Pb1C/NoWsjY7mtD8nyNeJytUzn+DK0Hyl9o6HppeWOrtnqgmhOYfWA== + dependencies: + is-retry-allowed "^3.0.0" + file-entry-cache@^6.0.1: version "6.0.1" resolved "https://registry.yarnpkg.com/file-entry-cache/-/file-entry-cache-6.0.1.tgz#211b2dd9659cb0394b073e7323ac3c933d522027" @@ -736,6 +744,11 @@ is-path-inside@^3.0.3: resolved "https://registry.yarnpkg.com/is-path-inside/-/is-path-inside-3.0.3.tgz#d231362e53a07ff2b0e0ea7fed049161ffd16283" integrity sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ== +is-retry-allowed@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/is-retry-allowed/-/is-retry-allowed-3.0.0.tgz#ea79389fd350d156823c491bee9c69f485b1445c" + integrity sha512-9xH0xvoggby+u0uGF7cZXdrutWiBiaFG8ZT4YFPXL8NzkyAwX3AKGLeFQLvzDpM430+nDFBZ1LHkie/8ocL06A== + isexe@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/isexe/-/isexe-2.0.0.tgz#e8fbf374dc556ff8947a10dcb0572d633f2cfa10" @@ -1016,10 +1029,10 @@ slash@^3.0.0: resolved "https://registry.yarnpkg.com/slash/-/slash-3.0.0.tgz#6539be870c165adbd5240220dbe361f1bc4d4634" integrity sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q== -sodium-native@^4.1.1: - version "4.1.1" - resolved "https://registry.yarnpkg.com/sodium-native/-/sodium-native-4.1.1.tgz#109bc924dd55c13db87c6dd30da047487595723c" - integrity sha512-LXkAfRd4FHtkQS4X6g+nRcVaN7mWVNepV06phIsC6+IZFvGh1voW5TNQiQp2twVaMf05gZqQjuS+uWLM6gHhNQ== +sodium-native@^4.3.0: + version "4.3.1" + resolved "https://registry.yarnpkg.com/sodium-native/-/sodium-native-4.3.1.tgz#221a11b10876259b85ccd288dd28f07ed4dbf35f" + integrity sha512-YdP64gAdpIKHfL4ttuX4aIfjeunh9f+hNeQJpE9C8UMndB3zkgZ7YmmGT4J2+v6Ibyp6Wem8D1TcSrtdW0bqtg== dependencies: node-gyp-build "^4.8.0" From 9636b1fbdb306479bb5f337a3c3cf5d2b7e050e5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rahim=20Klab=C3=A9r?= Date: Thu, 19 Dec 2024 11:44:06 +0100 Subject: [PATCH 4/7] Update soroswap to latest commit --- protocols/soroswap | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/protocols/soroswap b/protocols/soroswap index 6dfc31d7..568f9203 160000 --- a/protocols/soroswap +++ b/protocols/soroswap @@ -1 +1 @@ -Subproject commit 6dfc31d79c48742084075bc78e129fab958d645c +Subproject commit 568f9203b0e0001c43dc7647c3c10b3148d61867 From fc3b1c6e649a72cf8c8662d5fb1c9fb591cb5fd0 Mon Sep 17 00:00:00 2001 From: Matias Poblete <86752543+MattPoblete@users.noreply.github.com> Date: Fri, 20 Dec 2024 09:58:49 -0300 Subject: [PATCH 5/7] =?UTF-8?q?=E2=99=BB=EF=B8=8F=20Refactor=20comet=20set?= =?UTF-8?q?up?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- package.json | 5 +- src/deploy.ts | 2 +- src/deploy_comet_adapter.ts | 69 +++++++++++++++ src/protocols/comet/comet_deploy.ts | 50 +++++++++++ src/protocols/comet/comet_setup.ts | 61 +++++++++++++ src/protocols/comet/create_pool.ts | 42 +++++++++ src/setup_comet.ts | 128 ---------------------------- src/test_comet_adapter.ts | 1 - 8 files changed, 227 insertions(+), 131 deletions(-) create mode 100644 src/deploy_comet_adapter.ts create mode 100644 src/protocols/comet/comet_deploy.ts create mode 100644 src/protocols/comet/comet_setup.ts create mode 100644 src/protocols/comet/create_pool.ts delete mode 100644 src/setup_comet.ts diff --git a/package.json b/package.json index 8b52324d..62b70c82 100644 --- a/package.json +++ b/package.json @@ -7,12 +7,14 @@ "build": "tsc", "deploy": "tsc && node dist/deploy.js", "deploy-phoenix-adapter": "tsc && node dist/deploy_phoenix_adapter.js", + "deploy-comet-adapter": "tsc && node dist/deploy_comet_adapter.js", "add-liquidity:phoenix": "tsc && node dist/protocols/phoenix/add_liquidity.js", "test": "tsc && node dist/test.js", "test:manual": "tsc && node dist/manual_testing/manual_tests.js", "publish_addresses": "tsc && node dist/publish_addresses.js", "test_adapter": "tsc && node dist/test_soroswap_adapter.js", "test_phoenix_adapter": "tsc && node dist/test_phoenix_adapter.js", + "test_comet_adapter": "tsc && node dist/test_comet_adapter.js", "multi_test": "tsc && node dist/multi_test.js" }, "license": "MIT", @@ -30,5 +32,6 @@ "dependencies": { "@stellar/stellar-sdk": "^13.0.0", "dotenv": "^16.4.5" - } + }, + "packageManager": "yarn@1.22.22+sha512.a6b2f7906b721bba3d67d4aff083df04dad64c399707841b7acf00f6b133b7ac24255f2652fa22ae3534329dc6180534e98d17432037ff6fd140556e2bb3137e" } diff --git a/src/deploy.ts b/src/deploy.ts index 4cf85961..6f75a236 100644 --- a/src/deploy.ts +++ b/src/deploy.ts @@ -6,7 +6,7 @@ import { AddressBook } from './utils/address_book.js'; import { airdropAccount, deployContract, installContract, invokeContract } from './utils/contract.js'; import { config } from './utils/env_config.js'; import { TokensBook } from './utils/tokens_book.js'; -import { cometSetup } from './setup_comet.js'; +import { cometSetup } from './protocols/comet/comet_setup.js'; export async function deployAndInitAggregator(addressBook: AddressBook) { // if(network == 'mainnet') throw new Error('Mainnet not yet supported') diff --git a/src/deploy_comet_adapter.ts b/src/deploy_comet_adapter.ts new file mode 100644 index 00000000..8dc97cde --- /dev/null +++ b/src/deploy_comet_adapter.ts @@ -0,0 +1,69 @@ +import { Address, nativeToScVal, scValToNative, xdr } from '@stellar/stellar-sdk'; +import { randomBytes } from 'crypto'; +import { phoenixSetup } from './protocols/phoenix/phoenix_setup.js'; +import { updateAdapters } from './update_protocols.js'; +import { AddressBook } from './utils/address_book.js'; +import { airdropAccount, deployContract, installContract, invokeContract } from './utils/contract.js'; +import { config } from './utils/env_config.js'; +import { TokensBook } from './utils/tokens_book.js'; +import { createCometPool } from './protocols/comet/create_pool.js'; + +export async function deployCometAdapter(addressBook: AddressBook) { + // this is ment to be only for mainnet + + if(network != 'mainnet') throw new Error('Only Mainnet is Supported') + // await airdropAccount(loadedConfig.admin); + + console.log('-------------------------------------------------------'); + console.log('Deploying Adapter using the deployer'); + console.log('-------------------------------------------------------'); + console.log("** Comet Adapter"); + await installContract('comet_adapter', addressBook, loadedConfig.admin); + + const soroswapTokensBook = TokensBook.loadFromFile( + `../../protocols/soroswap/public` + ); + + const cometPairAddress = await createCometPool(addressBook, soroswapTokensBook, network, loadedConfig); + const initArgs = xdr.ScVal.scvVec([ + xdr.ScVal.scvString('comet_blend'), // protocol_id as ScVal string + new Address(cometPairAddress).toScVal(), // protocol_address as ScVal address + ]); + + const cometAdapterDeployParams: xdr.ScVal[] = [ + new Address(loadedConfig.admin.publicKey()).toScVal(), + nativeToScVal(Buffer.from(addressBook.getWasmHash('comet_adapter'), 'hex')), + nativeToScVal(randomBytes(32)), + xdr.ScVal.scvSymbol('initialize'), + initArgs, + ]; + const response = await invokeContract( + 'deployer', + addressBook, + 'deploy', + cometAdapterDeployParams, + loadedConfig.admin + ); + const cometAdapterAddress = scValToNative(response.returnValue)[0]; + console.log('🚀 « cometAdapterAddress:', cometAdapterAddress); + addressBook.setContractId('comet_adapter', cometAdapterAddress); + + console.log("Updating adapters on aggregator.. adding Phoenix") + await updateAdapters(addressBook); + +} + +const network = process.argv[2]; +if(network != 'mainnet') throw new Error('Only Mainnet is Supported') + +const addressBook = AddressBook.loadFromFile(network); + +const phoenixAddressBook = AddressBook.loadFromFile( + network, + `../../protocols/comet-addresses` +); + +const loadedConfig = config(network); + +await deployCometAdapter(addressBook); +addressBook.writeToFile(); diff --git a/src/protocols/comet/comet_deploy.ts b/src/protocols/comet/comet_deploy.ts new file mode 100644 index 00000000..38ec7097 --- /dev/null +++ b/src/protocols/comet/comet_deploy.ts @@ -0,0 +1,50 @@ +import { Address, Keypair, nativeToScVal } from '@stellar/stellar-sdk'; +import { AddressBook } from '../../utils/address_book.js'; +import { bumpContractCode, deployContract, installContract, invokeContract } from '../../utils/contract.js'; +import { config } from '../../utils/env_config.js'; + + +export async function deployAndInitComet(addressBook: AddressBook, cometAdmin: Keypair) { + console.log('Installing comet Contracts'); + // comet Factory + console.log('-------------------------------------------------------'); + console.log('Install and deploy Comet factory'); + console.log('-------------------------------------------------------'); + await installContract('comet_factory', addressBook, cometAdmin); + await bumpContractCode('comet_factory', addressBook, cometAdmin); + + // comet Pool + console.log('-------------------------------------------------------'); + console.log('Install and deploy Comet pool'); + console.log('-------------------------------------------------------'); + await installContract('comet_pool', addressBook, cometAdmin); + await bumpContractCode('comet_pool', addressBook, cometAdmin); + + // comet adapter + console.log('-------------------------------------------------------'); + console.log('Install and deploy Comet adapter'); + console.log('-------------------------------------------------------'); + await installContract('comet_adapter', addressBook, cometAdmin); + await bumpContractCode('comet_adapter', addressBook, cometAdmin); + + console.log('-------------------------------------------------------'); + console.log('Install and deploy Comet factory'); + console.log('-------------------------------------------------------'); + await deployContract('comet_factory', 'comet_factory', addressBook, cometAdmin); + + console.log('-------------------------------------------------------'); + console.log('Initializing comet Factory'); + console.log('-------------------------------------------------------'); + + // Initializing comet Factory + await invokeContract( + 'comet_factory', + addressBook, + 'init', + [nativeToScVal(Buffer.from(addressBook.getWasmHash('comet_pool'), 'hex'))], + loadedConfig.admin + ); +} + +const network = process.argv[2]; +const loadedConfig = config(network); diff --git a/src/protocols/comet/comet_setup.ts b/src/protocols/comet/comet_setup.ts new file mode 100644 index 00000000..96b0be23 --- /dev/null +++ b/src/protocols/comet/comet_setup.ts @@ -0,0 +1,61 @@ +import { Address, nativeToScVal, scValToNative, xdr } from '@stellar/stellar-sdk'; +import { airdropAccount, deployContract, installContract, invokeContract } from '../../utils/contract.js'; +import { TokensBook } from '../../utils/tokens_book.js'; +import { deployAndInitComet } from './comet_deploy.js'; +import { createCometPool } from './create_pool.js'; +import { randomBytes } from 'crypto'; + +export async function cometSetup(loadedConfig: any, addressBook: any) { + // Preparing setup + const network = process.argv[2]; + const soroswapDir = network === 'standalone' ? '.soroban' : 'public'; + const soroswapTokensBook = TokensBook.loadFromFile( + `../../protocols/soroswap/${soroswapDir}` + ); + // Preoaring users and admin + console.log('Loading Config for Comet'); + const admin = loadedConfig.getUser('TEST_USER_SECRET_KEY') + + console.log('Airdropping Admin'); + await airdropAccount(admin); + + const tokensAdminAccount = loadedConfig.getUser("TEST_TOKENS_ADMIN_SECRET_KEY"); + await airdropAccount(tokensAdminAccount); + + // Deploying and Initializing Comet + console.log('Deploying and Initalizing Comet'); + await deployAndInitComet(addressBook, admin) + + console.log('Installing Comet Adapter contract'); + await installContract('comet_adapter', addressBook, loadedConfig.admin); + await deployContract('comet_adapter', 'comet_adapter', addressBook, loadedConfig.admin); + + // Initializing Comet Adapter + console.log("Initializing Comet adapter") + + //Creating Comet Pool + const cometPairAddress = await createCometPool(addressBook, soroswapTokensBook, network, loadedConfig); + const initArgs = xdr.ScVal.scvVec([ + xdr.ScVal.scvString('comet_blend'), // protocol_id as ScVal string + new Address(cometPairAddress).toScVal(), // protocol_address as ScVal address + ]); + + const cometAdapterDeployParams: xdr.ScVal[] = [ + new Address(loadedConfig.admin.publicKey()).toScVal(), + nativeToScVal(Buffer.from(addressBook.getWasmHash('comet_adapter'), 'hex')), + nativeToScVal(randomBytes(32)), + xdr.ScVal.scvSymbol('initialize'), + initArgs, + ]; + const response = await invokeContract( + 'deployer', + addressBook, + 'deploy', + cometAdapterDeployParams, + loadedConfig.admin + ); + const cometAdapterAddress = scValToNative(response.returnValue)[0]; + console.log('🚀 « cometAdapterAddress:', cometAdapterAddress); + addressBook.setContractId('comet_adapter', cometAdapterAddress); + return cometAdapterAddress; +} \ No newline at end of file diff --git a/src/protocols/comet/create_pool.ts b/src/protocols/comet/create_pool.ts new file mode 100644 index 00000000..547e9c5f --- /dev/null +++ b/src/protocols/comet/create_pool.ts @@ -0,0 +1,42 @@ +import { Address, Asset, nativeToScVal, scValToNative } from '@stellar/stellar-sdk'; +import { AddressBook } from '../../utils/address_book.js'; +import { invokeContract } from '../../utils/contract.js'; +import { EnvConfig } from '../../utils/env_config.js'; +import { randomBytes } from 'crypto'; +import { TokensBook } from '../../utils/tokens_book.js'; +import { mintToken } from '../../mint_token.js'; + +export async function createCometPool(addressBook: AddressBook, tokensBook:TokensBook, network: string, loadedConfig: EnvConfig,) { + const tokens = tokensBook.getTokensByNetwork(network); + if(!tokens || tokens.length <= 0) throw new Error('No tokens found in the tokens book'); + console.log('🚀 « tokens:', tokens[0]); + console.log('🚀 « tokens:', tokens[2]); + console.log('creating comet pair...'); + + await mintToken(tokens[0].contract, 800_0000000, loadedConfig.admin.publicKey(), loadedConfig.tokenAdmin); + await mintToken(tokens[2].contract, 200_0000000, loadedConfig.admin.publicKey(), loadedConfig.tokenAdmin); + const createCometPairResponse = await invokeContract( + 'comet_factory', + addressBook, + 'new_c_pool', + [ + nativeToScVal(randomBytes(32)), //bytes32 salt + new Address(loadedConfig.admin.publicKey()).toScVal(), //controller + nativeToScVal([new Address(tokens[0].contract).toScVal(), new Address(tokens[2].contract).toScVal()]), //tokens + nativeToScVal([ //weights + nativeToScVal(8000000, { type: 'i128' }), + nativeToScVal(2000000, { type: 'i128' }), + ]), + nativeToScVal([ //balances + nativeToScVal(800_0000000, { type: 'i128' }), + nativeToScVal(200_0000000, { type: 'i128' }), + ]),//swap_fee + nativeToScVal(30_000, { type: 'i128' }), + ], + loadedConfig.admin + ); + const cometPairAddress = scValToNative(createCometPairResponse.returnValue) + console.log('🚀 « comet pair address:', cometPairAddress); + return cometPairAddress; +} + diff --git a/src/setup_comet.ts b/src/setup_comet.ts deleted file mode 100644 index 647bf490..00000000 --- a/src/setup_comet.ts +++ /dev/null @@ -1,128 +0,0 @@ -import { Address, Asset, nativeToScVal, Networks, scValToNative, xdr } from '@stellar/stellar-sdk'; -import { AddressBook } from './utils/address_book.js'; -import { deployContract, installContract, invokeContract } from './utils/contract.js'; -import { EnvConfig } from './utils/env_config.js'; -import { randomBytes } from 'crypto'; -import { TokensBook } from './utils/tokens_book.js'; -import test from 'node:test'; -import { mintToken } from './mint_token.js'; -import { deployAndMint } from './manual_testing/utils.js'; - -async function initTokens(loadedConfig: EnvConfig, tokensBook: TokensBook) { - const tokens = tokensBook.getTokensByNetwork('testnet'); - - if (tokens != undefined && tokens.length > 1) { - return; - } - - tokensBook.addToken('testnet', { - name: 'xlm', - contract: 'CDLZFC3SYJYDZT7K67VZ75HPJVIEUVNIXF47ZG2FB2RMQQVU2HHGCYSC', - code: 'XLM', - decimals: 7, - }); - - let asset = new Asset('hi', loadedConfig.tokenAdmin.publicKey()) - - await deployAndMint(asset, loadedConfig.admin, "100000000000"); - - tokensBook.addToken('testnet', { - name: 'hi', - contract: asset.contractId(Networks.TESTNET), - code: 'hi', - decimals: 7, - }); - - tokensBook.writeToFile() -} - -export async function cometSetup(loadedConfig: EnvConfig, addressBook: AddressBook) { - const tokensBook = TokensBook.loadFromFile(`../../.soroban`); - - await initTokens(loadedConfig, tokensBook) - - const tokens = tokensBook.getTokensByNetwork("testnet") - - if (tokens == undefined) { - throw 'could not find tokens'; - } - - let tokenA = tokens[0]; // xlm - let tokenB = tokens[1]; - - await mintToken( - tokenB.contract, - 25000000000000, - loadedConfig.admin.publicKey(), - loadedConfig.tokenAdmin - ); - - console.log('uploading comet pair...'); - await installContract('comet_pool', addressBook, loadedConfig.admin); - - console.log('deploying comet factory...'); - await installContract('comet_factory', addressBook, loadedConfig.admin); - await deployContract('comet_factory', 'comet_factory', addressBook, loadedConfig.admin); - - await invokeContract( - 'comet_factory', - addressBook, - 'init', - [nativeToScVal(Buffer.from(addressBook.getWasmHash('comet_pool'), 'hex'))], - loadedConfig.admin - ); - - console.log('creating comet pair...'); - const createCometPairResponse = await invokeContract( - 'comet_factory', - addressBook, - 'new_c_pool', - [ - nativeToScVal(randomBytes(32)), - new Address(loadedConfig.admin.publicKey()).toScVal(), - nativeToScVal([new Address(tokenA.contract).toScVal(), new Address(tokenB.contract).toScVal()]), - nativeToScVal([ - nativeToScVal(8000000, { type: 'i128' }), - nativeToScVal(2000000, { type: 'i128' }), - ]), - nativeToScVal([ - nativeToScVal(800_0000000, { type: 'i128' }), - nativeToScVal(200_0000000, { type: 'i128' }), - ]), - nativeToScVal(30000, { type: 'i128' }), - ], - loadedConfig.admin - ); - const cometPairAddress = scValToNative(createCometPairResponse.returnValue) - - addressBook.setContractId("comet_pair", cometPairAddress) - console.log('🚀 « comet pair address:', cometPairAddress); - - await installContract('comet_adapter', addressBook, loadedConfig.admin); - - const initArgs = xdr.ScVal.scvVec([ - xdr.ScVal.scvString('comet_blend'), // protocol_id as ScVal string - new Address(cometPairAddress).toScVal(), // protocol_address as ScVal address - ]); - - const cometAdapterDeployParams: xdr.ScVal[] = [ - new Address(loadedConfig.admin.publicKey()).toScVal(), - nativeToScVal(Buffer.from(addressBook.getWasmHash('comet_adapter'), 'hex')), - nativeToScVal(randomBytes(32)), - xdr.ScVal.scvSymbol('initialize'), - initArgs, - ]; - - const response = await invokeContract( - 'deployer', - addressBook, - 'deploy', - cometAdapterDeployParams, - loadedConfig.admin - ); - - const cometAdapterAddress = scValToNative(response.returnValue)[0]; - console.log('🚀 « cometAdapterAddress:', cometAdapterAddress); - // SAVE ADDRES IN ADDRESS BOOK - addressBook.setContractId('comet_adapter', cometAdapterAddress); -} diff --git a/src/test_comet_adapter.ts b/src/test_comet_adapter.ts index b2ef49f6..78416f23 100644 --- a/src/test_comet_adapter.ts +++ b/src/test_comet_adapter.ts @@ -4,7 +4,6 @@ import { invokeContract } from './utils/contract.js'; import { config } from './utils/env_config.js'; import { getCurrentTimePlusOneHour } from './utils/tx.js'; import { TokensBook } from './utils/tokens_book.js'; -import { cometSetup } from './setup_comet.js'; export async function testCometAdapter(addressBook: AddressBook) { console.log('-------------------------------------------------------'); From 8996eb13b11eac6183fdc62936db7496a0d2070a Mon Sep 17 00:00:00 2001 From: Matias Poblete <86752543+MattPoblete@users.noreply.github.com> Date: Fri, 20 Dec 2024 13:14:21 -0300 Subject: [PATCH 6/7] =?UTF-8?q?=E2=99=BB=EF=B8=8F=20Refactor=20deploy=20sc?= =?UTF-8?q?ripts?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/deploy.ts | 16 +++++++++++++--- src/deploy_comet_adapter.ts | 13 +++---------- src/deploy_phoenix_adapter.ts | 2 +- src/protocols/comet/create_pool.ts | 13 +++++++++---- src/update_protocols.ts | 24 ++++++++++++++++-------- 5 files changed, 42 insertions(+), 26 deletions(-) diff --git a/src/deploy.ts b/src/deploy.ts index 6f75a236..64ff4d58 100644 --- a/src/deploy.ts +++ b/src/deploy.ts @@ -74,6 +74,11 @@ export async function deployAndInitAggregator(addressBook: AddressBook) { protocol_id: "comet_blend", address: new Address(addressBook.getContractId('comet_adapter')), paused: false + }, + { + protocol_id: "phoenix", + address: new Address(addressBook.getContractId('phoenix_adapter')), + paused: false } ]; @@ -121,12 +126,17 @@ export async function deployAndInitAggregator(addressBook: AddressBook) { console.log("Aggregator initialized") + const adaptersNames = adaptersVec.map((adapter) => { + const protocol_id = adapter.protocol_id.toString() + return protocol_id + ', ' + } + ) if (network != 'mainnet') { console.log("Setting up Phoenix protocol") - // mocks + await phoenixSetup(loadedConfig, addressBook); - console.log("Updating adapters on aggregator.. adding Phoenix") - await updateAdapters(addressBook); + console.log("Updating adapters on aggregator.. adding: ", ...adaptersNames) + await updateAdapters(addressBook, adaptersVec); } // TODO: IF MAINNET, UPDATE PHOENIX ADAPTERS WITH MAINNET DEPLOYMENT ADDRESS diff --git a/src/deploy_comet_adapter.ts b/src/deploy_comet_adapter.ts index 8dc97cde..b2383595 100644 --- a/src/deploy_comet_adapter.ts +++ b/src/deploy_comet_adapter.ts @@ -1,9 +1,8 @@ import { Address, nativeToScVal, scValToNative, xdr } from '@stellar/stellar-sdk'; import { randomBytes } from 'crypto'; -import { phoenixSetup } from './protocols/phoenix/phoenix_setup.js'; import { updateAdapters } from './update_protocols.js'; import { AddressBook } from './utils/address_book.js'; -import { airdropAccount, deployContract, installContract, invokeContract } from './utils/contract.js'; +import { installContract, invokeContract } from './utils/contract.js'; import { config } from './utils/env_config.js'; import { TokensBook } from './utils/tokens_book.js'; import { createCometPool } from './protocols/comet/create_pool.js'; @@ -48,8 +47,8 @@ export async function deployCometAdapter(addressBook: AddressBook) { console.log('🚀 « cometAdapterAddress:', cometAdapterAddress); addressBook.setContractId('comet_adapter', cometAdapterAddress); - console.log("Updating adapters on aggregator.. adding Phoenix") - await updateAdapters(addressBook); + console.log("Updating adapters on aggregator.. adding Comet") + await updateAdapters(addressBook, [{protocol_id: 'comet_blend', address: new Address(cometAdapterAddress), paused: false}]); } @@ -57,12 +56,6 @@ const network = process.argv[2]; if(network != 'mainnet') throw new Error('Only Mainnet is Supported') const addressBook = AddressBook.loadFromFile(network); - -const phoenixAddressBook = AddressBook.loadFromFile( - network, - `../../protocols/comet-addresses` -); - const loadedConfig = config(network); await deployCometAdapter(addressBook); diff --git a/src/deploy_phoenix_adapter.ts b/src/deploy_phoenix_adapter.ts index be9aed32..5e8e2ece 100644 --- a/src/deploy_phoenix_adapter.ts +++ b/src/deploy_phoenix_adapter.ts @@ -51,7 +51,7 @@ export async function deployPhoenixAdapter(addressBook: AddressBook) { addressBook.setContractId("phoenix_adapter", phoenixAdapterAddress) console.log("Updating adapters on aggregator.. adding Phoenix") - await updateAdapters(addressBook); + await updateAdapters(addressBook, [{protocol_id: 'phoenix', address: new Address(phoenixAdapterAddress), paused: false}]); } diff --git a/src/protocols/comet/create_pool.ts b/src/protocols/comet/create_pool.ts index 547e9c5f..e83a3503 100644 --- a/src/protocols/comet/create_pool.ts +++ b/src/protocols/comet/create_pool.ts @@ -9,12 +9,17 @@ import { mintToken } from '../../mint_token.js'; export async function createCometPool(addressBook: AddressBook, tokensBook:TokensBook, network: string, loadedConfig: EnvConfig,) { const tokens = tokensBook.getTokensByNetwork(network); if(!tokens || tokens.length <= 0) throw new Error('No tokens found in the tokens book'); - console.log('🚀 « tokens:', tokens[0]); + console.log('🚀 « tokens:', tokens[3]); console.log('🚀 « tokens:', tokens[2]); console.log('creating comet pair...'); - await mintToken(tokens[0].contract, 800_0000000, loadedConfig.admin.publicKey(), loadedConfig.tokenAdmin); - await mintToken(tokens[2].contract, 200_0000000, loadedConfig.admin.publicKey(), loadedConfig.tokenAdmin); + const tokenPair = [tokens[3].contract, tokens[2].contract]; + if(tokens[2].contract > tokens[3].contract) { + tokenPair[0] = tokens[2].contract; + tokenPair[1] = tokens[3].contract; + } + await mintToken(tokenPair[0], 800_0000000, loadedConfig.admin.publicKey(), loadedConfig.tokenAdmin); + await mintToken(tokenPair[1], 200_0000000, loadedConfig.admin.publicKey(), loadedConfig.tokenAdmin); const createCometPairResponse = await invokeContract( 'comet_factory', addressBook, @@ -22,7 +27,7 @@ export async function createCometPool(addressBook: AddressBook, tokensBook:Token [ nativeToScVal(randomBytes(32)), //bytes32 salt new Address(loadedConfig.admin.publicKey()).toScVal(), //controller - nativeToScVal([new Address(tokens[0].contract).toScVal(), new Address(tokens[2].contract).toScVal()]), //tokens + nativeToScVal([new Address(tokenPair[0]).toScVal(), new Address(tokenPair[1]).toScVal()]), //tokens nativeToScVal([ //weights nativeToScVal(8000000, { type: 'i128' }), nativeToScVal(2000000, { type: 'i128' }), diff --git a/src/update_protocols.ts b/src/update_protocols.ts index dac5c68c..cb3e0e14 100644 --- a/src/update_protocols.ts +++ b/src/update_protocols.ts @@ -3,7 +3,13 @@ import { AddressBook } from './utils/address_book.js'; import { invokeContract } from './utils/contract.js'; import { config } from './utils/env_config.js'; -export async function updateAdapters(addressBook: AddressBook) { +interface UpdateAdapterProps { + protocol_id: string, + address: Address, + paused: boolean +} + +export async function updateAdapters(addressBook: AddressBook, adapters: UpdateAdapterProps[]) { // if(network == 'mainnet') throw new Error('Mainnet not yet supported') // pub struct Adapter { @@ -11,13 +17,15 @@ export async function updateAdapters(addressBook: AddressBook) { // pub address: Address, // pub paused: bool, // } - const adaptersVec = [ - { - protocol_id: "phoenix", - address: new Address(addressBook.getContractId('phoenix_adapter')), - paused: false - }, - ]; + + const adaptersVec: UpdateAdapterProps[] = []; + for (const adapter of adapters) { + adaptersVec.push({ + protocol_id: adapter.protocol_id, + address: adapter.address, + paused: adapter.paused, + }); + } const adaptersVecScVal = xdr.ScVal.scvVec(adaptersVec.map((adapter) => { return xdr.ScVal.scvMap([ From 4ec58ce8b1e7fa40a9e02cf77ef10a093cd2cca1 Mon Sep 17 00:00:00 2001 From: Matias Poblete <86752543+MattPoblete@users.noreply.github.com> Date: Fri, 20 Dec 2024 13:29:08 -0300 Subject: [PATCH 7/7] =?UTF-8?q?=E2=9C=A8Add=20script=20to=20setup=20protoc?= =?UTF-8?q?ols?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- package.json | 1 + src/protocols/setup_protocols.ts | 15 +++++++++++++++ 2 files changed, 16 insertions(+) create mode 100644 src/protocols/setup_protocols.ts diff --git a/package.json b/package.json index 62b70c82..9b3c0c8b 100644 --- a/package.json +++ b/package.json @@ -9,6 +9,7 @@ "deploy-phoenix-adapter": "tsc && node dist/deploy_phoenix_adapter.js", "deploy-comet-adapter": "tsc && node dist/deploy_comet_adapter.js", "add-liquidity:phoenix": "tsc && node dist/protocols/phoenix/add_liquidity.js", + "setup-protocols": "tsc && node dist/protocols/setup_protocols.js", "test": "tsc && node dist/test.js", "test:manual": "tsc && node dist/manual_testing/manual_tests.js", "publish_addresses": "tsc && node dist/publish_addresses.js", diff --git a/src/protocols/setup_protocols.ts b/src/protocols/setup_protocols.ts new file mode 100644 index 00000000..8673ea1b --- /dev/null +++ b/src/protocols/setup_protocols.ts @@ -0,0 +1,15 @@ +import { AddressBook } from "../utils/address_book.js"; +import { config } from "../utils/env_config.js"; +import { cometSetup } from "./comet/comet_setup.js"; +import { phoenixSetup } from "./phoenix/phoenix_setup.js"; + +const network = process.argv[2]; +const addressBook = AddressBook.loadFromFile(network); +const loadedConfig = config(network); + +async function setupProtocols(){ + await phoenixSetup(loadedConfig, addressBook); + await cometSetup(loadedConfig, addressBook); +} + +await setupProtocols(); \ No newline at end of file