From 912233e704dbb80159a7099c888c5a2de1dc74ec Mon Sep 17 00:00:00 2001 From: sagar sapkota Date: Fri, 26 Apr 2024 17:11:00 +0545 Subject: [PATCH 01/63] inittial commit --- .gitignore | 11 + asset_manager/.gitignore | 9 + asset_manager/Cargo.toml | 30 ++ asset_manager/README.md | 21 ++ asset_manager/src/admin.rs | 18 ++ asset_manager/src/contract.rs | 264 ++++++++++++++++++ asset_manager/src/event.rs | 0 asset_manager/src/lib.rs | 9 + asset_manager/src/states.rs | 47 ++++ asset_manager/src/storage_types.rs | 26 ++ asset_manager/src/test.rs | 65 +++++ balanced_dollar/.gitignore | 9 + balanced_dollar/Cargo.toml | 31 ++ balanced_dollar/README.md | 21 ++ .../src/BalancedDollarCrossChain.rs | 104 +++++++ balanced_dollar/src/admin.rs | 18 ++ balanced_dollar/src/allowance.rs | 63 +++++ balanced_dollar/src/balance.rs | 35 +++ balanced_dollar/src/contract.rs | 173 ++++++++++++ balanced_dollar/src/lib.rs | 12 + balanced_dollar/src/metadata.rs | 22 ++ balanced_dollar/src/states.rs | 8 + balanced_dollar/src/storage_types.rs | 42 +++ balanced_dollar/src/test.rs | 253 +++++++++++++++++ xcall/Cargo.toml | 30 ++ xcall/src/lib.rs | 19 ++ xcall_manager/.gitignore | 9 + xcall_manager/Cargo.toml | 30 ++ xcall_manager/README.md | 21 ++ xcall_manager/src/admin.rs | 18 ++ xcall_manager/src/contract.rs | 170 +++++++++++ xcall_manager/src/events.rs | 0 xcall_manager/src/lib.rs | 9 + xcall_manager/src/states.rs | 47 ++++ xcall_manager/src/storage_types.rs | 21 ++ xcall_manager/src/test.rs | 0 36 files changed, 1665 insertions(+) create mode 100644 .gitignore create mode 100644 asset_manager/.gitignore create mode 100644 asset_manager/Cargo.toml create mode 100644 asset_manager/README.md create mode 100644 asset_manager/src/admin.rs create mode 100644 asset_manager/src/contract.rs create mode 100644 asset_manager/src/event.rs create mode 100644 asset_manager/src/lib.rs create mode 100644 asset_manager/src/states.rs create mode 100644 asset_manager/src/storage_types.rs create mode 100644 asset_manager/src/test.rs create mode 100644 balanced_dollar/.gitignore create mode 100644 balanced_dollar/Cargo.toml create mode 100644 balanced_dollar/README.md create mode 100644 balanced_dollar/src/BalancedDollarCrossChain.rs create mode 100644 balanced_dollar/src/admin.rs create mode 100644 balanced_dollar/src/allowance.rs create mode 100644 balanced_dollar/src/balance.rs create mode 100644 balanced_dollar/src/contract.rs create mode 100644 balanced_dollar/src/lib.rs create mode 100644 balanced_dollar/src/metadata.rs create mode 100644 balanced_dollar/src/states.rs create mode 100644 balanced_dollar/src/storage_types.rs create mode 100644 balanced_dollar/src/test.rs create mode 100644 xcall/Cargo.toml create mode 100644 xcall/src/lib.rs create mode 100644 xcall_manager/.gitignore create mode 100644 xcall_manager/Cargo.toml create mode 100644 xcall_manager/README.md create mode 100644 xcall_manager/src/admin.rs create mode 100644 xcall_manager/src/contract.rs create mode 100644 xcall_manager/src/events.rs create mode 100644 xcall_manager/src/lib.rs create mode 100644 xcall_manager/src/states.rs create mode 100644 xcall_manager/src/storage_types.rs create mode 100644 xcall_manager/src/test.rs diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..bf964a9 --- /dev/null +++ b/.gitignore @@ -0,0 +1,11 @@ +target +.soroban + +# environment variables +.env +.env.production + +# macOS-specific files +.DS_Store +Cargo.lock +*/test_snapshots/* \ No newline at end of file diff --git a/asset_manager/.gitignore b/asset_manager/.gitignore new file mode 100644 index 0000000..8d9d75c --- /dev/null +++ b/asset_manager/.gitignore @@ -0,0 +1,9 @@ +target +.soroban + +# environment variables +.env +.env.production + +# macOS-specific files +.DS_Store diff --git a/asset_manager/Cargo.toml b/asset_manager/Cargo.toml new file mode 100644 index 0000000..b74bd03 --- /dev/null +++ b/asset_manager/Cargo.toml @@ -0,0 +1,30 @@ +[package] +name = "asset-manager" +version = "0.1.0" +edition = "2021" + +[lib] +crate-type = ["cdylib"] + +[features] +testutils = ["soroban-sdk/testutils"] + +[dependencies] +soroban-sdk = "20.0.0" + +[dev_dependencies] +soroban-sdk = { version = "20.0.0", features = ["testutils"] } + +[profile.release] +opt-level = "z" +overflow-checks = true +debug = 0 +strip = "symbols" +debug-assertions = false +panic = "abort" +codegen-units = 1 +lto = true + +[profile.release-with-logs] +inherits = "release" +debug-assertions = true \ No newline at end of file diff --git a/asset_manager/README.md b/asset_manager/README.md new file mode 100644 index 0000000..012e23c --- /dev/null +++ b/asset_manager/README.md @@ -0,0 +1,21 @@ +# Soroban Project + +## Project Structure + +This repository uses the recommended structure for a Soroban project: +```text +. +├── contracts +│   └── hello_world +│   ├── src +│   │   ├── lib.rs +│   │   └── test.rs +│   └── Cargo.toml +├── Cargo.toml +└── README.md +``` + +- New Soroban contracts can be put in `contracts`, each in their own directory. There is already a `hello_world` contract in there to get you started. +- If you initialized this project with any other example contracts via `--with-example`, those contracts will be in the `contracts` directory as well. +- Contracts should have their own `Cargo.toml` files that rely on the top-level `Cargo.toml` workspace for their dependencies. +- Frontend libraries can be added to the top-level directory as well. If you initialized this project with a frontend template via `--frontend-template` you will have those files already included. \ No newline at end of file diff --git a/asset_manager/src/admin.rs b/asset_manager/src/admin.rs new file mode 100644 index 0000000..85f4a52 --- /dev/null +++ b/asset_manager/src/admin.rs @@ -0,0 +1,18 @@ +use soroban_sdk::{Address, Env}; + +use crate::storage_types::DataKey; + +pub fn has_administrator(e: &Env) -> bool { + let key = DataKey::Admin; + e.storage().instance().has(&key) +} + +pub fn read_administrator(e: &Env) -> Address { + let key = DataKey::Admin; + e.storage().instance().get(&key).unwrap() +} + +pub fn write_administrator(e: &Env, id: &Address) { + let key = DataKey::Admin; + e.storage().instance().set(&key, id); +} \ No newline at end of file diff --git a/asset_manager/src/contract.rs b/asset_manager/src/contract.rs new file mode 100644 index 0000000..f1ea819 --- /dev/null +++ b/asset_manager/src/contract.rs @@ -0,0 +1,264 @@ +use soroban_sdk::{contract, contractimpl, contracttype, symbol_short, token, vec, Address, bytes, BytesN, Env, String, Symbol, Vec, Map}; + +use crate::{ + admin:: {has_administrator, read_administrator, write_administrator}, + storage_types::{DataKey, POINTS, INSTANCE_LIFETIME_THRESHOLD, INSTANCE_BUMP_AMOUNT}, + states::{has_state, read_address_state, read_string_state} +}; + +use crate::contract::xcall_manager::Client; + +pub mod xcall_manager { + soroban_sdk::contractimport!( + file = "../xcall_manager/target/wasm32-unknown-unknown/release/xcall_manager.wasm" + ); +} + +pub mod xcall { + soroban_sdk::contractimport!( + file = "../xcall/target/wasm32-unknown-unknown/release/xcall.wasm" + ); +} + +#[contract] +pub struct AssetManager; + +#[contractimpl] +impl AssetManager { + + pub fn initialize(env:Env, registry:Address, admin: Address, xcall: Address, + xcall_manager: Address, native_address: Address, icon_asset_manager: String) { + if has_state(env.clone(), DataKey::Registry) { + panic!("Contract already initialized.") + } + let xcall_network_address = String::from_str(&env, "xcall_network_address"); // xcall::Client::new(&env, &xcall).get_network_address(&icon_asset_manager); + env.storage().instance().set(&DataKey::Registry, ®istry); + env.storage().instance().set(&DataKey::Admin, &admin); + Self::configure(env, xcall, xcall_manager, native_address, icon_asset_manager, xcall_network_address ); + } + + pub fn set_admin(e: Env, new_admin: Address) { + let admin = read_administrator(&e); + admin.require_auth(); + + e.storage() + .instance() + .extend_ttl(INSTANCE_LIFETIME_THRESHOLD, INSTANCE_BUMP_AMOUNT); + + write_administrator(&e, &new_admin); + } + + pub fn configure(env:Env, xcall: Address, + xcall_manager: Address, native_address: Address, icon_asset_manager: String, xcall_network_address: String){ + let admin = read_administrator(&env.clone()); + admin.require_auth(); + + env.storage().instance().set(&DataKey::XCall, &xcall); + env.storage().instance().set(&DataKey::XCallManager, &xcall_manager); + env.storage().instance().set(&DataKey::NativeAddress, &native_address); + env.storage().instance().set(&DataKey::IconAssetManager, &icon_asset_manager); + env.storage().instance().set(&DataKey::XCallNetworkAddress, &xcall_network_address); + } + + + pub fn configure_rate_limit( + env: Env, + token: Address, + period: i128, + percentage: i128, + ) { + let admin = read_administrator(&env.clone()); + admin.require_auth(); + + if percentage > POINTS {panic!("Percentage should be less than or equal to POINTS"); } + + let token_client = token::Client::new(&env, &token); + let contract_token_balance = token_client.balance(&env.current_contract_address()); + + env.storage().instance().set(&DataKey::Period(token.clone()), &period); + env.storage().instance().set(&DataKey::Percentage(token.clone()), &percentage); + env.storage().instance().set(&DataKey::LastUpdate(token.clone()), &env.ledger().timestamp()); + env.storage().instance().set(&DataKey::CurrentLimit(token.clone()), &(contract_token_balance*percentage/POINTS)); + + } + + pub fn reset_limit(env: Env, token: Address){ + let token_client = token::Client::new(&env, &token); + let contract_token_balance = token_client.balance(&env.current_contract_address()); + let percentage: i128 = env.storage().instance().get(&DataKey::Percentage(token.clone())).unwrap(); + + env.storage().instance().set(&DataKey::CurrentLimit(token.clone()), &(contract_token_balance*percentage/POINTS)); + } + + pub fn verify_withdraw(env: Env, token: Address, amount: i128) { + let period: i128 = env.storage().instance().get(&DataKey::Period(token.clone())).unwrap(); + let percentage: i128 = env.storage().instance().get(&DataKey::Percentage(token.clone())).unwrap(); + if period == 0 { + return; + } + + let token_client = token::Client::new(&env, &token); + let balance = token_client.balance(&env.current_contract_address()); + + let max_limit = (balance * percentage) / POINTS; + + // The maximum amount that can be withdraw in one period + let max_withdraw = balance - max_limit; + let last_update: u64 = env.storage().instance().get(&DataKey::LastUpdate(token.clone())).unwrap(); + let time_diff = &env.ledger().timestamp() - last_update; + + // The amount that should be added as availbe + let added_allowed_withdrawal = (max_withdraw * i128::from(time_diff)) / period; + let current_limit: i128 = env.storage().instance().get(&DataKey::CurrentLimit(token.clone())).unwrap(); + let limit = current_limit - added_allowed_withdrawal; + + // If the balance is below the limit then set limt to current balance (no withdraws are possible) + let limit: i128 = if balance < limit { balance } else { limit }; + + // If limit goes below what the protected percentage is set it to the maxLimit + let fina_limit = if limit > max_limit { limit } else { max_limit }; + if balance - amount < fina_limit { panic!("exceeds withdraw limit"); }; + + env.storage().instance().set(&DataKey::CurrentLimit(token.clone()), &fina_limit); + env.storage().instance().set(&DataKey::LastUpdate(token.clone()), &env.ledger().timestamp()); + } + + pub fn deposit( + e: Env, + from: Address, + value: i128, + token: Address, + amount: i128, + to: Option, + data: Option> + ) { + if amount < 0 { + panic!("Amount less than minimum amount"); + } + let depositTo = to.unwrap_or(String::from_str(&e, "")); + let depositData = data.unwrap_or(BytesN::from_array(&e, &[0u8; 32])); + + Self::send_deposit_message(e, from, token, amount, depositTo, depositData, value); + } + + pub fn deposit_native( + e: Env, + from: Address, + value: i128, + amount: i128, + to: Option, + data: Option> + ) { + if value < amount { + panic!("Amount less than minimum amount"); + } + + let depositTo = to.unwrap_or(String::from_str(&e, "")); + let depositData = data.unwrap_or(BytesN::from_array(&e, &[0u8; 32])); + + let fee: i128 = value - amount; + let native_address = read_address_state(&e, DataKey::NativeAddress); + Self::send_deposit_message(e, from, native_address, amount, depositTo, depositData, fee); + } + + fn send_deposit_message( + e: Env, + from: Address, + token: Address, + amount: i128, + to: String, + data: BytesN<32>, + fee: i128 + ) { + Self::transfer_token_to(e.clone(), from, token, e.current_contract_address(), fee); + + // Messages.Deposit memory xcallMessage = Messages.Deposit( + // token.toString(), + // msg.sender.toString(), + // to, + // amount, + // data + // ); + // Messages.DepositRevert memory rollback = Messages.DepositRevert( + // token, + // amount, + // msg.sender + // ); + + let protocols: Map> = Self::get_xcall_manager_client(e).get_protocols(); + // ICallService(xCall).sendCallMessage{value: fee}( + // iconAssetManager, + // xcallMessage.encodeDeposit(), + // rollback.encodeDepositRevert(), + // protocols.sources, + // protocols.destinations + // ); + } + + fn get_xcall_manager_client(e: Env) -> Client<'static> { + return xcall_manager::Client::new(&e, &read_address_state(&e, DataKey::XCallManager)); + } + + pub fn handle_call_message( + e: Env, + from: Address, + data: BytesN<32>, + protocols: Vec + ) { + read_address_state(&e, DataKey::XCall).require_auth(); + if ! Self::get_xcall_manager_client(e).verify_protocols(&protocols) { + panic!("Protocol Mismatch"); + } + + // string memory method = data.getMethod(); + // if (method.compareTo(Messages.WITHDRAW_TO_NAME)) { + // require(from.compareTo(iconAssetManager), "onlyICONAssetManager"); + // Messages.WithdrawTo memory message = data.decodeWithdrawTo(); + // withdraw( + // message.tokenAddress.parseAddress("Invalid account"), + // message.to.parseAddress("Invalid account"), + // message.amount + // ); + // } else if (method.compareTo(Messages.WITHDRAW_NATIVE_TO_NAME)) { + // revert("Withdraw to native is currently not supported"); + // } else if (method.compareTo(Messages.DEPOSIT_REVERT_NAME)) { + // require(from.compareTo(xCallNetworkAddress), "onlyCallService"); + // Messages.DepositRevert memory message = data.decodeDepositRevert(); + // withdraw(message.tokenAddress, message.to, message.amount); + // } else { + // revert("Unknown message type"); + // } + } + + pub fn withdraw(e: Env, from: Address, token: Address, to: Address, amount: i128) { + if amount <= 0 { + panic!("Amount less than minimum amount"); + } + + Self::verify_withdraw(e.clone(), token.clone(), amount); + Self::transfer_token_to(e, from, token, to, amount); + } + + fn transfer_token_to(e: Env, from: Address, token: Address, to: Address, amount: i128){ + let token_client = token::Client::new(&e, &token); + token_client.transfer_from(&from, &from, &to, &amount); + } + + pub fn balanceOf(e: Env, token: Address) -> i128 { + let token_client = token::Client::new(&e, &token); + return token_client.balance(&e.current_contract_address()); + } + + + pub fn has_registry(e: Env) -> bool { + has_state(e, DataKey::Registry) + } + + pub fn upgrade(e: Env, new_wasm_hash: BytesN<32>) { + let admin: Address = e.storage().instance().get(&DataKey::Admin).unwrap(); + admin.require_auth(); + + e.deployer().update_current_contract_wasm(new_wasm_hash); + } + +} \ No newline at end of file diff --git a/asset_manager/src/event.rs b/asset_manager/src/event.rs new file mode 100644 index 0000000..e69de29 diff --git a/asset_manager/src/lib.rs b/asset_manager/src/lib.rs new file mode 100644 index 0000000..8bf025f --- /dev/null +++ b/asset_manager/src/lib.rs @@ -0,0 +1,9 @@ +#![no_std] + +mod admin; +mod contract; +mod storage_types; +mod test; +mod states; + +pub use crate::contract::AssetManagerClient; \ No newline at end of file diff --git a/asset_manager/src/states.rs b/asset_manager/src/states.rs new file mode 100644 index 0000000..49faea1 --- /dev/null +++ b/asset_manager/src/states.rs @@ -0,0 +1,47 @@ +use soroban_sdk::{Address, Env, String, Vec}; + +use crate::storage_types::DataKey; + +pub fn has_state(env:Env, key: DataKey) -> bool { + env.storage().instance().has(&key) +} + +pub fn write_string_state(e: &Env, key: DataKey, id: &String) { + e.storage().instance().set(&key, id); +} + +pub fn write_address_state(e: &Env, key: DataKey, id: &Address) { + e.storage().instance().set(&key, id); +} + +pub fn write_u64_state(e: &Env, key: DataKey, id: &u64) { + e.storage().instance().set(&key, id); +} + +pub fn write_i128_state(e: &Env, key: DataKey, id: &i128) { + e.storage().instance().set(&key, id); +} + +pub fn write_vec_string_state(e: &Env, key: DataKey, id: &Vec) { + e.storage().instance().set(&key, id); +} + +pub fn read_string_state(e: &Env, key: DataKey) -> String { + e.storage().instance().get(&key).unwrap() +} + +pub fn read_address_state(e: &Env, key: DataKey) -> Address { + e.storage().instance().get(&key).unwrap() +} + +pub fn read_u64_state(e: &Env, key: DataKey) -> u64 { + e.storage().instance().get(&key).unwrap() +} + +pub fn read_i128_state(e: &Env, key: DataKey) -> i128 { + e.storage().instance().get(&key).unwrap() +} + +pub fn read_vec_string_state(e: &Env, key: DataKey) -> Vec { + e.storage().instance().get(&key).unwrap() +} \ No newline at end of file diff --git a/asset_manager/src/storage_types.rs b/asset_manager/src/storage_types.rs new file mode 100644 index 0000000..153d74e --- /dev/null +++ b/asset_manager/src/storage_types.rs @@ -0,0 +1,26 @@ +use soroban_sdk::{contracttype, Address}; + +pub(crate) const DAY_IN_LEDGERS: u32 = 17280; +pub(crate) const INSTANCE_BUMP_AMOUNT: u32 = 7 * DAY_IN_LEDGERS; +pub(crate) const INSTANCE_LIFETIME_THRESHOLD: u32 = INSTANCE_BUMP_AMOUNT - DAY_IN_LEDGERS; + +pub(crate) const BALANCE_BUMP_AMOUNT: u32 = 30 * DAY_IN_LEDGERS; +pub(crate) const BALANCE_LIFETIME_THRESHOLD: u32 = BALANCE_BUMP_AMOUNT - DAY_IN_LEDGERS; + +pub(crate) const POINTS: i128 = 1000; + +#[derive(Clone)] +#[contracttype] +pub enum DataKey{ + Registry, + Admin, + XCall, + XCallNetworkAddress, + IconAssetManager, + XCallManager, + NativeAddress, + Period(Address), + Percentage(Address), + LastUpdate(Address), + CurrentLimit(Address) +} \ No newline at end of file diff --git a/asset_manager/src/test.rs b/asset_manager/src/test.rs new file mode 100644 index 0000000..550790f --- /dev/null +++ b/asset_manager/src/test.rs @@ -0,0 +1,65 @@ +#![cfg(test)] + +extern crate std; + +use crate::contract::{ + AssetManager, AssetManagerClient, xcall_manager +}; + +use crate::storage_types::{DataKey, POINTS}; + +use soroban_sdk::{ + symbol_short, + testutils::{Address as _, AuthorizedFunction, AuthorizedInvocation, Events}, + token, vec, Address, Bytes, Env, IntoVal, String, Symbol, +}; + +pub struct TestContext { + env: Env, + registry:Address, + admin: Address, + xcall: Address, + xcall_manager: Address, + native_address: Address, + icon_asset_manager: String, + xcall_network_address: String +} + +pub struct TokenRateLimit { + token: Address, + period: i128, + percentage: i128 +} + +impl TestContext { + pub fn default() -> Self { + let env = Env::default(); + let token_admin = Address::generate(&env); + Self { + registry: env.register_contract(None, AssetManager), + admin: Address::generate(&env), + xcall: Address::generate(&env), + xcall_manager: env.register_contract_wasm(None, xcall_manager::WASM), + native_address: env.register_stellar_asset_contract(token_admin.clone()), + icon_asset_manager: String::from_str(&env, "icon_asset_manager"), + xcall_network_address: String::from_str(&env, "xcall_network_address"), + env + } + } + + pub fn init_context(&self, client: &AssetManagerClient<'static>) { + self.env.mock_all_auths(); + client.initialize(&self.registry, &self.admin, &self.xcall, &self.xcall_manager, &self.native_address, &self.icon_asset_manager ); + } +} + +#[test] +fn test_initialize() { + let ctx = TestContext::default(); + let client = AssetManagerClient::new(&ctx.env, &ctx.registry); + + ctx.init_context(&client); + + let registry_exists = client.has_registry(); + assert_eq!(registry_exists, true) +} \ No newline at end of file diff --git a/balanced_dollar/.gitignore b/balanced_dollar/.gitignore new file mode 100644 index 0000000..8d9d75c --- /dev/null +++ b/balanced_dollar/.gitignore @@ -0,0 +1,9 @@ +target +.soroban + +# environment variables +.env +.env.production + +# macOS-specific files +.DS_Store diff --git a/balanced_dollar/Cargo.toml b/balanced_dollar/Cargo.toml new file mode 100644 index 0000000..c526bdf --- /dev/null +++ b/balanced_dollar/Cargo.toml @@ -0,0 +1,31 @@ +[package] +name = "balanced-dollar" +version = "0.1.0" +edition = "2021" + +[lib] +crate-type = ["cdylib"] + +[features] +testutils = ["soroban-sdk/testutils"] + +[dependencies] +soroban-sdk = "20.0.0" +soroban-token-sdk = { version = "20.0.0" } + +[dev_dependencies] +soroban-sdk = { version = "20.0.0", features = ["testutils"] } + +[profile.release] +opt-level = "z" +overflow-checks = true +debug = 0 +strip = "symbols" +debug-assertions = false +panic = "abort" +codegen-units = 1 +lto = true + +[profile.release-with-logs] +inherits = "release" +debug-assertions = true \ No newline at end of file diff --git a/balanced_dollar/README.md b/balanced_dollar/README.md new file mode 100644 index 0000000..012e23c --- /dev/null +++ b/balanced_dollar/README.md @@ -0,0 +1,21 @@ +# Soroban Project + +## Project Structure + +This repository uses the recommended structure for a Soroban project: +```text +. +├── contracts +│   └── hello_world +│   ├── src +│   │   ├── lib.rs +│   │   └── test.rs +│   └── Cargo.toml +├── Cargo.toml +└── README.md +``` + +- New Soroban contracts can be put in `contracts`, each in their own directory. There is already a `hello_world` contract in there to get you started. +- If you initialized this project with any other example contracts via `--with-example`, those contracts will be in the `contracts` directory as well. +- Contracts should have their own `Cargo.toml` files that rely on the top-level `Cargo.toml` workspace for their dependencies. +- Frontend libraries can be added to the top-level directory as well. If you initialized this project with a frontend template via `--frontend-template` you will have those files already included. \ No newline at end of file diff --git a/balanced_dollar/src/BalancedDollarCrossChain.rs b/balanced_dollar/src/BalancedDollarCrossChain.rs new file mode 100644 index 0000000..4466373 --- /dev/null +++ b/balanced_dollar/src/BalancedDollarCrossChain.rs @@ -0,0 +1,104 @@ +use soroban_sdk::{contractimpl, Address, Env, String}; + +pub mod xcall_manager { + soroban_sdk::contractimport!( + file = "../xcall_manager/target/wasm32-unknown-unknown/release/xcall_manager.wasm" + ); +} + +pub mod xcall { + soroban_sdk::contractimport!( + file = "../xcall/target/wasm32-unknown-unknown/release/xcall.wasm" + ); +} + +#[contractimpl] +impl BalancedDollar { + + pub fn cross_transfer( + from: Address, + amount: i128, + to: String, + value: i128 + ) { + from.require_auth(); + _cross_transfer(from, amount, to, value, String::from_str("")); + } + + pub fn cross_transfer( + from: Address, + amount: i128, + to: String, + value: i128, + data: BytesN + ) { + from.require_auth(); + _crossTransfer(from, amount, to, value, data); + } + + fn _crossTransfer( + from: Address, + amount: i128, + to: String, + value: i128, + data: BytesN + ) { + if value <= 0 { + panic!("Amount less than minimum amount"); + } + Self::burn(from, value); + + // string memory from = nid.networkAddress(msg.sender.toString()); + // // Validate address + // to.parseNetworkAddress(); + // Messages.XCrossTransfer memory xcallMessage = Messages.XCrossTransfer( + // from, + // to, + // value, + // data + // ); + + // Messages.XCrossTransferRevert memory rollback = Messages.XCrossTransferRevert( + // msg.sender, + // value + // ); + + let protocols: Vec = xcall_manager::Client::getProtocols(); + + // ICallService(xCall).sendCallMessage{value: msg.value}( + // iconBnUSD, + // xcallMessage.encodeCrossTransfer(), + // rollback.encodeCrossTransferRevert(), + // protocols.sources, + // protocols.destinations + // ); + + } + + pub fn handle_call_message( + from: String, + data: BytesN, + protocols: Vec + ) { + xCall.require_auth(); + let protocols: Vec = xcall_manager::Client::getProtocols(); + + // string memory method = data.getMethod(); + // if (method.compareTo(Messages.CROSS_TRANSFER)) { + // require(from.compareTo(iconBnUSD), "onlyICONBnUSD"); + // Messages.XCrossTransfer memory message = data.decodeCrossTransfer(); + // (,string memory to) = message.to.parseNetworkAddress(); + // _mint(to.parseAddress("Invalid account"), message.value); + // } else if (method.compareTo(Messages.CROSS_TRANSFER_REVERT)) { + // require(from.compareTo(xCallNetworkAddress), "onlyCallService"); + // Messages.XCrossTransferRevert memory message = data.decodeCrossTransferRevert(); + // _mint(message.to, message.value); + // } else { + // revert("Unknown message type"); + // } + } + + + + +} \ No newline at end of file diff --git a/balanced_dollar/src/admin.rs b/balanced_dollar/src/admin.rs new file mode 100644 index 0000000..85f4a52 --- /dev/null +++ b/balanced_dollar/src/admin.rs @@ -0,0 +1,18 @@ +use soroban_sdk::{Address, Env}; + +use crate::storage_types::DataKey; + +pub fn has_administrator(e: &Env) -> bool { + let key = DataKey::Admin; + e.storage().instance().has(&key) +} + +pub fn read_administrator(e: &Env) -> Address { + let key = DataKey::Admin; + e.storage().instance().get(&key).unwrap() +} + +pub fn write_administrator(e: &Env, id: &Address) { + let key = DataKey::Admin; + e.storage().instance().set(&key, id); +} \ No newline at end of file diff --git a/balanced_dollar/src/allowance.rs b/balanced_dollar/src/allowance.rs new file mode 100644 index 0000000..603ff09 --- /dev/null +++ b/balanced_dollar/src/allowance.rs @@ -0,0 +1,63 @@ +use crate::storage_types::{AllowanceDataKey, AllowanceValue, DataKey}; +use soroban_sdk::{Address, Env}; + +pub fn read_allowance(e: &Env, from: Address, spender: Address) -> AllowanceValue { + let key = DataKey::Allowance(AllowanceDataKey { from, spender }); + if let Some(allowance) = e.storage().temporary().get::<_, AllowanceValue>(&key) { + if allowance.expiration_ledger < e.ledger().sequence() { + AllowanceValue { + amount: 0, + expiration_ledger: allowance.expiration_ledger, + } + } else { + allowance + } + } else { + AllowanceValue { + amount: 0, + expiration_ledger: 0, + } + } +} + +pub fn write_allowance( + e: &Env, + from: Address, + spender: Address, + amount: i128, + expiration_ledger: u32, +) { + let allowance = AllowanceValue { + amount, + expiration_ledger, + }; + + if amount > 0 && expiration_ledger < e.ledger().sequence() { + panic!("expiration_ledger is less than ledger seq when amount > 0") + } + + let key = DataKey::Allowance(AllowanceDataKey { from, spender }); + e.storage().temporary().set(&key.clone(), &allowance); + + if amount > 0 { + let live_for = expiration_ledger + .checked_sub(e.ledger().sequence()) + .unwrap(); + + e.storage().temporary().extend_ttl(&key, live_for, live_for) + } +} + +pub fn spend_allowance(e: &Env, from: Address, spender: Address, amount: i128) { + let allowance = read_allowance(e, from.clone(), spender.clone()); + if allowance.amount < amount { + panic!("insufficient allowance"); + } + write_allowance( + e, + from, + spender, + allowance.amount - amount, + allowance.expiration_ledger, + ); +} \ No newline at end of file diff --git a/balanced_dollar/src/balance.rs b/balanced_dollar/src/balance.rs new file mode 100644 index 0000000..66184d4 --- /dev/null +++ b/balanced_dollar/src/balance.rs @@ -0,0 +1,35 @@ +use crate::storage_types::{DataKey, BALANCE_BUMP_AMOUNT, BALANCE_LIFETIME_THRESHOLD}; +use soroban_sdk::{Address, Env}; + +pub fn read_balance(e: &Env, addr: Address) -> i128 { + let key = DataKey::Balance(addr); + if let Some(balance) = e.storage().persistent().get::(&key) { + e.storage() + .persistent() + .extend_ttl(&key, BALANCE_LIFETIME_THRESHOLD, BALANCE_BUMP_AMOUNT); + balance + } else { + 0 + } +} + +fn write_balance(e: &Env, addr: Address, amount: i128) { + let key = DataKey::Balance(addr); + e.storage().persistent().set(&key, &amount); + e.storage() + .persistent() + .extend_ttl(&key, BALANCE_LIFETIME_THRESHOLD, BALANCE_BUMP_AMOUNT); +} + +pub fn receive_balance(e: &Env, addr: Address, amount: i128) { + let balance = read_balance(e, addr.clone()); + write_balance(e, addr, balance + amount); +} + +pub fn spend_balance(e: &Env, addr: Address, amount: i128) { + let balance = read_balance(e, addr.clone()); + if balance < amount { + panic!("insufficient balance"); + } + write_balance(e, addr, balance - amount); +} \ No newline at end of file diff --git a/balanced_dollar/src/contract.rs b/balanced_dollar/src/contract.rs new file mode 100644 index 0000000..25611f4 --- /dev/null +++ b/balanced_dollar/src/contract.rs @@ -0,0 +1,173 @@ +//! This contract demonstrates a sample implementation of the Soroban token +//! interface. +use crate::admin::{has_administrator, read_administrator, write_administrator}; +use crate::allowance::{read_allowance, spend_allowance, write_allowance}; +use crate::balance::{read_balance, receive_balance, spend_balance}; +use crate::metadata::{read_decimal, read_name, read_symbol, write_metadata}; +use crate::storage_types::{INSTANCE_BUMP_AMOUNT, INSTANCE_LIFETIME_THRESHOLD}; +use soroban_sdk::token::{self, Interface as _}; +use soroban_sdk::{contract, contractimpl, Address, Env, String}; +use soroban_token_sdk::metadata::TokenMetadata; +use soroban_token_sdk::TokenUtils; + +fn check_nonnegative_amount(amount: i128) { + if amount < 0 { + panic!("negative amount is not allowed: {}", amount) + } +} + +#[contract] +pub struct BalancedDollar; + +#[contractimpl] +impl BalancedDollar { + pub fn initialize(e: Env, admin: Address) { + if has_administrator(&e) { + panic!("already initialized") + } + + write_administrator(&e, &admin); + //initialize token properties + let decimal = 18; + let name = String::from_str(&e, "Balanced Dollar"); + let symbol = String::from_str(&e, "bnUSD"); + + if decimal > u8::MAX.into() { + panic!("Decimal must fit in a u8"); + } + + write_metadata( + &e, + TokenMetadata { + decimal, + name, + symbol, + }, + ) + } + + pub fn mint(e: Env, to: Address, amount: i128) { + check_nonnegative_amount(amount); + let admin = read_administrator(&e); + admin.require_auth(); + + e.storage() + .instance() + .extend_ttl(INSTANCE_LIFETIME_THRESHOLD, INSTANCE_BUMP_AMOUNT); + + receive_balance(&e, to.clone(), amount); + TokenUtils::new(&e).events().mint(admin, to, amount); + } + + pub fn set_admin(e: Env, new_admin: Address) { + let admin = read_administrator(&e); + admin.require_auth(); + + e.storage() + .instance() + .extend_ttl(INSTANCE_LIFETIME_THRESHOLD, INSTANCE_BUMP_AMOUNT); + + write_administrator(&e, &new_admin); + TokenUtils::new(&e).events().set_admin(admin, new_admin); + } +} + +#[contractimpl] +impl token::Interface for BalancedDollar { + fn allowance(e: Env, from: Address, spender: Address) -> i128 { + e.storage() + .instance() + .extend_ttl(INSTANCE_LIFETIME_THRESHOLD, INSTANCE_BUMP_AMOUNT); + read_allowance(&e, from, spender).amount + } + + fn approve(e: Env, from: Address, spender: Address, amount: i128, expiration_ledger: u32) { + from.require_auth(); + + check_nonnegative_amount(amount); + + e.storage() + .instance() + .extend_ttl(INSTANCE_LIFETIME_THRESHOLD, INSTANCE_BUMP_AMOUNT); + + write_allowance(&e, from.clone(), spender.clone(), amount, expiration_ledger); + TokenUtils::new(&e) + .events() + .approve(from, spender, amount, expiration_ledger); + } + + fn balance(e: Env, id: Address) -> i128 { + e.storage() + .instance() + .extend_ttl(INSTANCE_LIFETIME_THRESHOLD, INSTANCE_BUMP_AMOUNT); + read_balance(&e, id) + } + + fn transfer(e: Env, from: Address, to: Address, amount: i128) { + from.require_auth(); + + check_nonnegative_amount(amount); + + e.storage() + .instance() + .extend_ttl(INSTANCE_LIFETIME_THRESHOLD, INSTANCE_BUMP_AMOUNT); + + spend_balance(&e, from.clone(), amount); + receive_balance(&e, to.clone(), amount); + TokenUtils::new(&e).events().transfer(from, to, amount); + } + + fn transfer_from(e: Env, spender: Address, from: Address, to: Address, amount: i128) { + spender.require_auth(); + + check_nonnegative_amount(amount); + + e.storage() + .instance() + .extend_ttl(INSTANCE_LIFETIME_THRESHOLD, INSTANCE_BUMP_AMOUNT); + + spend_allowance(&e, from.clone(), spender, amount); + spend_balance(&e, from.clone(), amount); + receive_balance(&e, to.clone(), amount); + TokenUtils::new(&e).events().transfer(from, to, amount) + } + + fn burn(e: Env, from: Address, amount: i128) { + from.require_auth(); + + check_nonnegative_amount(amount); + + e.storage() + .instance() + .extend_ttl(INSTANCE_LIFETIME_THRESHOLD, INSTANCE_BUMP_AMOUNT); + + spend_balance(&e, from.clone(), amount); + TokenUtils::new(&e).events().burn(from, amount); + } + + fn burn_from(e: Env, spender: Address, from: Address, amount: i128) { + spender.require_auth(); + + check_nonnegative_amount(amount); + + e.storage() + .instance() + .extend_ttl(INSTANCE_LIFETIME_THRESHOLD, INSTANCE_BUMP_AMOUNT); + + spend_allowance(&e, from.clone(), spender, amount); + spend_balance(&e, from.clone(), amount); + TokenUtils::new(&e).events().burn(from, amount) + } + + fn decimals(e: Env) -> u32 { + read_decimal(&e) + } + + fn name(e: Env) -> String { + read_name(&e) + } + + fn symbol(e: Env) -> String { + read_symbol(&e) + } +} \ No newline at end of file diff --git a/balanced_dollar/src/lib.rs b/balanced_dollar/src/lib.rs new file mode 100644 index 0000000..bd4a125 --- /dev/null +++ b/balanced_dollar/src/lib.rs @@ -0,0 +1,12 @@ +#![no_std] + +mod admin; +mod allowance; +mod balance; +mod contract; +mod metadata; +mod states; +mod storage_types; +mod test; + +pub use crate::contract::BalancedDollarClient; \ No newline at end of file diff --git a/balanced_dollar/src/metadata.rs b/balanced_dollar/src/metadata.rs new file mode 100644 index 0000000..7977778 --- /dev/null +++ b/balanced_dollar/src/metadata.rs @@ -0,0 +1,22 @@ +use soroban_sdk::{Env, String}; +use soroban_token_sdk::{metadata::TokenMetadata, TokenUtils}; + +pub fn read_decimal(e: &Env) -> u32 { + let util = TokenUtils::new(e); + util.metadata().get_metadata().decimal +} + +pub fn read_name(e: &Env) -> String { + let util = TokenUtils::new(e); + util.metadata().get_metadata().name +} + +pub fn read_symbol(e: &Env) -> String { + let util = TokenUtils::new(e); + util.metadata().get_metadata().symbol +} + +pub fn write_metadata(e: &Env, metadata: TokenMetadata) { + let util = TokenUtils::new(e); + util.metadata().set_metadata(&metadata); +} \ No newline at end of file diff --git a/balanced_dollar/src/states.rs b/balanced_dollar/src/states.rs new file mode 100644 index 0000000..49caaff --- /dev/null +++ b/balanced_dollar/src/states.rs @@ -0,0 +1,8 @@ +use soroban_sdk::{Address, Env}; + +use crate::storage_types::DataKey; + +pub fn has_state(env:Env, key: DataKey) -> bool { + env.storage().instance().has(&key) +} + diff --git a/balanced_dollar/src/storage_types.rs b/balanced_dollar/src/storage_types.rs new file mode 100644 index 0000000..424f449 --- /dev/null +++ b/balanced_dollar/src/storage_types.rs @@ -0,0 +1,42 @@ +use soroban_sdk::{contracttype, Address}; + +pub(crate) const DAY_IN_LEDGERS: u32 = 17280; +pub(crate) const INSTANCE_BUMP_AMOUNT: u32 = 7 * DAY_IN_LEDGERS; +pub(crate) const INSTANCE_LIFETIME_THRESHOLD: u32 = INSTANCE_BUMP_AMOUNT - DAY_IN_LEDGERS; + +pub(crate) const BALANCE_BUMP_AMOUNT: u32 = 30 * DAY_IN_LEDGERS; +pub(crate) const BALANCE_LIFETIME_THRESHOLD: u32 = BALANCE_BUMP_AMOUNT - DAY_IN_LEDGERS; + +#[derive(Clone)] +#[contracttype] +pub struct AllowanceDataKey { + pub from: Address, + pub spender: Address, +} + +#[contracttype] +pub struct AllowanceValue { + pub amount: i128, + pub expiration_ledger: u32, +} + +#[derive(Clone)] +#[contracttype] +pub enum DataKey { + Registry, + Allowance(AllowanceDataKey), + Balance(Address), + Nonce(Address), + State(Address), + Admin, +} + +#[derive(Clone)] +#[contracttype] +pub enum BnUSDDataKey { + Xcall, + XcallNetworkAddress, + Nid, + IconBnUSD, + XcallManager +} \ No newline at end of file diff --git a/balanced_dollar/src/test.rs b/balanced_dollar/src/test.rs new file mode 100644 index 0000000..825f0be --- /dev/null +++ b/balanced_dollar/src/test.rs @@ -0,0 +1,253 @@ +#![cfg(test)] +extern crate std; + +use crate::{contract::BalancedDollar, BalancedDollarClient}; +use soroban_sdk::{ + symbol_short, + testutils::{Address as _, AuthorizedFunction, AuthorizedInvocation}, + Address, Env, IntoVal, Symbol, +}; + +fn create_token<'a>(e: &Env, admin: &Address) -> BalancedDollarClient<'a> { + let token = BalancedDollarClient::new(e, &e.register_contract(None, BalancedDollar {})); + token.initialize(admin); + token +} + +#[test] +fn test() { + let e = Env::default(); + e.mock_all_auths(); + + let admin1 = Address::generate(&e); + let admin2 = Address::generate(&e); + let user1 = Address::generate(&e); + let user2 = Address::generate(&e); + let user3 = Address::generate(&e); + let token = create_token(&e, &admin1); + + token.mint(&user1, &1000); + assert_eq!( + e.auths(), + std::vec![( + admin1.clone(), + AuthorizedInvocation { + function: AuthorizedFunction::Contract(( + token.address.clone(), + symbol_short!("mint"), + (&user1, 1000_i128).into_val(&e), + )), + sub_invocations: std::vec![] + } + )] + ); + assert_eq!(token.balance(&user1), 1000); + + token.approve(&user2, &user3, &500, &200); + assert_eq!( + e.auths(), + std::vec![( + user2.clone(), + AuthorizedInvocation { + function: AuthorizedFunction::Contract(( + token.address.clone(), + symbol_short!("approve"), + (&user2, &user3, 500_i128, 200_u32).into_val(&e), + )), + sub_invocations: std::vec![] + } + )] + ); + assert_eq!(token.allowance(&user2, &user3), 500); + + token.transfer(&user1, &user2, &600); + assert_eq!( + e.auths(), + std::vec![( + user1.clone(), + AuthorizedInvocation { + function: AuthorizedFunction::Contract(( + token.address.clone(), + symbol_short!("transfer"), + (&user1, &user2, 600_i128).into_val(&e), + )), + sub_invocations: std::vec![] + } + )] + ); + assert_eq!(token.balance(&user1), 400); + assert_eq!(token.balance(&user2), 600); + + token.transfer_from(&user3, &user2, &user1, &400); + assert_eq!( + e.auths(), + std::vec![( + user3.clone(), + AuthorizedInvocation { + function: AuthorizedFunction::Contract(( + token.address.clone(), + Symbol::new(&e, "transfer_from"), + (&user3, &user2, &user1, 400_i128).into_val(&e), + )), + sub_invocations: std::vec![] + } + )] + ); + assert_eq!(token.balance(&user1), 800); + assert_eq!(token.balance(&user2), 200); + + token.transfer(&user1, &user3, &300); + assert_eq!(token.balance(&user1), 500); + assert_eq!(token.balance(&user3), 300); + + token.set_admin(&admin2); + assert_eq!( + e.auths(), + std::vec![( + admin1.clone(), + AuthorizedInvocation { + function: AuthorizedFunction::Contract(( + token.address.clone(), + symbol_short!("set_admin"), + (&admin2,).into_val(&e), + )), + sub_invocations: std::vec![] + } + )] + ); + + // Increase to 500 + token.approve(&user2, &user3, &500, &200); + assert_eq!(token.allowance(&user2, &user3), 500); + token.approve(&user2, &user3, &0, &200); + assert_eq!( + e.auths(), + std::vec![( + user2.clone(), + AuthorizedInvocation { + function: AuthorizedFunction::Contract(( + token.address.clone(), + symbol_short!("approve"), + (&user2, &user3, 0_i128, 200_u32).into_val(&e), + )), + sub_invocations: std::vec![] + } + )] + ); + assert_eq!(token.allowance(&user2, &user3), 0); +} + +#[test] +fn test_burn() { + let e = Env::default(); + e.mock_all_auths(); + + let admin = Address::generate(&e); + let user1 = Address::generate(&e); + let user2 = Address::generate(&e); + let token = create_token(&e, &admin); + + token.mint(&user1, &1000); + assert_eq!(token.balance(&user1), 1000); + + token.approve(&user1, &user2, &500, &200); + assert_eq!(token.allowance(&user1, &user2), 500); + + token.burn_from(&user2, &user1, &500); + assert_eq!( + e.auths(), + std::vec![( + user2.clone(), + AuthorizedInvocation { + function: AuthorizedFunction::Contract(( + token.address.clone(), + symbol_short!("burn_from"), + (&user2, &user1, 500_i128).into_val(&e), + )), + sub_invocations: std::vec![] + } + )] + ); + + assert_eq!(token.allowance(&user1, &user2), 0); + assert_eq!(token.balance(&user1), 500); + assert_eq!(token.balance(&user2), 0); + + token.burn(&user1, &500); + assert_eq!( + e.auths(), + std::vec![( + user1.clone(), + AuthorizedInvocation { + function: AuthorizedFunction::Contract(( + token.address.clone(), + symbol_short!("burn"), + (&user1, 500_i128).into_val(&e), + )), + sub_invocations: std::vec![] + } + )] + ); + + assert_eq!(token.balance(&user1), 0); + assert_eq!(token.balance(&user2), 0); +} + +#[test] +#[should_panic(expected = "insufficient balance")] +fn transfer_insufficient_balance() { + let e = Env::default(); + e.mock_all_auths(); + + let admin = Address::generate(&e); + let user1 = Address::generate(&e); + let user2 = Address::generate(&e); + let token = create_token(&e, &admin); + + token.mint(&user1, &1000); + assert_eq!(token.balance(&user1), 1000); + + token.transfer(&user1, &user2, &1001); +} + +#[test] +#[should_panic(expected = "insufficient allowance")] +fn transfer_from_insufficient_allowance() { + let e = Env::default(); + e.mock_all_auths(); + + let admin = Address::generate(&e); + let user1 = Address::generate(&e); + let user2 = Address::generate(&e); + let user3 = Address::generate(&e); + let token = create_token(&e, &admin); + + token.mint(&user1, &1000); + assert_eq!(token.balance(&user1), 1000); + + token.approve(&user1, &user3, &100, &200); + assert_eq!(token.allowance(&user1, &user3), 100); + + token.transfer_from(&user3, &user1, &user2, &101); +} + +#[test] +#[should_panic(expected = "already initialized")] +fn initialize_already_initialized() { + let e = Env::default(); + let admin = Address::generate(&e); + let token = create_token(&e, &admin); + + token.initialize(&admin); +} + +#[test] +#[should_panic(expected = "Decimal must fit in a u8")] +fn decimal_is_over_max() { + let e = Env::default(); + let admin = Address::generate(&e); + let token = BalancedDollarClient::new(&e, &e.register_contract(None, BalancedDollar {})); + token.initialize( + &admin + ); +} \ No newline at end of file diff --git a/xcall/Cargo.toml b/xcall/Cargo.toml new file mode 100644 index 0000000..53bacb9 --- /dev/null +++ b/xcall/Cargo.toml @@ -0,0 +1,30 @@ +[package] +name = "xcall" +version = "0.1.0" +edition = "2021" + +[lib] +crate-type = ["cdylib"] + +[features] +testutils = ["soroban-sdk/testutils"] + +[dependencies] +soroban-sdk = "20.0.0" + +[dev_dependencies] +soroban-sdk = { version = "20.0.0", features = ["testutils"] } + +[profile.release] +opt-level = "z" +overflow-checks = true +debug = 0 +strip = "symbols" +debug-assertions = false +panic = "abort" +codegen-units = 1 +lto = true + +[profile.release-with-logs] +inherits = "release" +debug-assertions = true \ No newline at end of file diff --git a/xcall/src/lib.rs b/xcall/src/lib.rs new file mode 100644 index 0000000..9849236 --- /dev/null +++ b/xcall/src/lib.rs @@ -0,0 +1,19 @@ +#![no_std] + +use soroban_sdk::{contract, contractimpl, Address, Env, String, Vec, Bytes}; + +#[contract] +pub struct Xcall; + +#[contractimpl] +impl Xcall { + + pub fn send_call_message(env: Env, from: Address, amount: i128, icon_asset_manager: String, data: Bytes, rollback: Bytes, sources: Vec, destinations: Vec){ + + } + + pub fn get_network_address(env: Env, address: String)-> String { + address + } + +} \ No newline at end of file diff --git a/xcall_manager/.gitignore b/xcall_manager/.gitignore new file mode 100644 index 0000000..8d9d75c --- /dev/null +++ b/xcall_manager/.gitignore @@ -0,0 +1,9 @@ +target +.soroban + +# environment variables +.env +.env.production + +# macOS-specific files +.DS_Store diff --git a/xcall_manager/Cargo.toml b/xcall_manager/Cargo.toml new file mode 100644 index 0000000..77d8879 --- /dev/null +++ b/xcall_manager/Cargo.toml @@ -0,0 +1,30 @@ +[package] +name = "xcall-manager" +version = "0.1.0" +edition = "2021" + +[lib] +crate-type = ["cdylib"] + +[features] +testutils = ["soroban-sdk/testutils"] + +[dependencies] +soroban-sdk = "20.0.0" + +[dev_dependencies] +soroban-sdk = { version = "20.0.0", features = ["testutils"] } + +[profile.release] +opt-level = "z" +overflow-checks = true +debug = 0 +strip = "symbols" +debug-assertions = false +panic = "abort" +codegen-units = 1 +lto = true + +[profile.release-with-logs] +inherits = "release" +debug-assertions = true \ No newline at end of file diff --git a/xcall_manager/README.md b/xcall_manager/README.md new file mode 100644 index 0000000..012e23c --- /dev/null +++ b/xcall_manager/README.md @@ -0,0 +1,21 @@ +# Soroban Project + +## Project Structure + +This repository uses the recommended structure for a Soroban project: +```text +. +├── contracts +│   └── hello_world +│   ├── src +│   │   ├── lib.rs +│   │   └── test.rs +│   └── Cargo.toml +├── Cargo.toml +└── README.md +``` + +- New Soroban contracts can be put in `contracts`, each in their own directory. There is already a `hello_world` contract in there to get you started. +- If you initialized this project with any other example contracts via `--with-example`, those contracts will be in the `contracts` directory as well. +- Contracts should have their own `Cargo.toml` files that rely on the top-level `Cargo.toml` workspace for their dependencies. +- Frontend libraries can be added to the top-level directory as well. If you initialized this project with a frontend template via `--frontend-template` you will have those files already included. \ No newline at end of file diff --git a/xcall_manager/src/admin.rs b/xcall_manager/src/admin.rs new file mode 100644 index 0000000..85f4a52 --- /dev/null +++ b/xcall_manager/src/admin.rs @@ -0,0 +1,18 @@ +use soroban_sdk::{Address, Env}; + +use crate::storage_types::DataKey; + +pub fn has_administrator(e: &Env) -> bool { + let key = DataKey::Admin; + e.storage().instance().has(&key) +} + +pub fn read_administrator(e: &Env) -> Address { + let key = DataKey::Admin; + e.storage().instance().get(&key).unwrap() +} + +pub fn write_administrator(e: &Env, id: &Address) { + let key = DataKey::Admin; + e.storage().instance().set(&key, id); +} \ No newline at end of file diff --git a/xcall_manager/src/contract.rs b/xcall_manager/src/contract.rs new file mode 100644 index 0000000..134e783 --- /dev/null +++ b/xcall_manager/src/contract.rs @@ -0,0 +1,170 @@ +use soroban_sdk::{contract, contractimpl, symbol_short, vec, Env, Symbol, Vec, Address, BytesN, String, Map}; + +use crate::{ + admin:: {self, has_administrator, read_administrator, write_administrator}, + states::{has_state, read_address_state, read_i128_state, read_string_state, read_u64_state, write_address_state, write_i128_state, write_string_state, write_u64_state, + write_vec_string_state, read_vec_string_state }, + storage_types::{DataKey, INSTANCE_BUMP_AMOUNT, INSTANCE_LIFETIME_THRESHOLD } +}; + +pub mod xcall { + soroban_sdk::contractimport!( + file = "../xcall/target/wasm32-unknown-unknown/release/xcall.wasm" + ); +} + +#[contract] +pub struct XcallManager; + +#[contractimpl] +impl XcallManager { + + pub fn initialize(env:Env, registry:Address, admin: Address, xcall: Address, + icon_governance: String, xcall_network_address: String, proposed_protocol_to_remove: String, sources: Vec, destinations: Vec) { + if has_state(env.clone(), DataKey::Registry) { + panic!("Contract already initialized.") + } + env.storage().instance().set(&DataKey::Registry, ®istry); + env.storage().instance().set(&DataKey::Admin, &admin); + Self::configure(env, xcall, icon_governance, xcall_network_address, proposed_protocol_to_remove, sources, destinations ); + } + + pub fn configure(env:Env, xcall: Address, + icon_governance: String, xcall_network_address: String, proposed_protocol_to_remove: String, sources: Vec, destinations: Vec){ + let admin = read_administrator(&env.clone()); + admin.require_auth(); + + env.storage().instance().set(&DataKey::Xcall, &xcall); + env.storage().instance().set(&DataKey::IconGovernance, &icon_governance); + env.storage().instance().set(&DataKey::XcallNetworkAddress, &xcall_network_address); + env.storage().instance().set(&DataKey::ProposedProtocolToRemove, &proposed_protocol_to_remove); + env.storage().instance().set(&DataKey::Sources, &sources); + env.storage().instance().set(&DataKey::Destinations, &destinations); + } + + pub fn set_admin(e: Env, new_admin: Address) { + let admin = read_administrator(&e); + admin.require_auth(); + + e.storage() + .instance() + .extend_ttl(INSTANCE_LIFETIME_THRESHOLD, INSTANCE_BUMP_AMOUNT); + + write_administrator(&e, &new_admin); + } + + pub fn propose_removal(e: Env, protocol: String) { + let admin = read_administrator(&e); + admin.require_auth(); + + write_string_state(&e, DataKey::ProposedProtocolToRemove, &protocol); + } + + pub fn set_protocols(e: Env, sources: Vec, destinations: Vec) { + let admin = read_administrator(&e); + admin.require_auth(); + + write_vec_string_state(&e, DataKey::Sources, &sources); + write_vec_string_state(&e, DataKey::Destinations, &destinations); + } + + pub fn verify_protocols( + e: Env, + protocols: Vec + ) -> bool { + let sources = read_vec_string_state(&e, DataKey::Sources); + return Self::verify_protocols_unordered(e, protocols, sources); + } + + pub fn get_protocols(e: Env) -> Map> { + let sources = read_vec_string_state(&e, DataKey::Sources); + let destinations = read_vec_string_state(&e, DataKey::Destinations); + let mut protocols = Map::new(&e); + protocols.set(String::from_str(&e, "sources"), sources); + protocols.set(String::from_str(&e, "destinations"), destinations); + protocols + } + + pub fn verify_protocols_unordered(_e: Env, array1: Vec, array2: Vec) -> bool { + // Check if the arrays have the same length + if array1.len() != array2.len() { + return false; + } + for p in array1.iter() { + let mut j = 0; + for s in array2.iter() { + j = j+1; + if p.eq(&s) { + break; + } else { + if j == array2.len() { + return false; + } + continue; + } + + } + } + return true; + } + + pub fn handle_call_message( + e: Env, + from: String, + data: BytesN<32>, + protocols: Vec + ) { + if !from.eq(&read_string_state(&e, DataKey::IconGovernance)) { + panic!("Only ICON Balanced governance is allowed") + } + + // string memory method = data.getMethod(); + // if (!verifyProtocolsUnordered(protocols, sources)) { + // require( + // method.compareTo(Messages.CONFIGURE_PROTOCOLS_NAME), + // "Protocol Mismatch" + // ); + // verifyProtocolRecovery(protocols); + // } + + // if (method.compareTo(Messages.EXECUTE_NAME)) { + // Messages.Execute memory message = data.decodeExecute(); + // (bool _success, ) = message.contractAddress.call(message.data); + // require(_success, "Failed to excute message"); + // } else if (method.compareTo(Messages.CONFIGURE_PROTOCOLS_NAME)) { + // Messages.ConfigureProtocols memory message = data + // .decodeConfigureProtocols(); + // sources = message.sources; + // destinations = message.destinations; + // } else { + // revert("Unknown message type"); + // } + } + + pub fn verify_protocol_recovery(e: Env, protocols: Vec) { + let modifiedSources = Self::get_modified_protocols(e.clone()); + if !Self::verify_protocols_unordered(e.clone(), modifiedSources, protocols) { + panic!("Protocol Mismatch") + } + } + + + pub fn get_modified_protocols(e: Env) -> Vec{ + if !has_state(e.clone(), DataKey::ProposedProtocolToRemove) { + panic!( "No proposal for removal exists") + } + + let sources = read_vec_string_state(&e, DataKey::Sources); + let protocol_to_remove = read_string_state(&e, DataKey::ProposedProtocolToRemove); + let mut new_array = Vec::new(&e); + for s in sources.iter() { + if !s.eq(&protocol_to_remove) { + new_array.push_back(s); + } + } + + return new_array; + } + + +} \ No newline at end of file diff --git a/xcall_manager/src/events.rs b/xcall_manager/src/events.rs new file mode 100644 index 0000000..e69de29 diff --git a/xcall_manager/src/lib.rs b/xcall_manager/src/lib.rs new file mode 100644 index 0000000..d6e27dc --- /dev/null +++ b/xcall_manager/src/lib.rs @@ -0,0 +1,9 @@ +#![no_std] + +mod admin; +mod contract; +mod storage_types; +mod states; +mod test; + +pub use crate::contract::XcallManagerClient; \ No newline at end of file diff --git a/xcall_manager/src/states.rs b/xcall_manager/src/states.rs new file mode 100644 index 0000000..49faea1 --- /dev/null +++ b/xcall_manager/src/states.rs @@ -0,0 +1,47 @@ +use soroban_sdk::{Address, Env, String, Vec}; + +use crate::storage_types::DataKey; + +pub fn has_state(env:Env, key: DataKey) -> bool { + env.storage().instance().has(&key) +} + +pub fn write_string_state(e: &Env, key: DataKey, id: &String) { + e.storage().instance().set(&key, id); +} + +pub fn write_address_state(e: &Env, key: DataKey, id: &Address) { + e.storage().instance().set(&key, id); +} + +pub fn write_u64_state(e: &Env, key: DataKey, id: &u64) { + e.storage().instance().set(&key, id); +} + +pub fn write_i128_state(e: &Env, key: DataKey, id: &i128) { + e.storage().instance().set(&key, id); +} + +pub fn write_vec_string_state(e: &Env, key: DataKey, id: &Vec) { + e.storage().instance().set(&key, id); +} + +pub fn read_string_state(e: &Env, key: DataKey) -> String { + e.storage().instance().get(&key).unwrap() +} + +pub fn read_address_state(e: &Env, key: DataKey) -> Address { + e.storage().instance().get(&key).unwrap() +} + +pub fn read_u64_state(e: &Env, key: DataKey) -> u64 { + e.storage().instance().get(&key).unwrap() +} + +pub fn read_i128_state(e: &Env, key: DataKey) -> i128 { + e.storage().instance().get(&key).unwrap() +} + +pub fn read_vec_string_state(e: &Env, key: DataKey) -> Vec { + e.storage().instance().get(&key).unwrap() +} \ No newline at end of file diff --git a/xcall_manager/src/storage_types.rs b/xcall_manager/src/storage_types.rs new file mode 100644 index 0000000..7fbc8b6 --- /dev/null +++ b/xcall_manager/src/storage_types.rs @@ -0,0 +1,21 @@ +use soroban_sdk::{contracttype, symbol_short, vec, Env, Symbol, Vec}; + +pub(crate) const DAY_IN_LEDGERS: u32 = 17280; +pub(crate) const INSTANCE_BUMP_AMOUNT: u32 = 7 * DAY_IN_LEDGERS; +pub(crate) const INSTANCE_LIFETIME_THRESHOLD: u32 = INSTANCE_BUMP_AMOUNT - DAY_IN_LEDGERS; + +pub(crate) const BALANCE_BUMP_AMOUNT: u32 = 30 * DAY_IN_LEDGERS; +pub(crate) const BALANCE_LIFETIME_THRESHOLD: u32 = BALANCE_BUMP_AMOUNT - DAY_IN_LEDGERS; + +#[derive(Clone)] +#[contracttype] +pub enum DataKey{ + Registry, + Admin, + Xcall, + XcallNetworkAddress, + IconGovernance, + ProposedProtocolToRemove, + Sources, + Destinations +} \ No newline at end of file diff --git a/xcall_manager/src/test.rs b/xcall_manager/src/test.rs new file mode 100644 index 0000000..e69de29 From bc49ec013c1549c412338f7f3742ef3ead07f4dc Mon Sep 17 00:00:00 2001 From: sagar sapkota Date: Thu, 16 May 2024 15:24:19 +0545 Subject: [PATCH 02/63] restructure, rlp integration and xcall integration --- .gitignore | 3 +- Cargo.toml | 24 ++ asset_manager/.gitignore | 9 - asset_manager/Cargo.toml | 30 -- asset_manager/README.md | 21 -- asset_manager/src/contract.rs | 264 ---------------- asset_manager/src/lib.rs | 9 - asset_manager/src/test.rs | 65 ---- balanced_dollar/.gitignore | 9 - balanced_dollar/Cargo.toml | 31 -- balanced_dollar/README.md | 21 -- .../src/BalancedDollarCrossChain.rs | 104 ------- balanced_dollar/src/states.rs | 8 - contracts/asset_manager/Cargo.toml | 17 ++ .../asset_manager}/src/admin.rs | 0 contracts/asset_manager/src/config.rs | 22 ++ contracts/asset_manager/src/contract.rs | 281 ++++++++++++++++++ contracts/asset_manager/src/errors.rs | 9 + .../asset_manager}/src/event.rs | 0 contracts/asset_manager/src/lib.rs | 13 + .../asset_manager/src/messages/deposit.rs | 88 ++++++ .../src/messages/deposit_revert.rs | 61 ++++ contracts/asset_manager/src/messages/mod.rs | 3 + .../asset_manager/src/messages/withdraw_to.rs | 61 ++++ .../asset_manager}/src/states.rs | 0 .../asset_manager}/src/storage_types.rs | 8 +- contracts/asset_manager/src/test.rs | 77 +++++ .../src/xcall_manager_interface.rs | 15 + contracts/balanced_doller/Cargo.toml | 18 ++ .../balanced_doller}/src/admin.rs | 0 .../balanced_doller}/src/allowance.rs | 0 .../balanced_doller}/src/balance.rs | 0 .../balanced_doller/src/balanced_dollar.rs | 134 +++++++++ contracts/balanced_doller/src/config.rs | 22 ++ .../balanced_doller}/src/contract.rs | 7 +- contracts/balanced_doller/src/errors.rs | 8 + .../balanced_doller}/src/lib.rs | 9 +- .../src/messages/cross_transfer.rs | 71 +++++ .../src/messages/cross_transfer_revert.rs | 53 ++++ contracts/balanced_doller/src/messages/mod.rs | 2 + .../balanced_doller}/src/metadata.rs | 0 .../balanced_doller}/src/storage_types.rs | 1 + .../balanced_doller}/src/test.rs | 59 ++-- .../src/xcall_manager_interface.rs | 15 + contracts/xcall_manager/Cargo.toml | 17 ++ .../xcall_manager}/src/admin.rs | 5 - contracts/xcall_manager/src/config.rs | 20 ++ contracts/xcall_manager/src/contract.rs | 176 +++++++++++ contracts/xcall_manager/src/errors.rs | 8 + .../xcall_manager}/src/events.rs | 0 .../xcall_manager}/src/lib.rs | 5 +- .../src/messages/configure_protocols.rs | 62 ++++ .../xcall_manager/src/messages/execute.rs | 52 ++++ contracts/xcall_manager/src/messages/mod.rs | 2 + contracts/xcall_manager/src/states.rs | 23 ++ .../xcall_manager}/src/storage_types.rs | 7 +- .../xcall_manager}/src/test.rs | 0 libs/soroban-rlp/Cargo.toml | 12 + libs/soroban-rlp/src/decoder.rs | 140 +++++++++ libs/soroban-rlp/src/encoder.rs | 92 ++++++ libs/soroban-rlp/src/lib.rs | 5 + libs/soroban-rlp/src/utils.rs | 104 +++++++ xcall/Cargo.toml | 30 -- xcall/src/lib.rs | 19 -- xcall_manager/.gitignore | 9 - xcall_manager/Cargo.toml | 30 -- xcall_manager/README.md | 21 -- xcall_manager/src/contract.rs | 170 ----------- xcall_manager/src/states.rs | 47 --- 69 files changed, 1768 insertions(+), 940 deletions(-) create mode 100644 Cargo.toml delete mode 100644 asset_manager/.gitignore delete mode 100644 asset_manager/Cargo.toml delete mode 100644 asset_manager/README.md delete mode 100644 asset_manager/src/contract.rs delete mode 100644 asset_manager/src/lib.rs delete mode 100644 asset_manager/src/test.rs delete mode 100644 balanced_dollar/.gitignore delete mode 100644 balanced_dollar/Cargo.toml delete mode 100644 balanced_dollar/README.md delete mode 100644 balanced_dollar/src/BalancedDollarCrossChain.rs delete mode 100644 balanced_dollar/src/states.rs create mode 100644 contracts/asset_manager/Cargo.toml rename {asset_manager => contracts/asset_manager}/src/admin.rs (100%) create mode 100644 contracts/asset_manager/src/config.rs create mode 100644 contracts/asset_manager/src/contract.rs create mode 100644 contracts/asset_manager/src/errors.rs rename {asset_manager => contracts/asset_manager}/src/event.rs (100%) create mode 100644 contracts/asset_manager/src/lib.rs create mode 100644 contracts/asset_manager/src/messages/deposit.rs create mode 100644 contracts/asset_manager/src/messages/deposit_revert.rs create mode 100644 contracts/asset_manager/src/messages/mod.rs create mode 100644 contracts/asset_manager/src/messages/withdraw_to.rs rename {asset_manager => contracts/asset_manager}/src/states.rs (100%) rename {asset_manager => contracts/asset_manager}/src/storage_types.rs (81%) create mode 100644 contracts/asset_manager/src/test.rs create mode 100644 contracts/asset_manager/src/xcall_manager_interface.rs create mode 100644 contracts/balanced_doller/Cargo.toml rename {balanced_dollar => contracts/balanced_doller}/src/admin.rs (100%) rename {balanced_dollar => contracts/balanced_doller}/src/allowance.rs (100%) rename {balanced_dollar => contracts/balanced_doller}/src/balance.rs (100%) create mode 100644 contracts/balanced_doller/src/balanced_dollar.rs create mode 100644 contracts/balanced_doller/src/config.rs rename {balanced_dollar => contracts/balanced_doller}/src/contract.rs (95%) create mode 100644 contracts/balanced_doller/src/errors.rs rename {balanced_dollar => contracts/balanced_doller}/src/lib.rs (51%) create mode 100644 contracts/balanced_doller/src/messages/cross_transfer.rs create mode 100644 contracts/balanced_doller/src/messages/cross_transfer_revert.rs create mode 100644 contracts/balanced_doller/src/messages/mod.rs rename {balanced_dollar => contracts/balanced_doller}/src/metadata.rs (100%) rename {balanced_dollar => contracts/balanced_doller}/src/storage_types.rs (98%) rename {balanced_dollar => contracts/balanced_doller}/src/test.rs (77%) create mode 100644 contracts/balanced_doller/src/xcall_manager_interface.rs create mode 100644 contracts/xcall_manager/Cargo.toml rename {xcall_manager => contracts/xcall_manager}/src/admin.rs (73%) create mode 100644 contracts/xcall_manager/src/config.rs create mode 100644 contracts/xcall_manager/src/contract.rs create mode 100644 contracts/xcall_manager/src/errors.rs rename {xcall_manager => contracts/xcall_manager}/src/events.rs (100%) rename {xcall_manager => contracts/xcall_manager}/src/lib.rs (66%) create mode 100644 contracts/xcall_manager/src/messages/configure_protocols.rs create mode 100644 contracts/xcall_manager/src/messages/execute.rs create mode 100644 contracts/xcall_manager/src/messages/mod.rs create mode 100644 contracts/xcall_manager/src/states.rs rename {xcall_manager => contracts/xcall_manager}/src/storage_types.rs (79%) rename {xcall_manager => contracts/xcall_manager}/src/test.rs (100%) create mode 100644 libs/soroban-rlp/Cargo.toml create mode 100644 libs/soroban-rlp/src/decoder.rs create mode 100644 libs/soroban-rlp/src/encoder.rs create mode 100644 libs/soroban-rlp/src/lib.rs create mode 100644 libs/soroban-rlp/src/utils.rs delete mode 100644 xcall/Cargo.toml delete mode 100644 xcall/src/lib.rs delete mode 100644 xcall_manager/.gitignore delete mode 100644 xcall_manager/Cargo.toml delete mode 100644 xcall_manager/README.md delete mode 100644 xcall_manager/src/contract.rs delete mode 100644 xcall_manager/src/states.rs diff --git a/.gitignore b/.gitignore index bf964a9..e978b31 100644 --- a/.gitignore +++ b/.gitignore @@ -8,4 +8,5 @@ target # macOS-specific files .DS_Store Cargo.lock -*/test_snapshots/* \ No newline at end of file +test_snapshots +xcall.wasm \ No newline at end of file diff --git a/Cargo.toml b/Cargo.toml new file mode 100644 index 0000000..e030416 --- /dev/null +++ b/Cargo.toml @@ -0,0 +1,24 @@ +[workspace] +resolver = "2" +members = [ + "contracts/*", + "libs/*" +] + +[workspace.dependencies] +soroban-sdk = "20.3.2" + +[profile.release] +opt-level = "z" +overflow-checks = true +debug = 0 +strip = "symbols" +debug-assertions = false +panic = "abort" +codegen-units = 1 +lto = true + +# For more information about this profile see https://soroban.stellar.org/docs/basic-tutorials/logging#cargotoml-profile +[profile.release-with-logs] +inherits = "release" +debug-assertions = true \ No newline at end of file diff --git a/asset_manager/.gitignore b/asset_manager/.gitignore deleted file mode 100644 index 8d9d75c..0000000 --- a/asset_manager/.gitignore +++ /dev/null @@ -1,9 +0,0 @@ -target -.soroban - -# environment variables -.env -.env.production - -# macOS-specific files -.DS_Store diff --git a/asset_manager/Cargo.toml b/asset_manager/Cargo.toml deleted file mode 100644 index b74bd03..0000000 --- a/asset_manager/Cargo.toml +++ /dev/null @@ -1,30 +0,0 @@ -[package] -name = "asset-manager" -version = "0.1.0" -edition = "2021" - -[lib] -crate-type = ["cdylib"] - -[features] -testutils = ["soroban-sdk/testutils"] - -[dependencies] -soroban-sdk = "20.0.0" - -[dev_dependencies] -soroban-sdk = { version = "20.0.0", features = ["testutils"] } - -[profile.release] -opt-level = "z" -overflow-checks = true -debug = 0 -strip = "symbols" -debug-assertions = false -panic = "abort" -codegen-units = 1 -lto = true - -[profile.release-with-logs] -inherits = "release" -debug-assertions = true \ No newline at end of file diff --git a/asset_manager/README.md b/asset_manager/README.md deleted file mode 100644 index 012e23c..0000000 --- a/asset_manager/README.md +++ /dev/null @@ -1,21 +0,0 @@ -# Soroban Project - -## Project Structure - -This repository uses the recommended structure for a Soroban project: -```text -. -├── contracts -│   └── hello_world -│   ├── src -│   │   ├── lib.rs -│   │   └── test.rs -│   └── Cargo.toml -├── Cargo.toml -└── README.md -``` - -- New Soroban contracts can be put in `contracts`, each in their own directory. There is already a `hello_world` contract in there to get you started. -- If you initialized this project with any other example contracts via `--with-example`, those contracts will be in the `contracts` directory as well. -- Contracts should have their own `Cargo.toml` files that rely on the top-level `Cargo.toml` workspace for their dependencies. -- Frontend libraries can be added to the top-level directory as well. If you initialized this project with a frontend template via `--frontend-template` you will have those files already included. \ No newline at end of file diff --git a/asset_manager/src/contract.rs b/asset_manager/src/contract.rs deleted file mode 100644 index f1ea819..0000000 --- a/asset_manager/src/contract.rs +++ /dev/null @@ -1,264 +0,0 @@ -use soroban_sdk::{contract, contractimpl, contracttype, symbol_short, token, vec, Address, bytes, BytesN, Env, String, Symbol, Vec, Map}; - -use crate::{ - admin:: {has_administrator, read_administrator, write_administrator}, - storage_types::{DataKey, POINTS, INSTANCE_LIFETIME_THRESHOLD, INSTANCE_BUMP_AMOUNT}, - states::{has_state, read_address_state, read_string_state} -}; - -use crate::contract::xcall_manager::Client; - -pub mod xcall_manager { - soroban_sdk::contractimport!( - file = "../xcall_manager/target/wasm32-unknown-unknown/release/xcall_manager.wasm" - ); -} - -pub mod xcall { - soroban_sdk::contractimport!( - file = "../xcall/target/wasm32-unknown-unknown/release/xcall.wasm" - ); -} - -#[contract] -pub struct AssetManager; - -#[contractimpl] -impl AssetManager { - - pub fn initialize(env:Env, registry:Address, admin: Address, xcall: Address, - xcall_manager: Address, native_address: Address, icon_asset_manager: String) { - if has_state(env.clone(), DataKey::Registry) { - panic!("Contract already initialized.") - } - let xcall_network_address = String::from_str(&env, "xcall_network_address"); // xcall::Client::new(&env, &xcall).get_network_address(&icon_asset_manager); - env.storage().instance().set(&DataKey::Registry, ®istry); - env.storage().instance().set(&DataKey::Admin, &admin); - Self::configure(env, xcall, xcall_manager, native_address, icon_asset_manager, xcall_network_address ); - } - - pub fn set_admin(e: Env, new_admin: Address) { - let admin = read_administrator(&e); - admin.require_auth(); - - e.storage() - .instance() - .extend_ttl(INSTANCE_LIFETIME_THRESHOLD, INSTANCE_BUMP_AMOUNT); - - write_administrator(&e, &new_admin); - } - - pub fn configure(env:Env, xcall: Address, - xcall_manager: Address, native_address: Address, icon_asset_manager: String, xcall_network_address: String){ - let admin = read_administrator(&env.clone()); - admin.require_auth(); - - env.storage().instance().set(&DataKey::XCall, &xcall); - env.storage().instance().set(&DataKey::XCallManager, &xcall_manager); - env.storage().instance().set(&DataKey::NativeAddress, &native_address); - env.storage().instance().set(&DataKey::IconAssetManager, &icon_asset_manager); - env.storage().instance().set(&DataKey::XCallNetworkAddress, &xcall_network_address); - } - - - pub fn configure_rate_limit( - env: Env, - token: Address, - period: i128, - percentage: i128, - ) { - let admin = read_administrator(&env.clone()); - admin.require_auth(); - - if percentage > POINTS {panic!("Percentage should be less than or equal to POINTS"); } - - let token_client = token::Client::new(&env, &token); - let contract_token_balance = token_client.balance(&env.current_contract_address()); - - env.storage().instance().set(&DataKey::Period(token.clone()), &period); - env.storage().instance().set(&DataKey::Percentage(token.clone()), &percentage); - env.storage().instance().set(&DataKey::LastUpdate(token.clone()), &env.ledger().timestamp()); - env.storage().instance().set(&DataKey::CurrentLimit(token.clone()), &(contract_token_balance*percentage/POINTS)); - - } - - pub fn reset_limit(env: Env, token: Address){ - let token_client = token::Client::new(&env, &token); - let contract_token_balance = token_client.balance(&env.current_contract_address()); - let percentage: i128 = env.storage().instance().get(&DataKey::Percentage(token.clone())).unwrap(); - - env.storage().instance().set(&DataKey::CurrentLimit(token.clone()), &(contract_token_balance*percentage/POINTS)); - } - - pub fn verify_withdraw(env: Env, token: Address, amount: i128) { - let period: i128 = env.storage().instance().get(&DataKey::Period(token.clone())).unwrap(); - let percentage: i128 = env.storage().instance().get(&DataKey::Percentage(token.clone())).unwrap(); - if period == 0 { - return; - } - - let token_client = token::Client::new(&env, &token); - let balance = token_client.balance(&env.current_contract_address()); - - let max_limit = (balance * percentage) / POINTS; - - // The maximum amount that can be withdraw in one period - let max_withdraw = balance - max_limit; - let last_update: u64 = env.storage().instance().get(&DataKey::LastUpdate(token.clone())).unwrap(); - let time_diff = &env.ledger().timestamp() - last_update; - - // The amount that should be added as availbe - let added_allowed_withdrawal = (max_withdraw * i128::from(time_diff)) / period; - let current_limit: i128 = env.storage().instance().get(&DataKey::CurrentLimit(token.clone())).unwrap(); - let limit = current_limit - added_allowed_withdrawal; - - // If the balance is below the limit then set limt to current balance (no withdraws are possible) - let limit: i128 = if balance < limit { balance } else { limit }; - - // If limit goes below what the protected percentage is set it to the maxLimit - let fina_limit = if limit > max_limit { limit } else { max_limit }; - if balance - amount < fina_limit { panic!("exceeds withdraw limit"); }; - - env.storage().instance().set(&DataKey::CurrentLimit(token.clone()), &fina_limit); - env.storage().instance().set(&DataKey::LastUpdate(token.clone()), &env.ledger().timestamp()); - } - - pub fn deposit( - e: Env, - from: Address, - value: i128, - token: Address, - amount: i128, - to: Option, - data: Option> - ) { - if amount < 0 { - panic!("Amount less than minimum amount"); - } - let depositTo = to.unwrap_or(String::from_str(&e, "")); - let depositData = data.unwrap_or(BytesN::from_array(&e, &[0u8; 32])); - - Self::send_deposit_message(e, from, token, amount, depositTo, depositData, value); - } - - pub fn deposit_native( - e: Env, - from: Address, - value: i128, - amount: i128, - to: Option, - data: Option> - ) { - if value < amount { - panic!("Amount less than minimum amount"); - } - - let depositTo = to.unwrap_or(String::from_str(&e, "")); - let depositData = data.unwrap_or(BytesN::from_array(&e, &[0u8; 32])); - - let fee: i128 = value - amount; - let native_address = read_address_state(&e, DataKey::NativeAddress); - Self::send_deposit_message(e, from, native_address, amount, depositTo, depositData, fee); - } - - fn send_deposit_message( - e: Env, - from: Address, - token: Address, - amount: i128, - to: String, - data: BytesN<32>, - fee: i128 - ) { - Self::transfer_token_to(e.clone(), from, token, e.current_contract_address(), fee); - - // Messages.Deposit memory xcallMessage = Messages.Deposit( - // token.toString(), - // msg.sender.toString(), - // to, - // amount, - // data - // ); - // Messages.DepositRevert memory rollback = Messages.DepositRevert( - // token, - // amount, - // msg.sender - // ); - - let protocols: Map> = Self::get_xcall_manager_client(e).get_protocols(); - // ICallService(xCall).sendCallMessage{value: fee}( - // iconAssetManager, - // xcallMessage.encodeDeposit(), - // rollback.encodeDepositRevert(), - // protocols.sources, - // protocols.destinations - // ); - } - - fn get_xcall_manager_client(e: Env) -> Client<'static> { - return xcall_manager::Client::new(&e, &read_address_state(&e, DataKey::XCallManager)); - } - - pub fn handle_call_message( - e: Env, - from: Address, - data: BytesN<32>, - protocols: Vec - ) { - read_address_state(&e, DataKey::XCall).require_auth(); - if ! Self::get_xcall_manager_client(e).verify_protocols(&protocols) { - panic!("Protocol Mismatch"); - } - - // string memory method = data.getMethod(); - // if (method.compareTo(Messages.WITHDRAW_TO_NAME)) { - // require(from.compareTo(iconAssetManager), "onlyICONAssetManager"); - // Messages.WithdrawTo memory message = data.decodeWithdrawTo(); - // withdraw( - // message.tokenAddress.parseAddress("Invalid account"), - // message.to.parseAddress("Invalid account"), - // message.amount - // ); - // } else if (method.compareTo(Messages.WITHDRAW_NATIVE_TO_NAME)) { - // revert("Withdraw to native is currently not supported"); - // } else if (method.compareTo(Messages.DEPOSIT_REVERT_NAME)) { - // require(from.compareTo(xCallNetworkAddress), "onlyCallService"); - // Messages.DepositRevert memory message = data.decodeDepositRevert(); - // withdraw(message.tokenAddress, message.to, message.amount); - // } else { - // revert("Unknown message type"); - // } - } - - pub fn withdraw(e: Env, from: Address, token: Address, to: Address, amount: i128) { - if amount <= 0 { - panic!("Amount less than minimum amount"); - } - - Self::verify_withdraw(e.clone(), token.clone(), amount); - Self::transfer_token_to(e, from, token, to, amount); - } - - fn transfer_token_to(e: Env, from: Address, token: Address, to: Address, amount: i128){ - let token_client = token::Client::new(&e, &token); - token_client.transfer_from(&from, &from, &to, &amount); - } - - pub fn balanceOf(e: Env, token: Address) -> i128 { - let token_client = token::Client::new(&e, &token); - return token_client.balance(&e.current_contract_address()); - } - - - pub fn has_registry(e: Env) -> bool { - has_state(e, DataKey::Registry) - } - - pub fn upgrade(e: Env, new_wasm_hash: BytesN<32>) { - let admin: Address = e.storage().instance().get(&DataKey::Admin).unwrap(); - admin.require_auth(); - - e.deployer().update_current_contract_wasm(new_wasm_hash); - } - -} \ No newline at end of file diff --git a/asset_manager/src/lib.rs b/asset_manager/src/lib.rs deleted file mode 100644 index 8bf025f..0000000 --- a/asset_manager/src/lib.rs +++ /dev/null @@ -1,9 +0,0 @@ -#![no_std] - -mod admin; -mod contract; -mod storage_types; -mod test; -mod states; - -pub use crate::contract::AssetManagerClient; \ No newline at end of file diff --git a/asset_manager/src/test.rs b/asset_manager/src/test.rs deleted file mode 100644 index 550790f..0000000 --- a/asset_manager/src/test.rs +++ /dev/null @@ -1,65 +0,0 @@ -#![cfg(test)] - -extern crate std; - -use crate::contract::{ - AssetManager, AssetManagerClient, xcall_manager -}; - -use crate::storage_types::{DataKey, POINTS}; - -use soroban_sdk::{ - symbol_short, - testutils::{Address as _, AuthorizedFunction, AuthorizedInvocation, Events}, - token, vec, Address, Bytes, Env, IntoVal, String, Symbol, -}; - -pub struct TestContext { - env: Env, - registry:Address, - admin: Address, - xcall: Address, - xcall_manager: Address, - native_address: Address, - icon_asset_manager: String, - xcall_network_address: String -} - -pub struct TokenRateLimit { - token: Address, - period: i128, - percentage: i128 -} - -impl TestContext { - pub fn default() -> Self { - let env = Env::default(); - let token_admin = Address::generate(&env); - Self { - registry: env.register_contract(None, AssetManager), - admin: Address::generate(&env), - xcall: Address::generate(&env), - xcall_manager: env.register_contract_wasm(None, xcall_manager::WASM), - native_address: env.register_stellar_asset_contract(token_admin.clone()), - icon_asset_manager: String::from_str(&env, "icon_asset_manager"), - xcall_network_address: String::from_str(&env, "xcall_network_address"), - env - } - } - - pub fn init_context(&self, client: &AssetManagerClient<'static>) { - self.env.mock_all_auths(); - client.initialize(&self.registry, &self.admin, &self.xcall, &self.xcall_manager, &self.native_address, &self.icon_asset_manager ); - } -} - -#[test] -fn test_initialize() { - let ctx = TestContext::default(); - let client = AssetManagerClient::new(&ctx.env, &ctx.registry); - - ctx.init_context(&client); - - let registry_exists = client.has_registry(); - assert_eq!(registry_exists, true) -} \ No newline at end of file diff --git a/balanced_dollar/.gitignore b/balanced_dollar/.gitignore deleted file mode 100644 index 8d9d75c..0000000 --- a/balanced_dollar/.gitignore +++ /dev/null @@ -1,9 +0,0 @@ -target -.soroban - -# environment variables -.env -.env.production - -# macOS-specific files -.DS_Store diff --git a/balanced_dollar/Cargo.toml b/balanced_dollar/Cargo.toml deleted file mode 100644 index c526bdf..0000000 --- a/balanced_dollar/Cargo.toml +++ /dev/null @@ -1,31 +0,0 @@ -[package] -name = "balanced-dollar" -version = "0.1.0" -edition = "2021" - -[lib] -crate-type = ["cdylib"] - -[features] -testutils = ["soroban-sdk/testutils"] - -[dependencies] -soroban-sdk = "20.0.0" -soroban-token-sdk = { version = "20.0.0" } - -[dev_dependencies] -soroban-sdk = { version = "20.0.0", features = ["testutils"] } - -[profile.release] -opt-level = "z" -overflow-checks = true -debug = 0 -strip = "symbols" -debug-assertions = false -panic = "abort" -codegen-units = 1 -lto = true - -[profile.release-with-logs] -inherits = "release" -debug-assertions = true \ No newline at end of file diff --git a/balanced_dollar/README.md b/balanced_dollar/README.md deleted file mode 100644 index 012e23c..0000000 --- a/balanced_dollar/README.md +++ /dev/null @@ -1,21 +0,0 @@ -# Soroban Project - -## Project Structure - -This repository uses the recommended structure for a Soroban project: -```text -. -├── contracts -│   └── hello_world -│   ├── src -│   │   ├── lib.rs -│   │   └── test.rs -│   └── Cargo.toml -├── Cargo.toml -└── README.md -``` - -- New Soroban contracts can be put in `contracts`, each in their own directory. There is already a `hello_world` contract in there to get you started. -- If you initialized this project with any other example contracts via `--with-example`, those contracts will be in the `contracts` directory as well. -- Contracts should have their own `Cargo.toml` files that rely on the top-level `Cargo.toml` workspace for their dependencies. -- Frontend libraries can be added to the top-level directory as well. If you initialized this project with a frontend template via `--frontend-template` you will have those files already included. \ No newline at end of file diff --git a/balanced_dollar/src/BalancedDollarCrossChain.rs b/balanced_dollar/src/BalancedDollarCrossChain.rs deleted file mode 100644 index 4466373..0000000 --- a/balanced_dollar/src/BalancedDollarCrossChain.rs +++ /dev/null @@ -1,104 +0,0 @@ -use soroban_sdk::{contractimpl, Address, Env, String}; - -pub mod xcall_manager { - soroban_sdk::contractimport!( - file = "../xcall_manager/target/wasm32-unknown-unknown/release/xcall_manager.wasm" - ); -} - -pub mod xcall { - soroban_sdk::contractimport!( - file = "../xcall/target/wasm32-unknown-unknown/release/xcall.wasm" - ); -} - -#[contractimpl] -impl BalancedDollar { - - pub fn cross_transfer( - from: Address, - amount: i128, - to: String, - value: i128 - ) { - from.require_auth(); - _cross_transfer(from, amount, to, value, String::from_str("")); - } - - pub fn cross_transfer( - from: Address, - amount: i128, - to: String, - value: i128, - data: BytesN - ) { - from.require_auth(); - _crossTransfer(from, amount, to, value, data); - } - - fn _crossTransfer( - from: Address, - amount: i128, - to: String, - value: i128, - data: BytesN - ) { - if value <= 0 { - panic!("Amount less than minimum amount"); - } - Self::burn(from, value); - - // string memory from = nid.networkAddress(msg.sender.toString()); - // // Validate address - // to.parseNetworkAddress(); - // Messages.XCrossTransfer memory xcallMessage = Messages.XCrossTransfer( - // from, - // to, - // value, - // data - // ); - - // Messages.XCrossTransferRevert memory rollback = Messages.XCrossTransferRevert( - // msg.sender, - // value - // ); - - let protocols: Vec = xcall_manager::Client::getProtocols(); - - // ICallService(xCall).sendCallMessage{value: msg.value}( - // iconBnUSD, - // xcallMessage.encodeCrossTransfer(), - // rollback.encodeCrossTransferRevert(), - // protocols.sources, - // protocols.destinations - // ); - - } - - pub fn handle_call_message( - from: String, - data: BytesN, - protocols: Vec - ) { - xCall.require_auth(); - let protocols: Vec = xcall_manager::Client::getProtocols(); - - // string memory method = data.getMethod(); - // if (method.compareTo(Messages.CROSS_TRANSFER)) { - // require(from.compareTo(iconBnUSD), "onlyICONBnUSD"); - // Messages.XCrossTransfer memory message = data.decodeCrossTransfer(); - // (,string memory to) = message.to.parseNetworkAddress(); - // _mint(to.parseAddress("Invalid account"), message.value); - // } else if (method.compareTo(Messages.CROSS_TRANSFER_REVERT)) { - // require(from.compareTo(xCallNetworkAddress), "onlyCallService"); - // Messages.XCrossTransferRevert memory message = data.decodeCrossTransferRevert(); - // _mint(message.to, message.value); - // } else { - // revert("Unknown message type"); - // } - } - - - - -} \ No newline at end of file diff --git a/balanced_dollar/src/states.rs b/balanced_dollar/src/states.rs deleted file mode 100644 index 49caaff..0000000 --- a/balanced_dollar/src/states.rs +++ /dev/null @@ -1,8 +0,0 @@ -use soroban_sdk::{Address, Env}; - -use crate::storage_types::DataKey; - -pub fn has_state(env:Env, key: DataKey) -> bool { - env.storage().instance().has(&key) -} - diff --git a/contracts/asset_manager/Cargo.toml b/contracts/asset_manager/Cargo.toml new file mode 100644 index 0000000..20cb3cd --- /dev/null +++ b/contracts/asset_manager/Cargo.toml @@ -0,0 +1,17 @@ +[package] +name = "asset-manager" +version = "0.1.0" +edition = "2021" + +[lib] +crate-type = ["cdylib", "rlib"] + +[features] +testutils = ["soroban-sdk/testutils"] + +[dependencies] +soroban-sdk = { workspace = true, features = ["alloc"] } +soroban-rlp = { path = "../../libs/soroban-rlp" } + +[dev_dependencies] +soroban-sdk = { workspace = true, features = ["testutils"] } \ No newline at end of file diff --git a/asset_manager/src/admin.rs b/contracts/asset_manager/src/admin.rs similarity index 100% rename from asset_manager/src/admin.rs rename to contracts/asset_manager/src/admin.rs diff --git a/contracts/asset_manager/src/config.rs b/contracts/asset_manager/src/config.rs new file mode 100644 index 0000000..99073a9 --- /dev/null +++ b/contracts/asset_manager/src/config.rs @@ -0,0 +1,22 @@ +use soroban_sdk::{contracttype, unwrap::UnwrapOptimized, Env, String, Address}; +use crate::storage_types::DataKey; + +#[derive(Clone)] +#[contracttype] +pub struct ConfigData { + pub xcall: Address, + pub xcall_manager: Address, + pub native_address: Address, + pub icon_assset_manager: String, + pub xcall_network_address: String +} + +pub fn get_config(e: &Env) -> ConfigData { + let key = DataKey::Config; + e + .storage() + .instance() + .get(&key) + .unwrap_optimized() +} + diff --git a/contracts/asset_manager/src/contract.rs b/contracts/asset_manager/src/contract.rs new file mode 100644 index 0000000..54749f6 --- /dev/null +++ b/contracts/asset_manager/src/contract.rs @@ -0,0 +1,281 @@ +use soroban_sdk::{contract, contractimpl, token, Address, Bytes, BytesN, Env, String, Vec}; + +mod xcall { + soroban_sdk::contractimport!(file = "xcall.wasm"); +} + +use crate::{ + admin::{read_administrator, write_administrator}, + config::{get_config, ConfigData}, + messages::{ + deposit::Deposit, + deposit_revert :: DepositRevert, + withdraw_to::WithdrawTo + }, + states::has_state, + storage_types::{DataKey, INSTANCE_BUMP_AMOUNT, INSTANCE_LIFETIME_THRESHOLD, POINTS}, xcall_manager_interface::XcallManagerClient +}; + +use crate::errors::ContractError; + +use xcall::{AnyMessage, CallMessageWithRollback, Client, Envelope}; + +const DEPOSIT_NAME: &str = "Deposit"; +const WITHDRAW_TO_NAME: &str = "WithdrawTo"; +const DEPOSIT_REVERT_NAME: &str = "DepositRevert"; + +#[contract] +pub struct AssetManager; + +#[contractimpl] +impl AssetManager { + + pub fn initialize(env:Env, registry:Address, admin: Address, xcall: Address, + xcall_manager: Address, native_address: Address, icon_asset_manager: String) { + if has_state(env.clone(), DataKey::Registry) { + panic!("Contract already initialized.") + } + let xcall_network_address = String::from_str(&env, "xcall_network_address"); // xcall::Client::new(&env, &xcall).get_network_address(&icon_asset_manager); + env.storage().instance().set(&DataKey::Registry, ®istry); + env.storage().instance().set(&DataKey::Admin, &admin); + Self::configure(env, xcall, xcall_manager, native_address, icon_asset_manager, xcall_network_address ); + } + + pub fn set_admin(e: Env, new_admin: Address) { + let admin = read_administrator(&e); + admin.require_auth(); + + e.storage() + .instance() + .extend_ttl(INSTANCE_LIFETIME_THRESHOLD, INSTANCE_BUMP_AMOUNT); + + write_administrator(&e, &new_admin); + } + + pub fn get_admin(e: Env) -> Address{ + read_administrator(&e) + } + + pub fn configure(env:Env, xcall: Address, + xcall_manager: Address, native_address: Address, icon_asset_manager: String, xcall_network_address: String){ + let admin = read_administrator(&env.clone()); + admin.require_auth(); + + let config: ConfigData = ConfigData { xcall: xcall, xcall_manager: xcall_manager, native_address: native_address, icon_assset_manager: icon_asset_manager, xcall_network_address: xcall_network_address }; + env.storage().instance().set(&DataKey::Config, &config); + } + + + pub fn configure_rate_limit( + env: Env, + token: Address, + period: u128, + percentage: u128, + ) { + let admin = read_administrator(&env.clone()); + admin.require_auth(); + + if percentage > POINTS {panic!("Percentage should be less than or equal to POINTS"); } + + let token_client = token::Client::new(&env, &token); + let contract_token_balance = token_client.balance(&env.current_contract_address()); + + env.storage().instance().set(&DataKey::Period(token.clone()), &period); + env.storage().instance().set(&DataKey::Percentage(token.clone()), &percentage); + env.storage().instance().set(&DataKey::LastUpdate(token.clone()), &env.ledger().timestamp()); + env.storage().instance().set(&DataKey::CurrentLimit(token.clone()), &(u128::try_from(contract_token_balance).unwrap() * percentage/POINTS)); + + } + + pub fn reset_limit(env: Env, token: Address){ + let token_client = token::Client::new(&env, &token); + let contract_token_balance = token_client.balance(&env.current_contract_address()); + let percentage: u128 = env.storage().instance().get(&DataKey::Percentage(token.clone())).unwrap(); + + env.storage().instance().set(&DataKey::CurrentLimit(token.clone()), &(u128::try_from(contract_token_balance).unwrap()*percentage/POINTS)); + } + + pub fn verify_withdraw(env: Env, token: Address, amount: u128) { + let period: u128 = env.storage().instance().get(&DataKey::Period(token.clone())).unwrap(); + let percentage: u128 = env.storage().instance().get(&DataKey::Percentage(token.clone())).unwrap(); + if period == 0 { + return; + } + + let token_client = token::Client::new(&env, &token); + let balance = token_client.balance(&env.current_contract_address()); + let u128_balnace = u128::try_from(balance).unwrap(); + + let max_limit = (u128::try_from(balance).unwrap() * percentage) / POINTS; + + let max_withdraw = u128_balnace - max_limit; + let last_update: u64 = env.storage().instance().get(&DataKey::LastUpdate(token.clone())).unwrap(); + let time_diff = &env.ledger().timestamp() - last_update; + + let added_allowed_withdrawal = (max_withdraw * u128::from(time_diff)) / period; + let current_limit: u128 = env.storage().instance().get(&DataKey::CurrentLimit(token.clone())).unwrap(); + let limit = current_limit - added_allowed_withdrawal; + + let limit = if u128_balnace < limit { u128_balnace } else { limit }; + + let final_limit = if limit > max_limit { limit } else { max_limit }; + if u128_balnace - amount < final_limit { panic!("exceeds withdraw limit"); }; + + env.storage().instance().set(&DataKey::CurrentLimit(token.clone()), &final_limit); + env.storage().instance().set(&DataKey::LastUpdate(token.clone()), &env.ledger().timestamp()); + } + + pub fn deposit( + e: Env, + from: Address, + value: u128, + token: Address, + amount: u128, + to: Option, + data: Option + ) { + let deposit_to = to.unwrap_or(String::from_str(&e, "")); + let deposit_data = data.unwrap_or(Bytes::from_array(&e, &[0u8; 32])); + + Self::send_deposit_message(e, from, token, amount, deposit_to, deposit_data, value).unwrap(); + } + + pub fn deposit_native( + e: Env, + from: Address, + value: u128, + amount: u128, + to: Option, + data: Option + ) { + if value < amount { + panic!("Amount less than minimum amount"); + } + + let deposit_to = to.unwrap_or(String::from_str(&e, "")); + let deposit_data = data.unwrap_or(Bytes::from_array(&e, &[0u8; 32])); + + let fee = value - amount; + let native_address = get_config(&e).native_address; + Self::send_deposit_message(e, from, native_address, amount, deposit_to, deposit_data, fee).unwrap(); + } + + fn send_deposit_message( + e: Env, + from: Address, + token: Address, + amount: u128, + to: String, + data: Bytes, + fee: u128 + ) -> Result<(), ContractError> { + let current_address = e.clone().current_contract_address(); + Self::transfer_token_to(e.clone(), from.clone(), token.clone(), current_address.clone(), fee); + + let xcall_message: Deposit = Deposit::new( + token.to_string(), + from.to_string(), + to.clone(), + amount, + data + ); + + let rollback: DepositRevert = DepositRevert::new( + token, + from.clone(), + amount + ); + + let rollback_bytes = rollback.encode(&e, String::from_str(&e.clone(), DEPOSIT_REVERT_NAME)); + let message_bytes = xcall_message.encode(&e, String::from_str(&e.clone(), DEPOSIT_NAME)); + let (sources, destinations) = Self::xcall_manager(e.clone()).get_protocols(); + + let message = AnyMessage::CallMessageWithRollback(CallMessageWithRollback { data: message_bytes, rollback: rollback_bytes }); + let envelope: &Envelope = &Envelope { + message, + sources, + destinations + }; + let icon_asset_manager = &get_config(&e).icon_assset_manager; + Self::xcall_client(e).send_call(&from, ¤t_address, envelope, icon_asset_manager ); + Ok(()) + } + + fn xcall_manager(e: Env) -> XcallManagerClient<'static> { + let client = XcallManagerClient::new(&e, &get_config(&e).xcall_manager); + return client; + } + + fn xcall_client(e: Env) -> Client<'static> { + return xcall::Client::new(&e, &get_config(&e).xcall); + } + + pub fn handle_call_message( + e: Env, + _xcall: Address, + from: String, + data: Bytes, + protocols: Vec + ) { + get_config(&e).xcall.require_auth(); + + if !Self::xcall_manager(e.clone()).verify_protocols(&protocols) { + panic!("Protocol Mismatch"); + }; + + let method = Deposit::get_method(&e, data.clone()).unwrap(); + + let icon_asset_manager = get_config(&e).icon_assset_manager; + let current_contract = e.current_contract_address(); + if method == String::from_str(&e, &WITHDRAW_TO_NAME){ + if from != icon_asset_manager{ + panic!("onlyICONAssetManager") + } + let message = WithdrawTo::decode(&e, data).unwrap(); + + Self::withdraw(e, current_contract, Address::from_string(&message.token_address), Address::from_string(&message.to), message.amount); + } else if method == String::from_str(&e, &DEPOSIT_REVERT_NAME){ + let xcall_network_address = Self::xcall_client(e.clone()).get_network_address(); + + if from != xcall_network_address { + panic!("onlyCallService") + }; + let message: DepositRevert = DepositRevert::decode(&e.clone(), data).unwrap(); + Self::withdraw(e, current_contract, message.token_address, message.to, message.amount); + } else { + panic!("Unknown message type"); + } + } + + pub fn withdraw(e: Env, from: Address, token: Address, to: Address, amount: u128) { + if amount <= 0 { + panic!("Amount less than minimum amount"); + } + + Self::verify_withdraw(e.clone(), token.clone(), amount); + Self::transfer_token_to(e, from, token, to, amount); + } + + fn transfer_token_to(e: Env, from: Address, token: Address, to: Address, amount: u128){ + let token_client = token::Client::new(&e, &token); + token_client.transfer_from(&from, &from, &to, &i128::try_from(amount).unwrap()); + } + + pub fn balance_of(e: Env, token: Address) -> i128 { + let token_client = token::Client::new(&e, &token); + return token_client.balance(&e.current_contract_address()); + } + + + pub fn has_registry(e: Env) -> bool { + has_state(e, DataKey::Registry) + } + + pub fn upgrade(e: Env, new_wasm_hash: BytesN<32>) { + let admin: Address = e.storage().instance().get(&DataKey::Admin).unwrap(); + admin.require_auth(); + + e.deployer().update_current_contract_wasm(new_wasm_hash); + } + +} \ No newline at end of file diff --git a/contracts/asset_manager/src/errors.rs b/contracts/asset_manager/src/errors.rs new file mode 100644 index 0000000..8194dcf --- /dev/null +++ b/contracts/asset_manager/src/errors.rs @@ -0,0 +1,9 @@ +use soroban_sdk::contracterror; + +#[contracterror] +#[repr(u32)] +#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord)] +pub enum ContractError { + InvalidRlpLength = 1, + InvalidRollbackMessage = 2 +} \ No newline at end of file diff --git a/asset_manager/src/event.rs b/contracts/asset_manager/src/event.rs similarity index 100% rename from asset_manager/src/event.rs rename to contracts/asset_manager/src/event.rs diff --git a/contracts/asset_manager/src/lib.rs b/contracts/asset_manager/src/lib.rs new file mode 100644 index 0000000..0f1d39c --- /dev/null +++ b/contracts/asset_manager/src/lib.rs @@ -0,0 +1,13 @@ +#![no_std] + +pub mod admin; +pub mod contract; +pub mod storage_types; +mod test; +pub mod states; +mod config; +mod errors; +mod messages; +mod xcall_manager_interface; + +pub use crate::contract::AssetManagerClient; \ No newline at end of file diff --git a/contracts/asset_manager/src/messages/deposit.rs b/contracts/asset_manager/src/messages/deposit.rs new file mode 100644 index 0000000..5608302 --- /dev/null +++ b/contracts/asset_manager/src/messages/deposit.rs @@ -0,0 +1,88 @@ +use soroban_sdk::{contracttype, Env, String, Bytes, Vec}; +use soroban_rlp::{encoder, decoder}; +use crate::errors::ContractError; + +#[derive(Clone)] +#[contracttype] +pub struct Deposit { + pub token_address: String, + pub from: String, + pub to: String, + pub amount: u128, + pub data: Bytes +} + +impl Deposit{ + pub fn new(token_address: String, from: String, to: String, amount: u128, data: Bytes) -> Self { + Self { + token_address, + from, + to, + amount, + data + } + } + + pub fn token_address(&self) -> &String { + &self.token_address + } + + pub fn from(&self) -> &String { + &self.from + } + + pub fn to(&self) -> &String { + &self.to + } + + pub fn amount(&self) -> &u128 { + &self.amount + } + + pub fn data(&self) -> &Bytes { + &self.data + } + + pub fn encode(&self, e: &Env, method: String) -> Bytes { + let mut list: Vec = Vec::new(&e); + list.push_back(encoder::encode_string(&e, method)); + list.push_back(encoder::encode_string(&e, self.token_address.clone())); + list.push_back(encoder::encode_string(&e, self.from.clone())); + list.push_back(encoder::encode_string(&e, self.to.clone())); + list.push_back(encoder::encode_u128(&e, self.amount.clone())); + list.push_back(self.data.clone()); + + let encoded = encoder::encode_list(&e, list, false); + encoded + } + + pub fn decode(e: &Env, bytes: Bytes) -> Result { + let decoded = decoder::decode_list(&e, bytes); + if decoded.len() != 6 { + return Err(ContractError::InvalidRlpLength); + } + + let token_address = decoder::decode_string(e, decoded.get(1).unwrap()); + let from = decoder::decode_string(e, decoded.get(2).unwrap()); + let to = decoder::decode_string(e, decoded.get(3).unwrap()); + let amount = decoder::decode_u128(e, decoded.get(4).unwrap()); + let data = decoded.get(5).unwrap(); + + Ok(Self { + token_address, + from, + to, + amount, + data + }) + } + + pub fn get_method(e: &Env, bytes: Bytes)-> Result { + let decoded = decoder::decode_list(&e, bytes); + if decoded.len() != 6 { + return Err(ContractError::InvalidRlpLength); + } + let method = decoder::decode_string(e, decoded.get(0).unwrap()); + Ok(method) + } +} \ No newline at end of file diff --git a/contracts/asset_manager/src/messages/deposit_revert.rs b/contracts/asset_manager/src/messages/deposit_revert.rs new file mode 100644 index 0000000..bbb4df8 --- /dev/null +++ b/contracts/asset_manager/src/messages/deposit_revert.rs @@ -0,0 +1,61 @@ +use soroban_sdk::{contracttype, Env, String, Address, Bytes, Vec}; +use soroban_rlp::{encoder, decoder}; +use crate::errors::ContractError; + +#[derive(Clone)] +#[contracttype] +pub struct DepositRevert { + pub token_address: Address, + pub to: Address, + pub amount: u128 +} + +impl DepositRevert{ + pub fn new(token_address: Address, to: Address, amount: u128) -> Self { + Self { + token_address, + to, + amount, + } + } + + pub fn token_address(&self) -> &Address { + &self.token_address + } + + pub fn to(&self) -> &Address { + &self.to + } + + pub fn amount(&self) -> &u128 { + &self.amount + } + + pub fn encode(&self, e: &Env, method: String) -> Bytes { + let mut list: Vec = Vec::new(&e); + list.push_back(encoder::encode_string(&e, method)); + list.push_back(encoder::encode_string(&e, self.token_address.to_string().clone())); + list.push_back(encoder::encode_string(&e, self.to.to_string().clone())); + list.push_back(encoder::encode_u128(&e, self.amount.clone())); + + let encoded = encoder::encode_list(&e, list, false); + encoded + } + + pub fn decode(e: &Env, bytes: Bytes) -> Result { + let decoded = decoder::decode_list(&e, bytes); + if decoded.len() != 6 { + return Err(ContractError::InvalidRlpLength); + } + + let token_address = Address::from_string(&decoder::decode_string(e, decoded.get(1).unwrap())); + let to = Address::from_string(&decoder::decode_string(e, decoded.get(2).unwrap())); + let amount = decoder::decode_u128(e, decoded.get(3).unwrap()); + + Ok(Self { + token_address, + to, + amount + }) + } +} \ No newline at end of file diff --git a/contracts/asset_manager/src/messages/mod.rs b/contracts/asset_manager/src/messages/mod.rs new file mode 100644 index 0000000..55836d2 --- /dev/null +++ b/contracts/asset_manager/src/messages/mod.rs @@ -0,0 +1,3 @@ +pub mod deposit_revert; +pub mod deposit; +pub mod withdraw_to; diff --git a/contracts/asset_manager/src/messages/withdraw_to.rs b/contracts/asset_manager/src/messages/withdraw_to.rs new file mode 100644 index 0000000..3f51f35 --- /dev/null +++ b/contracts/asset_manager/src/messages/withdraw_to.rs @@ -0,0 +1,61 @@ +use soroban_sdk::{contracttype, Env, String, Bytes, Vec}; +use soroban_rlp::{encoder, decoder}; +use crate::errors::ContractError; + +#[derive(Clone)] +#[contracttype] +pub struct WithdrawTo { + pub token_address: String, + pub to: String, + pub amount: u128 +} + +impl WithdrawTo{ + pub fn new(token_address: String, to: String, amount: u128) -> Self { + Self { + token_address, + to, + amount + } + } + + pub fn token_address(&self) -> &String { + &self.token_address + } + + pub fn to(&self) -> &String { + &self.to + } + + pub fn amount(&self) -> &u128 { + &self.amount + } + + pub fn encode(&self, e: &Env, method: String) -> Bytes { + let mut list: Vec = Vec::new(&e); + list.push_back(encoder::encode_string(&e, method)); + list.push_back(encoder::encode_string(&e, self.token_address.clone())); + list.push_back(encoder::encode_string(&e, self.to.clone())); + list.push_back(encoder::encode_u128(&e, self.amount.clone())); + + let encoded = encoder::encode_list(&e, list, false); + encoded + } + + pub fn decode(e: &Env, bytes: Bytes) -> Result { + let decoded = decoder::decode_list(&e, bytes); + if decoded.len() != 6 { + //return Err(ContractError::InvalidRlpLength); + } + + let token_address = decoder::decode_string(e, decoded.get(1).unwrap()); + let to = decoder::decode_string(e, decoded.get(2).unwrap()); + let amount = decoder::decode_u128(e, decoded.get(3).unwrap()); + + Ok(Self { + token_address, + to, + amount + }) + } +} \ No newline at end of file diff --git a/asset_manager/src/states.rs b/contracts/asset_manager/src/states.rs similarity index 100% rename from asset_manager/src/states.rs rename to contracts/asset_manager/src/states.rs diff --git a/asset_manager/src/storage_types.rs b/contracts/asset_manager/src/storage_types.rs similarity index 81% rename from asset_manager/src/storage_types.rs rename to contracts/asset_manager/src/storage_types.rs index 153d74e..4f8924f 100644 --- a/asset_manager/src/storage_types.rs +++ b/contracts/asset_manager/src/storage_types.rs @@ -7,18 +7,14 @@ pub(crate) const INSTANCE_LIFETIME_THRESHOLD: u32 = INSTANCE_BUMP_AMOUNT - DAY_I pub(crate) const BALANCE_BUMP_AMOUNT: u32 = 30 * DAY_IN_LEDGERS; pub(crate) const BALANCE_LIFETIME_THRESHOLD: u32 = BALANCE_BUMP_AMOUNT - DAY_IN_LEDGERS; -pub(crate) const POINTS: i128 = 1000; +pub(crate) const POINTS: u128 = 1000; #[derive(Clone)] #[contracttype] pub enum DataKey{ Registry, Admin, - XCall, - XCallNetworkAddress, - IconAssetManager, - XCallManager, - NativeAddress, + Config, Period(Address), Percentage(Address), LastUpdate(Address), diff --git a/contracts/asset_manager/src/test.rs b/contracts/asset_manager/src/test.rs new file mode 100644 index 0000000..36775f0 --- /dev/null +++ b/contracts/asset_manager/src/test.rs @@ -0,0 +1,77 @@ +#![cfg(test)] + +extern crate std; + +use crate::contract::{ + AssetManager, AssetManagerClient//, xcall_manager +}; + +use crate::storage_types::{DataKey, POINTS}; + +use soroban_sdk::{ + symbol_short, + testutils::{Address as _, AuthorizedFunction, AuthorizedInvocation, Events}, + token, vec, Address, Bytes, Env, IntoVal, String, Symbol, +}; + +pub struct TestContext { + env: Env, + registry:Address, + admin: Address, + xcall: Address, + xcall_manager: Address, + native_address: Address, + icon_asset_manager: String, + xcall_network_address: String +} + +pub struct TokenRateLimit { + token: Address, + period: i128, + percentage: i128 +} + +impl TestContext { + // pub fn default() -> Self { + // let env = Env::default(); + // let token_admin = Address::generate(&env); + // Self { + // registry: env.register_contract(None, AssetManager), + // admin: Address::generate(&env), + // xcall: Address::generate(&env), + // xcall_manager: env.register_contract_wasm(None, xcall_manager::WASM), + // native_address: env.register_stellar_asset_contract(token_admin.clone()), + // icon_asset_manager: String::from_str(&env, "icon01:hxjnfh4u"), + // xcall_network_address: String::from_str(&env, "ST001"), + // env + // } + // } + + // pub fn init_context(&self, client: &AssetManagerClient<'static>) { + // self.env.mock_all_auths(); + // client.initialize(&self.registry, &self.admin, &self.xcall, &self.xcall_manager, &self.native_address, &self.icon_asset_manager ); + // } +} + +// #[test] +// fn test_initialize() { +// let ctx = TestContext::default(); +// let client = AssetManagerClient::new(&ctx.env, &ctx.registry); + +// ctx.init_context(&client); + +// let registry_exists = client.has_registry(); +// assert_eq!(registry_exists, true) +// } + +// #[test] +// fn test_set_admin() { +// let ctx = TestContext::default(); +// let client = AssetManagerClient::new(&ctx.env, &ctx.registry); +// ctx.init_context(&client); + +// let new_admin: Address = Address::generate(&ctx.env); +// client.set_admin(&new_admin); + +// assert_eq!(client.get_admin(), new_admin) +// } \ No newline at end of file diff --git a/contracts/asset_manager/src/xcall_manager_interface.rs b/contracts/asset_manager/src/xcall_manager_interface.rs new file mode 100644 index 0000000..17c7698 --- /dev/null +++ b/contracts/asset_manager/src/xcall_manager_interface.rs @@ -0,0 +1,15 @@ +use soroban_sdk::{contractclient, Env, String, Vec}; + +use crate::errors::ContractError; + +#[contractclient(name = "XcallManagerClient")] +pub trait XcallManagerInterface { + + fn verify_protocols( + e: Env, + protocols: Vec + ) -> Result; + + fn get_protocols(e: Env) -> Result<(Vec, Vec), ContractError>; + +} \ No newline at end of file diff --git a/contracts/balanced_doller/Cargo.toml b/contracts/balanced_doller/Cargo.toml new file mode 100644 index 0000000..d177567 --- /dev/null +++ b/contracts/balanced_doller/Cargo.toml @@ -0,0 +1,18 @@ +[package] +name = "balanced-dollar" +version = "0.1.0" +edition = "2021" + +[lib] +crate-type = ["cdylib", "rlib"] + +[features] +testutils = ["soroban-sdk/testutils"] + +[dependencies] +soroban-sdk = { workspace = true } +soroban-token-sdk = { version = "20.3.2" } +soroban-rlp = { path = "../../libs/soroban-rlp" } + +[dev_dependencies] +soroban-sdk = { workspace = true, features = ["testutils"] } \ No newline at end of file diff --git a/balanced_dollar/src/admin.rs b/contracts/balanced_doller/src/admin.rs similarity index 100% rename from balanced_dollar/src/admin.rs rename to contracts/balanced_doller/src/admin.rs diff --git a/balanced_dollar/src/allowance.rs b/contracts/balanced_doller/src/allowance.rs similarity index 100% rename from balanced_dollar/src/allowance.rs rename to contracts/balanced_doller/src/allowance.rs diff --git a/balanced_dollar/src/balance.rs b/contracts/balanced_doller/src/balance.rs similarity index 100% rename from balanced_dollar/src/balance.rs rename to contracts/balanced_doller/src/balance.rs diff --git a/contracts/balanced_doller/src/balanced_dollar.rs b/contracts/balanced_doller/src/balanced_dollar.rs new file mode 100644 index 0000000..8291f42 --- /dev/null +++ b/contracts/balanced_doller/src/balanced_dollar.rs @@ -0,0 +1,134 @@ +use soroban_sdk::{token::TokenInterface, Address, Bytes, Env, String, Vec}; + +mod xcall { + soroban_sdk::contractimport!(file = "xcall.wasm"); +} + +use crate::{ + admin::read_administrator, config::{get_config, ConfigData}, contract::BalancedDollar, messages::{cross_transfer::CrossTransfer, cross_transfer_revert::CrossTransferRevert}, storage_types::DataKey, xcall_manager_interface::XcallManagerClient +}; + +use crate::errors::ContractError; + +use xcall::{AnyMessage, CallMessageWithRollback, Client, Envelope}; + +const CROSS_TRANSFER: &str = "xCrossTransfer"; +const CROSS_TRANSFER_REVERT: &str = "xCrossTransferRevert"; + +impl BalancedDollar { + + pub fn configure(env:Env, xcall: Address, + xcall_manager: Address, nid: String, icon_bn_usd: String, xcall_network_address: String){ + let admin = read_administrator(&env.clone()); + admin.require_auth(); + + let config: ConfigData = ConfigData{ xcall: xcall, xcall_manager: xcall_manager, icon_bn_usd: icon_bn_usd, nid: nid, xcall_network_address: xcall_network_address }; + env.storage().instance().set(&DataKey::Config, &config); + } + + pub fn cross_transfer( + e: Env, + from: Address, + amount: u128, + to: String, + value: u128 + ) { + from.require_auth(); + Self::_cross_transfer(e.clone(), from, amount, to, value, Bytes::new(&e)).unwrap(); + } + + pub fn cross_transfer_data( + e: Env, + from: Address, + amount: u128, + to: String, + value: u128, + data: Bytes + ) { + from.require_auth(); + Self::_cross_transfer(e, from, amount, to, value, data).unwrap(); + } + + fn _cross_transfer( + e: Env, + from: Address, + amount: u128, + to: String, + value: u128, + data: Bytes + ) -> Result<(), ContractError> { + if value == 0 { + panic!("Amount less than minimum amount"); + } + Self::burn(e.clone(), from.clone(), u128::try_into(amount).unwrap()); + let xcall_message = CrossTransfer::new( + from.clone().to_string(), + to, + value, + data + ); + + let rollback = CrossTransferRevert::new( + from.clone(), + value + ); + + let rollback_bytes = rollback.encode(&e, String::from_str(&e.clone(), CROSS_TRANSFER_REVERT)); + let message_bytes = xcall_message.encode(&e, String::from_str(&e.clone(), CROSS_TRANSFER)); + let (sources, destinations) = Self::xcall_manager(e.clone()).get_protocols(); + + let message = AnyMessage::CallMessageWithRollback(CallMessageWithRollback { data: message_bytes, rollback: rollback_bytes }); + let envelope: &Envelope = &Envelope { + message, + sources, + destinations + }; + let icon_bn_usd = &get_config(&e).icon_bn_usd; + let current_address = e.clone().current_contract_address(); + Self::xcall_client(e).send_call(&from, ¤t_address, envelope, icon_bn_usd ); + Ok(()) + + } + + + pub fn handle_call_message( + e: Env, + from: String, + data: Bytes, + protocols: Vec + ) { + let xcall = get_config(&e).xcall; + xcall.require_auth(); + if !Self::xcall_manager(e.clone()).verify_protocols(&protocols) { + panic!("Protocol Mismatch"); + }; + + let method = CrossTransfer::get_method(&e, data.clone()).unwrap(); + let icon_bn_usd = get_config(&e).icon_bn_usd; + if method == String::from_str(&e, &CROSS_TRANSFER){ + if from!=icon_bn_usd { + panic!("onlyICONBnUSD"); + } + let message = CrossTransfer::decode(&e.clone(), data).unwrap(); + Self::mint(e.clone(), Address::from_string( &message.to), u128::try_into(message.amount).unwrap()); + } else if method == String::from_str(&e, &CROSS_TRANSFER_REVERT){ + if from!=xcall.to_string() { + panic!("onlyCallService"); + } + let message = CrossTransferRevert::decode(&e.clone(), data).unwrap(); + Self::mint(e.clone(), message.to, u128::try_into(message.amount).unwrap()); + }else{ + panic!("Unknown message type") + } + } + + fn xcall_client(e: Env) -> Client<'static> { + return xcall::Client::new(&e, &get_config(&e).xcall); + } + + fn xcall_manager(e: Env) -> XcallManagerClient<'static> { + let client = XcallManagerClient::new(&e, &get_config(&e).xcall_manager); + return client; + } + +} \ No newline at end of file diff --git a/contracts/balanced_doller/src/config.rs b/contracts/balanced_doller/src/config.rs new file mode 100644 index 0000000..59c24d1 --- /dev/null +++ b/contracts/balanced_doller/src/config.rs @@ -0,0 +1,22 @@ +use soroban_sdk::{contracttype, unwrap::UnwrapOptimized, Env, String, Address}; +use crate::storage_types::DataKey; + +#[derive(Clone)] +#[contracttype] +pub struct ConfigData { + pub xcall: Address, + pub xcall_manager: Address, + pub nid: String, + pub icon_bn_usd: String, + pub xcall_network_address: String +} + +pub fn get_config(e: &Env) -> ConfigData { + let key = DataKey::Config; + e + .storage() + .instance() + .get(&key) + .unwrap_optimized() +} + diff --git a/balanced_dollar/src/contract.rs b/contracts/balanced_doller/src/contract.rs similarity index 95% rename from balanced_dollar/src/contract.rs rename to contracts/balanced_doller/src/contract.rs index 25611f4..f54bd9f 100644 --- a/balanced_dollar/src/contract.rs +++ b/contracts/balanced_doller/src/contract.rs @@ -21,7 +21,8 @@ pub struct BalancedDollar; #[contractimpl] impl BalancedDollar { - pub fn initialize(e: Env, admin: Address) { + pub fn initialize(e: Env, admin: Address, xcall: Address, + xcall_manager: Address, xcall_network_address: String, icon_bn_usd: String, nid: String) { if has_administrator(&e) { panic!("already initialized") } @@ -43,7 +44,9 @@ impl BalancedDollar { name, symbol, }, - ) + ); + + Self::configure(e, xcall, xcall_manager, xcall_network_address, icon_bn_usd, nid ); } pub fn mint(e: Env, to: Address, amount: i128) { diff --git a/contracts/balanced_doller/src/errors.rs b/contracts/balanced_doller/src/errors.rs new file mode 100644 index 0000000..f48b14f --- /dev/null +++ b/contracts/balanced_doller/src/errors.rs @@ -0,0 +1,8 @@ +use soroban_sdk::contracterror; + +#[contracterror] +#[repr(u32)] +#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord)] +pub enum ContractError { + InvalidRlpLength = 1 +} \ No newline at end of file diff --git a/balanced_dollar/src/lib.rs b/contracts/balanced_doller/src/lib.rs similarity index 51% rename from balanced_dollar/src/lib.rs rename to contracts/balanced_doller/src/lib.rs index bd4a125..33eac5a 100644 --- a/balanced_dollar/src/lib.rs +++ b/contracts/balanced_doller/src/lib.rs @@ -3,10 +3,15 @@ mod admin; mod allowance; mod balance; -mod contract; +pub mod contract; +//mod balanced_dollar; mod metadata; -mod states; mod storage_types; mod test; +mod config; +pub mod balanced_dollar; +mod messages; +mod errors; +mod xcall_manager_interface; pub use crate::contract::BalancedDollarClient; \ No newline at end of file diff --git a/contracts/balanced_doller/src/messages/cross_transfer.rs b/contracts/balanced_doller/src/messages/cross_transfer.rs new file mode 100644 index 0000000..826a2c9 --- /dev/null +++ b/contracts/balanced_doller/src/messages/cross_transfer.rs @@ -0,0 +1,71 @@ +use soroban_sdk::{contracttype, Env, String, Bytes, Vec}; +use soroban_rlp::{encoder, decoder}; +use crate::errors::ContractError; + +#[derive(Clone)] +#[contracttype] +pub struct CrossTransfer { + pub from: String, + pub to: String, + pub amount: u128, + pub data: Bytes +} + +impl CrossTransfer{ + pub fn new(from: String, to: String, amount: u128, data: Bytes) -> Self { + Self { + from, + to, + amount, + data + } + } + + pub fn from(&self) -> &String { + &self.from + } + + pub fn to(&self) -> &String { + &self.to + } + + pub fn encode(&self, e: &Env, method: String) -> Bytes { + let mut list: Vec = Vec::new(&e); + list.push_back(encoder::encode_string(&e, method)); + list.push_back(encoder::encode_string(&e, self.from.clone())); + list.push_back(encoder::encode_string(&e, self.to.clone())); + list.push_back(encoder::encode_u128(&e, self.amount.clone())); + list.push_back(self.data.clone()); + + let encoded = encoder::encode_list(&e, list, false); + encoded + } + + pub fn decode(e: &Env, bytes: Bytes) -> Result { + let decoded = decoder::decode_list(&e, bytes); + if decoded.len() != 6 { + return Err(ContractError::InvalidRlpLength); + } + + let from = decoder::decode_string(e, decoded.get(1).unwrap()); + let to = decoder::decode_string(e, decoded.get(2).unwrap()); + let amount = decoder::decode_u128(e, decoded.get(3).unwrap()); + let data = decoded.get(4).unwrap(); + + Ok(Self { + from, + to, + amount, + data + }) + } + + pub fn get_method(e: &Env, bytes: Bytes) -> Result { + let decoded = decoder::decode_list(&e, bytes); + if decoded.len() != 6 { + return Err(ContractError::InvalidRlpLength); + } + let method = decoder::decode_string(e, decoded.get(0).unwrap()); + Ok(method) + } +} \ No newline at end of file diff --git a/contracts/balanced_doller/src/messages/cross_transfer_revert.rs b/contracts/balanced_doller/src/messages/cross_transfer_revert.rs new file mode 100644 index 0000000..468979f --- /dev/null +++ b/contracts/balanced_doller/src/messages/cross_transfer_revert.rs @@ -0,0 +1,53 @@ +use soroban_sdk::{contracttype, Env, String, Address, Bytes, Vec}; +use soroban_rlp::{encoder, decoder}; +use crate::errors::ContractError; + +#[derive(Clone)] +#[contracttype] +pub struct CrossTransferRevert { + pub to: Address, + pub amount: u128 +} + +impl CrossTransferRevert{ + pub fn new(to: Address, amount: u128) -> Self { + Self { + to, + amount, + } + } + + pub fn to(&self) -> &Address { + &self.to + } + + pub fn amount(&self) -> &u128 { + &self.amount + } + + pub fn encode(&self, e: &Env, method: String) -> Bytes { + let mut list: Vec = Vec::new(&e); + + list.push_back(encoder::encode_string(&e, method)); + list.push_back(encoder::encode_string(&e, self.to.clone().to_string())); + list.push_back(encoder::encode_u128(&e, self.amount.clone())); + + let encoded = encoder::encode_list(&e, list, false); + encoded + } + + pub fn decode(e: &Env, bytes: Bytes) -> Result { + let decoded = decoder::decode_list(&e, bytes); + if decoded.len() != 6 { + return Err(ContractError::InvalidRlpLength); + } + + let to = Address::from_string(&decoder::decode_string(e, decoded.get(1).unwrap())); + let amount = decoder::decode_u128(e, decoded.get(2).unwrap()); + + Ok(Self { + to, + amount + }) + } +} \ No newline at end of file diff --git a/contracts/balanced_doller/src/messages/mod.rs b/contracts/balanced_doller/src/messages/mod.rs new file mode 100644 index 0000000..746aec8 --- /dev/null +++ b/contracts/balanced_doller/src/messages/mod.rs @@ -0,0 +1,2 @@ +pub mod cross_transfer_revert; +pub mod cross_transfer; \ No newline at end of file diff --git a/balanced_dollar/src/metadata.rs b/contracts/balanced_doller/src/metadata.rs similarity index 100% rename from balanced_dollar/src/metadata.rs rename to contracts/balanced_doller/src/metadata.rs diff --git a/balanced_dollar/src/storage_types.rs b/contracts/balanced_doller/src/storage_types.rs similarity index 98% rename from balanced_dollar/src/storage_types.rs rename to contracts/balanced_doller/src/storage_types.rs index 424f449..e4fccca 100644 --- a/balanced_dollar/src/storage_types.rs +++ b/contracts/balanced_doller/src/storage_types.rs @@ -29,6 +29,7 @@ pub enum DataKey { Nonce(Address), State(Address), Admin, + Config } #[derive(Clone)] diff --git a/balanced_dollar/src/test.rs b/contracts/balanced_doller/src/test.rs similarity index 77% rename from balanced_dollar/src/test.rs rename to contracts/balanced_doller/src/test.rs index 825f0be..f3f5eb5 100644 --- a/balanced_dollar/src/test.rs +++ b/contracts/balanced_doller/src/test.rs @@ -3,14 +3,19 @@ extern crate std; use crate::{contract::BalancedDollar, BalancedDollarClient}; use soroban_sdk::{ - symbol_short, - testutils::{Address as _, AuthorizedFunction, AuthorizedInvocation}, - Address, Env, IntoVal, Symbol, + symbol_short, testutils::{Address as _, AuthorizedFunction, AuthorizedInvocation}, Address, Env, IntoVal, String, Symbol }; fn create_token<'a>(e: &Env, admin: &Address) -> BalancedDollarClient<'a> { let token = BalancedDollarClient::new(e, &e.register_contract(None, BalancedDollar {})); - token.initialize(admin); + + let xcall = Address::generate(&e.clone()); + let xcall_manager = Address::generate(&e.clone()); + let xcall_network_address = String::from_str(&e.clone(), "ste/address"); + let icon_bn_usd = String::from_str(&e.clone(), "icon/hxeoriweo"); + let nid = String::from_str(&e.clone(), "ste"); + + token.initialize(&admin, &xcall, &xcall_manager, &xcall_network_address, &icon_bn_usd, &nid); token } @@ -231,23 +236,33 @@ fn transfer_from_insufficient_allowance() { token.transfer_from(&user3, &user1, &user2, &101); } -#[test] -#[should_panic(expected = "already initialized")] -fn initialize_already_initialized() { - let e = Env::default(); - let admin = Address::generate(&e); - let token = create_token(&e, &admin); +// #[test] +// #[should_panic(expected = "already initialized")] +// fn initialize_already_initialized() { +// let e = Env::default(); +// let admin = Address::generate(&e); +// let token = create_token(&e, &admin); - token.initialize(&admin); -} +// let xcall = Address::generate(&e.clone()); +// let xcall_manager = Address::generate(&e.clone()); +// let xcall_network_address = String::from_str(&e.clone(), "ste/address"); +// let icon_bn_usd = String::from_str(&e.clone(), "icon/hxeoriweo"); +// let nid = String::from_str(&e.clone(), "ste"); -#[test] -#[should_panic(expected = "Decimal must fit in a u8")] -fn decimal_is_over_max() { - let e = Env::default(); - let admin = Address::generate(&e); - let token = BalancedDollarClient::new(&e, &e.register_contract(None, BalancedDollar {})); - token.initialize( - &admin - ); -} \ No newline at end of file +// token.initialize(&admin, &xcall, &xcall_manager, &xcall_network_address, &icon_bn_usd, &nid); +// } + +// #[test] +// #[should_panic(expected = "Decimal must fit in a u8")] +// fn decimal_is_over_max() { +// let e = Env::default(); +// let admin = Address::generate(&e); +// let token = BalancedDollarClient::new(&e, &e.register_contract(None, BalancedDollar {})); +// let xcall = Address::generate(&e.clone()); +// let xcall_manager = Address::generate(&e.clone()); +// let xcall_network_address = String::from_str(&e.clone(), "ste/address"); +// let icon_bn_usd = String::from_str(&e.clone(), "icon/hxeoriweo"); +// let nid = String::from_str(&e.clone(), "ste"); + +// token.initialize(&admin, &xcall, &xcall_manager, &xcall_network_address, &icon_bn_usd, &nid); +// } \ No newline at end of file diff --git a/contracts/balanced_doller/src/xcall_manager_interface.rs b/contracts/balanced_doller/src/xcall_manager_interface.rs new file mode 100644 index 0000000..325a064 --- /dev/null +++ b/contracts/balanced_doller/src/xcall_manager_interface.rs @@ -0,0 +1,15 @@ +use soroban_sdk::{contractclient, Env, String, Vec}; + +use crate::errors::ContractError; + +#[contractclient(name = "XcallManagerClient")] +pub trait IXcallManager { + + fn verify_protocols( + e: Env, + protocols: Vec + ) -> Result; + + fn get_protocols(e: Env) -> Result<(Vec, Vec), ContractError>; + +} \ No newline at end of file diff --git a/contracts/xcall_manager/Cargo.toml b/contracts/xcall_manager/Cargo.toml new file mode 100644 index 0000000..00380f8 --- /dev/null +++ b/contracts/xcall_manager/Cargo.toml @@ -0,0 +1,17 @@ +[package] +name = "xcall-manager" +version = "0.1.0" +edition = "2021" + +[lib] +crate-type = ["cdylib", "rlib"] + +[features] +testutils = ["soroban-sdk/testutils"] + +[dependencies] +soroban-sdk = { workspace = true } +soroban-rlp = { path = "../../libs/soroban-rlp" } + +[dev_dependencies] +soroban-sdk = { workspace = true, features = ["testutils"] } \ No newline at end of file diff --git a/xcall_manager/src/admin.rs b/contracts/xcall_manager/src/admin.rs similarity index 73% rename from xcall_manager/src/admin.rs rename to contracts/xcall_manager/src/admin.rs index 85f4a52..f571e95 100644 --- a/xcall_manager/src/admin.rs +++ b/contracts/xcall_manager/src/admin.rs @@ -2,11 +2,6 @@ use soroban_sdk::{Address, Env}; use crate::storage_types::DataKey; -pub fn has_administrator(e: &Env) -> bool { - let key = DataKey::Admin; - e.storage().instance().has(&key) -} - pub fn read_administrator(e: &Env) -> Address { let key = DataKey::Admin; e.storage().instance().get(&key).unwrap() diff --git a/contracts/xcall_manager/src/config.rs b/contracts/xcall_manager/src/config.rs new file mode 100644 index 0000000..ca09dbf --- /dev/null +++ b/contracts/xcall_manager/src/config.rs @@ -0,0 +1,20 @@ +use soroban_sdk::{contracttype, unwrap::UnwrapOptimized, Env, String, Address}; +use crate::storage_types::DataKey; + +#[derive(Clone)] +#[contracttype] +pub struct ConfigData { + pub xcall: Address, + pub icon_governance: String, + pub xcall_network_address: String, +} + +pub fn get_config(e: &Env) -> ConfigData { + let key = DataKey::Config; + e + .storage() + .instance() + .get(&key) + .unwrap_optimized() +} + diff --git a/contracts/xcall_manager/src/contract.rs b/contracts/xcall_manager/src/contract.rs new file mode 100644 index 0000000..c5e8cb1 --- /dev/null +++ b/contracts/xcall_manager/src/contract.rs @@ -0,0 +1,176 @@ +use soroban_sdk::{contract, contractimpl, Address, Bytes, Env, String, Vec}; +mod xcall { + soroban_sdk::contractimport!(file = "xcall.wasm" ); +} + +use crate::{ + admin:: {read_administrator, write_administrator}, + config::{get_config, ConfigData}, + states::{has_state, read_string_state, read_vec_string_state, write_string_state, write_vec_string_state }, + storage_types::{DataKey, INSTANCE_BUMP_AMOUNT, INSTANCE_LIFETIME_THRESHOLD }, + messages::{configure_protocols::ConfigureProtocols, execute::Execute } + +}; +use crate::errors::ContractError; + +const CONFIGURE_PROTOCOLS_NAME: &str = "ConfigureProtocols"; +const EXECUTE_NAME: &str = "Execute"; + +#[contract] +pub struct XcallManager; + +#[contractimpl] +impl XcallManager { + + pub fn initialize(env:Env, registry:Address, admin: Address, xcall: Address, + icon_governance: String, xcall_network_address: String, proposed_protocol_to_remove: String, sources: Vec, destinations: Vec) { + if has_state(env.clone(), DataKey::Registry) { + panic!("Contract already initialized.") + } + env.storage().instance().set(&DataKey::Registry, ®istry); + env.storage().instance().set(&DataKey::Admin, &admin); + Self::configure(env, xcall, icon_governance, xcall_network_address, proposed_protocol_to_remove, sources, destinations ); + } + + pub fn configure(env:Env, xcall: Address, + icon_governance: String, xcall_network_address: String, proposed_protocol_to_remove: String, sources: Vec, destinations: Vec){ + let admin = read_administrator(&env.clone()); + admin.require_auth(); + + let config: ConfigData = ConfigData{ xcall: xcall, icon_governance: icon_governance, xcall_network_address: xcall_network_address }; + env.storage().instance().set(&DataKey::Config, &config); + env.storage().instance().set(&DataKey::Sources, &sources); + env.storage().instance().set(&DataKey::Destinations, &destinations); + env.storage().instance().set(&DataKey::ProposedProtocolToRemove, &proposed_protocol_to_remove); + } + + + + pub fn set_admin(e: Env, new_admin: Address) { + let admin = read_administrator(&e); + admin.require_auth(); + + e.storage() + .instance() + .extend_ttl(INSTANCE_LIFETIME_THRESHOLD, INSTANCE_BUMP_AMOUNT); + + write_administrator(&e, &new_admin); + } + + pub fn propose_removal(e: Env, protocol: String) { + let admin = read_administrator(&e); + admin.require_auth(); + + write_string_state(&e, DataKey::ProposedProtocolToRemove, &protocol); + } + + pub fn verify_protocols( + e: Env, + protocols: Vec + ) -> Result { + let sources = read_vec_string_state(&e, DataKey::Sources); + return Self::verify_protocols_unordered(e, protocols, sources); + } + + pub fn get_protocols(e: Env) -> Result<(Vec, Vec), ContractError> { + let sources = read_vec_string_state(&e, DataKey::Sources); + let destinations = read_vec_string_state(&e, DataKey::Destinations); + Ok((sources, destinations)) + } + + pub fn verify_protocols_unordered(_e: Env, array1: Vec, array2: Vec) -> Result { + // Check if the arrays have the same length + if array1.len() != array2.len() { + return Ok(false); + } + for p in array1.iter() { + let mut j = 0; + for s in array2.iter() { + j = j+1; + if p.eq(&s) { + break; + } else { + if j == array2.len() { + return Ok(false); + } + continue; + } + + } + } + return Ok(true); + } + + pub fn handle_call_message( + e: Env, + from: String, + data: Bytes, + protocols: Vec + ) { + let xcall = get_config(&e.clone()).xcall; + xcall.require_auth(); + + let icon_governance = get_config(&e.clone()).icon_governance; + if from != icon_governance { + panic!("Only ICON Balanced governance is allowed") + } + + + if !Self::verify_protocols(e.clone(), protocols.clone()).unwrap() { + panic!("Protocol Mismatch"); + }; + + let method = ConfigureProtocols::get_method(&e.clone(), data.clone()).unwrap(); + + let sources = read_vec_string_state(&e, DataKey::Sources); + if !Self::verify_protocols_unordered(e.clone(), protocols.clone(), sources).unwrap() { + if method != String::from_str(&e.clone(), CONFIGURE_PROTOCOLS_NAME) { + panic!("Protocol Mismatch"); + } + Self::verify_protocol_recovery(e.clone(), protocols); + } + + if method == String::from_str(&e.clone(), EXECUTE_NAME) { + let message = Execute::decode(&e.clone(), data).unwrap(); + // (bool _success, ) = message.contractAddress.call(message.data); + // require(_success, "Failed to excute message"); + //e.invoke_contract(&message.contract_address, &Symbol::new(&e.clone(), "test"), data); + } else if method == String::from_str(&e, CONFIGURE_PROTOCOLS_NAME) { + let message = ConfigureProtocols::decode(&e, data).unwrap(); + let sources = message.sources; + let destinations = message.destinations; + write_vec_string_state(&e, DataKey::Sources, &sources); + write_vec_string_state(&e, DataKey::Destinations, &destinations); + } else { + panic!("Unknown message type"); + } + } + + pub fn verify_protocol_recovery(e: Env, protocols: Vec) { + let modified_sources = Self::get_modified_protocols(e.clone()); + let verify_unordered = Self::verify_protocols_unordered(e.clone(), modified_sources, protocols).unwrap(); + if !verify_unordered { + panic!("Protocol Mismatch") + } + } + + + pub fn get_modified_protocols(e: Env) -> Vec{ + if !has_state(e.clone(), DataKey::ProposedProtocolToRemove) { + panic!( "No proposal for removal exists") + } + + let sources = read_vec_string_state(&e, DataKey::Sources); + let protocol_to_remove = read_string_state(&e, DataKey::ProposedProtocolToRemove); + let mut new_array = Vec::new(&e); + for s in sources.iter() { + if !s.eq(&protocol_to_remove) { + new_array.push_back(s); + } + } + + return new_array; + } + + +} \ No newline at end of file diff --git a/contracts/xcall_manager/src/errors.rs b/contracts/xcall_manager/src/errors.rs new file mode 100644 index 0000000..f48b14f --- /dev/null +++ b/contracts/xcall_manager/src/errors.rs @@ -0,0 +1,8 @@ +use soroban_sdk::contracterror; + +#[contracterror] +#[repr(u32)] +#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord)] +pub enum ContractError { + InvalidRlpLength = 1 +} \ No newline at end of file diff --git a/xcall_manager/src/events.rs b/contracts/xcall_manager/src/events.rs similarity index 100% rename from xcall_manager/src/events.rs rename to contracts/xcall_manager/src/events.rs diff --git a/xcall_manager/src/lib.rs b/contracts/xcall_manager/src/lib.rs similarity index 66% rename from xcall_manager/src/lib.rs rename to contracts/xcall_manager/src/lib.rs index d6e27dc..db0d07c 100644 --- a/xcall_manager/src/lib.rs +++ b/contracts/xcall_manager/src/lib.rs @@ -1,9 +1,12 @@ #![no_std] mod admin; -mod contract; +pub mod contract; mod storage_types; mod states; mod test; +mod errors; +mod config; +mod messages; pub use crate::contract::XcallManagerClient; \ No newline at end of file diff --git a/contracts/xcall_manager/src/messages/configure_protocols.rs b/contracts/xcall_manager/src/messages/configure_protocols.rs new file mode 100644 index 0000000..802901c --- /dev/null +++ b/contracts/xcall_manager/src/messages/configure_protocols.rs @@ -0,0 +1,62 @@ +use soroban_sdk::{contracttype, Env, String, Bytes, Vec}; +use soroban_rlp::{encoder, decoder}; +use crate::errors::ContractError; + +#[derive(Clone)] +#[contracttype] +pub struct ConfigureProtocols { + pub sources: Vec, + pub destinations: Vec +} + + +impl ConfigureProtocols{ + pub fn new(sources: Vec, destinations: Vec) -> Self { + Self { + sources, + destinations + } + } + + pub fn sources(&self) -> &Vec { + &self.sources + } + + pub fn destinations(&self) -> &Vec { + &self.destinations + } + + pub fn encode(&self, e: &Env, method: String) -> Bytes { + let mut list: Vec = Vec::new(&e); + list.push_back(encoder::encode_string(&e, method)); + list.push_back(encoder::encode_strings(&e, self.sources.clone())); + list.push_back(encoder::encode_strings(&e, self.destinations.clone())); + + let encoded = encoder::encode_list(&e, list, false); + encoded + } + + pub fn decode(e: &Env, bytes: Bytes) -> Result { + let decoded = decoder::decode_list(&e, bytes); + if decoded.len() != 6 { + return Err(ContractError::InvalidRlpLength); + } + + let sources = decoder::decode_strings(e, decoded.get(1).unwrap()); + let destinations = decoder::decode_strings(e, decoded.get(2).unwrap()); + + Ok(Self { + sources, + destinations + }) + } + + pub fn get_method(e: &Env, bytes: Bytes) -> Result { + let decoded = decoder::decode_list(&e, bytes); + if decoded.len() != 6 { + return Err(ContractError::InvalidRlpLength); + } + let method = decoder::decode_string(e, decoded.get(0).unwrap()); + Ok(method) + } +} \ No newline at end of file diff --git a/contracts/xcall_manager/src/messages/execute.rs b/contracts/xcall_manager/src/messages/execute.rs new file mode 100644 index 0000000..cbdded2 --- /dev/null +++ b/contracts/xcall_manager/src/messages/execute.rs @@ -0,0 +1,52 @@ +use soroban_sdk::{contracttype, Env, String, Bytes, Vec, Address}; +use soroban_rlp::{encoder, decoder}; +use crate::errors::ContractError; + +#[derive(Clone)] +#[contracttype] +pub struct Execute { + pub contract_address: Address, + pub data: Bytes +} + +impl Execute{ + pub fn new(contract_address: Address, data: Bytes) -> Self { + Self { + contract_address, + data + } + } + + pub fn contract_address(&self) -> &Address { + &self.contract_address + } + + pub fn data(&self) -> &Bytes { + &self.data + } + + pub fn encode(&self, e: &Env, method: String) -> Bytes { + let mut list: Vec = Vec::new(&e); + list.push_back(encoder::encode_string(&e, method)); + list.push_back(encoder::encode_string(&e, self.contract_address.clone().to_string() )); + list.push_back(encoder::encode(&e, self.data.clone())); + + let encoded = encoder::encode_list(&e, list, false); + encoded + } + + pub fn decode(e: &Env, bytes: Bytes) -> Result { + let decoded = decoder::decode_list(&e, bytes); + if decoded.len() != 6 { + return Err(ContractError::InvalidRlpLength); + } + + let contract_address = Address::from_string(&decoder::decode_string(e, decoded.get(1).unwrap())); + let data = decoded.get(2).unwrap(); + + Ok(Self { + contract_address, + data + }) + } +} \ No newline at end of file diff --git a/contracts/xcall_manager/src/messages/mod.rs b/contracts/xcall_manager/src/messages/mod.rs new file mode 100644 index 0000000..678d8ed --- /dev/null +++ b/contracts/xcall_manager/src/messages/mod.rs @@ -0,0 +1,2 @@ +pub mod configure_protocols; +pub mod execute; \ No newline at end of file diff --git a/contracts/xcall_manager/src/states.rs b/contracts/xcall_manager/src/states.rs new file mode 100644 index 0000000..5c845ae --- /dev/null +++ b/contracts/xcall_manager/src/states.rs @@ -0,0 +1,23 @@ +use soroban_sdk::{Env, String, Vec}; + +use crate::storage_types::DataKey; + +pub fn has_state(env:Env, key: DataKey) -> bool { + env.storage().instance().has(&key) +} + +pub fn write_string_state(e: &Env, key: DataKey, id: &String) { + e.storage().instance().set(&key, id); +} + +pub fn write_vec_string_state(e: &Env, key: DataKey, id: &Vec) { + e.storage().instance().set(&key, id); +} + +pub fn read_string_state(e: &Env, key: DataKey) -> String { + e.storage().instance().get(&key).unwrap() +} + +pub fn read_vec_string_state(e: &Env, key: DataKey) -> Vec { + e.storage().instance().get(&key).unwrap() +} \ No newline at end of file diff --git a/xcall_manager/src/storage_types.rs b/contracts/xcall_manager/src/storage_types.rs similarity index 79% rename from xcall_manager/src/storage_types.rs rename to contracts/xcall_manager/src/storage_types.rs index 7fbc8b6..c702a64 100644 --- a/xcall_manager/src/storage_types.rs +++ b/contracts/xcall_manager/src/storage_types.rs @@ -1,4 +1,4 @@ -use soroban_sdk::{contracttype, symbol_short, vec, Env, Symbol, Vec}; +use soroban_sdk::contracttype; pub(crate) const DAY_IN_LEDGERS: u32 = 17280; pub(crate) const INSTANCE_BUMP_AMOUNT: u32 = 7 * DAY_IN_LEDGERS; @@ -12,10 +12,9 @@ pub(crate) const BALANCE_LIFETIME_THRESHOLD: u32 = BALANCE_BUMP_AMOUNT - DAY_IN_ pub enum DataKey{ Registry, Admin, - Xcall, - XcallNetworkAddress, - IconGovernance, ProposedProtocolToRemove, + Config, Sources, Destinations + } \ No newline at end of file diff --git a/xcall_manager/src/test.rs b/contracts/xcall_manager/src/test.rs similarity index 100% rename from xcall_manager/src/test.rs rename to contracts/xcall_manager/src/test.rs diff --git a/libs/soroban-rlp/Cargo.toml b/libs/soroban-rlp/Cargo.toml new file mode 100644 index 0000000..d1fb1a1 --- /dev/null +++ b/libs/soroban-rlp/Cargo.toml @@ -0,0 +1,12 @@ +[package] +name = "soroban-rlp" +version = "0.1.0" +edition = "2021" +publish = false + +[lib] +crate-type = ["cdylib", "rlib"] +doctest = false + +[dependencies] +soroban-sdk = { workspace = true } \ No newline at end of file diff --git a/libs/soroban-rlp/src/decoder.rs b/libs/soroban-rlp/src/decoder.rs new file mode 100644 index 0000000..c49077d --- /dev/null +++ b/libs/soroban-rlp/src/decoder.rs @@ -0,0 +1,140 @@ +use super::utils::*; +use soroban_sdk::{vec, Bytes, Env, String, Vec}; + +pub fn decode(env: &Env, bytes: Bytes) -> Bytes { + assert!(bytes.len() > 0); + + let rlp_byte = bytes.get(0).unwrap(); + + let decoded = if rlp_byte == 0x80 { + Bytes::new(&env) + } else if rlp_byte < 0x80 { + bytes + } else if rlp_byte < 0xb8 { + let data_len = rlp_byte - 0x80; + let data = slice_vector(&env, bytes, 1, data_len as u64); + data + } else { + let data_bytes_len = rlp_byte - 0xb7; + let len_bytes = slice_vector(&env, bytes.clone(), 1, data_bytes_len as u64); + + let data_len = bytes_to_u64(len_bytes.clone()); + let data_start = len_bytes.len() + 1; + + let data = slice_vector(&env, bytes, data_start as u64, data_len); + data + }; + + decoded +} + +pub fn decode_list(env: &Env, list: Bytes) -> Vec { + let data_len = decode_length(&env, list.clone(), 0xc0); + let start = list.len() as u64 - data_len; + let encoded = slice_vector(&env, list, start, data_len); + + let mut decoded: Vec = Vec::new(&env); + let mut i = 0; + while i < encoded.len() { + let byte = encoded.get(i).unwrap(); + + #[allow(unused_comparisons)] + if byte == 0x80 { + decoded.push_back(Bytes::new(&env)); + i = i + 1; + } else if byte < 0x80 { + let mut singleton = Bytes::new(&env); + singleton.push_back(byte); + decoded.push_back(singleton); + i = i + 1; + } else if byte > 0x80 && byte < 0xB8 { + let len = (byte - 0x80) as u64; + decoded.push_back(slice_vector(&env, encoded.clone(), i as u64 + 1, len)); + i = i + (len as u32 + 1); + } else if byte == 0xc0 { + decoded.push_back(Bytes::new(&env)); + i = i + 1; + } else if byte > 0xc0 && byte < 0xf7 { + let len = (byte - 0xc0) as u64; + decoded.push_back(slice_vector(&env, encoded.clone(), i as u64 + 1, len)); + i = i + (len as u32 + 1) + } else if byte > 0xb7 && byte < 0xc0 { + let data_bytes_len = (byte - 0xb7) as u64; + let len_bytes = slice_vector(&env, encoded.clone(), i as u64 + 1, data_bytes_len); + let len = bytes_to_u64(len_bytes); + decoded.push_back(slice_vector( + &env, + encoded.clone(), + i as u64 + data_bytes_len + 1, + len, + )); + i = i + (data_bytes_len + len + 1) as u32 + } else if byte > 0xf7 && byte <= 0xff { + let data_bytes_len = (byte - 0xf7) as u64; + let len_bytes = slice_vector(&env, encoded.clone(), i as u64 + 1, data_bytes_len); + let len = bytes_to_u64(len_bytes); + + decoded.push_back(slice_vector( + &env, + encoded.clone(), + i as u64, + data_bytes_len + len + 1, + )); + i = i + (data_bytes_len + len + 1) as u32 + } else { + panic!("invalid rlp byte length") + } + } + decoded +} + +pub fn decode_length(env: &Env, bytes: Bytes, offset: u8) -> u64 { + let bytes_len = bytes.len(); + + let len = if bytes_len == 0 { + 0 + } else if bytes_len < 56 { + (bytes.get(0).unwrap() - offset) as u64 + } else { + let len = bytes.get(0).unwrap() - offset - 55; + let len_bytes = slice_vector(env, bytes, 1, len as u64); + bytes_to_u64(len_bytes) + }; + + len +} + +pub fn decode_u8(env: &Env, bytes: Bytes) -> u8 { + decode(&env, bytes).get(0).unwrap_or(0) +} + +pub fn decode_u32(env: &Env, bytes: Bytes) -> u32 { + let decoded = decode(&env, bytes); + bytes_to_u32(decoded) +} + +pub fn decode_u64(env: &Env, bytes: Bytes) -> u64 { + let decoded = decode(&env, bytes); + bytes_to_u64(decoded) +} + +pub fn decode_u128(env: &Env, bytes: Bytes) -> u128 { + let decoded = decode(&env, bytes); + bytes_to_u128(decoded) +} + +pub fn decode_string(env: &Env, bytes: Bytes) -> String { + let decoded = decode(&env, bytes); + bytes_to_string(&env, decoded) +} + +pub fn decode_strings(env: &Env, bytes: Bytes) -> Vec { + let list = decode_list(&env, bytes); + + let mut strings: Vec = vec![&env]; + for byte in list { + strings.push_back(bytes_to_string(&env, byte)) + } + + strings +} \ No newline at end of file diff --git a/libs/soroban-rlp/src/encoder.rs b/libs/soroban-rlp/src/encoder.rs new file mode 100644 index 0000000..ade67a9 --- /dev/null +++ b/libs/soroban-rlp/src/encoder.rs @@ -0,0 +1,92 @@ +use super::utils::*; +use soroban_sdk::{bytes, vec, Bytes, Env, String, Vec}; + +pub fn encode(env: &Env, bytes: Bytes) -> Bytes { + let len = bytes.len(); + + let encoded = if len == 0 { + bytes!(&env, 0x80) + } else if len == 1 && bytes.get(0).unwrap() < 128 { + bytes + } else { + let mut res = encode_length(&env, len as u64, 0x80); + res.append(&bytes); + res + }; + + encoded +} + +pub fn encode_list(env: &Env, list: Vec, raw: bool) -> Bytes { + let mut res = Bytes::new(&env); + if list.len() == 0 { + res.push_back(0xc0); + } else { + for bytes in list { + if raw == true { + res.append(&encode(&env, bytes.clone())) + } else { + res.append(&bytes) + } + } + let len = res.len(); + let mut len_buffer = encode_length(&env, len as u64, 0xc0); + + len_buffer.append(&res); + res = len_buffer + } + res +} + +pub fn encode_length(env: &Env, len: u64, offset: u8) -> Bytes { + let mut len_info = Bytes::new(&env); + + if len < 56 { + let len_u8 = len as u8; + len_info.push_back(len_u8 + offset) + } else { + let mut bytes_length = u64_to_bytes(&env, len); + let rlp_bytes_len = bytes_length.len() as u8; + len_info.push_back(rlp_bytes_len + offset + 55); + len_info.append(&mut bytes_length); + } + + len_info +} + +pub fn encode_u8(env: &Env, num: u8) -> Bytes { + let mut bytes = Bytes::new(&env); + bytes.push_back(num); + + encode(&env, bytes) +} + +pub fn encode_u32(env: &Env, num: u32) -> Bytes { + let bytes = u32_to_bytes(&env, num); + encode(&env, bytes) +} + +pub fn encode_u64(env: &Env, num: u64) -> Bytes { + let bytes = u64_to_bytes(&env, num); + encode(&env, bytes) +} + +pub fn encode_u128(env: &Env, num: u128) -> Bytes { + let bytes = u128_to_bytes(&env, num); + encode(&env, bytes) +} + +pub fn encode_string(env: &Env, value: String) -> Bytes { + let bytes = string_to_bytes(&env, value); + encode(&env, bytes) +} + +pub fn encode_strings(env: &Env, values: Vec) -> Bytes { + let mut list: Vec = vec![&env]; + + for value in values { + list.push_back(encode_string(&env, value)); + } + + encode_list(&env, list, false) +} \ No newline at end of file diff --git a/libs/soroban-rlp/src/lib.rs b/libs/soroban-rlp/src/lib.rs new file mode 100644 index 0000000..8ab22f6 --- /dev/null +++ b/libs/soroban-rlp/src/lib.rs @@ -0,0 +1,5 @@ +#![no_std] + +pub mod decoder; +pub mod encoder; +mod utils; diff --git a/libs/soroban-rlp/src/utils.rs b/libs/soroban-rlp/src/utils.rs new file mode 100644 index 0000000..69d91d0 --- /dev/null +++ b/libs/soroban-rlp/src/utils.rs @@ -0,0 +1,104 @@ +use soroban_sdk::{ + xdr::{FromXdr, ToXdr}, + Bytes, Env, String, +}; + +pub fn u32_to_bytes(env: &Env, number: u32) -> Bytes { + let mut bytes = Bytes::new(&env); + let mut i = 3; + while i >= 0 { + let val = (number >> (i * 8) & 0xff) as u8; + if val > 0 { + bytes.push_back(val); + } + + i -= 1; + } + bytes +} + +pub fn bytes_to_u32(bytes: Bytes) -> u32 { + let mut num = 0; + for byte in bytes.iter() { + num = (num << 8) | byte as u32; + } + num +} + +pub fn u64_to_bytes(env: &Env, number: u64) -> Bytes { + let mut bytes = Bytes::new(&env); + let mut i = 7; + while i >= 0 { + let val = (number >> (i * 8) & 0xff) as u8; + if val > 0 { + bytes.push_back(val); + } + + i -= 1; + } + bytes +} + +pub fn bytes_to_u64(bytes: Bytes) -> u64 { + let mut num = 0; + for byte in bytes.iter() { + num = (num << 8) | byte as u64; + } + num +} + +pub fn u128_to_bytes(env: &Env, number: u128) -> Bytes { + let mut bytes = Bytes::new(&env); + let mut i = 15; + while i >= 0 { + let val = (number >> (i * 8) & 0xff) as u8; + if val > 0 { + bytes.push_back(val); + } + + i -= 1; + } + + bytes +} + +pub fn bytes_to_u128(bytes: Bytes) -> u128 { + let mut num = 0; + for byte in bytes.iter() { + num = (num << 8) | byte as u128 + } + num +} + +pub fn slice_vector(env: &Env, arr: Bytes, start: u64, length: u64) -> Bytes { + let mut sliced = Bytes::new(&env); + let mut start = start; + let end = start + length; + + while start < end { + let item = arr.get(start as u32).unwrap(); + sliced.push_back(item); + start += 1; + } + sliced +} + +pub fn string_to_bytes(env: &Env, value: String) -> Bytes { + let mut start_index = 8; + let end_index = start_index + value.len(); + let string_xdr = value.to_xdr(&env); + + let mut bytes = Bytes::new(&env); + while start_index < end_index { + bytes.push_back(string_xdr.get(start_index).unwrap()); + start_index += 1; + } + bytes +} + +pub fn bytes_to_string(env: &Env, bytes: Bytes) -> String { + let mut bytes_xdr = bytes.to_xdr(&env); + bytes_xdr.set(3, 14); + + String::from_xdr(&env, &bytes_xdr).unwrap() +} \ No newline at end of file diff --git a/xcall/Cargo.toml b/xcall/Cargo.toml deleted file mode 100644 index 53bacb9..0000000 --- a/xcall/Cargo.toml +++ /dev/null @@ -1,30 +0,0 @@ -[package] -name = "xcall" -version = "0.1.0" -edition = "2021" - -[lib] -crate-type = ["cdylib"] - -[features] -testutils = ["soroban-sdk/testutils"] - -[dependencies] -soroban-sdk = "20.0.0" - -[dev_dependencies] -soroban-sdk = { version = "20.0.0", features = ["testutils"] } - -[profile.release] -opt-level = "z" -overflow-checks = true -debug = 0 -strip = "symbols" -debug-assertions = false -panic = "abort" -codegen-units = 1 -lto = true - -[profile.release-with-logs] -inherits = "release" -debug-assertions = true \ No newline at end of file diff --git a/xcall/src/lib.rs b/xcall/src/lib.rs deleted file mode 100644 index 9849236..0000000 --- a/xcall/src/lib.rs +++ /dev/null @@ -1,19 +0,0 @@ -#![no_std] - -use soroban_sdk::{contract, contractimpl, Address, Env, String, Vec, Bytes}; - -#[contract] -pub struct Xcall; - -#[contractimpl] -impl Xcall { - - pub fn send_call_message(env: Env, from: Address, amount: i128, icon_asset_manager: String, data: Bytes, rollback: Bytes, sources: Vec, destinations: Vec){ - - } - - pub fn get_network_address(env: Env, address: String)-> String { - address - } - -} \ No newline at end of file diff --git a/xcall_manager/.gitignore b/xcall_manager/.gitignore deleted file mode 100644 index 8d9d75c..0000000 --- a/xcall_manager/.gitignore +++ /dev/null @@ -1,9 +0,0 @@ -target -.soroban - -# environment variables -.env -.env.production - -# macOS-specific files -.DS_Store diff --git a/xcall_manager/Cargo.toml b/xcall_manager/Cargo.toml deleted file mode 100644 index 77d8879..0000000 --- a/xcall_manager/Cargo.toml +++ /dev/null @@ -1,30 +0,0 @@ -[package] -name = "xcall-manager" -version = "0.1.0" -edition = "2021" - -[lib] -crate-type = ["cdylib"] - -[features] -testutils = ["soroban-sdk/testutils"] - -[dependencies] -soroban-sdk = "20.0.0" - -[dev_dependencies] -soroban-sdk = { version = "20.0.0", features = ["testutils"] } - -[profile.release] -opt-level = "z" -overflow-checks = true -debug = 0 -strip = "symbols" -debug-assertions = false -panic = "abort" -codegen-units = 1 -lto = true - -[profile.release-with-logs] -inherits = "release" -debug-assertions = true \ No newline at end of file diff --git a/xcall_manager/README.md b/xcall_manager/README.md deleted file mode 100644 index 012e23c..0000000 --- a/xcall_manager/README.md +++ /dev/null @@ -1,21 +0,0 @@ -# Soroban Project - -## Project Structure - -This repository uses the recommended structure for a Soroban project: -```text -. -├── contracts -│   └── hello_world -│   ├── src -│   │   ├── lib.rs -│   │   └── test.rs -│   └── Cargo.toml -├── Cargo.toml -└── README.md -``` - -- New Soroban contracts can be put in `contracts`, each in their own directory. There is already a `hello_world` contract in there to get you started. -- If you initialized this project with any other example contracts via `--with-example`, those contracts will be in the `contracts` directory as well. -- Contracts should have their own `Cargo.toml` files that rely on the top-level `Cargo.toml` workspace for their dependencies. -- Frontend libraries can be added to the top-level directory as well. If you initialized this project with a frontend template via `--frontend-template` you will have those files already included. \ No newline at end of file diff --git a/xcall_manager/src/contract.rs b/xcall_manager/src/contract.rs deleted file mode 100644 index 134e783..0000000 --- a/xcall_manager/src/contract.rs +++ /dev/null @@ -1,170 +0,0 @@ -use soroban_sdk::{contract, contractimpl, symbol_short, vec, Env, Symbol, Vec, Address, BytesN, String, Map}; - -use crate::{ - admin:: {self, has_administrator, read_administrator, write_administrator}, - states::{has_state, read_address_state, read_i128_state, read_string_state, read_u64_state, write_address_state, write_i128_state, write_string_state, write_u64_state, - write_vec_string_state, read_vec_string_state }, - storage_types::{DataKey, INSTANCE_BUMP_AMOUNT, INSTANCE_LIFETIME_THRESHOLD } -}; - -pub mod xcall { - soroban_sdk::contractimport!( - file = "../xcall/target/wasm32-unknown-unknown/release/xcall.wasm" - ); -} - -#[contract] -pub struct XcallManager; - -#[contractimpl] -impl XcallManager { - - pub fn initialize(env:Env, registry:Address, admin: Address, xcall: Address, - icon_governance: String, xcall_network_address: String, proposed_protocol_to_remove: String, sources: Vec, destinations: Vec) { - if has_state(env.clone(), DataKey::Registry) { - panic!("Contract already initialized.") - } - env.storage().instance().set(&DataKey::Registry, ®istry); - env.storage().instance().set(&DataKey::Admin, &admin); - Self::configure(env, xcall, icon_governance, xcall_network_address, proposed_protocol_to_remove, sources, destinations ); - } - - pub fn configure(env:Env, xcall: Address, - icon_governance: String, xcall_network_address: String, proposed_protocol_to_remove: String, sources: Vec, destinations: Vec){ - let admin = read_administrator(&env.clone()); - admin.require_auth(); - - env.storage().instance().set(&DataKey::Xcall, &xcall); - env.storage().instance().set(&DataKey::IconGovernance, &icon_governance); - env.storage().instance().set(&DataKey::XcallNetworkAddress, &xcall_network_address); - env.storage().instance().set(&DataKey::ProposedProtocolToRemove, &proposed_protocol_to_remove); - env.storage().instance().set(&DataKey::Sources, &sources); - env.storage().instance().set(&DataKey::Destinations, &destinations); - } - - pub fn set_admin(e: Env, new_admin: Address) { - let admin = read_administrator(&e); - admin.require_auth(); - - e.storage() - .instance() - .extend_ttl(INSTANCE_LIFETIME_THRESHOLD, INSTANCE_BUMP_AMOUNT); - - write_administrator(&e, &new_admin); - } - - pub fn propose_removal(e: Env, protocol: String) { - let admin = read_administrator(&e); - admin.require_auth(); - - write_string_state(&e, DataKey::ProposedProtocolToRemove, &protocol); - } - - pub fn set_protocols(e: Env, sources: Vec, destinations: Vec) { - let admin = read_administrator(&e); - admin.require_auth(); - - write_vec_string_state(&e, DataKey::Sources, &sources); - write_vec_string_state(&e, DataKey::Destinations, &destinations); - } - - pub fn verify_protocols( - e: Env, - protocols: Vec - ) -> bool { - let sources = read_vec_string_state(&e, DataKey::Sources); - return Self::verify_protocols_unordered(e, protocols, sources); - } - - pub fn get_protocols(e: Env) -> Map> { - let sources = read_vec_string_state(&e, DataKey::Sources); - let destinations = read_vec_string_state(&e, DataKey::Destinations); - let mut protocols = Map::new(&e); - protocols.set(String::from_str(&e, "sources"), sources); - protocols.set(String::from_str(&e, "destinations"), destinations); - protocols - } - - pub fn verify_protocols_unordered(_e: Env, array1: Vec, array2: Vec) -> bool { - // Check if the arrays have the same length - if array1.len() != array2.len() { - return false; - } - for p in array1.iter() { - let mut j = 0; - for s in array2.iter() { - j = j+1; - if p.eq(&s) { - break; - } else { - if j == array2.len() { - return false; - } - continue; - } - - } - } - return true; - } - - pub fn handle_call_message( - e: Env, - from: String, - data: BytesN<32>, - protocols: Vec - ) { - if !from.eq(&read_string_state(&e, DataKey::IconGovernance)) { - panic!("Only ICON Balanced governance is allowed") - } - - // string memory method = data.getMethod(); - // if (!verifyProtocolsUnordered(protocols, sources)) { - // require( - // method.compareTo(Messages.CONFIGURE_PROTOCOLS_NAME), - // "Protocol Mismatch" - // ); - // verifyProtocolRecovery(protocols); - // } - - // if (method.compareTo(Messages.EXECUTE_NAME)) { - // Messages.Execute memory message = data.decodeExecute(); - // (bool _success, ) = message.contractAddress.call(message.data); - // require(_success, "Failed to excute message"); - // } else if (method.compareTo(Messages.CONFIGURE_PROTOCOLS_NAME)) { - // Messages.ConfigureProtocols memory message = data - // .decodeConfigureProtocols(); - // sources = message.sources; - // destinations = message.destinations; - // } else { - // revert("Unknown message type"); - // } - } - - pub fn verify_protocol_recovery(e: Env, protocols: Vec) { - let modifiedSources = Self::get_modified_protocols(e.clone()); - if !Self::verify_protocols_unordered(e.clone(), modifiedSources, protocols) { - panic!("Protocol Mismatch") - } - } - - - pub fn get_modified_protocols(e: Env) -> Vec{ - if !has_state(e.clone(), DataKey::ProposedProtocolToRemove) { - panic!( "No proposal for removal exists") - } - - let sources = read_vec_string_state(&e, DataKey::Sources); - let protocol_to_remove = read_string_state(&e, DataKey::ProposedProtocolToRemove); - let mut new_array = Vec::new(&e); - for s in sources.iter() { - if !s.eq(&protocol_to_remove) { - new_array.push_back(s); - } - } - - return new_array; - } - - -} \ No newline at end of file diff --git a/xcall_manager/src/states.rs b/xcall_manager/src/states.rs deleted file mode 100644 index 49faea1..0000000 --- a/xcall_manager/src/states.rs +++ /dev/null @@ -1,47 +0,0 @@ -use soroban_sdk::{Address, Env, String, Vec}; - -use crate::storage_types::DataKey; - -pub fn has_state(env:Env, key: DataKey) -> bool { - env.storage().instance().has(&key) -} - -pub fn write_string_state(e: &Env, key: DataKey, id: &String) { - e.storage().instance().set(&key, id); -} - -pub fn write_address_state(e: &Env, key: DataKey, id: &Address) { - e.storage().instance().set(&key, id); -} - -pub fn write_u64_state(e: &Env, key: DataKey, id: &u64) { - e.storage().instance().set(&key, id); -} - -pub fn write_i128_state(e: &Env, key: DataKey, id: &i128) { - e.storage().instance().set(&key, id); -} - -pub fn write_vec_string_state(e: &Env, key: DataKey, id: &Vec) { - e.storage().instance().set(&key, id); -} - -pub fn read_string_state(e: &Env, key: DataKey) -> String { - e.storage().instance().get(&key).unwrap() -} - -pub fn read_address_state(e: &Env, key: DataKey) -> Address { - e.storage().instance().get(&key).unwrap() -} - -pub fn read_u64_state(e: &Env, key: DataKey) -> u64 { - e.storage().instance().get(&key).unwrap() -} - -pub fn read_i128_state(e: &Env, key: DataKey) -> i128 { - e.storage().instance().get(&key).unwrap() -} - -pub fn read_vec_string_state(e: &Env, key: DataKey) -> Vec { - e.storage().instance().get(&key).unwrap() -} \ No newline at end of file From 693af2f459dd8e2ed1fff5485aea869e6807099e Mon Sep 17 00:00:00 2001 From: sagar sapkota Date: Wed, 22 May 2024 13:58:18 +0545 Subject: [PATCH 03/63] unit test happy cases completed --- .gitignore | 3 +- contracts/asset_manager/src/admin.rs | 2 +- contracts/asset_manager/src/config.rs | 7 +- contracts/asset_manager/src/contract.rs | 186 ++++++++++-------- contracts/asset_manager/src/errors.rs | 11 +- contracts/asset_manager/src/lib.rs | 7 +- contracts/asset_manager/src/messages/mod.rs | 3 - contracts/asset_manager/src/states.rs | 6 +- contracts/asset_manager/src/storage_types.rs | 4 +- contracts/asset_manager/src/test.rs | 77 -------- .../src/tests/asset_manager_test.rs | 181 +++++++++++++++++ contracts/asset_manager/src/tests/mod.rs | 2 + contracts/asset_manager/src/tests/setup.rs | 129 ++++++++++++ .../balanced_doller/src/balanced_dollar.rs | 63 ++---- contracts/balanced_doller/src/config.rs | 5 +- contracts/balanced_doller/src/contract.rs | 51 ++++- contracts/balanced_doller/src/lib.rs | 9 +- contracts/balanced_doller/src/messages/mod.rs | 2 - contracts/balanced_doller/src/states.rs | 51 +++++ contracts/balanced_doller/src/test.rs | 47 ++--- .../src/tests/balanced_dollar_test.rs | 101 ++++++++++ contracts/balanced_doller/src/tests/mod.rs | 2 + contracts/balanced_doller/src/tests/setup.rs | 132 +++++++++++++ contracts/xcall_manager/src/config.rs | 5 +- contracts/xcall_manager/src/contract.rs | 53 +++-- contracts/xcall_manager/src/lib.rs | 7 +- contracts/xcall_manager/src/messages/mod.rs | 2 - contracts/xcall_manager/src/states.rs | 10 +- contracts/xcall_manager/src/tests/mod.rs | 2 + contracts/xcall_manager/src/tests/setup.rs | 115 +++++++++++ .../src/tests/xcall_manager_test.rs | 65 ++++++ libs/soroban-rlp/src/decoder.rs | 31 +-- libs/soroban-rlp/src/lib.rs | 1 + .../src/messages/configure_protocols.rs | 30 +-- .../src/messages/cross_transfer.rs | 25 ++- .../src/messages/cross_transfer_revert.rs | 14 +- .../soroban-rlp}/src/messages/deposit.rs | 19 +- .../src/messages/deposit_revert.rs | 14 +- .../soroban-rlp}/src/messages/execute.rs | 14 +- libs/soroban-rlp/src/messages/mod.rs | 8 + .../soroban-rlp}/src/messages/withdraw_to.rs | 14 +- 41 files changed, 1123 insertions(+), 387 deletions(-) delete mode 100644 contracts/asset_manager/src/messages/mod.rs delete mode 100644 contracts/asset_manager/src/test.rs create mode 100644 contracts/asset_manager/src/tests/asset_manager_test.rs create mode 100644 contracts/asset_manager/src/tests/mod.rs create mode 100644 contracts/asset_manager/src/tests/setup.rs delete mode 100644 contracts/balanced_doller/src/messages/mod.rs create mode 100644 contracts/balanced_doller/src/states.rs create mode 100644 contracts/balanced_doller/src/tests/balanced_dollar_test.rs create mode 100644 contracts/balanced_doller/src/tests/mod.rs create mode 100644 contracts/balanced_doller/src/tests/setup.rs delete mode 100644 contracts/xcall_manager/src/messages/mod.rs create mode 100644 contracts/xcall_manager/src/tests/mod.rs create mode 100644 contracts/xcall_manager/src/tests/setup.rs create mode 100644 contracts/xcall_manager/src/tests/xcall_manager_test.rs rename {contracts/xcall_manager => libs/soroban-rlp}/src/messages/configure_protocols.rs (72%) rename {contracts/balanced_doller => libs/soroban-rlp}/src/messages/cross_transfer.rs (76%) rename {contracts/balanced_doller => libs/soroban-rlp}/src/messages/cross_transfer_revert.rs (80%) rename {contracts/asset_manager => libs/soroban-rlp}/src/messages/deposit.rs (83%) rename {contracts/asset_manager => libs/soroban-rlp}/src/messages/deposit_revert.rs (84%) rename {contracts/xcall_manager => libs/soroban-rlp}/src/messages/execute.rs (81%) create mode 100644 libs/soroban-rlp/src/messages/mod.rs rename {contracts/asset_manager => libs/soroban-rlp}/src/messages/withdraw_to.rs (83%) diff --git a/.gitignore b/.gitignore index e978b31..8127c54 100644 --- a/.gitignore +++ b/.gitignore @@ -9,4 +9,5 @@ target .DS_Store Cargo.lock test_snapshots -xcall.wasm \ No newline at end of file +xcall.wasm +centralized_connection.wasm \ No newline at end of file diff --git a/contracts/asset_manager/src/admin.rs b/contracts/asset_manager/src/admin.rs index 85f4a52..76b7683 100644 --- a/contracts/asset_manager/src/admin.rs +++ b/contracts/asset_manager/src/admin.rs @@ -1,5 +1,5 @@ use soroban_sdk::{Address, Env}; - +extern crate std; use crate::storage_types::DataKey; pub fn has_administrator(e: &Env) -> bool { diff --git a/contracts/asset_manager/src/config.rs b/contracts/asset_manager/src/config.rs index 99073a9..e924316 100644 --- a/contracts/asset_manager/src/config.rs +++ b/contracts/asset_manager/src/config.rs @@ -7,8 +7,11 @@ pub struct ConfigData { pub xcall: Address, pub xcall_manager: Address, pub native_address: Address, - pub icon_assset_manager: String, - pub xcall_network_address: String + pub icon_asset_manager: String, +} + +pub fn set_config(e: &Env, config: ConfigData){ + e.storage().instance().set(&DataKey::Config, &config); } pub fn get_config(e: &Env) -> ConfigData { diff --git a/contracts/asset_manager/src/contract.rs b/contracts/asset_manager/src/contract.rs index 54749f6..a1dda5b 100644 --- a/contracts/asset_manager/src/contract.rs +++ b/contracts/asset_manager/src/contract.rs @@ -1,18 +1,14 @@ -use soroban_sdk::{contract, contractimpl, token, Address, Bytes, BytesN, Env, String, Vec}; +use soroban_sdk::{contract, contractimpl, token, Address, Bytes, BytesN, Env, String, Vec, panic_with_error}; +extern crate std; mod xcall { - soroban_sdk::contractimport!(file = "xcall.wasm"); + soroban_sdk::contractimport!(file = "../../wasm/xcall.wasm"); } - +use soroban_rlp::messages::{deposit::Deposit, deposit_revert::DepositRevert, withdraw_to::WithdrawTo}; use crate::{ admin::{read_administrator, write_administrator}, - config::{get_config, ConfigData}, - messages::{ - deposit::Deposit, - deposit_revert :: DepositRevert, - withdraw_to::WithdrawTo - }, - states::has_state, + config::{get_config, set_config, ConfigData}, + states:: {has_state, read_u128_state, read_u64_state, write_address_state, write_u128_state, write_u64_state }, storage_types::{DataKey, INSTANCE_BUMP_AMOUNT, INSTANCE_LIFETIME_THRESHOLD, POINTS}, xcall_manager_interface::XcallManagerClient }; @@ -30,15 +26,18 @@ pub struct AssetManager; #[contractimpl] impl AssetManager { - pub fn initialize(env:Env, registry:Address, admin: Address, xcall: Address, - xcall_manager: Address, native_address: Address, icon_asset_manager: String) { + pub fn initialize(env:Env, registry:Address, admin: Address, config: ConfigData) { if has_state(env.clone(), DataKey::Registry) { - panic!("Contract already initialized.") + panic_with_error!(&env, ContractError::ContractAlreadyInitialized) } - let xcall_network_address = String::from_str(&env, "xcall_network_address"); // xcall::Client::new(&env, &xcall).get_network_address(&icon_asset_manager); - env.storage().instance().set(&DataKey::Registry, ®istry); - env.storage().instance().set(&DataKey::Admin, &admin); - Self::configure(env, xcall, xcall_manager, native_address, icon_asset_manager, xcall_network_address ); + + write_address_state(&env, DataKey::Registry, ®istry); + write_administrator(&env, &admin); + Self::configure(env, config); + } + + pub fn get_config(env: Env) -> ConfigData { + get_config(&env) } pub fn set_admin(e: Env, new_admin: Address) { @@ -56,16 +55,13 @@ impl AssetManager { read_administrator(&e) } - pub fn configure(env:Env, xcall: Address, - xcall_manager: Address, native_address: Address, icon_asset_manager: String, xcall_network_address: String){ - let admin = read_administrator(&env.clone()); - admin.require_auth(); + pub fn configure(env:Env, config: ConfigData){ + let admin = read_administrator(&env.clone()); + admin.require_auth(); - let config: ConfigData = ConfigData { xcall: xcall, xcall_manager: xcall_manager, native_address: native_address, icon_assset_manager: icon_asset_manager, xcall_network_address: xcall_network_address }; - env.storage().instance().set(&DataKey::Config, &config); + set_config(&env, config); } - pub fn configure_rate_limit( env: Env, token: Address, @@ -73,71 +69,89 @@ impl AssetManager { percentage: u128, ) { let admin = read_administrator(&env.clone()); - admin.require_auth(); - - if percentage > POINTS {panic!("Percentage should be less than or equal to POINTS"); } - + admin.require_auth(); + if percentage > POINTS { + panic_with_error!(&env, ContractError::PercentageShouldBeLessThanOrEqualToPOINTS); + } let token_client = token::Client::new(&env, &token); let contract_token_balance = token_client.balance(&env.current_contract_address()); - - env.storage().instance().set(&DataKey::Period(token.clone()), &period); - env.storage().instance().set(&DataKey::Percentage(token.clone()), &percentage); - env.storage().instance().set(&DataKey::LastUpdate(token.clone()), &env.ledger().timestamp()); - env.storage().instance().set(&DataKey::CurrentLimit(token.clone()), &(u128::try_from(contract_token_balance).unwrap() * percentage/POINTS)); + write_u128_state(&env, DataKey::Period(token.clone()), &period); + write_u128_state(&env, DataKey::Percentage(token.clone()), &percentage); + write_u64_state(&env, DataKey::LastUpdate(token.clone()), &env.ledger().timestamp()); + write_u128_state(&env, DataKey::CurrentLimit(token.clone()), &((contract_token_balance as u128) * percentage/POINTS)); + } + + pub fn get_rate_limit(env: Env, token: Address ) -> (u128, u128, u128, u128){ + ( + read_u128_state(&env, DataKey::Period(token.clone())), + read_u128_state(&env, DataKey::Percentage(token.clone())), + read_u128_state(&env, DataKey::LastUpdate(token.clone())), + read_u128_state(&env, DataKey::CurrentLimit(token.clone())), + ) } pub fn reset_limit(env: Env, token: Address){ let token_client = token::Client::new(&env, &token); let contract_token_balance = token_client.balance(&env.current_contract_address()); - let percentage: u128 = env.storage().instance().get(&DataKey::Percentage(token.clone())).unwrap(); + let percentage: u128 = read_u128_state(&env, DataKey::Percentage(token.clone())); env.storage().instance().set(&DataKey::CurrentLimit(token.clone()), &(u128::try_from(contract_token_balance).unwrap()*percentage/POINTS)); } - pub fn verify_withdraw(env: Env, token: Address, amount: u128) { - let period: u128 = env.storage().instance().get(&DataKey::Period(token.clone())).unwrap(); - let percentage: u128 = env.storage().instance().get(&DataKey::Percentage(token.clone())).unwrap(); + pub fn get_withdraw_limit(env: Env, token: Address) -> Result { + return Ok(Self::calculate_limit(env, token)?) + } + + pub fn verify_withdraw(env: Env, token: Address, amount: u128) -> Result { + let token_client = token::Client::new(&env, &token); + let balance = token_client.balance(&env.current_contract_address()) as u128; + let limit = Self::calculate_limit(env.clone(), token.clone())?; + if balance - amount < limit { panic_with_error!(&env, ContractError::ExceedsWithdrawLimit); }; + + write_u128_state(&env, DataKey::CurrentLimit(token.clone()), &limit); + write_u64_state(&env, DataKey::LastUpdate(token.clone()), &env.ledger().timestamp()); + Ok(true) + } + + pub fn calculate_limit(env: Env, token: Address) -> Result { + let period: u128 = read_u128_state(&env, DataKey::Period(token.clone())); + let percentage: u128 = read_u128_state(&env, DataKey::Percentage(token.clone())); if period == 0 { - return; + return Ok(0); } let token_client = token::Client::new(&env, &token); - let balance = token_client.balance(&env.current_contract_address()); - let u128_balnace = u128::try_from(balance).unwrap(); + let balance = token_client.balance(&env.current_contract_address()) as u128; - let max_limit = (u128::try_from(balance).unwrap() * percentage) / POINTS; + let max_limit = (balance * percentage) / POINTS; - let max_withdraw = u128_balnace - max_limit; - let last_update: u64 = env.storage().instance().get(&DataKey::LastUpdate(token.clone())).unwrap(); + let max_withdraw = balance - max_limit; + let last_update: u64 = read_u64_state(&env, DataKey::LastUpdate(token.clone())); let time_diff = &env.ledger().timestamp() - last_update; let added_allowed_withdrawal = (max_withdraw * u128::from(time_diff)) / period; - let current_limit: u128 = env.storage().instance().get(&DataKey::CurrentLimit(token.clone())).unwrap(); - let limit = current_limit - added_allowed_withdrawal; + let current_limit: u128 = read_u128_state(&env, DataKey::CurrentLimit(token.clone())); + let limit: u128 = current_limit - added_allowed_withdrawal; - let limit = if u128_balnace < limit { u128_balnace } else { limit }; + let limit = if balance < limit { balance } else { limit }; let final_limit = if limit > max_limit { limit } else { max_limit }; - if u128_balnace - amount < final_limit { panic!("exceeds withdraw limit"); }; - - env.storage().instance().set(&DataKey::CurrentLimit(token.clone()), &final_limit); - env.storage().instance().set(&DataKey::LastUpdate(token.clone()), &env.ledger().timestamp()); + Ok(final_limit) } pub fn deposit( e: Env, from: Address, - value: u128, token: Address, amount: u128, to: Option, data: Option - ) { + ) -> Result<(), ContractError> { let deposit_to = to.unwrap_or(String::from_str(&e, "")); let deposit_data = data.unwrap_or(Bytes::from_array(&e, &[0u8; 32])); - Self::send_deposit_message(e, from, token, amount, deposit_to, deposit_data, value).unwrap(); + Ok(Self::send_deposit_message(e, from, token, amount, deposit_to, deposit_data)?) } pub fn deposit_native( @@ -147,17 +161,16 @@ impl AssetManager { amount: u128, to: Option, data: Option - ) { + ) -> Result<(), ContractError> { if value < amount { - panic!("Amount less than minimum amount"); + panic_with_error!(&e, ContractError::AmountIsLessThanMinimumAmount); } let deposit_to = to.unwrap_or(String::from_str(&e, "")); let deposit_data = data.unwrap_or(Bytes::from_array(&e, &[0u8; 32])); - let fee = value - amount; let native_address = get_config(&e).native_address; - Self::send_deposit_message(e, from, native_address, amount, deposit_to, deposit_data, fee).unwrap(); + Ok(Self::send_deposit_message(e, from, native_address, amount, deposit_to, deposit_data)?) } fn send_deposit_message( @@ -167,10 +180,10 @@ impl AssetManager { amount: u128, to: String, data: Bytes, - fee: u128 ) -> Result<(), ContractError> { + from.require_auth(); let current_address = e.clone().current_contract_address(); - Self::transfer_token_to(e.clone(), from.clone(), token.clone(), current_address.clone(), fee); + Self::transfer_token_to(e.clone(), from.clone(), token.clone(), current_address.clone(), amount); let xcall_message: Deposit = Deposit::new( token.to_string(), @@ -189,15 +202,15 @@ impl AssetManager { let rollback_bytes = rollback.encode(&e, String::from_str(&e.clone(), DEPOSIT_REVERT_NAME)); let message_bytes = xcall_message.encode(&e, String::from_str(&e.clone(), DEPOSIT_NAME)); let (sources, destinations) = Self::xcall_manager(e.clone()).get_protocols(); - let message = AnyMessage::CallMessageWithRollback(CallMessageWithRollback { data: message_bytes, rollback: rollback_bytes }); let envelope: &Envelope = &Envelope { + destinations, message, - sources, - destinations + sources }; - let icon_asset_manager = &get_config(&e).icon_assset_manager; - Self::xcall_client(e).send_call(&from, ¤t_address, envelope, icon_asset_manager ); + let icon_asset_manager = &get_config(&e).icon_asset_manager; + + Self::xcall_client(e).send_call(&from, ¤t_address, envelope, icon_asset_manager); Ok(()) } @@ -216,49 +229,50 @@ impl AssetManager { from: String, data: Bytes, protocols: Vec - ) { + ) -> Result<(), ContractError> { get_config(&e).xcall.require_auth(); - if !Self::xcall_manager(e.clone()).verify_protocols(&protocols) { - panic!("Protocol Mismatch"); + panic_with_error!(&e, ContractError::ProtocolMismatch); }; - - let method = Deposit::get_method(&e, data.clone()).unwrap(); - - let icon_asset_manager = get_config(&e).icon_assset_manager; + let method = Deposit::get_method(&e, data.clone()); + let icon_asset_manager = get_config(&e).icon_asset_manager; let current_contract = e.current_contract_address(); if method == String::from_str(&e, &WITHDRAW_TO_NAME){ if from != icon_asset_manager{ - panic!("onlyICONAssetManager") - } - let message = WithdrawTo::decode(&e, data).unwrap(); - - Self::withdraw(e, current_contract, Address::from_string(&message.token_address), Address::from_string(&message.to), message.amount); + panic_with_error!(&e, ContractError::OnlyICONAssetManager); + }; + let message = WithdrawTo::decode(&e, data); + Self::withdraw(e, current_contract, Address::from_string(&message.token_address), Address::from_string(&message.to), message.amount)?; } else if method == String::from_str(&e, &DEPOSIT_REVERT_NAME){ let xcall_network_address = Self::xcall_client(e.clone()).get_network_address(); if from != xcall_network_address { - panic!("onlyCallService") + panic_with_error!(&e, ContractError::OnlyCallService) }; - let message: DepositRevert = DepositRevert::decode(&e.clone(), data).unwrap(); - Self::withdraw(e, current_contract, message.token_address, message.to, message.amount); + let message: DepositRevert = DepositRevert::decode(&e.clone(), data); + Self::withdraw(e, current_contract, message.token_address, message.to, message.amount)?; } else { - panic!("Unknown message type"); + panic_with_error!(&e, ContractError::UnknownMessageType); } + Ok(()) } - pub fn withdraw(e: Env, from: Address, token: Address, to: Address, amount: u128) { + pub fn withdraw(e: Env, from: Address, token: Address, to: Address, amount: u128) -> Result<(), ContractError> { if amount <= 0 { - panic!("Amount less than minimum amount"); + panic_with_error!(&e, ContractError::AmountIsLessThanMinimumAmount); } - - Self::verify_withdraw(e.clone(), token.clone(), amount); - Self::transfer_token_to(e, from, token, to, amount); + std::println!("before verify"); + let verified = Self::verify_withdraw(e.clone(), token.clone(), amount)?; + if verified { + std::println!("before transfer"); + Self::transfer_token_to(e, from, token, to, amount); + } + Ok(()) } fn transfer_token_to(e: Env, from: Address, token: Address, to: Address, amount: u128){ let token_client = token::Client::new(&e, &token); - token_client.transfer_from(&from, &from, &to, &i128::try_from(amount).unwrap()); + token_client.transfer(&from, &to, &(amount as i128)); } pub fn balance_of(e: Env, token: Address) -> i128 { diff --git a/contracts/asset_manager/src/errors.rs b/contracts/asset_manager/src/errors.rs index 8194dcf..17f7d69 100644 --- a/contracts/asset_manager/src/errors.rs +++ b/contracts/asset_manager/src/errors.rs @@ -5,5 +5,14 @@ use soroban_sdk::contracterror; #[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord)] pub enum ContractError { InvalidRlpLength = 1, - InvalidRollbackMessage = 2 + InvalidRollbackMessage = 2, + ContractAlreadyInitialized = 3, + PercentageShouldBeLessThanOrEqualToPOINTS = 4, + ExceedsWithdrawLimit = 5, + AmountIsLessThanMinimumAmount = 6, + ProtocolMismatch = 7, + OnlyICONAssetManager = 8, + OnlyCallService = 9, + UnknownMessageType = 10 + } \ No newline at end of file diff --git a/contracts/asset_manager/src/lib.rs b/contracts/asset_manager/src/lib.rs index 0f1d39c..3ff002c 100644 --- a/contracts/asset_manager/src/lib.rs +++ b/contracts/asset_manager/src/lib.rs @@ -3,11 +3,8 @@ pub mod admin; pub mod contract; pub mod storage_types; -mod test; +pub mod tests; pub mod states; mod config; mod errors; -mod messages; -mod xcall_manager_interface; - -pub use crate::contract::AssetManagerClient; \ No newline at end of file +mod xcall_manager_interface; \ No newline at end of file diff --git a/contracts/asset_manager/src/messages/mod.rs b/contracts/asset_manager/src/messages/mod.rs deleted file mode 100644 index 55836d2..0000000 --- a/contracts/asset_manager/src/messages/mod.rs +++ /dev/null @@ -1,3 +0,0 @@ -pub mod deposit_revert; -pub mod deposit; -pub mod withdraw_to; diff --git a/contracts/asset_manager/src/states.rs b/contracts/asset_manager/src/states.rs index 49faea1..f879bb3 100644 --- a/contracts/asset_manager/src/states.rs +++ b/contracts/asset_manager/src/states.rs @@ -18,7 +18,7 @@ pub fn write_u64_state(e: &Env, key: DataKey, id: &u64) { e.storage().instance().set(&key, id); } -pub fn write_i128_state(e: &Env, key: DataKey, id: &i128) { +pub fn write_u128_state(e: &Env, key: DataKey, id: &u128) { e.storage().instance().set(&key, id); } @@ -42,6 +42,10 @@ pub fn read_i128_state(e: &Env, key: DataKey) -> i128 { e.storage().instance().get(&key).unwrap() } +pub fn read_u128_state(e: &Env, key: DataKey) -> u128 { + e.storage().instance().get(&key).unwrap() +} + pub fn read_vec_string_state(e: &Env, key: DataKey) -> Vec { e.storage().instance().get(&key).unwrap() } \ No newline at end of file diff --git a/contracts/asset_manager/src/storage_types.rs b/contracts/asset_manager/src/storage_types.rs index 4f8924f..1a89e28 100644 --- a/contracts/asset_manager/src/storage_types.rs +++ b/contracts/asset_manager/src/storage_types.rs @@ -4,8 +4,8 @@ pub(crate) const DAY_IN_LEDGERS: u32 = 17280; pub(crate) const INSTANCE_BUMP_AMOUNT: u32 = 7 * DAY_IN_LEDGERS; pub(crate) const INSTANCE_LIFETIME_THRESHOLD: u32 = INSTANCE_BUMP_AMOUNT - DAY_IN_LEDGERS; -pub(crate) const BALANCE_BUMP_AMOUNT: u32 = 30 * DAY_IN_LEDGERS; -pub(crate) const BALANCE_LIFETIME_THRESHOLD: u32 = BALANCE_BUMP_AMOUNT - DAY_IN_LEDGERS; +//pub(crate) const BALANCE_BUMP_AMOUNT: u32 = 30 * DAY_IN_LEDGERS; +//pub(crate) const BALANCE_LIFETIME_THRESHOLD: u32 = BALANCE_BUMP_AMOUNT - DAY_IN_LEDGERS; pub(crate) const POINTS: u128 = 1000; diff --git a/contracts/asset_manager/src/test.rs b/contracts/asset_manager/src/test.rs deleted file mode 100644 index 36775f0..0000000 --- a/contracts/asset_manager/src/test.rs +++ /dev/null @@ -1,77 +0,0 @@ -#![cfg(test)] - -extern crate std; - -use crate::contract::{ - AssetManager, AssetManagerClient//, xcall_manager -}; - -use crate::storage_types::{DataKey, POINTS}; - -use soroban_sdk::{ - symbol_short, - testutils::{Address as _, AuthorizedFunction, AuthorizedInvocation, Events}, - token, vec, Address, Bytes, Env, IntoVal, String, Symbol, -}; - -pub struct TestContext { - env: Env, - registry:Address, - admin: Address, - xcall: Address, - xcall_manager: Address, - native_address: Address, - icon_asset_manager: String, - xcall_network_address: String -} - -pub struct TokenRateLimit { - token: Address, - period: i128, - percentage: i128 -} - -impl TestContext { - // pub fn default() -> Self { - // let env = Env::default(); - // let token_admin = Address::generate(&env); - // Self { - // registry: env.register_contract(None, AssetManager), - // admin: Address::generate(&env), - // xcall: Address::generate(&env), - // xcall_manager: env.register_contract_wasm(None, xcall_manager::WASM), - // native_address: env.register_stellar_asset_contract(token_admin.clone()), - // icon_asset_manager: String::from_str(&env, "icon01:hxjnfh4u"), - // xcall_network_address: String::from_str(&env, "ST001"), - // env - // } - // } - - // pub fn init_context(&self, client: &AssetManagerClient<'static>) { - // self.env.mock_all_auths(); - // client.initialize(&self.registry, &self.admin, &self.xcall, &self.xcall_manager, &self.native_address, &self.icon_asset_manager ); - // } -} - -// #[test] -// fn test_initialize() { -// let ctx = TestContext::default(); -// let client = AssetManagerClient::new(&ctx.env, &ctx.registry); - -// ctx.init_context(&client); - -// let registry_exists = client.has_registry(); -// assert_eq!(registry_exists, true) -// } - -// #[test] -// fn test_set_admin() { -// let ctx = TestContext::default(); -// let client = AssetManagerClient::new(&ctx.env, &ctx.registry); -// ctx.init_context(&client); - -// let new_admin: Address = Address::generate(&ctx.env); -// client.set_admin(&new_admin); - -// assert_eq!(client.get_admin(), new_admin) -// } \ No newline at end of file diff --git a/contracts/asset_manager/src/tests/asset_manager_test.rs b/contracts/asset_manager/src/tests/asset_manager_test.rs new file mode 100644 index 0000000..4ec1e06 --- /dev/null +++ b/contracts/asset_manager/src/tests/asset_manager_test.rs @@ -0,0 +1,181 @@ +#![cfg(test)] +extern crate std; + + +use soroban_sdk::{ + testutils::Address as _, + token, Address, Bytes, String, Vec +}; +use crate::contract::AssetManagerClient; + +use soroban_rlp::messages::{deposit_revert:: DepositRevert, withdraw_to:: WithdrawTo}; + +use super::setup::*; + +#[test] +fn test_initialize() { + let ctx = TestContext::default(); + let client = AssetManagerClient::new(&ctx.env, &ctx.registry); + + ctx.init_context(&client); + + let registry_exists = client.has_registry(); + assert_eq!(registry_exists, true) +} + +#[test] +fn test_set_admin() { + let ctx = TestContext::default(); + let client = AssetManagerClient::new(&ctx.env, &ctx.registry); + ctx.init_context(&client); + + let new_admin: Address = Address::generate(&ctx.env); + client.set_admin(&new_admin); + + assert_eq!(client.get_admin(), new_admin) +} + +#[test] +fn test_configure_rate_limit() { + let ctx = TestContext::default(); + let client = AssetManagerClient::new(&ctx.env, &ctx.registry); + ctx.init_context(&client); + + client.configure_rate_limit( &ctx.token, &300, &300 ); + + let limit = client.get_withdraw_limit(&ctx.token); + let verified = client.verify_withdraw(&ctx.token, &limit); + assert_eq!(verified, true); +} + +#[test] +fn test_deposit_without_to_and_data(){ + let ctx = TestContext::default(); + let client = AssetManagerClient::new(&ctx.env, &ctx.registry); + ctx.init_context(&client); + + client.configure_rate_limit( &ctx.token, &300, &300 ); + let token_client = token::Client::new(&ctx.env, &ctx.token); + let stellar_asset_client: token::StellarAssetClient = token::StellarAssetClient::new(&ctx.env, &ctx.token); + let amount_i128: i128 = 100000 ; + let amount = &(amount_i128 as u128); + let mint_amount = &(amount_i128+amount_i128); + + stellar_asset_client.mint(&ctx.depositor, mint_amount); + + ctx.mint_native_token(&ctx.depositor, 500); + assert_eq!(ctx.get_native_token_balance(&ctx.depositor), 500); + + token_client.approve(&ctx.depositor, &ctx.registry, &(amount_i128+amount_i128), &1312000); + client.deposit(&ctx.depositor, &ctx.token, &amount, &Option::Some(String::from_str(&ctx.env, "")), &Option::Some(Bytes::from_array(&ctx.env, &[0u8; 32]))); + + assert_eq!(ctx.get_native_token_balance(&ctx.depositor), 400) // why 300? +} + +#[test] +fn test_deposit_with_to_and_without_data(){ + let ctx = TestContext::default(); + let client = AssetManagerClient::new(&ctx.env, &ctx.registry); + ctx.init_context(&client); + + client.configure_rate_limit( &ctx.token, &300, &300 ); + let token_client = token::Client::new(&ctx.env, &ctx.token); + let stellar_asset_client: token::StellarAssetClient = token::StellarAssetClient::new(&ctx.env, &ctx.token); + let amount_i128: i128 = 100000 ; + let amount = &(amount_i128 as u128); + let mint_amount = &(amount_i128+amount_i128); + + stellar_asset_client.mint(&ctx.depositor, mint_amount); + + ctx.mint_native_token(&ctx.depositor, 500); + assert_eq!(ctx.get_native_token_balance(&ctx.depositor), 500); + + token_client.approve(&ctx.depositor, &ctx.registry, &(amount_i128+amount_i128), &1312000); + client.deposit(&ctx.depositor, &ctx.token, &amount, &Option::Some(String::from_str(&ctx.env, "icon01/hxjkdvhui")), &Option::Some(Bytes::from_array(&ctx.env, &[0u8; 32]))); + + assert_eq!(ctx.get_native_token_balance(&ctx.depositor), 400) // why 300? +} + +#[test] +fn test_deposit_with_to_and_data(){ + let ctx = TestContext::default(); + let client = AssetManagerClient::new(&ctx.env, &ctx.registry); + ctx.init_context(&client); + + client.configure_rate_limit( &ctx.token, &300, &300 ); + let token_client = token::Client::new(&ctx.env, &ctx.token); + let stellar_asset_client: token::StellarAssetClient = token::StellarAssetClient::new(&ctx.env, &ctx.token); + let amount_i128: i128 = 100000 ; + let amount = &(amount_i128 as u128); + let mint_amount = &(amount_i128+amount_i128); + + stellar_asset_client.mint(&ctx.depositor, mint_amount); + + ctx.mint_native_token(&ctx.depositor, 500); + assert_eq!(ctx.get_native_token_balance(&ctx.depositor), 500); + + token_client.approve(&ctx.depositor, &ctx.registry, &(amount_i128+amount_i128), &1312000); + + let data: [u8; 32] = [ + 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, + 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0x10, + 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, + 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F, 0x20, + ]; + client.deposit(&ctx.depositor, &ctx.token, &amount, &Option::Some(String::from_str(&ctx.env, "icon01/hxjkdvhui")), &Option::Some(Bytes::from_array(&ctx.env, &data))); + + assert_eq!(ctx.get_native_token_balance(&ctx.depositor), 400) // why 300? +} + + +#[test] +fn test_handle_call_message_for_withdraw_to(){ + let ctx = TestContext::default(); + let client = AssetManagerClient::new(&ctx.env, &ctx.registry); + ctx.env.mock_all_auths(); + + ctx.init_context(&client); + client.configure_rate_limit( &ctx.token, &300, &300 ); + + let bnusd_amount = 100000 as u128; + let token_client = token::Client::new(&ctx.env, &ctx.token); + let stellar_asset_client: token::StellarAssetClient = token::StellarAssetClient::new(&ctx.env, &ctx.token); + stellar_asset_client.mint(&ctx.registry, &((bnusd_amount*2) as i128)); + + let data = WithdrawTo::new(ctx.token.to_string(), ctx.withdrawer.to_string(), bnusd_amount).encode(&ctx.env, String::from_str(&ctx.env, "WithdrawTo")); + let decoded = WithdrawTo::decode(&ctx.env, data.clone()); + assert_eq!(decoded.to, ctx.withdrawer.to_string()); + + assert_eq!(token_client.balance(&ctx.withdrawer), 0); + + let sources = Vec::from_array(&ctx.env, [ctx.centralized_connection.to_string()]); + client.handle_call_message(&ctx.xcall, &ctx.icon_asset_manager, &data, &sources); + + assert_eq!(token_client.balance(&ctx.withdrawer), bnusd_amount as i128) +} + +#[test] +fn test_handle_call_message_for_deposit_rollback(){ + let ctx = TestContext::default(); + let client = AssetManagerClient::new(&ctx.env, &ctx.registry); + ctx.env.mock_all_auths(); + + ctx.init_context(&client); + client.configure_rate_limit( &ctx.token, &300, &300 ); + + let bnusd_amount = 100000 as u128; + let token_client = token::Client::new(&ctx.env, &ctx.token); + let stellar_asset_client: token::StellarAssetClient = token::StellarAssetClient::new(&ctx.env, &ctx.token); + stellar_asset_client.mint(&ctx.registry, &((bnusd_amount*2) as i128)); + + let data = DepositRevert::new(ctx.token, ctx.withdrawer.clone(), bnusd_amount).encode(&ctx.env, String::from_str(&ctx.env, "DepositRevert")); + let decoded = DepositRevert::decode(&ctx.env, data.clone()); + assert_eq!(decoded.to, ctx.withdrawer); + + assert_eq!(token_client.balance(&ctx.withdrawer), 0); + + let sources = Vec::from_array(&ctx.env, [ctx.centralized_connection.to_string()]); + client.handle_call_message(&ctx.xcall, &ctx.xcall_client.get_network_address(), &data, &sources); + + assert_eq!(token_client.balance(&ctx.withdrawer), bnusd_amount as i128) +} \ No newline at end of file diff --git a/contracts/asset_manager/src/tests/mod.rs b/contracts/asset_manager/src/tests/mod.rs new file mode 100644 index 0000000..06a7192 --- /dev/null +++ b/contracts/asset_manager/src/tests/mod.rs @@ -0,0 +1,2 @@ +pub mod setup; +pub mod asset_manager_test; \ No newline at end of file diff --git a/contracts/asset_manager/src/tests/setup.rs b/contracts/asset_manager/src/tests/setup.rs new file mode 100644 index 0000000..41308f4 --- /dev/null +++ b/contracts/asset_manager/src/tests/setup.rs @@ -0,0 +1,129 @@ +#![cfg(test)] +extern crate std; + +use crate::contract::{ + AssetManager, AssetManagerClient +}; + +use crate::config::ConfigData; + +use soroban_sdk::Vec; +use soroban_sdk::{ + testutils::Address as _, + token, Address, Env, String, +}; + +mod xcall { + soroban_sdk::contractimport!(file = "../../wasm/xcall.wasm" ); +} + +mod connection { + soroban_sdk::contractimport!(file = "../../wasm/centralized_connection.wasm"); +} + +mod xcall_manager { + soroban_sdk::contractimport!(file = "../../target/wasm32-unknown-unknown/release/xcall_manager.wasm" ); +} + +use xcall_manager::ConfigData as XcallManagerConfigData; + +pub struct TestContext { + pub env: Env, + pub registry:Address, + pub admin: Address, + pub depositor: Address, + pub withdrawer: Address, + pub xcall: Address, + pub xcall_manager: Address, + pub icon_asset_manager: String, + pub icon_governance: String, + pub token: Address, + pub centralized_connection: Address, + pub nid: String, + pub native_token: Address, + pub xcall_client: xcall::Client<'static> +} + +impl TestContext { + pub fn default() -> Self { + let env = Env::default(); + let token_admin = Address::generate(&env); + let token = env.register_stellar_asset_contract(token_admin.clone()); + let asset_manager = env.register_contract(None, AssetManager); + let centralized_connection = env.register_contract_wasm(None, connection::WASM); + let xcall_manager = env.register_contract_wasm(None, xcall_manager::WASM); + let xcall = env.register_contract_wasm(None, xcall::WASM); + + Self { + registry: asset_manager, + admin: Address::generate(&env), + depositor: Address::generate(&env), + withdrawer: Address::generate(&env), + xcall: xcall.clone(), + xcall_manager: xcall_manager, + icon_asset_manager: String::from_str(&env, "icon01/hxjnfh4u"), + icon_governance: String::from_str(&env, "icon01/kjdnoi"), + token: token, + centralized_connection: centralized_connection, + nid: String::from_str(&env, "stellar"), + native_token: env.register_stellar_asset_contract(token_admin.clone()), + xcall_client: xcall::Client::new(&env, &xcall), + env + } + } + + pub fn init_context(&self, client: &AssetManagerClient<'static>) { + self.env.mock_all_auths(); + let config = ConfigData {xcall: self.xcall.clone(), xcall_manager: self.xcall_manager.clone(), native_address: self.native_token.clone(), icon_asset_manager: self.icon_asset_manager.clone()}; + client.initialize(&self.registry, &self.admin, &config); + self.init_xcall_manager_context(); + self.init_xcall_state(); + } + + pub fn init_xcall_manager_context(&self) { + let client = self::xcall_manager::Client::new(&self.env, &self.xcall_manager); + let config = XcallManagerConfigData {xcall: self.xcall.clone(), icon_governance: self.icon_governance.clone()}; + let sources = Vec::from_array(&self.env, [self.centralized_connection.to_string()]); + let destinations = Vec::from_array(&self.env, [String::from_str(&self.env, "icon/address")]); + client.initialize(&self.xcall_manager, &self.admin, &config, &sources, &destinations); + } + + pub fn init_xcall_state(&self){ + self.xcall_client.initialize(&xcall::InitializeMsg { + sender: self.admin.clone(), + network_id: self.nid.clone(), + native_token: self.native_token.clone(), + }); + + self.init_connection_state(); + self.xcall_client.set_protocol_fee(&100); + self.xcall_client.set_default_connection(&self.nid, &self.centralized_connection); + } + + pub fn init_connection_state(&self) { + let connection_client = connection::Client::new(&self.env, &self.centralized_connection); + + let initialize_msg = connection::InitializeMsg { + native_token: self.native_token.clone(), + relayer: self.admin.clone(), + xcall_address: self.xcall.clone(), + }; + connection_client.initialize(&initialize_msg); + + let message_fee = 100; + let response_fee = 100; + connection_client.set_fee(&self.nid, &message_fee, &response_fee); + } + + pub fn mint_native_token(&self, address: &Address, amount: u128) { + let native_token_client = token::StellarAssetClient::new(&self.env, &self.native_token); + native_token_client.mint(&address, &(*&amount as i128)); + } + + pub fn get_native_token_balance(&self, address: &Address) -> u128 { + let native_token_client = token::TokenClient::new(&self.env, &self.native_token); + let balance = native_token_client.balance(address); + + *&balance as u128 + } +} diff --git a/contracts/balanced_doller/src/balanced_dollar.rs b/contracts/balanced_doller/src/balanced_dollar.rs index 8291f42..d2aad51 100644 --- a/contracts/balanced_doller/src/balanced_dollar.rs +++ b/contracts/balanced_doller/src/balanced_dollar.rs @@ -1,11 +1,12 @@ -use soroban_sdk::{token::TokenInterface, Address, Bytes, Env, String, Vec}; - +use soroban_sdk::{Address, Bytes, Env, String, Vec}; mod xcall { - soroban_sdk::contractimport!(file = "xcall.wasm"); + soroban_sdk::contractimport!(file = "../../wasm/xcall.wasm"); } +use soroban_rlp::messages::{cross_transfer::CrossTransfer, cross_transfer_revert::CrossTransferRevert}; + use crate::{ - admin::read_administrator, config::{get_config, ConfigData}, contract::BalancedDollar, messages::{cross_transfer::CrossTransfer, cross_transfer_revert::CrossTransferRevert}, storage_types::DataKey, xcall_manager_interface::XcallManagerClient + config::{ get_config, set_config, ConfigData}, contract::BalancedDollar, xcall_manager_interface::XcallManagerClient }; use crate::errors::ContractError; @@ -17,60 +18,29 @@ const CROSS_TRANSFER_REVERT: &str = "xCrossTransferRevert"; impl BalancedDollar { - pub fn configure(env:Env, xcall: Address, - xcall_manager: Address, nid: String, icon_bn_usd: String, xcall_network_address: String){ - let admin = read_administrator(&env.clone()); - admin.require_auth(); - - let config: ConfigData = ConfigData{ xcall: xcall, xcall_manager: xcall_manager, icon_bn_usd: icon_bn_usd, nid: nid, xcall_network_address: xcall_network_address }; - env.storage().instance().set(&DataKey::Config, &config); - } - - pub fn cross_transfer( - e: Env, - from: Address, - amount: u128, - to: String, - value: u128 - ) { - from.require_auth(); - Self::_cross_transfer(e.clone(), from, amount, to, value, Bytes::new(&e)).unwrap(); - } - - pub fn cross_transfer_data( - e: Env, - from: Address, - amount: u128, - to: String, - value: u128, - data: Bytes - ) { - from.require_auth(); - Self::_cross_transfer(e, from, amount, to, value, data).unwrap(); + pub fn configure(env:Env, config: ConfigData){ + set_config(&env, config); } - fn _cross_transfer( + pub fn _cross_transfer( e: Env, from: Address, amount: u128, to: String, - value: u128, data: Bytes ) -> Result<(), ContractError> { - if value == 0 { - panic!("Amount less than minimum amount"); - } - Self::burn(e.clone(), from.clone(), u128::try_into(amount).unwrap()); + //todo:: fix and uncomment the below line + //Self::burn(e.clone(), from.clone(), amount as i128); let xcall_message = CrossTransfer::new( from.clone().to_string(), to, - value, + amount, data ); let rollback = CrossTransferRevert::new( from.clone(), - value + amount ); let rollback_bytes = rollback.encode(&e, String::from_str(&e.clone(), CROSS_TRANSFER_REVERT)); @@ -91,7 +61,7 @@ impl BalancedDollar { } - pub fn handle_call_message( + pub fn _handle_call_message( e: Env, from: String, data: Bytes, @@ -103,19 +73,19 @@ impl BalancedDollar { panic!("Protocol Mismatch"); }; - let method = CrossTransfer::get_method(&e, data.clone()).unwrap(); + let method = CrossTransfer::get_method(&e, data.clone()); let icon_bn_usd = get_config(&e).icon_bn_usd; if method == String::from_str(&e, &CROSS_TRANSFER){ if from!=icon_bn_usd { panic!("onlyICONBnUSD"); } - let message = CrossTransfer::decode(&e.clone(), data).unwrap(); + let message = CrossTransfer::decode(&e.clone(), data); Self::mint(e.clone(), Address::from_string( &message.to), u128::try_into(message.amount).unwrap()); } else if method == String::from_str(&e, &CROSS_TRANSFER_REVERT){ if from!=xcall.to_string() { panic!("onlyCallService"); } - let message = CrossTransferRevert::decode(&e.clone(), data).unwrap(); + let message = CrossTransferRevert::decode(&e.clone(), data); Self::mint(e.clone(), message.to, u128::try_into(message.amount).unwrap()); }else{ panic!("Unknown message type") @@ -130,5 +100,4 @@ impl BalancedDollar { let client = XcallManagerClient::new(&e, &get_config(&e).xcall_manager); return client; } - } \ No newline at end of file diff --git a/contracts/balanced_doller/src/config.rs b/contracts/balanced_doller/src/config.rs index 59c24d1..9d9c36e 100644 --- a/contracts/balanced_doller/src/config.rs +++ b/contracts/balanced_doller/src/config.rs @@ -8,7 +8,10 @@ pub struct ConfigData { pub xcall_manager: Address, pub nid: String, pub icon_bn_usd: String, - pub xcall_network_address: String +} + +pub fn set_config(e: &Env, config: ConfigData){ + e.storage().instance().set(&DataKey::Config, &config); } pub fn get_config(e: &Env) -> ConfigData { diff --git a/contracts/balanced_doller/src/contract.rs b/contracts/balanced_doller/src/contract.rs index f54bd9f..4f4d987 100644 --- a/contracts/balanced_doller/src/contract.rs +++ b/contracts/balanced_doller/src/contract.rs @@ -3,13 +3,13 @@ use crate::admin::{has_administrator, read_administrator, write_administrator}; use crate::allowance::{read_allowance, spend_allowance, write_allowance}; use crate::balance::{read_balance, receive_balance, spend_balance}; +use crate::config::ConfigData; use crate::metadata::{read_decimal, read_name, read_symbol, write_metadata}; use crate::storage_types::{INSTANCE_BUMP_AMOUNT, INSTANCE_LIFETIME_THRESHOLD}; use soroban_sdk::token::{self, Interface as _}; -use soroban_sdk::{contract, contractimpl, Address, Env, String}; +use soroban_sdk::{contract, contractimpl, Address, Env, String, Bytes, Vec}; use soroban_token_sdk::metadata::TokenMetadata; use soroban_token_sdk::TokenUtils; - fn check_nonnegative_amount(amount: i128) { if amount < 0 { panic!("negative amount is not allowed: {}", amount) @@ -21,13 +21,12 @@ pub struct BalancedDollar; #[contractimpl] impl BalancedDollar { - pub fn initialize(e: Env, admin: Address, xcall: Address, - xcall_manager: Address, xcall_network_address: String, icon_bn_usd: String, nid: String) { + pub fn initialize(e: Env, admin: Address, config: ConfigData) { if has_administrator(&e) { panic!("already initialized") } - write_administrator(&e, &admin); + //initialize token properties let decimal = 18; let name = String::from_str(&e, "Balanced Dollar"); @@ -45,14 +44,13 @@ impl BalancedDollar { symbol, }, ); - - Self::configure(e, xcall, xcall_manager, xcall_network_address, icon_bn_usd, nid ); + Self::configure(e, config ); } pub fn mint(e: Env, to: Address, amount: i128) { check_nonnegative_amount(amount); let admin = read_administrator(&e); - admin.require_auth(); + //admin.require_auth(); e.storage() .instance() @@ -73,6 +71,40 @@ impl BalancedDollar { write_administrator(&e, &new_admin); TokenUtils::new(&e).events().set_admin(admin, new_admin); } + + pub fn cross_transfer( + e: Env, + from: Address, + amount: u128, + to: String, + ) { + from.require_auth(); + Self::_cross_transfer(e.clone(), from, amount, to, Bytes::new(&e)).unwrap(); + } + + pub fn cross_transfer_data( + e: Env, + from: Address, + amount: u128, + to: String, + data: Bytes + ) { + from.require_auth(); + Self::_cross_transfer(e, from, amount, to, data).unwrap(); + } + + pub fn handle_call_message( + e: Env, + from: String, + data: Bytes, + protocols: Vec + ) { + Self::_handle_call_message(e, from, data, protocols); + } + + pub fn is_initialized(e: Env) -> Address { + read_administrator(&e) + } } #[contractimpl] @@ -173,4 +205,7 @@ impl token::Interface for BalancedDollar { fn symbol(e: Env) -> String { read_symbol(&e) } + + + } \ No newline at end of file diff --git a/contracts/balanced_doller/src/lib.rs b/contracts/balanced_doller/src/lib.rs index 33eac5a..e07af08 100644 --- a/contracts/balanced_doller/src/lib.rs +++ b/contracts/balanced_doller/src/lib.rs @@ -4,14 +4,11 @@ mod admin; mod allowance; mod balance; pub mod contract; -//mod balanced_dollar; mod metadata; mod storage_types; -mod test; +mod states; +mod tests; mod config; pub mod balanced_dollar; -mod messages; mod errors; -mod xcall_manager_interface; - -pub use crate::contract::BalancedDollarClient; \ No newline at end of file +mod xcall_manager_interface; \ No newline at end of file diff --git a/contracts/balanced_doller/src/messages/mod.rs b/contracts/balanced_doller/src/messages/mod.rs deleted file mode 100644 index 746aec8..0000000 --- a/contracts/balanced_doller/src/messages/mod.rs +++ /dev/null @@ -1,2 +0,0 @@ -pub mod cross_transfer_revert; -pub mod cross_transfer; \ No newline at end of file diff --git a/contracts/balanced_doller/src/states.rs b/contracts/balanced_doller/src/states.rs new file mode 100644 index 0000000..f879bb3 --- /dev/null +++ b/contracts/balanced_doller/src/states.rs @@ -0,0 +1,51 @@ +use soroban_sdk::{Address, Env, String, Vec}; + +use crate::storage_types::DataKey; + +pub fn has_state(env:Env, key: DataKey) -> bool { + env.storage().instance().has(&key) +} + +pub fn write_string_state(e: &Env, key: DataKey, id: &String) { + e.storage().instance().set(&key, id); +} + +pub fn write_address_state(e: &Env, key: DataKey, id: &Address) { + e.storage().instance().set(&key, id); +} + +pub fn write_u64_state(e: &Env, key: DataKey, id: &u64) { + e.storage().instance().set(&key, id); +} + +pub fn write_u128_state(e: &Env, key: DataKey, id: &u128) { + e.storage().instance().set(&key, id); +} + +pub fn write_vec_string_state(e: &Env, key: DataKey, id: &Vec) { + e.storage().instance().set(&key, id); +} + +pub fn read_string_state(e: &Env, key: DataKey) -> String { + e.storage().instance().get(&key).unwrap() +} + +pub fn read_address_state(e: &Env, key: DataKey) -> Address { + e.storage().instance().get(&key).unwrap() +} + +pub fn read_u64_state(e: &Env, key: DataKey) -> u64 { + e.storage().instance().get(&key).unwrap() +} + +pub fn read_i128_state(e: &Env, key: DataKey) -> i128 { + e.storage().instance().get(&key).unwrap() +} + +pub fn read_u128_state(e: &Env, key: DataKey) -> u128 { + e.storage().instance().get(&key).unwrap() +} + +pub fn read_vec_string_state(e: &Env, key: DataKey) -> Vec { + e.storage().instance().get(&key).unwrap() +} \ No newline at end of file diff --git a/contracts/balanced_doller/src/test.rs b/contracts/balanced_doller/src/test.rs index f3f5eb5..108f22f 100644 --- a/contracts/balanced_doller/src/test.rs +++ b/contracts/balanced_doller/src/test.rs @@ -236,33 +236,20 @@ fn transfer_from_insufficient_allowance() { token.transfer_from(&user3, &user1, &user2, &101); } -// #[test] -// #[should_panic(expected = "already initialized")] -// fn initialize_already_initialized() { -// let e = Env::default(); -// let admin = Address::generate(&e); -// let token = create_token(&e, &admin); - -// let xcall = Address::generate(&e.clone()); -// let xcall_manager = Address::generate(&e.clone()); -// let xcall_network_address = String::from_str(&e.clone(), "ste/address"); -// let icon_bn_usd = String::from_str(&e.clone(), "icon/hxeoriweo"); -// let nid = String::from_str(&e.clone(), "ste"); - -// token.initialize(&admin, &xcall, &xcall_manager, &xcall_network_address, &icon_bn_usd, &nid); -// } - -// #[test] -// #[should_panic(expected = "Decimal must fit in a u8")] -// fn decimal_is_over_max() { -// let e = Env::default(); -// let admin = Address::generate(&e); -// let token = BalancedDollarClient::new(&e, &e.register_contract(None, BalancedDollar {})); -// let xcall = Address::generate(&e.clone()); -// let xcall_manager = Address::generate(&e.clone()); -// let xcall_network_address = String::from_str(&e.clone(), "ste/address"); -// let icon_bn_usd = String::from_str(&e.clone(), "icon/hxeoriweo"); -// let nid = String::from_str(&e.clone(), "ste"); - -// token.initialize(&admin, &xcall, &xcall_manager, &xcall_network_address, &icon_bn_usd, &nid); -// } \ No newline at end of file +#[test] +#[should_panic(expected = "already initialized")] +fn initialize_already_initialized() { + let e = Env::default(); + let admin = Address::generate(&e); + let token = create_token(&e, &admin); + + let xcall = Address::generate(&e.clone()); + let xcall_manager = Address::generate(&e.clone()); + let xcall_network_address = String::from_str(&e.clone(), "ste/address"); + let icon_bn_usd = String::from_str(&e.clone(), "icon/hxeoriweo"); + let nid = String::from_str(&e.clone(), "ste"); + + token.initialize(&admin, &xcall, &xcall_manager, &xcall_network_address, &icon_bn_usd, &nid); + + token.initialize(&admin, &xcall, &xcall_manager, &xcall_network_address, &icon_bn_usd, &nid); +} \ No newline at end of file diff --git a/contracts/balanced_doller/src/tests/balanced_dollar_test.rs b/contracts/balanced_doller/src/tests/balanced_dollar_test.rs new file mode 100644 index 0000000..210dfc2 --- /dev/null +++ b/contracts/balanced_doller/src/tests/balanced_dollar_test.rs @@ -0,0 +1,101 @@ +#![cfg(test)] +extern crate std; + +use crate::contract::BalancedDollarClient; + +use soroban_rlp::messages::{cross_transfer::CrossTransfer, cross_transfer_revert::CrossTransferRevert}; +use soroban_sdk::{ + token, Bytes, String, Vec +}; +use super::setup::*; + +#[test] +fn test_initialize() { + let ctx = TestContext::default(); + let client = BalancedDollarClient::new(&ctx.env, &ctx.registry); + + ctx.init_context(&client); + + let registry_exists = client.is_initialized(); + assert_eq!(registry_exists, ctx.admin) +} + + +#[test] +fn test_cross_transfer_with_to_and_data(){ + let ctx = TestContext::default(); + let client = BalancedDollarClient::new(&ctx.env, &ctx.registry); + ctx.init_context(&client); + + let amount_i128: i128 = 100000 ; + let amount = &(amount_i128 as u128); + let mint_amount = &(amount_i128+amount_i128); + + client.mint(&ctx.depositor, mint_amount); + + ctx.mint_native_token(&ctx.depositor, 500); + assert_eq!(ctx.get_native_token_balance(&ctx.depositor), 500); + + client.approve(&ctx.depositor, &ctx.registry, &(amount_i128+amount_i128), &1312000); + let data: [u8; 32] = [ + 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, + 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0x10, + 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, + 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F, 0x20, + ]; + client.cross_transfer_data(&ctx.depositor, &amount, &String::from_str(&ctx.env, "icon01/hxjkdvhui"), &Bytes::from_array(&ctx.env, &data)); + std::println!("call"); + assert_eq!(ctx.get_native_token_balance(&ctx.depositor), 400) // why 300? +} + + +#[test] +fn test_handle_call_message_for_cross_transfer(){ + let ctx = TestContext::default(); + let client = BalancedDollarClient::new(&ctx.env, &ctx.registry); + ctx.env.mock_all_auths(); + + ctx.init_context(&client); + + let bnusd_amount = 100000 as u128; + + let items: [u8; 32] = [ + 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, + 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0x10, + 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, + 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F, 0x20, + ]; + let data = CrossTransfer::new(ctx.depositor.to_string(), ctx.withdrawer.to_string(), bnusd_amount, Bytes::from_array(&ctx.env, &items)).encode(&ctx.env, String::from_str(&ctx.env, "xCrossTransfer")); + let decoded = CrossTransfer::decode(&ctx.env, data.clone()); + assert_eq!(decoded.to, ctx.withdrawer.to_string()); + + assert_eq!(client.balance(&ctx.withdrawer), 0); + + let sources = Vec::from_array(&ctx.env, [ctx.centralized_connection.to_string()]); + client.handle_call_message( &ctx.icon_bn_usd, &data, &sources); + + assert_eq!(client.balance(&ctx.withdrawer), bnusd_amount as i128) +} + +#[test] +fn test_handle_call_message_for_cross_transfer_revert(){ + let ctx = TestContext::default(); + let client = BalancedDollarClient::new(&ctx.env, &ctx.registry); + ctx.env.mock_all_auths(); + + ctx.init_context(&client); + + let bnusd_amount = 100000 as u128; + + let data = CrossTransferRevert::new( ctx.withdrawer.clone(), bnusd_amount).encode(&ctx.env, String::from_str(&ctx.env, "xCrossTransferRevert")); + let decoded = CrossTransferRevert::decode(&ctx.env, data.clone()); + assert_eq!(decoded.to, ctx.withdrawer); + + assert_eq!(client.balance(&ctx.withdrawer), 0); + + let sources = Vec::from_array(&ctx.env, [ctx.centralized_connection.to_string()]); + client.handle_call_message( &ctx.xcall.to_string(), &data, &sources); + + assert_eq!(client.balance(&ctx.withdrawer), bnusd_amount as i128) +} + diff --git a/contracts/balanced_doller/src/tests/mod.rs b/contracts/balanced_doller/src/tests/mod.rs new file mode 100644 index 0000000..7918a54 --- /dev/null +++ b/contracts/balanced_doller/src/tests/mod.rs @@ -0,0 +1,2 @@ +pub mod setup; +pub mod balanced_dollar_test; \ No newline at end of file diff --git a/contracts/balanced_doller/src/tests/setup.rs b/contracts/balanced_doller/src/tests/setup.rs new file mode 100644 index 0000000..16eacc3 --- /dev/null +++ b/contracts/balanced_doller/src/tests/setup.rs @@ -0,0 +1,132 @@ +#![cfg(test)] +extern crate std; + +use crate::contract::{ + BalancedDollar, BalancedDollarClient +}; + +use crate::config::ConfigData; + +use soroban_sdk::{ + testutils::Address as _, + token, Vec, Address, Env, String, +}; + +mod xcall { + soroban_sdk::contractimport!(file = "../../wasm/xcall.wasm" ); +} + +mod connection { + soroban_sdk::contractimport!(file = "../../wasm/centralized_connection.wasm"); +} + +mod xcall_manager { + soroban_sdk::contractimport!(file = "../../target/wasm32-unknown-unknown/release/xcall_manager.wasm" ); +} + +use xcall_manager::ConfigData as XcallManagerConfigData; + +pub struct TestContext { + pub env: Env, + pub registry:Address, + pub admin: Address, + pub depositor: Address, + pub withdrawer: Address, + pub xcall: Address, + pub xcall_manager: Address, + pub icon_bn_usd: String, + pub icon_governance: String, + pub token: Address, + pub centralized_connection: Address, + pub nid: String, + pub native_token: Address +} + +impl TestContext { + pub fn default() -> Self { + let env = Env::default(); + let token_admin = Address::generate(&env); + let token = env.register_stellar_asset_contract(token_admin.clone()); + let balanced_dollar = env.register_contract(None, BalancedDollar); + let centralized_connection = env.register_contract_wasm(None, connection::WASM); + let xcall_manager = env.register_contract_wasm(None, xcall_manager::WASM); + let xcall = env.register_contract_wasm(None, xcall::WASM); + std::println!("asset manager {:?}", balanced_dollar); + std::println!("xcall manager{:?}", xcall_manager); + std::println!("xcall {:?}", xcall); + std::println!("centralized {:?}", centralized_connection); + + Self { + registry: balanced_dollar, + admin: Address::generate(&env), + depositor: Address::generate(&env), + withdrawer: Address::generate(&env), + xcall: xcall, + xcall_manager: xcall_manager, + icon_bn_usd: String::from_str(&env, "icon01/hxjnfh4u"), + icon_governance: String::from_str(&env, "icon01/kjdnoi"), + token: token, + centralized_connection: centralized_connection, + nid: String::from_str(&env, "stellar"), + native_token: env.register_stellar_asset_contract(token_admin.clone()), + env + } + } + + pub fn init_context(&self, client: &BalancedDollarClient<'static>) { + self.env.mock_all_auths(); + let config = ConfigData {xcall: self.xcall.clone(), xcall_manager: self.xcall_manager.clone(), nid: self.nid.clone(), icon_bn_usd: self.icon_bn_usd.clone()}; + client.initialize( &self.admin, &config); + self.init_xcall_manager_context(); + self.init_xcall_state(); + } + + pub fn init_xcall_manager_context(&self) { + let client = self::xcall_manager::Client::new(&self.env, &self.xcall_manager); + let config = XcallManagerConfigData {xcall: self.xcall.clone(), icon_governance: self.icon_governance.clone()}; + let sources = Vec::from_array(&self.env, [self.centralized_connection.to_string()]); + let destinations = Vec::from_array(&self.env, [String::from_str(&self.env, "icon/address")]); + client.initialize(&self.xcall_manager, &self.admin, &config, &sources, &destinations); + } + + pub fn init_xcall_state(&self){ + let xcall_client = xcall::Client::new(&self.env, &self.xcall); + + xcall_client.initialize(&xcall::InitializeMsg { + sender: self.admin.clone(), + network_id: self.nid.clone(), + native_token: self.native_token.clone(), + }); + + self.init_connection_state(); + xcall_client.set_protocol_fee(&100); + xcall_client.set_default_connection(&self.nid, &self.centralized_connection); + } + + pub fn init_connection_state(&self) { + let connection_client = connection::Client::new(&self.env, &self.centralized_connection); + + let initialize_msg = connection::InitializeMsg { + native_token: self.native_token.clone(), + relayer: self.admin.clone(), + xcall_address: self.xcall.clone(), + }; + connection_client.initialize(&initialize_msg); + + let message_fee = 100; + let response_fee = 100; + connection_client.set_fee(&self.nid, &message_fee, &response_fee); + } + + pub fn mint_native_token(&self, address: &Address, amount: u128) { + let native_token_client = token::StellarAssetClient::new(&self.env, &self.native_token); + native_token_client.mint(&address, &(*&amount as i128)); + } + + pub fn get_native_token_balance(&self, address: &Address) -> u128 { + let native_token_client = token::TokenClient::new(&self.env, &self.native_token); + let balance = native_token_client.balance(address); + + *&balance as u128 + } +} diff --git a/contracts/xcall_manager/src/config.rs b/contracts/xcall_manager/src/config.rs index ca09dbf..cd1b43e 100644 --- a/contracts/xcall_manager/src/config.rs +++ b/contracts/xcall_manager/src/config.rs @@ -6,7 +6,10 @@ use crate::storage_types::DataKey; pub struct ConfigData { pub xcall: Address, pub icon_governance: String, - pub xcall_network_address: String, +} + +pub fn set_config(e: &Env, config: ConfigData){ + e.storage().instance().set(&DataKey::Config, &config); } pub fn get_config(e: &Env) -> ConfigData { diff --git a/contracts/xcall_manager/src/contract.rs b/contracts/xcall_manager/src/contract.rs index c5e8cb1..cb89a8e 100644 --- a/contracts/xcall_manager/src/contract.rs +++ b/contracts/xcall_manager/src/contract.rs @@ -1,16 +1,15 @@ -use soroban_sdk::{contract, contractimpl, Address, Bytes, Env, String, Vec}; +use soroban_sdk::{contract, contractimpl, Address, Bytes, Env, String, Vec, panic_with_error}; mod xcall { - soroban_sdk::contractimport!(file = "xcall.wasm" ); + soroban_sdk::contractimport!(file = "../../wasm/xcall.wasm" ); } - +use soroban_rlp::messages::{configure_protocols::ConfigureProtocols, execute::Execute }; use crate::{ admin:: {read_administrator, write_administrator}, - config::{get_config, ConfigData}, - states::{has_state, read_string_state, read_vec_string_state, write_string_state, write_vec_string_state }, - storage_types::{DataKey, INSTANCE_BUMP_AMOUNT, INSTANCE_LIFETIME_THRESHOLD }, - messages::{configure_protocols::ConfigureProtocols, execute::Execute } - + config::{get_config, set_config, ConfigData}, + states::{has_state, write_address_state, read_string_state, read_vec_string_state, write_string_state, write_vec_string_state }, + storage_types::{DataKey, INSTANCE_BUMP_AMOUNT, INSTANCE_LIFETIME_THRESHOLD } }; + use crate::errors::ContractError; const CONFIGURE_PROTOCOLS_NAME: &str = "ConfigureProtocols"; @@ -22,29 +21,27 @@ pub struct XcallManager; #[contractimpl] impl XcallManager { - pub fn initialize(env:Env, registry:Address, admin: Address, xcall: Address, - icon_governance: String, xcall_network_address: String, proposed_protocol_to_remove: String, sources: Vec, destinations: Vec) { + pub fn initialize(env:Env, registry:Address, admin: Address, config: ConfigData, sources: Vec, destinations: Vec) { if has_state(env.clone(), DataKey::Registry) { panic!("Contract already initialized.") } - env.storage().instance().set(&DataKey::Registry, ®istry); - env.storage().instance().set(&DataKey::Admin, &admin); - Self::configure(env, xcall, icon_governance, xcall_network_address, proposed_protocol_to_remove, sources, destinations ); + write_address_state(&env, DataKey::Registry, ®istry); + write_address_state(&env, DataKey::Admin, &admin); + Self::configure(env, config, sources, destinations ); } - pub fn configure(env:Env, xcall: Address, - icon_governance: String, xcall_network_address: String, proposed_protocol_to_remove: String, sources: Vec, destinations: Vec){ + pub fn configure(env:Env, config: ConfigData, sources: Vec, destinations: Vec){ let admin = read_administrator(&env.clone()); admin.require_auth(); - let config: ConfigData = ConfigData{ xcall: xcall, icon_governance: icon_governance, xcall_network_address: xcall_network_address }; - env.storage().instance().set(&DataKey::Config, &config); - env.storage().instance().set(&DataKey::Sources, &sources); - env.storage().instance().set(&DataKey::Destinations, &destinations); - env.storage().instance().set(&DataKey::ProposedProtocolToRemove, &proposed_protocol_to_remove); + set_config(&env, config); + write_vec_string_state(&env, DataKey::Sources, &sources); + write_vec_string_state(&env, DataKey::Destinations, &destinations); } - + pub fn get_config(env: Env) -> ConfigData{ + get_config(&env) + } pub fn set_admin(e: Env, new_admin: Address) { let admin = read_administrator(&e); @@ -57,6 +54,10 @@ impl XcallManager { write_administrator(&e, &new_admin); } + pub fn get_admin(e: Env) -> Address { + read_administrator(&e) + } + pub fn propose_removal(e: Env, protocol: String) { let admin = read_administrator(&e); admin.require_auth(); @@ -75,7 +76,7 @@ impl XcallManager { pub fn get_protocols(e: Env) -> Result<(Vec, Vec), ContractError> { let sources = read_vec_string_state(&e, DataKey::Sources); let destinations = read_vec_string_state(&e, DataKey::Destinations); - Ok((sources, destinations)) + Ok((sources, destinations)) } pub fn verify_protocols_unordered(_e: Env, array1: Vec, array2: Vec) -> Result { @@ -120,7 +121,7 @@ impl XcallManager { panic!("Protocol Mismatch"); }; - let method = ConfigureProtocols::get_method(&e.clone(), data.clone()).unwrap(); + let method = ConfigureProtocols::get_method(&e.clone(), data.clone()); let sources = read_vec_string_state(&e, DataKey::Sources); if !Self::verify_protocols_unordered(e.clone(), protocols.clone(), sources).unwrap() { @@ -131,12 +132,12 @@ impl XcallManager { } if method == String::from_str(&e.clone(), EXECUTE_NAME) { - let message = Execute::decode(&e.clone(), data).unwrap(); + let message = Execute::decode(&e.clone(), data); // (bool _success, ) = message.contractAddress.call(message.data); // require(_success, "Failed to excute message"); //e.invoke_contract(&message.contract_address, &Symbol::new(&e.clone(), "test"), data); } else if method == String::from_str(&e, CONFIGURE_PROTOCOLS_NAME) { - let message = ConfigureProtocols::decode(&e, data).unwrap(); + let message = ConfigureProtocols::decode(&e, data); let sources = message.sources; let destinations = message.destinations; write_vec_string_state(&e, DataKey::Sources, &sources); @@ -154,7 +155,6 @@ impl XcallManager { } } - pub fn get_modified_protocols(e: Env) -> Vec{ if !has_state(e.clone(), DataKey::ProposedProtocolToRemove) { panic!( "No proposal for removal exists") @@ -172,5 +172,4 @@ impl XcallManager { return new_array; } - } \ No newline at end of file diff --git a/contracts/xcall_manager/src/lib.rs b/contracts/xcall_manager/src/lib.rs index db0d07c..4d9aa65 100644 --- a/contracts/xcall_manager/src/lib.rs +++ b/contracts/xcall_manager/src/lib.rs @@ -4,9 +4,6 @@ mod admin; pub mod contract; mod storage_types; mod states; -mod test; +mod tests; mod errors; -mod config; -mod messages; - -pub use crate::contract::XcallManagerClient; \ No newline at end of file +mod config; \ No newline at end of file diff --git a/contracts/xcall_manager/src/messages/mod.rs b/contracts/xcall_manager/src/messages/mod.rs deleted file mode 100644 index 678d8ed..0000000 --- a/contracts/xcall_manager/src/messages/mod.rs +++ /dev/null @@ -1,2 +0,0 @@ -pub mod configure_protocols; -pub mod execute; \ No newline at end of file diff --git a/contracts/xcall_manager/src/states.rs b/contracts/xcall_manager/src/states.rs index 5c845ae..696d644 100644 --- a/contracts/xcall_manager/src/states.rs +++ b/contracts/xcall_manager/src/states.rs @@ -1,4 +1,4 @@ -use soroban_sdk::{Env, String, Vec}; +use soroban_sdk::{Address, Env, String, Vec}; use crate::storage_types::DataKey; @@ -10,6 +10,14 @@ pub fn write_string_state(e: &Env, key: DataKey, id: &String) { e.storage().instance().set(&key, id); } +pub fn write_address_state(e: &Env, key: DataKey, id: &Address) { + e.storage().instance().set(&key, id); +} + +pub fn read_address_state(e: &Env, key: DataKey) -> Address { + e.storage().instance().get(&key).unwrap() +} + pub fn write_vec_string_state(e: &Env, key: DataKey, id: &Vec) { e.storage().instance().set(&key, id); } diff --git a/contracts/xcall_manager/src/tests/mod.rs b/contracts/xcall_manager/src/tests/mod.rs new file mode 100644 index 0000000..08c141b --- /dev/null +++ b/contracts/xcall_manager/src/tests/mod.rs @@ -0,0 +1,2 @@ +pub mod setup; +pub mod xcall_manager_test; \ No newline at end of file diff --git a/contracts/xcall_manager/src/tests/setup.rs b/contracts/xcall_manager/src/tests/setup.rs new file mode 100644 index 0000000..5e4157c --- /dev/null +++ b/contracts/xcall_manager/src/tests/setup.rs @@ -0,0 +1,115 @@ +#![cfg(test)] +extern crate std; + + +use crate::contract::{ + XcallManager, XcallManagerClient +}; + +use crate::config::ConfigData; + +use soroban_sdk::Vec; +use soroban_sdk::{ + testutils::Address as _, + token, Address, Env, String +}; + +mod xcall { + soroban_sdk::contractimport!(file = "../../wasm/xcall.wasm" ); +} + +mod connection { + soroban_sdk::contractimport!(file = "../../wasm/centralized_connection.wasm"); +} + +pub struct TestContext { + pub env: Env, + pub registry:Address, + pub admin: Address, + pub depositor: Address, + pub xcall: Address, + pub icon_governance: String, + pub xcall_network_address: String, + pub token: Address, + pub centralized_connection: Address, + pub nid: String, + pub native_token: Address +} + +impl TestContext { + pub fn default() -> Self { + let env = Env::default(); + let token_admin = Address::generate(&env); + let token = env.register_stellar_asset_contract(token_admin.clone()); + let xcall_manager = env.register_contract(None, XcallManager); + let centralized_connection = env.register_contract_wasm(None, connection::WASM); + let xcall = env.register_contract_wasm(None, xcall::WASM); + std::println!("xcall manager{:?}", xcall_manager); + std::println!("xcall {:?}", xcall); + std::println!("centralized {:?}", centralized_connection); + + Self { + registry: xcall_manager, + admin: Address::generate(&env), + depositor: Address::generate(&env), + xcall: xcall, + icon_governance: String::from_str(&env, "icon01/kjdnoi"), + xcall_network_address: String::from_str(&env, "stellar/address"), + token: token, + centralized_connection: centralized_connection, + nid: String::from_str(&env, "stellar"), + native_token: env.register_stellar_asset_contract(token_admin.clone()), + env + } + } + + pub fn init_context(&self, client: &XcallManagerClient<'static>) { + self.env.mock_all_auths(); + let config = ConfigData {xcall: self.xcall.clone(), icon_governance: self.icon_governance.clone()}; + let sources = Vec::from_array(&self.env, [self.centralized_connection.to_string()]); + let destinations = Vec::from_array(&self.env, [String::from_str(&self.env, "icon/address")]); + client.initialize(&self.registry, &self.admin, &config, &sources, &destinations); + self.init_xcall_state(); + } + + pub fn init_xcall_state(&self){ + let xcall_client = xcall::Client::new(&self.env, &self.xcall); + + xcall_client.initialize(&xcall::InitializeMsg { + sender: self.admin.clone(), + network_id: self.nid.clone(), + native_token: self.native_token.clone(), + }); + + self.init_connection_state(); + xcall_client.set_protocol_fee(&100); + xcall_client.set_default_connection(&self.nid, &self.centralized_connection); + } + + pub fn init_connection_state(&self) { + let connection_client = connection::Client::new(&self.env, &self.centralized_connection); + + let initialize_msg = connection::InitializeMsg { + native_token: self.native_token.clone(), + relayer: self.admin.clone(), + xcall_address: self.xcall.clone(), + }; + connection_client.initialize(&initialize_msg); + + let message_fee = 100; + let response_fee = 100; + connection_client.set_fee(&self.nid, &message_fee, &response_fee); + } + + pub fn mint_native_token(&self, address: &Address, amount: u128) { + let native_token_client = token::StellarAssetClient::new(&self.env, &self.native_token); + native_token_client.mint(&address, &(*&amount as i128)); + } + + pub fn get_native_token_balance(&self, address: &Address) -> u128 { + let native_token_client = token::TokenClient::new(&self.env, &self.native_token); + let balance = native_token_client.balance(address); + + *&balance as u128 + } +} diff --git a/contracts/xcall_manager/src/tests/xcall_manager_test.rs b/contracts/xcall_manager/src/tests/xcall_manager_test.rs new file mode 100644 index 0000000..199321c --- /dev/null +++ b/contracts/xcall_manager/src/tests/xcall_manager_test.rs @@ -0,0 +1,65 @@ +#![cfg(test)] +extern crate std; + +use crate::contract::XcallManagerClient; + +use soroban_sdk::{ + Vec, String +}; +use soroban_rlp::messages::configure_protocols::ConfigureProtocols; +use super::setup::*; + +#[test] +fn test_initialize() { + let ctx = TestContext::default(); + let client = XcallManagerClient::new(&ctx.env, &ctx.registry); + + ctx.init_context(&client); + + let sources = Vec::from_array(&ctx.env, [ctx.centralized_connection.to_string()]); + let destinations = Vec::from_array(&ctx.env, [String::from_str(&ctx.env, "icon/address")]); + let (s, d) = client.get_protocols(); + assert_eq!(s, sources); + assert_eq!(d, destinations); + +} + +#[test] +fn test_verify_protocols(){ + let ctx = TestContext::default(); + let client = XcallManagerClient::new(&ctx.env, &ctx.registry); + + ctx.init_context(&client); + let protocols = Vec::from_array(&ctx.env, [ctx.centralized_connection.to_string()]); + client.verify_protocols(&protocols); +} + +#[test] +fn test_handle_call_message_for_configure_protocols(){ + std::println!("first"); + let ctx = TestContext::default(); + let client = XcallManagerClient::new(&ctx.env, &ctx.registry); + ctx.env.mock_all_auths(); + std::println!("second"); + ctx.init_context(&client); + + + let source_items = [String::from_str(&ctx.env, "sui/address"), String::from_str(&ctx.env, "sui/address1")]; + std::println!("source_items : {:?}", source_items); + let destination_items = [String::from_str(&ctx.env, "icon/address"), String::from_str(&ctx.env, "icon/address1")]; + let sources = Vec::from_array(&ctx.env, source_items); + let destinations = Vec::from_array(&ctx.env, destination_items); + let data = ConfigureProtocols::new(sources.clone(), destinations.clone()).encode(&ctx.env, String::from_str(&ctx.env, "ConfigureProtocols")); + std::println!("encoded data : {:?}", data); + let decoded: ConfigureProtocols = ConfigureProtocols::decode(&ctx.env, data.clone()); + + std::println!("decoded source : {:?}", decoded.sources); + assert_eq!(decoded.sources, sources); + assert_eq!(decoded.destinations, destinations); + let (s, _) = client.get_protocols(); + client.handle_call_message(&ctx.icon_governance, &data, &s); + + let (s, d) = client.get_protocols(); + assert_eq!(s, sources); + assert_eq!(d, destinations); +} \ No newline at end of file diff --git a/libs/soroban-rlp/src/decoder.rs b/libs/soroban-rlp/src/decoder.rs index c49077d..f9b67ce 100644 --- a/libs/soroban-rlp/src/decoder.rs +++ b/libs/soroban-rlp/src/decoder.rs @@ -6,23 +6,35 @@ pub fn decode(env: &Env, bytes: Bytes) -> Bytes { let rlp_byte = bytes.get(0).unwrap(); - let decoded = if rlp_byte == 0x80 { + #[allow(unused_comparisons)] + let decoded = if rlp_byte == 0x80 || rlp_byte == 0xc0 { Bytes::new(&env) } else if rlp_byte < 0x80 { bytes } else if rlp_byte < 0xb8 { let data_len = rlp_byte - 0x80; - let data = slice_vector(&env, bytes, 1, data_len as u64); - data - } else { + slice_vector(&env, bytes, 1, data_len as u64) + } else if rlp_byte > 0xb7 && rlp_byte < 0xc0 { let data_bytes_len = rlp_byte - 0xb7; let len_bytes = slice_vector(&env, bytes.clone(), 1, data_bytes_len as u64); let data_len = bytes_to_u64(len_bytes.clone()); let data_start = len_bytes.len() + 1; - let data = slice_vector(&env, bytes, data_start as u64, data_len); - data + slice_vector(&env, bytes, data_start as u64, data_len) + } else if rlp_byte > 0xc0 && rlp_byte <= 0xf7 { + let data_len = rlp_byte - 0xc0; + slice_vector(&env, bytes, 1, data_len as u64) + } else if rlp_byte > 0xf7 && rlp_byte <= 0xff { + let data_bytes_len = rlp_byte - 0xf7; + let len_bytes = slice_vector(&env, bytes.clone(), 1, data_bytes_len as u64); + + let data_len = bytes_to_u64(len_bytes.clone()); + let data_start = len_bytes.len() + 1; + + slice_vector(&env, bytes, data_start as u64, data_len) + } else { + panic!("invalid rlp byte length") }; decoded @@ -39,7 +51,7 @@ pub fn decode_list(env: &Env, list: Bytes) -> Vec { let byte = encoded.get(i).unwrap(); #[allow(unused_comparisons)] - if byte == 0x80 { + if byte == 0x80 || byte == 0xc0 { decoded.push_back(Bytes::new(&env)); i = i + 1; } else if byte < 0x80 { @@ -51,12 +63,9 @@ pub fn decode_list(env: &Env, list: Bytes) -> Vec { let len = (byte - 0x80) as u64; decoded.push_back(slice_vector(&env, encoded.clone(), i as u64 + 1, len)); i = i + (len as u32 + 1); - } else if byte == 0xc0 { - decoded.push_back(Bytes::new(&env)); - i = i + 1; } else if byte > 0xc0 && byte < 0xf7 { let len = (byte - 0xc0) as u64; - decoded.push_back(slice_vector(&env, encoded.clone(), i as u64 + 1, len)); + decoded.push_back(slice_vector(&env, encoded.clone(), i as u64, len+1)); i = i + (len as u32 + 1) } else if byte > 0xb7 && byte < 0xc0 { let data_bytes_len = (byte - 0xb7) as u64; diff --git a/libs/soroban-rlp/src/lib.rs b/libs/soroban-rlp/src/lib.rs index 8ab22f6..32c2a98 100644 --- a/libs/soroban-rlp/src/lib.rs +++ b/libs/soroban-rlp/src/lib.rs @@ -3,3 +3,4 @@ pub mod decoder; pub mod encoder; mod utils; +pub mod messages; diff --git a/contracts/xcall_manager/src/messages/configure_protocols.rs b/libs/soroban-rlp/src/messages/configure_protocols.rs similarity index 72% rename from contracts/xcall_manager/src/messages/configure_protocols.rs rename to libs/soroban-rlp/src/messages/configure_protocols.rs index 802901c..3c2409d 100644 --- a/contracts/xcall_manager/src/messages/configure_protocols.rs +++ b/libs/soroban-rlp/src/messages/configure_protocols.rs @@ -1,6 +1,8 @@ use soroban_sdk::{contracttype, Env, String, Bytes, Vec}; -use soroban_rlp::{encoder, decoder}; -use crate::errors::ContractError; +use crate::encoder; +use crate::decoder; + +extern crate std; #[derive(Clone)] #[contracttype] @@ -36,27 +38,27 @@ impl ConfigureProtocols{ encoded } - pub fn decode(e: &Env, bytes: Bytes) -> Result { + pub fn decode(e: &Env, bytes: Bytes) -> ConfigureProtocols { + std::println!("encoded bytes: {:?}", bytes); let decoded = decoder::decode_list(&e, bytes); - if decoded.len() != 6 { - return Err(ContractError::InvalidRlpLength); + std::println!("decoded bytes: {:?}", decoded); + if decoded.len() != 3 { + panic!("InvalidRlpLength"); } - + let sources = decoder::decode_strings(e, decoded.get(1).unwrap()); let destinations = decoder::decode_strings(e, decoded.get(2).unwrap()); - - Ok(Self { + // std::println!("vec sources: {:?}", sources); + // std::println!("vec destinations: {:?}", destinations); + Self { sources, destinations - }) + } } - pub fn get_method(e: &Env, bytes: Bytes) -> Result { + pub fn get_method(e: &Env, bytes: Bytes) -> String { let decoded = decoder::decode_list(&e, bytes); - if decoded.len() != 6 { - return Err(ContractError::InvalidRlpLength); - } let method = decoder::decode_string(e, decoded.get(0).unwrap()); - Ok(method) + method } } \ No newline at end of file diff --git a/contracts/balanced_doller/src/messages/cross_transfer.rs b/libs/soroban-rlp/src/messages/cross_transfer.rs similarity index 76% rename from contracts/balanced_doller/src/messages/cross_transfer.rs rename to libs/soroban-rlp/src/messages/cross_transfer.rs index 826a2c9..840a7ca 100644 --- a/contracts/balanced_doller/src/messages/cross_transfer.rs +++ b/libs/soroban-rlp/src/messages/cross_transfer.rs @@ -1,6 +1,6 @@ use soroban_sdk::{contracttype, Env, String, Bytes, Vec}; -use soroban_rlp::{encoder, decoder}; -use crate::errors::ContractError; +use crate::encoder; +use crate::decoder; #[derive(Clone)] #[contracttype] @@ -41,31 +41,28 @@ impl CrossTransfer{ encoded } - pub fn decode(e: &Env, bytes: Bytes) -> Result { + pub fn decode(e: &Env, bytes: Bytes) -> CrossTransfer { let decoded = decoder::decode_list(&e, bytes); - if decoded.len() != 6 { - return Err(ContractError::InvalidRlpLength); - } + //todo: check length + // if decoded.len() != 5 { + // panic!("InvalidRlpLength"); + // } let from = decoder::decode_string(e, decoded.get(1).unwrap()); let to = decoder::decode_string(e, decoded.get(2).unwrap()); let amount = decoder::decode_u128(e, decoded.get(3).unwrap()); let data = decoded.get(4).unwrap(); - - Ok(Self { + Self { from, to, amount, data - }) + } } - pub fn get_method(e: &Env, bytes: Bytes) -> Result { + pub fn get_method(e: &Env, bytes: Bytes) -> String { let decoded = decoder::decode_list(&e, bytes); - if decoded.len() != 6 { - return Err(ContractError::InvalidRlpLength); - } let method = decoder::decode_string(e, decoded.get(0).unwrap()); - Ok(method) + method } } \ No newline at end of file diff --git a/contracts/balanced_doller/src/messages/cross_transfer_revert.rs b/libs/soroban-rlp/src/messages/cross_transfer_revert.rs similarity index 80% rename from contracts/balanced_doller/src/messages/cross_transfer_revert.rs rename to libs/soroban-rlp/src/messages/cross_transfer_revert.rs index 468979f..9e2fef5 100644 --- a/contracts/balanced_doller/src/messages/cross_transfer_revert.rs +++ b/libs/soroban-rlp/src/messages/cross_transfer_revert.rs @@ -1,6 +1,6 @@ use soroban_sdk::{contracttype, Env, String, Address, Bytes, Vec}; -use soroban_rlp::{encoder, decoder}; -use crate::errors::ContractError; +use crate::encoder; +use crate::decoder; #[derive(Clone)] #[contracttype] @@ -36,18 +36,18 @@ impl CrossTransferRevert{ encoded } - pub fn decode(e: &Env, bytes: Bytes) -> Result { + pub fn decode(e: &Env, bytes: Bytes) -> CrossTransferRevert{ let decoded = decoder::decode_list(&e, bytes); - if decoded.len() != 6 { - return Err(ContractError::InvalidRlpLength); + if decoded.len() != 3 { + panic!("InvalidRlpLength"); } let to = Address::from_string(&decoder::decode_string(e, decoded.get(1).unwrap())); let amount = decoder::decode_u128(e, decoded.get(2).unwrap()); - Ok(Self { + Self { to, amount - }) + } } } \ No newline at end of file diff --git a/contracts/asset_manager/src/messages/deposit.rs b/libs/soroban-rlp/src/messages/deposit.rs similarity index 83% rename from contracts/asset_manager/src/messages/deposit.rs rename to libs/soroban-rlp/src/messages/deposit.rs index 5608302..5a5706c 100644 --- a/contracts/asset_manager/src/messages/deposit.rs +++ b/libs/soroban-rlp/src/messages/deposit.rs @@ -1,6 +1,6 @@ use soroban_sdk::{contracttype, Env, String, Bytes, Vec}; -use soroban_rlp::{encoder, decoder}; -use crate::errors::ContractError; +use crate::encoder; +use crate::decoder; #[derive(Clone)] #[contracttype] @@ -56,10 +56,10 @@ impl Deposit{ encoded } - pub fn decode(e: &Env, bytes: Bytes) -> Result { + pub fn decode(e: &Env, bytes: Bytes) -> Deposit { let decoded = decoder::decode_list(&e, bytes); if decoded.len() != 6 { - return Err(ContractError::InvalidRlpLength); + panic!("InvalidRlpLength"); } let token_address = decoder::decode_string(e, decoded.get(1).unwrap()); @@ -68,21 +68,18 @@ impl Deposit{ let amount = decoder::decode_u128(e, decoded.get(4).unwrap()); let data = decoded.get(5).unwrap(); - Ok(Self { + Self { token_address, from, to, amount, data - }) + } } - pub fn get_method(e: &Env, bytes: Bytes)-> Result { + pub fn get_method(e: &Env, bytes: Bytes)-> String { let decoded = decoder::decode_list(&e, bytes); - if decoded.len() != 6 { - return Err(ContractError::InvalidRlpLength); - } let method = decoder::decode_string(e, decoded.get(0).unwrap()); - Ok(method) + method } } \ No newline at end of file diff --git a/contracts/asset_manager/src/messages/deposit_revert.rs b/libs/soroban-rlp/src/messages/deposit_revert.rs similarity index 84% rename from contracts/asset_manager/src/messages/deposit_revert.rs rename to libs/soroban-rlp/src/messages/deposit_revert.rs index bbb4df8..8ad1742 100644 --- a/contracts/asset_manager/src/messages/deposit_revert.rs +++ b/libs/soroban-rlp/src/messages/deposit_revert.rs @@ -1,6 +1,6 @@ use soroban_sdk::{contracttype, Env, String, Address, Bytes, Vec}; -use soroban_rlp::{encoder, decoder}; -use crate::errors::ContractError; +use crate::encoder; +use crate::decoder; #[derive(Clone)] #[contracttype] @@ -42,20 +42,20 @@ impl DepositRevert{ encoded } - pub fn decode(e: &Env, bytes: Bytes) -> Result { + pub fn decode(e: &Env, bytes: Bytes) -> DepositRevert { let decoded = decoder::decode_list(&e, bytes); - if decoded.len() != 6 { - return Err(ContractError::InvalidRlpLength); + if decoded.len() != 4 { + panic!("InvalidRlpLength"); } let token_address = Address::from_string(&decoder::decode_string(e, decoded.get(1).unwrap())); let to = Address::from_string(&decoder::decode_string(e, decoded.get(2).unwrap())); let amount = decoder::decode_u128(e, decoded.get(3).unwrap()); - Ok(Self { + Self { token_address, to, amount - }) + } } } \ No newline at end of file diff --git a/contracts/xcall_manager/src/messages/execute.rs b/libs/soroban-rlp/src/messages/execute.rs similarity index 81% rename from contracts/xcall_manager/src/messages/execute.rs rename to libs/soroban-rlp/src/messages/execute.rs index cbdded2..4af0ea8 100644 --- a/contracts/xcall_manager/src/messages/execute.rs +++ b/libs/soroban-rlp/src/messages/execute.rs @@ -1,6 +1,6 @@ use soroban_sdk::{contracttype, Env, String, Bytes, Vec, Address}; -use soroban_rlp::{encoder, decoder}; -use crate::errors::ContractError; +use crate::encoder; +use crate::decoder; #[derive(Clone)] #[contracttype] @@ -35,18 +35,18 @@ impl Execute{ encoded } - pub fn decode(e: &Env, bytes: Bytes) -> Result { + pub fn decode(e: &Env, bytes: Bytes) -> Execute { let decoded = decoder::decode_list(&e, bytes); - if decoded.len() != 6 { - return Err(ContractError::InvalidRlpLength); + if decoded.len() != 3 { + panic!("InvalidRlpLength"); } let contract_address = Address::from_string(&decoder::decode_string(e, decoded.get(1).unwrap())); let data = decoded.get(2).unwrap(); - Ok(Self { + Self { contract_address, data - }) + } } } \ No newline at end of file diff --git a/libs/soroban-rlp/src/messages/mod.rs b/libs/soroban-rlp/src/messages/mod.rs new file mode 100644 index 0000000..d47f963 --- /dev/null +++ b/libs/soroban-rlp/src/messages/mod.rs @@ -0,0 +1,8 @@ +pub mod deposit_revert; +pub mod deposit; +pub mod withdraw_to; +pub mod cross_transfer; +pub mod cross_transfer_revert; +pub mod configure_protocols; +pub mod execute; + diff --git a/contracts/asset_manager/src/messages/withdraw_to.rs b/libs/soroban-rlp/src/messages/withdraw_to.rs similarity index 83% rename from contracts/asset_manager/src/messages/withdraw_to.rs rename to libs/soroban-rlp/src/messages/withdraw_to.rs index 3f51f35..ca06dd9 100644 --- a/contracts/asset_manager/src/messages/withdraw_to.rs +++ b/libs/soroban-rlp/src/messages/withdraw_to.rs @@ -1,6 +1,6 @@ use soroban_sdk::{contracttype, Env, String, Bytes, Vec}; -use soroban_rlp::{encoder, decoder}; -use crate::errors::ContractError; +use crate::encoder; +use crate::decoder; #[derive(Clone)] #[contracttype] @@ -42,20 +42,20 @@ impl WithdrawTo{ encoded } - pub fn decode(e: &Env, bytes: Bytes) -> Result { + pub fn decode(e: &Env, bytes: Bytes) -> WithdrawTo { let decoded = decoder::decode_list(&e, bytes); - if decoded.len() != 6 { - //return Err(ContractError::InvalidRlpLength); + if decoded.len() != 4 { + panic!("InvalidRlpLength"); } let token_address = decoder::decode_string(e, decoded.get(1).unwrap()); let to = decoder::decode_string(e, decoded.get(2).unwrap()); let amount = decoder::decode_u128(e, decoded.get(3).unwrap()); - Ok(Self { + Self { token_address, to, amount - }) + } } } \ No newline at end of file From 15bf1472669206c099b4f6fd92fb9b32583d3724 Mon Sep 17 00:00:00 2001 From: sagar sapkota Date: Fri, 24 May 2024 13:09:49 +0545 Subject: [PATCH 04/63] panic case unit test completed --- contracts/asset_manager/src/contract.rs | 22 -- contracts/asset_manager/src/errors.rs | 3 +- .../src/tests/asset_manager_test.rs | 214 +++++++++++++++++- .../balanced_doller/src/balanced_dollar.rs | 185 ++++++++------- contracts/balanced_doller/src/contract.rs | 45 ++-- contracts/balanced_doller/src/errors.rs | 8 +- .../src/tests/balanced_dollar_test.rs | 141 +++++++++++- contracts/xcall_manager/src/contract.rs | 22 +- contracts/xcall_manager/src/errors.rs | 10 +- .../src/tests/xcall_manager_test.rs | 186 ++++++++++++++- .../src/messages/configure_protocols.rs | 6 - 11 files changed, 681 insertions(+), 161 deletions(-) diff --git a/contracts/asset_manager/src/contract.rs b/contracts/asset_manager/src/contract.rs index a1dda5b..c237b44 100644 --- a/contracts/asset_manager/src/contract.rs +++ b/contracts/asset_manager/src/contract.rs @@ -154,25 +154,6 @@ impl AssetManager { Ok(Self::send_deposit_message(e, from, token, amount, deposit_to, deposit_data)?) } - pub fn deposit_native( - e: Env, - from: Address, - value: u128, - amount: u128, - to: Option, - data: Option - ) -> Result<(), ContractError> { - if value < amount { - panic_with_error!(&e, ContractError::AmountIsLessThanMinimumAmount); - } - - let deposit_to = to.unwrap_or(String::from_str(&e, "")); - let deposit_data = data.unwrap_or(Bytes::from_array(&e, &[0u8; 32])); - - let native_address = get_config(&e).native_address; - Ok(Self::send_deposit_message(e, from, native_address, amount, deposit_to, deposit_data)?) - } - fn send_deposit_message( e: Env, from: Address, @@ -261,10 +242,8 @@ impl AssetManager { if amount <= 0 { panic_with_error!(&e, ContractError::AmountIsLessThanMinimumAmount); } - std::println!("before verify"); let verified = Self::verify_withdraw(e.clone(), token.clone(), amount)?; if verified { - std::println!("before transfer"); Self::transfer_token_to(e, from, token, to, amount); } Ok(()) @@ -280,7 +259,6 @@ impl AssetManager { return token_client.balance(&e.current_contract_address()); } - pub fn has_registry(e: Env) -> bool { has_state(e, DataKey::Registry) } diff --git a/contracts/asset_manager/src/errors.rs b/contracts/asset_manager/src/errors.rs index 17f7d69..aa3163c 100644 --- a/contracts/asset_manager/src/errors.rs +++ b/contracts/asset_manager/src/errors.rs @@ -13,6 +13,7 @@ pub enum ContractError { ProtocolMismatch = 7, OnlyICONAssetManager = 8, OnlyCallService = 9, - UnknownMessageType = 10 + UnknownMessageType = 10, + AdminRequired = 11 } \ No newline at end of file diff --git a/contracts/asset_manager/src/tests/asset_manager_test.rs b/contracts/asset_manager/src/tests/asset_manager_test.rs index 4ec1e06..090df28 100644 --- a/contracts/asset_manager/src/tests/asset_manager_test.rs +++ b/contracts/asset_manager/src/tests/asset_manager_test.rs @@ -3,8 +3,7 @@ extern crate std; use soroban_sdk::{ - testutils::Address as _, - token, Address, Bytes, String, Vec + symbol_short, testutils::{Address as _, AuthorizedFunction, AuthorizedInvocation}, token, Address, Bytes, IntoVal, String, Vec }; use crate::contract::AssetManagerClient; @@ -31,8 +30,39 @@ fn test_set_admin() { let new_admin: Address = Address::generate(&ctx.env); client.set_admin(&new_admin); + assert_eq!( + ctx.env.auths(), + std::vec![ + ( + ctx.admin.clone(), + AuthorizedInvocation { + function: AuthorizedFunction::Contract(( + ctx.registry.clone(), + symbol_short!("set_admin"), + (&new_admin,) + .into_val(&ctx.env) + )), + sub_invocations: std::vec![] + } + ) + ] + ); + assert_eq!(client.get_admin(), new_admin); +} + +#[test] +#[should_panic(expected = "HostError: Error(Contract, #4)")] +fn test_configure_rate_limit_panic() { + let ctx = TestContext::default(); + let client = AssetManagerClient::new(&ctx.env, &ctx.registry); + ctx.init_context(&client); + let period = &300; + let percentage = &1001; + client.configure_rate_limit( &ctx.token, period, percentage ); - assert_eq!(client.get_admin(), new_admin) + let limit = client.get_withdraw_limit(&ctx.token); + let verified = client.verify_withdraw(&ctx.token, &limit); + assert_eq!(verified, true); } #[test] @@ -40,9 +70,10 @@ fn test_configure_rate_limit() { let ctx = TestContext::default(); let client = AssetManagerClient::new(&ctx.env, &ctx.registry); ctx.init_context(&client); + let period = &300; + let percentage = &300; + client.configure_rate_limit( &ctx.token, period, percentage ); - client.configure_rate_limit( &ctx.token, &300, &300 ); - let limit = client.get_withdraw_limit(&ctx.token); let verified = client.verify_withdraw(&ctx.token, &limit); assert_eq!(verified, true); @@ -69,7 +100,68 @@ fn test_deposit_without_to_and_data(){ token_client.approve(&ctx.depositor, &ctx.registry, &(amount_i128+amount_i128), &1312000); client.deposit(&ctx.depositor, &ctx.token, &amount, &Option::Some(String::from_str(&ctx.env, "")), &Option::Some(Bytes::from_array(&ctx.env, &[0u8; 32]))); - assert_eq!(ctx.get_native_token_balance(&ctx.depositor), 400) // why 300? + assert_eq!(ctx.get_native_token_balance(&ctx.depositor), 400); // why 300? +} + +#[test] +fn test_veryfy_rate_limit() { + let ctx = TestContext::default(); + let client = AssetManagerClient::new(&ctx.env, &ctx.registry); + ctx.init_context(&client); + let period = &300; + let percentage = &300; + client.configure_rate_limit( &ctx.token, period, percentage ); + + client.configure_rate_limit( &ctx.token, &300, &300 ); + let token_client = token::Client::new(&ctx.env, &ctx.token); + let stellar_asset_client: token::StellarAssetClient = token::StellarAssetClient::new(&ctx.env, &ctx.token); + let amount_i128: i128 = 100000 ; + let amount = &(amount_i128 as u128); + let mint_amount = &(amount_i128+amount_i128); + + stellar_asset_client.mint(&ctx.depositor, mint_amount); + + ctx.mint_native_token(&ctx.depositor, 500); + assert_eq!(ctx.get_native_token_balance(&ctx.depositor), 500); + + token_client.approve(&ctx.depositor, &ctx.registry, &(amount_i128+amount_i128), &1312000); + client.deposit(&ctx.depositor, &ctx.token, &amount, &Option::Some(String::from_str(&ctx.env, "")), &Option::Some(Bytes::from_array(&ctx.env, &[0u8; 32]))); + + let limit = client.get_withdraw_limit(&ctx.token); + assert_eq!(limit, 30000); + let verified = client.verify_withdraw(&ctx.token, &(amount-30000-1)); + assert_eq!(verified, true); +} + +#[test] +#[should_panic(expected = "HostError: Error(Contract, #5)")] +fn test_veryfy_rate_limit_panic_exceeds_withdraw_limit() { + let ctx = TestContext::default(); + let client = AssetManagerClient::new(&ctx.env, &ctx.registry); + ctx.init_context(&client); + let period = &300; + let percentage = &300; + client.configure_rate_limit( &ctx.token, period, percentage ); + + client.configure_rate_limit( &ctx.token, &300, &300 ); + let token_client = token::Client::new(&ctx.env, &ctx.token); + let stellar_asset_client: token::StellarAssetClient = token::StellarAssetClient::new(&ctx.env, &ctx.token); + let amount_i128: i128 = 100000 ; + let amount = &(amount_i128 as u128); + let mint_amount = &(amount_i128+amount_i128); + + stellar_asset_client.mint(&ctx.depositor, mint_amount); + + ctx.mint_native_token(&ctx.depositor, 500); + assert_eq!(ctx.get_native_token_balance(&ctx.depositor), 500); + + token_client.approve(&ctx.depositor, &ctx.registry, &(amount_i128+amount_i128), &1312000); + client.deposit(&ctx.depositor, &ctx.token, &amount, &Option::Some(String::from_str(&ctx.env, "")), &Option::Some(Bytes::from_array(&ctx.env, &[0u8; 32]))); + + let limit = client.get_withdraw_limit(&ctx.token); + assert_eq!(limit, 30000); + let verified = client.verify_withdraw(&ctx.token, &(amount-30000+1)); + assert_eq!(verified, true); } #[test] @@ -123,8 +215,8 @@ fn test_deposit_with_to_and_data(){ 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F, 0x20, ]; client.deposit(&ctx.depositor, &ctx.token, &amount, &Option::Some(String::from_str(&ctx.env, "icon01/hxjkdvhui")), &Option::Some(Bytes::from_array(&ctx.env, &data))); + assert_eq!(ctx.get_native_token_balance(&ctx.depositor), 400); // why 300? - assert_eq!(ctx.get_native_token_balance(&ctx.depositor), 400) // why 300? } @@ -154,6 +246,87 @@ fn test_handle_call_message_for_withdraw_to(){ assert_eq!(token_client.balance(&ctx.withdrawer), bnusd_amount as i128) } +#[test] +#[should_panic(expected = "HostError: Error(Contract, #7)")] +fn test_handle_call_message_for_withdraw_to_panic_with_protocal_mismatch(){ + let ctx = TestContext::default(); + let client = AssetManagerClient::new(&ctx.env, &ctx.registry); + ctx.env.mock_all_auths(); + + ctx.init_context(&client); + client.configure_rate_limit( &ctx.token, &300, &300 ); + + let bnusd_amount = 100000 as u128; + let token_client = token::Client::new(&ctx.env, &ctx.token); + let stellar_asset_client: token::StellarAssetClient = token::StellarAssetClient::new(&ctx.env, &ctx.token); + stellar_asset_client.mint(&ctx.registry, &((bnusd_amount*2) as i128)); + + let data = WithdrawTo::new(ctx.token.to_string(), ctx.withdrawer.to_string(), bnusd_amount).encode(&ctx.env, String::from_str(&ctx.env, "WithdrawTo")); + let decoded = WithdrawTo::decode(&ctx.env, data.clone()); + assert_eq!(decoded.to, ctx.withdrawer.to_string()); + + assert_eq!(token_client.balance(&ctx.withdrawer), 0); + + let sources = Vec::from_array(&ctx.env, [ctx.xcall.to_string()]); + client.handle_call_message(&ctx.xcall, &ctx.icon_asset_manager, &data, &sources); + + assert_eq!(token_client.balance(&ctx.withdrawer), bnusd_amount as i128) +} + +#[test] +#[should_panic(expected = "HostError: Error(Contract, #8)")] +fn test_handle_call_message_for_withdraw_to_panic_with_not_icon_asset_manager(){ + let ctx = TestContext::default(); + let client = AssetManagerClient::new(&ctx.env, &ctx.registry); + ctx.env.mock_all_auths(); + + ctx.init_context(&client); + client.configure_rate_limit( &ctx.token, &300, &300 ); + + let bnusd_amount = 100000 as u128; + let token_client = token::Client::new(&ctx.env, &ctx.token); + let stellar_asset_client: token::StellarAssetClient = token::StellarAssetClient::new(&ctx.env, &ctx.token); + stellar_asset_client.mint(&ctx.registry, &((bnusd_amount*2) as i128)); + + let data = WithdrawTo::new(ctx.token.to_string(), ctx.withdrawer.to_string(), bnusd_amount).encode(&ctx.env, String::from_str(&ctx.env, "WithdrawTo")); + let decoded = WithdrawTo::decode(&ctx.env, data.clone()); + assert_eq!(decoded.to, ctx.withdrawer.to_string()); + + assert_eq!(token_client.balance(&ctx.withdrawer), 0); + + let sources = Vec::from_array(&ctx.env, [ctx.centralized_connection.to_string()]); + client.handle_call_message(&ctx.xcall, &ctx.centralized_connection.to_string(), &data, &sources); + + assert_eq!(token_client.balance(&ctx.withdrawer), bnusd_amount as i128) +} + +#[test] +#[should_panic(expected = "HostError: Error(Contract, #10)")] +fn test_handle_call_message_for_withdraw_to_panic_with_unknown_message_type(){ + let ctx = TestContext::default(); + let client = AssetManagerClient::new(&ctx.env, &ctx.registry); + ctx.env.mock_all_auths(); + + ctx.init_context(&client); + client.configure_rate_limit( &ctx.token, &300, &300 ); + + let bnusd_amount = 100000 as u128; + let token_client = token::Client::new(&ctx.env, &ctx.token); + let stellar_asset_client: token::StellarAssetClient = token::StellarAssetClient::new(&ctx.env, &ctx.token); + stellar_asset_client.mint(&ctx.registry, &((bnusd_amount*2) as i128)); + + let data = WithdrawTo::new(ctx.token.to_string(), ctx.withdrawer.to_string(), bnusd_amount).encode(&ctx.env, String::from_str(&ctx.env, "WithdrawToUnknown")); + let decoded = WithdrawTo::decode(&ctx.env, data.clone()); + assert_eq!(decoded.to, ctx.withdrawer.to_string()); + + assert_eq!(token_client.balance(&ctx.withdrawer), 0); + + let sources = Vec::from_array(&ctx.env, [ctx.centralized_connection.to_string()]); + client.handle_call_message(&ctx.xcall, &ctx.icon_asset_manager, &data, &sources); + + assert_eq!(token_client.balance(&ctx.withdrawer), bnusd_amount as i128) +} + #[test] fn test_handle_call_message_for_deposit_rollback(){ let ctx = TestContext::default(); @@ -177,5 +350,32 @@ fn test_handle_call_message_for_deposit_rollback(){ let sources = Vec::from_array(&ctx.env, [ctx.centralized_connection.to_string()]); client.handle_call_message(&ctx.xcall, &ctx.xcall_client.get_network_address(), &data, &sources); + assert_eq!(token_client.balance(&ctx.withdrawer), bnusd_amount as i128) +} + +#[test] +#[should_panic(expected = "HostError: Error(Contract, #9)")] +fn test_handle_call_message_for_deposit_rollback_panic_with_only_call_service(){ + let ctx = TestContext::default(); + let client = AssetManagerClient::new(&ctx.env, &ctx.registry); + ctx.env.mock_all_auths(); + + ctx.init_context(&client); + client.configure_rate_limit( &ctx.token, &300, &300 ); + + let bnusd_amount = 100000 as u128; + let token_client = token::Client::new(&ctx.env, &ctx.token); + let stellar_asset_client: token::StellarAssetClient = token::StellarAssetClient::new(&ctx.env, &ctx.token); + stellar_asset_client.mint(&ctx.registry, &((bnusd_amount*2) as i128)); + + let data = DepositRevert::new(ctx.token, ctx.withdrawer.clone(), bnusd_amount).encode(&ctx.env, String::from_str(&ctx.env, "DepositRevert")); + let decoded = DepositRevert::decode(&ctx.env, data.clone()); + assert_eq!(decoded.to, ctx.withdrawer); + + assert_eq!(token_client.balance(&ctx.withdrawer), 0); + + let sources = Vec::from_array(&ctx.env, [ctx.centralized_connection.to_string()]); + client.handle_call_message(&ctx.xcall, &ctx.xcall_manager.to_string(), &data, &sources); + assert_eq!(token_client.balance(&ctx.withdrawer), bnusd_amount as i128) } \ No newline at end of file diff --git a/contracts/balanced_doller/src/balanced_dollar.rs b/contracts/balanced_doller/src/balanced_dollar.rs index d2aad51..21860d5 100644 --- a/contracts/balanced_doller/src/balanced_dollar.rs +++ b/contracts/balanced_doller/src/balanced_dollar.rs @@ -1,103 +1,128 @@ -use soroban_sdk::{Address, Bytes, Env, String, Vec}; +use soroban_sdk::{panic_with_error, Address, Bytes, Env, String, Vec}; +use crate::balance::{spend_balance, receive_balance}; mod xcall { soroban_sdk::contractimport!(file = "../../wasm/xcall.wasm"); } use soroban_rlp::messages::{cross_transfer::CrossTransfer, cross_transfer_revert::CrossTransferRevert}; +use crate::storage_types::{INSTANCE_BUMP_AMOUNT, INSTANCE_LIFETIME_THRESHOLD}; use crate::{ - config::{ get_config, set_config, ConfigData}, contract::BalancedDollar, xcall_manager_interface::XcallManagerClient + config::{ get_config, set_config, ConfigData}, xcall_manager_interface::XcallManagerClient }; use crate::errors::ContractError; use xcall::{AnyMessage, CallMessageWithRollback, Client, Envelope}; +use soroban_token_sdk::TokenUtils; +use crate::contract; +use crate::admin::read_administrator; const CROSS_TRANSFER: &str = "xCrossTransfer"; const CROSS_TRANSFER_REVERT: &str = "xCrossTransferRevert"; + +pub fn configure(env:Env, config: ConfigData){ + set_config(&env, config); +} -impl BalancedDollar { - - pub fn configure(env:Env, config: ConfigData){ - set_config(&env, config); - } +pub fn _cross_transfer( + e: Env, + from: Address, + amount: u128, + to: String, + data: Bytes +) -> Result<(), ContractError> { + _burn(e.clone(), from.clone(), amount as i128); + let xcall_message = CrossTransfer::new( + from.clone().to_string(), + to, + amount, + data + ); + + let rollback = CrossTransferRevert::new( + from.clone(), + amount + ); + + let rollback_bytes = rollback.encode(&e, String::from_str(&e.clone(), CROSS_TRANSFER_REVERT)); + let message_bytes = xcall_message.encode(&e, String::from_str(&e.clone(), CROSS_TRANSFER)); + let (sources, destinations) = xcall_manager_client(e.clone()).get_protocols(); + + let message = AnyMessage::CallMessageWithRollback(CallMessageWithRollback { data: message_bytes, rollback: rollback_bytes }); + let envelope: &Envelope = &Envelope { + message, + sources, + destinations + }; + let icon_bn_usd = &get_config(&e).icon_bn_usd; + let current_address = e.clone().current_contract_address(); + xcall_client(e).send_call(&from, ¤t_address, envelope, icon_bn_usd ); + Ok(()) - pub fn _cross_transfer( - e: Env, - from: Address, - amount: u128, - to: String, - data: Bytes - ) -> Result<(), ContractError> { - //todo:: fix and uncomment the below line - //Self::burn(e.clone(), from.clone(), amount as i128); - let xcall_message = CrossTransfer::new( - from.clone().to_string(), - to, - amount, - data - ); - - let rollback = CrossTransferRevert::new( - from.clone(), - amount - ); - - let rollback_bytes = rollback.encode(&e, String::from_str(&e.clone(), CROSS_TRANSFER_REVERT)); - let message_bytes = xcall_message.encode(&e, String::from_str(&e.clone(), CROSS_TRANSFER)); - let (sources, destinations) = Self::xcall_manager(e.clone()).get_protocols(); - - let message = AnyMessage::CallMessageWithRollback(CallMessageWithRollback { data: message_bytes, rollback: rollback_bytes }); - let envelope: &Envelope = &Envelope { - message, - sources, - destinations - }; - let icon_bn_usd = &get_config(&e).icon_bn_usd; - let current_address = e.clone().current_contract_address(); - Self::xcall_client(e).send_call(&from, ¤t_address, envelope, icon_bn_usd ); - Ok(()) +} - } - - pub fn _handle_call_message( - e: Env, - from: String, - data: Bytes, - protocols: Vec - ) { - let xcall = get_config(&e).xcall; - xcall.require_auth(); - if !Self::xcall_manager(e.clone()).verify_protocols(&protocols) { - panic!("Protocol Mismatch"); - }; - - let method = CrossTransfer::get_method(&e, data.clone()); - let icon_bn_usd = get_config(&e).icon_bn_usd; - if method == String::from_str(&e, &CROSS_TRANSFER){ - if from!=icon_bn_usd { - panic!("onlyICONBnUSD"); - } - let message = CrossTransfer::decode(&e.clone(), data); - Self::mint(e.clone(), Address::from_string( &message.to), u128::try_into(message.amount).unwrap()); - } else if method == String::from_str(&e, &CROSS_TRANSFER_REVERT){ - if from!=xcall.to_string() { - panic!("onlyCallService"); - } - let message = CrossTransferRevert::decode(&e.clone(), data); - Self::mint(e.clone(), message.to, u128::try_into(message.amount).unwrap()); - }else{ - panic!("Unknown message type") +pub fn _handle_call_message( + e: Env, + from: String, + data: Bytes, + protocols: Vec +) { + let xcall = get_config(&e).xcall; + xcall.require_auth(); + if !xcall_manager_client(e.clone()).verify_protocols(&protocols) { + panic_with_error!(e, ContractError::ProtocolMismatch) + }; + + let method = CrossTransfer::get_method(&e, data.clone()); + let icon_bn_usd = get_config(&e).icon_bn_usd; + if method == String::from_str(&e, &CROSS_TRANSFER){ + if from!=icon_bn_usd { + panic_with_error!(e, ContractError::onlyICONBnUSD) + } + let message = CrossTransfer::decode(&e.clone(), data); + _mint(e.clone(), Address::from_string( &message.to), u128::try_into(message.amount).unwrap()); + } else if method == String::from_str(&e, &CROSS_TRANSFER_REVERT){ + if from!=xcall.to_string() { + panic_with_error!(e, ContractError::OnlyCallService) } + let message = CrossTransferRevert::decode(&e.clone(), data); + _mint(e.clone(), message.to, u128::try_into(message.amount).unwrap()); + }else{ + panic_with_error!(e, ContractError::UnknownMessageType) } +} - fn xcall_client(e: Env) -> Client<'static> { - return xcall::Client::new(&e, &get_config(&e).xcall); - } +pub fn _mint(e: Env, to: Address, amount: i128) { + contract::check_nonnegative_amount(amount); + let admin = read_administrator(&e); + + e.storage() + .instance() + .extend_ttl(INSTANCE_LIFETIME_THRESHOLD, INSTANCE_BUMP_AMOUNT); - fn xcall_manager(e: Env) -> XcallManagerClient<'static> { - let client = XcallManagerClient::new(&e, &get_config(&e).xcall_manager); - return client; - } -} \ No newline at end of file + receive_balance(&e, to.clone(), amount); + TokenUtils::new(&e).events().mint(admin, to, amount); +} + +pub fn _burn(e: Env, from: Address, amount: i128) { + contract::check_nonnegative_amount(amount); + + e.storage() + .instance() + .extend_ttl(INSTANCE_LIFETIME_THRESHOLD, INSTANCE_BUMP_AMOUNT); + + spend_balance(&e, from.clone(), amount); + TokenUtils::new(&e).events().burn(from, amount); +} + + +fn xcall_client(e: Env) -> Client<'static> { + return xcall::Client::new(&e, &get_config(&e).xcall); +} + +fn xcall_manager_client(e: Env) -> XcallManagerClient<'static> { + let client = XcallManagerClient::new(&e, &get_config(&e).xcall_manager); + return client; +} diff --git a/contracts/balanced_doller/src/contract.rs b/contracts/balanced_doller/src/contract.rs index 4f4d987..4962d1f 100644 --- a/contracts/balanced_doller/src/contract.rs +++ b/contracts/balanced_doller/src/contract.rs @@ -7,10 +7,12 @@ use crate::config::ConfigData; use crate::metadata::{read_decimal, read_name, read_symbol, write_metadata}; use crate::storage_types::{INSTANCE_BUMP_AMOUNT, INSTANCE_LIFETIME_THRESHOLD}; use soroban_sdk::token::{self, Interface as _}; -use soroban_sdk::{contract, contractimpl, Address, Env, String, Bytes, Vec}; +use soroban_sdk::{contract, contractimpl, panic_with_error, Address, Bytes, Env, String, Vec}; use soroban_token_sdk::metadata::TokenMetadata; use soroban_token_sdk::TokenUtils; -fn check_nonnegative_amount(amount: i128) { +use crate::balanced_dollar; +use crate::errors::ContractError; +pub fn check_nonnegative_amount(amount: i128) { if amount < 0 { panic!("negative amount is not allowed: {}", amount) } @@ -23,7 +25,7 @@ pub struct BalancedDollar; impl BalancedDollar { pub fn initialize(e: Env, admin: Address, config: ConfigData) { if has_administrator(&e) { - panic!("already initialized") + panic_with_error!(e, ContractError::ContractAlreadyInitialized) } write_administrator(&e, &admin); @@ -33,7 +35,7 @@ impl BalancedDollar { let symbol = String::from_str(&e, "bnUSD"); if decimal > u8::MAX.into() { - panic!("Decimal must fit in a u8"); + panic_with_error!(e, ContractError::DecimalMustFitInAu8) } write_metadata( @@ -44,20 +46,14 @@ impl BalancedDollar { symbol, }, ); - Self::configure(e, config ); + balanced_dollar::configure(e, config ); } pub fn mint(e: Env, to: Address, amount: i128) { - check_nonnegative_amount(amount); let admin = read_administrator(&e); - //admin.require_auth(); - - e.storage() - .instance() - .extend_ttl(INSTANCE_LIFETIME_THRESHOLD, INSTANCE_BUMP_AMOUNT); - - receive_balance(&e, to.clone(), amount); - TokenUtils::new(&e).events().mint(admin, to, amount); + admin.require_auth(); + + balanced_dollar::_mint(e, to, amount) } pub fn set_admin(e: Env, new_admin: Address) { @@ -72,6 +68,10 @@ impl BalancedDollar { TokenUtils::new(&e).events().set_admin(admin, new_admin); } + pub fn get_admin(e: Env) -> Address { + read_administrator(&e) + } + pub fn cross_transfer( e: Env, from: Address, @@ -79,7 +79,7 @@ impl BalancedDollar { to: String, ) { from.require_auth(); - Self::_cross_transfer(e.clone(), from, amount, to, Bytes::new(&e)).unwrap(); + balanced_dollar::_cross_transfer(e.clone(), from, amount, to, Bytes::new(&e)).unwrap(); } pub fn cross_transfer_data( @@ -90,7 +90,7 @@ impl BalancedDollar { data: Bytes ) { from.require_auth(); - Self::_cross_transfer(e, from, amount, to, data).unwrap(); + balanced_dollar::_cross_transfer(e, from, amount, to, data).unwrap(); } pub fn handle_call_message( @@ -99,7 +99,7 @@ impl BalancedDollar { data: Bytes, protocols: Vec ) { - Self::_handle_call_message(e, from, data, protocols); + balanced_dollar::_handle_call_message(e, from, data, protocols); } pub fn is_initialized(e: Env) -> Address { @@ -168,16 +168,7 @@ impl token::Interface for BalancedDollar { } fn burn(e: Env, from: Address, amount: i128) { - from.require_auth(); - - check_nonnegative_amount(amount); - - e.storage() - .instance() - .extend_ttl(INSTANCE_LIFETIME_THRESHOLD, INSTANCE_BUMP_AMOUNT); - - spend_balance(&e, from.clone(), amount); - TokenUtils::new(&e).events().burn(from, amount); + balanced_dollar::_burn(e, from, amount); } fn burn_from(e: Env, spender: Address, from: Address, amount: i128) { diff --git a/contracts/balanced_doller/src/errors.rs b/contracts/balanced_doller/src/errors.rs index f48b14f..867eb06 100644 --- a/contracts/balanced_doller/src/errors.rs +++ b/contracts/balanced_doller/src/errors.rs @@ -4,5 +4,11 @@ use soroban_sdk::contracterror; #[repr(u32)] #[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord)] pub enum ContractError { - InvalidRlpLength = 1 + InvalidRlpLength = 1, + ContractAlreadyInitialized = 2, + DecimalMustFitInAu8 = 3, + ProtocolMismatch = 4, + onlyICONBnUSD = 5, + OnlyCallService = 6, + UnknownMessageType = 7, } \ No newline at end of file diff --git a/contracts/balanced_doller/src/tests/balanced_dollar_test.rs b/contracts/balanced_doller/src/tests/balanced_dollar_test.rs index 210dfc2..ff8da24 100644 --- a/contracts/balanced_doller/src/tests/balanced_dollar_test.rs +++ b/contracts/balanced_doller/src/tests/balanced_dollar_test.rs @@ -5,7 +5,7 @@ use crate::contract::BalancedDollarClient; use soroban_rlp::messages::{cross_transfer::CrossTransfer, cross_transfer_revert::CrossTransferRevert}; use soroban_sdk::{ - token, Bytes, String, Vec + symbol_short, testutils::{Address as _, AuthorizedFunction, AuthorizedInvocation}, vec, xdr::FromXdr, Address, Bytes, IntoVal, String, Symbol, Val, Vec }; use super::setup::*; @@ -18,8 +18,36 @@ fn test_initialize() { let registry_exists = client.is_initialized(); assert_eq!(registry_exists, ctx.admin) + } +#[test] +fn test_set_admin() { + let ctx = TestContext::default(); + let client = BalancedDollarClient::new(&ctx.env, &ctx.registry); + ctx.init_context(&client); + + let new_admin: Address = Address::generate(&ctx.env); + client.set_admin(&new_admin); + assert_eq!( + ctx.env.auths(), + std::vec![ + ( + ctx.admin.clone(), + AuthorizedInvocation { + function: AuthorizedFunction::Contract(( + ctx.registry.clone(), + symbol_short!("set_admin"), + (&new_admin,) + .into_val(&ctx.env) + )), + sub_invocations: std::vec![] + } + ) + ] + ); + assert_eq!(client.get_admin(), new_admin); +} #[test] fn test_cross_transfer_with_to_and_data(){ @@ -71,6 +99,94 @@ fn test_handle_call_message_for_cross_transfer(){ assert_eq!(client.balance(&ctx.withdrawer), 0); + let sources = Vec::from_array(&ctx.env, [ctx.centralized_connection.to_string()]); + client.handle_call_message( &ctx.icon_bn_usd, &data, &sources); + assert_eq!(client.balance(&ctx.withdrawer), bnusd_amount as i128) + + +} + +#[test] +#[should_panic(expected = "HostError: Error(Contract, #4)")] +fn test_handle_call_message_for_cross_transfer_panic_for_protocol_mismatch(){ + let ctx = TestContext::default(); + let client = BalancedDollarClient::new(&ctx.env, &ctx.registry); + ctx.env.mock_all_auths(); + + ctx.init_context(&client); + + let bnusd_amount = 100000 as u128; + + let items: [u8; 32] = [ + 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, + 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0x10, + 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, + 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F, 0x20, + ]; + let data = CrossTransfer::new(ctx.depositor.to_string(), ctx.withdrawer.to_string(), bnusd_amount, Bytes::from_array(&ctx.env, &items)).encode(&ctx.env, String::from_str(&ctx.env, "xCrossTransfer")); + let decoded = CrossTransfer::decode(&ctx.env, data.clone()); + assert_eq!(decoded.to, ctx.withdrawer.to_string()); + + assert_eq!(client.balance(&ctx.withdrawer), 0); + + let sources = Vec::from_array(&ctx.env, [ctx.xcall.to_string()]); + client.handle_call_message( &ctx.icon_bn_usd, &data, &sources); + + assert_eq!(client.balance(&ctx.withdrawer), bnusd_amount as i128) +} + +#[test] +#[should_panic(expected = "HostError: Error(Contract, #5)")] +fn test_handle_call_message_for_cross_transfer_panic_for_icon_bnusd(){ + let ctx = TestContext::default(); + let client = BalancedDollarClient::new(&ctx.env, &ctx.registry); + ctx.env.mock_all_auths(); + + ctx.init_context(&client); + + let bnusd_amount = 100000 as u128; + + let items: [u8; 32] = [ + 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, + 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0x10, + 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, + 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F, 0x20, + ]; + let data = CrossTransfer::new(ctx.depositor.to_string(), ctx.withdrawer.to_string(), bnusd_amount, Bytes::from_array(&ctx.env, &items)).encode(&ctx.env, String::from_str(&ctx.env, "xCrossTransfer")); + let decoded = CrossTransfer::decode(&ctx.env, data.clone()); + assert_eq!(decoded.to, ctx.withdrawer.to_string()); + + assert_eq!(client.balance(&ctx.withdrawer), 0); + + let sources = Vec::from_array(&ctx.env, [ctx.centralized_connection.to_string()]); + client.handle_call_message( &ctx.icon_governance, &data, &sources); + + assert_eq!(client.balance(&ctx.withdrawer), bnusd_amount as i128) +} + +#[test] +#[should_panic(expected = "HostError: Error(Contract, #7)")] +fn test_handle_call_message_for_cross_transfer_panic_for_wront_message_type(){ + let ctx = TestContext::default(); + let client = BalancedDollarClient::new(&ctx.env, &ctx.registry); + ctx.env.mock_all_auths(); + + ctx.init_context(&client); + + let bnusd_amount = 100000 as u128; + + let items: [u8; 32] = [ + 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, + 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0x10, + 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, + 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F, 0x20, + ]; + let data = CrossTransfer::new(ctx.depositor.to_string(), ctx.withdrawer.to_string(), bnusd_amount, Bytes::from_array(&ctx.env, &items)).encode(&ctx.env, String::from_str(&ctx.env, "xCrossTransferPanic")); + let decoded = CrossTransfer::decode(&ctx.env, data.clone()); + assert_eq!(decoded.to, ctx.withdrawer.to_string()); + + assert_eq!(client.balance(&ctx.withdrawer), 0); + let sources = Vec::from_array(&ctx.env, [ctx.centralized_connection.to_string()]); client.handle_call_message( &ctx.icon_bn_usd, &data, &sources); @@ -99,3 +215,26 @@ fn test_handle_call_message_for_cross_transfer_revert(){ assert_eq!(client.balance(&ctx.withdrawer), bnusd_amount as i128) } +#[test] +#[should_panic(expected = "HostError: Error(Contract, #6)")] +fn test_handle_call_message_for_cross_transfer_revert_panic_for_xcall(){ + let ctx = TestContext::default(); + let client = BalancedDollarClient::new(&ctx.env, &ctx.registry); + ctx.env.mock_all_auths(); + + ctx.init_context(&client); + + let bnusd_amount = 100000 as u128; + + let data = CrossTransferRevert::new( ctx.withdrawer.clone(), bnusd_amount).encode(&ctx.env, String::from_str(&ctx.env, "xCrossTransferRevert")); + let decoded = CrossTransferRevert::decode(&ctx.env, data.clone()); + assert_eq!(decoded.to, ctx.withdrawer); + + assert_eq!(client.balance(&ctx.withdrawer), 0); + + let sources = Vec::from_array(&ctx.env, [ctx.centralized_connection.to_string()]); + client.handle_call_message( &ctx.centralized_connection.to_string(), &data, &sources); + + assert_eq!(client.balance(&ctx.withdrawer), bnusd_amount as i128) +} + diff --git a/contracts/xcall_manager/src/contract.rs b/contracts/xcall_manager/src/contract.rs index cb89a8e..2a1f2aa 100644 --- a/contracts/xcall_manager/src/contract.rs +++ b/contracts/xcall_manager/src/contract.rs @@ -23,7 +23,7 @@ impl XcallManager { pub fn initialize(env:Env, registry:Address, admin: Address, config: ConfigData, sources: Vec, destinations: Vec) { if has_state(env.clone(), DataKey::Registry) { - panic!("Contract already initialized.") + panic_with_error!(env, ContractError::ContractAlreadyInitialized) } write_address_state(&env, DataKey::Registry, ®istry); write_address_state(&env, DataKey::Admin, &admin); @@ -61,15 +61,19 @@ impl XcallManager { pub fn propose_removal(e: Env, protocol: String) { let admin = read_administrator(&e); admin.require_auth(); - + write_string_state(&e, DataKey::ProposedProtocolToRemove, &protocol); } + pub fn get_proposed_removal(e: Env) -> String { + read_string_state(&e, DataKey::ProposedProtocolToRemove) + } + pub fn verify_protocols( e: Env, protocols: Vec ) -> Result { - let sources = read_vec_string_state(&e, DataKey::Sources); + let sources: Vec = read_vec_string_state(&e, DataKey::Sources); return Self::verify_protocols_unordered(e, protocols, sources); } @@ -113,12 +117,12 @@ impl XcallManager { let icon_governance = get_config(&e.clone()).icon_governance; if from != icon_governance { - panic!("Only ICON Balanced governance is allowed") + panic_with_error!(e, ContractError::OnlyICONGovernance) } if !Self::verify_protocols(e.clone(), protocols.clone()).unwrap() { - panic!("Protocol Mismatch"); + panic_with_error!(e, ContractError::ProtocolMismatch) }; let method = ConfigureProtocols::get_method(&e.clone(), data.clone()); @@ -126,7 +130,7 @@ impl XcallManager { let sources = read_vec_string_state(&e, DataKey::Sources); if !Self::verify_protocols_unordered(e.clone(), protocols.clone(), sources).unwrap() { if method != String::from_str(&e.clone(), CONFIGURE_PROTOCOLS_NAME) { - panic!("Protocol Mismatch"); + panic_with_error!(e, ContractError::ProtocolMismatch) } Self::verify_protocol_recovery(e.clone(), protocols); } @@ -143,7 +147,7 @@ impl XcallManager { write_vec_string_state(&e, DataKey::Sources, &sources); write_vec_string_state(&e, DataKey::Destinations, &destinations); } else { - panic!("Unknown message type"); + panic_with_error!(e, ContractError::UnknownMessageType) } } @@ -151,13 +155,13 @@ impl XcallManager { let modified_sources = Self::get_modified_protocols(e.clone()); let verify_unordered = Self::verify_protocols_unordered(e.clone(), modified_sources, protocols).unwrap(); if !verify_unordered { - panic!("Protocol Mismatch") + panic_with_error!(e, ContractError::ProtocolMismatch) } } pub fn get_modified_protocols(e: Env) -> Vec{ if !has_state(e.clone(), DataKey::ProposedProtocolToRemove) { - panic!( "No proposal for removal exists") + panic_with_error!(e, ContractError::NoProposalForRemovalExists) } let sources = read_vec_string_state(&e, DataKey::Sources); diff --git a/contracts/xcall_manager/src/errors.rs b/contracts/xcall_manager/src/errors.rs index f48b14f..61cb64f 100644 --- a/contracts/xcall_manager/src/errors.rs +++ b/contracts/xcall_manager/src/errors.rs @@ -4,5 +4,13 @@ use soroban_sdk::contracterror; #[repr(u32)] #[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord)] pub enum ContractError { - InvalidRlpLength = 1 + InvalidRlpLength = 1, + ContractAlreadyInitialized = 3, + AmountIsLessThanMinimumAmount = 6, + ProtocolMismatch = 7, + OnlyICONGovernance = 8, + OnlyCallService = 9, + UnknownMessageType = 10, + AdminRequired = 11, + NoProposalForRemovalExists = 12 } \ No newline at end of file diff --git a/contracts/xcall_manager/src/tests/xcall_manager_test.rs b/contracts/xcall_manager/src/tests/xcall_manager_test.rs index 199321c..917a57e 100644 --- a/contracts/xcall_manager/src/tests/xcall_manager_test.rs +++ b/contracts/xcall_manager/src/tests/xcall_manager_test.rs @@ -4,7 +4,7 @@ extern crate std; use crate::contract::XcallManagerClient; use soroban_sdk::{ - Vec, String + symbol_short, testutils::{Address as _, AuthorizedFunction, AuthorizedInvocation}, Address, IntoVal, String, Vec, vec }; use soroban_rlp::messages::configure_protocols::ConfigureProtocols; use super::setup::*; @@ -24,6 +24,51 @@ fn test_initialize() { } +#[test] +fn test_set_admin() { + let ctx = TestContext::default(); + let client = XcallManagerClient::new(&ctx.env, &ctx.registry); + ctx.init_context(&client); + + let new_admin: Address = Address::generate(&ctx.env); + client.set_admin(&new_admin); + assert_eq!( + ctx.env.auths(), + std::vec![ + ( + ctx.admin.clone(), + AuthorizedInvocation { + function: AuthorizedFunction::Contract(( + ctx.registry.clone(), + symbol_short!("set_admin"), + (&new_admin,) + .into_val(&ctx.env) + )), + sub_invocations: std::vec![] + } + ) + ] + ); + assert_eq!(client.get_admin(), new_admin); +} + +#[test] +#[should_panic(expected = "HostError: Error(Contract, #3)")] +fn test_initialize_panic_already_initialized() { + let ctx = TestContext::default(); + let client = XcallManagerClient::new(&ctx.env, &ctx.registry); + + ctx.init_context(&client); + ctx.init_context(&client); + + let sources = Vec::from_array(&ctx.env, [ctx.centralized_connection.to_string()]); + let destinations = Vec::from_array(&ctx.env, [String::from_str(&ctx.env, "icon/address")]); + let (s, d) = client.get_protocols(); + assert_eq!(s, sources); + assert_eq!(d, destinations); + +} + #[test] fn test_verify_protocols(){ let ctx = TestContext::default(); @@ -36,29 +81,158 @@ fn test_verify_protocols(){ #[test] fn test_handle_call_message_for_configure_protocols(){ - std::println!("first"); let ctx = TestContext::default(); let client = XcallManagerClient::new(&ctx.env, &ctx.registry); ctx.env.mock_all_auths(); - std::println!("second"); ctx.init_context(&client); let source_items = [String::from_str(&ctx.env, "sui/address"), String::from_str(&ctx.env, "sui/address1")]; - std::println!("source_items : {:?}", source_items); let destination_items = [String::from_str(&ctx.env, "icon/address"), String::from_str(&ctx.env, "icon/address1")]; let sources = Vec::from_array(&ctx.env, source_items); let destinations = Vec::from_array(&ctx.env, destination_items); let data = ConfigureProtocols::new(sources.clone(), destinations.clone()).encode(&ctx.env, String::from_str(&ctx.env, "ConfigureProtocols")); - std::println!("encoded data : {:?}", data); let decoded: ConfigureProtocols = ConfigureProtocols::decode(&ctx.env, data.clone()); - std::println!("decoded source : {:?}", decoded.sources); assert_eq!(decoded.sources, sources); assert_eq!(decoded.destinations, destinations); let (s, _) = client.get_protocols(); client.handle_call_message(&ctx.icon_governance, &data, &s); + let (s, d) = client.get_protocols(); + assert_eq!(s, sources); + assert_eq!(d, destinations); +} + +#[test] +fn test_proposal_removal(){ + let ctx = TestContext::default(); + let client = XcallManagerClient::new(&ctx.env, &ctx.registry); + ctx.env.mock_all_auths(); + ctx.init_context(&client); + + client.propose_removal(&String::from_str(&ctx.env, "sui/address")); + assert_eq!(String::from_str(&ctx.env, "sui/address"), client.get_proposed_removal()) +} + +#[test] +fn test_get_modified_proposals(){ + let ctx = TestContext::default(); + let client = XcallManagerClient::new(&ctx.env, &ctx.registry); + ctx.env.mock_all_auths(); + ctx.init_context(&client); + + let source_items = [String::from_str(&ctx.env, "sui/address"), String::from_str(&ctx.env, "sui/address1")]; + let destination_items = [String::from_str(&ctx.env, "icon/address"), String::from_str(&ctx.env, "icon/address1")]; + let sources = Vec::from_array(&ctx.env, source_items); + let destinations = Vec::from_array(&ctx.env, destination_items); + let data = ConfigureProtocols::new(sources.clone(), destinations.clone()).encode(&ctx.env, String::from_str(&ctx.env, "ConfigureProtocols")); + + let (s, _) = client.get_protocols(); + client.handle_call_message(&ctx.icon_governance, &data, &s); + + client.propose_removal(&String::from_str(&ctx.env, "sui/address")); + + let updated_protocal = vec![&ctx.env, String::from_str(&ctx.env, "sui/address1")]; + assert_eq!(updated_protocal, client.get_modified_protocols()); +} + +#[test] +#[should_panic(expected = "HostError: Error(Contract, #12)")] +fn test_get_modified_proposals_panic_no_proposed_removal(){ + let ctx = TestContext::default(); + let client = XcallManagerClient::new(&ctx.env, &ctx.registry); + ctx.env.mock_all_auths(); + ctx.init_context(&client); + + let source_items = [String::from_str(&ctx.env, "sui/address"), String::from_str(&ctx.env, "sui/address1")]; + let destination_items = [String::from_str(&ctx.env, "icon/address"), String::from_str(&ctx.env, "icon/address1")]; + let sources = Vec::from_array(&ctx.env, source_items); + let destinations = Vec::from_array(&ctx.env, destination_items); + let data = ConfigureProtocols::new(sources.clone(), destinations.clone()).encode(&ctx.env, String::from_str(&ctx.env, "ConfigureProtocols")); + + let (s, _) = client.get_protocols(); + client.handle_call_message(&ctx.icon_governance, &data, &s); + + //client.propose_removal(&String::from_str(&ctx.env, "sui/address")); + + let updated_protocal = vec![&ctx.env, String::from_str(&ctx.env, "sui/address1")]; + assert_eq!(updated_protocal, client.get_modified_protocols()); +} + +#[test] +#[should_panic(expected = "HostError: Error(Contract, #8)")] +fn test_handle_call_message_for_configure_protocols_panic_for_only_icon_governance(){ + let ctx = TestContext::default(); + let client = XcallManagerClient::new(&ctx.env, &ctx.registry); + ctx.env.mock_all_auths(); + ctx.init_context(&client); + + + let source_items = [String::from_str(&ctx.env, "sui/address"), String::from_str(&ctx.env, "sui/address1")]; + let destination_items = [String::from_str(&ctx.env, "icon/address"), String::from_str(&ctx.env, "icon/address1")]; + let sources = Vec::from_array(&ctx.env, source_items); + let destinations = Vec::from_array(&ctx.env, destination_items); + let data = ConfigureProtocols::new(sources.clone(), destinations.clone()).encode(&ctx.env, String::from_str(&ctx.env, "ConfigureProtocols")); + let decoded: ConfigureProtocols = ConfigureProtocols::decode(&ctx.env, data.clone()); + + assert_eq!(decoded.sources, sources); + assert_eq!(decoded.destinations, destinations); + let (s, _) = client.get_protocols(); + client.handle_call_message(&ctx.xcall_network_address, &data, &s); + + let (s, d) = client.get_protocols(); + assert_eq!(s, sources); + assert_eq!(d, destinations); +} + +#[test] +#[should_panic(expected = "HostError: Error(Contract, #7)")] +fn test_handle_call_message_for_configure_protocols_panic_for_protocol_mismatch(){ + let ctx = TestContext::default(); + let client = XcallManagerClient::new(&ctx.env, &ctx.registry); + ctx.env.mock_all_auths(); + ctx.init_context(&client); + + + let source_items = [String::from_str(&ctx.env, "sui/address"), String::from_str(&ctx.env, "sui/address1")]; + let destination_items = [String::from_str(&ctx.env, "icon/address"), String::from_str(&ctx.env, "icon/address1")]; + let sources = Vec::from_array(&ctx.env, source_items); + let destinations = Vec::from_array(&ctx.env, destination_items); + let data = ConfigureProtocols::new(sources.clone(), destinations.clone()).encode(&ctx.env, String::from_str(&ctx.env, "ConfigureProtocols")); + let decoded: ConfigureProtocols = ConfigureProtocols::decode(&ctx.env, data.clone()); + + assert_eq!(decoded.sources, sources); + assert_eq!(decoded.destinations, destinations); + let s = Vec::from_array(&ctx.env, [ctx.xcall.to_string()]); + client.handle_call_message(&ctx.icon_governance, &data, &s); + + let (s, d) = client.get_protocols(); + assert_eq!(s, sources); + assert_eq!(d, destinations); +} + +#[test] +#[should_panic(expected = "HostError: Error(Contract, #10)")] +fn test_handle_call_message_for_configure_protocols_panic_for_unknown_mesage_type(){ + let ctx = TestContext::default(); + let client = XcallManagerClient::new(&ctx.env, &ctx.registry); + ctx.env.mock_all_auths(); + ctx.init_context(&client); + + + let source_items = [String::from_str(&ctx.env, "sui/address"), String::from_str(&ctx.env, "sui/address1")]; + let destination_items = [String::from_str(&ctx.env, "icon/address"), String::from_str(&ctx.env, "icon/address1")]; + let sources = Vec::from_array(&ctx.env, source_items); + let destinations = Vec::from_array(&ctx.env, destination_items); + let data = ConfigureProtocols::new(sources.clone(), destinations.clone()).encode(&ctx.env, String::from_str(&ctx.env, "ConfigureProtocolsPanic")); + let decoded: ConfigureProtocols = ConfigureProtocols::decode(&ctx.env, data.clone()); + + assert_eq!(decoded.sources, sources); + assert_eq!(decoded.destinations, destinations); + let s = Vec::from_array(&ctx.env, [ctx.centralized_connection.to_string()]); + client.handle_call_message(&ctx.icon_governance, &data, &s); + let (s, d) = client.get_protocols(); assert_eq!(s, sources); assert_eq!(d, destinations); diff --git a/libs/soroban-rlp/src/messages/configure_protocols.rs b/libs/soroban-rlp/src/messages/configure_protocols.rs index 3c2409d..425d119 100644 --- a/libs/soroban-rlp/src/messages/configure_protocols.rs +++ b/libs/soroban-rlp/src/messages/configure_protocols.rs @@ -2,8 +2,6 @@ use soroban_sdk::{contracttype, Env, String, Bytes, Vec}; use crate::encoder; use crate::decoder; -extern crate std; - #[derive(Clone)] #[contracttype] pub struct ConfigureProtocols { @@ -39,17 +37,13 @@ impl ConfigureProtocols{ } pub fn decode(e: &Env, bytes: Bytes) -> ConfigureProtocols { - std::println!("encoded bytes: {:?}", bytes); let decoded = decoder::decode_list(&e, bytes); - std::println!("decoded bytes: {:?}", decoded); if decoded.len() != 3 { panic!("InvalidRlpLength"); } let sources = decoder::decode_strings(e, decoded.get(1).unwrap()); let destinations = decoder::decode_strings(e, decoded.get(2).unwrap()); - // std::println!("vec sources: {:?}", sources); - // std::println!("vec destinations: {:?}", destinations); Self { sources, destinations From c65d215ea2f462026e8582ea584ca5d5dd3ab2f5 Mon Sep 17 00:00:00 2001 From: sagar sapkota Date: Fri, 31 May 2024 10:47:40 +0545 Subject: [PATCH 05/63] storate and extend ttl updates --- .gitignore | 3 +- contracts/asset_manager/src/admin.rs | 18 --- contracts/asset_manager/src/contract.rs | 62 +++++---- contracts/asset_manager/src/errors.rs | 3 +- contracts/asset_manager/src/lib.rs | 1 - contracts/asset_manager/src/states.rs | 118 ++++++++++++++---- contracts/asset_manager/src/storage_types.rs | 11 +- .../src/tests/asset_manager_test.rs | 13 +- contracts/balanced_doller/src/contract.rs | 41 ++---- contracts/balanced_doller/src/states.rs | 48 ++----- .../balanced_doller/src/storage_types.rs | 13 -- .../src/tests/balanced_dollar_test.rs | 16 ++- contracts/xcall_manager/src/contract.rs | 44 ++++--- contracts/xcall_manager/src/states.rs | 57 +++++++-- contracts/xcall_manager/src/storage_types.rs | 8 -- contracts/xcall_manager/src/test.rs | 0 .../src/tests/xcall_manager_test.rs | 10 ++ 17 files changed, 258 insertions(+), 208 deletions(-) delete mode 100644 contracts/asset_manager/src/admin.rs delete mode 100644 contracts/xcall_manager/src/test.rs diff --git a/.gitignore b/.gitignore index 8127c54..5e72518 100644 --- a/.gitignore +++ b/.gitignore @@ -9,5 +9,4 @@ target .DS_Store Cargo.lock test_snapshots -xcall.wasm -centralized_connection.wasm \ No newline at end of file +wasm \ No newline at end of file diff --git a/contracts/asset_manager/src/admin.rs b/contracts/asset_manager/src/admin.rs deleted file mode 100644 index 76b7683..0000000 --- a/contracts/asset_manager/src/admin.rs +++ /dev/null @@ -1,18 +0,0 @@ -use soroban_sdk::{Address, Env}; -extern crate std; -use crate::storage_types::DataKey; - -pub fn has_administrator(e: &Env) -> bool { - let key = DataKey::Admin; - e.storage().instance().has(&key) -} - -pub fn read_administrator(e: &Env) -> Address { - let key = DataKey::Admin; - e.storage().instance().get(&key).unwrap() -} - -pub fn write_administrator(e: &Env, id: &Address) { - let key = DataKey::Admin; - e.storage().instance().set(&key, id); -} \ No newline at end of file diff --git a/contracts/asset_manager/src/contract.rs b/contracts/asset_manager/src/contract.rs index c237b44..fc733ee 100644 --- a/contracts/asset_manager/src/contract.rs +++ b/contracts/asset_manager/src/contract.rs @@ -6,10 +6,11 @@ mod xcall { } use soroban_rlp::messages::{deposit::Deposit, deposit_revert::DepositRevert, withdraw_to::WithdrawTo}; use crate::{ - admin::{read_administrator, write_administrator}, config::{get_config, set_config, ConfigData}, - states:: {has_state, read_u128_state, read_u64_state, write_address_state, write_u128_state, write_u64_state }, - storage_types::{DataKey, INSTANCE_BUMP_AMOUNT, INSTANCE_LIFETIME_THRESHOLD, POINTS}, xcall_manager_interface::XcallManagerClient + states:: {has_registry, read_administrator, read_token_last_current_limit, read_token_last_update, + read_token_percentage, read_token_period, write_administrator, write_registry, write_token_current_limit, + write_token_last_update, write_token_percentage, write_token_period, extent_ttl, read_tokens, write_tokens}, + storage_types::{DataKey, POINTS}, xcall_manager_interface::XcallManagerClient }; use crate::errors::ContractError; @@ -27,11 +28,11 @@ pub struct AssetManager; impl AssetManager { pub fn initialize(env:Env, registry:Address, admin: Address, config: ConfigData) { - if has_state(env.clone(), DataKey::Registry) { + if has_registry(&env.clone()) { panic_with_error!(&env, ContractError::ContractAlreadyInitialized) } - write_address_state(&env, DataKey::Registry, ®istry); + write_registry(&env, ®istry); write_administrator(&env, &admin); Self::configure(env, config); } @@ -44,10 +45,6 @@ impl AssetManager { let admin = read_administrator(&e); admin.require_auth(); - e.storage() - .instance() - .extend_ttl(INSTANCE_LIFETIME_THRESHOLD, INSTANCE_BUMP_AMOUNT); - write_administrator(&e, &new_admin); } @@ -70,31 +67,38 @@ impl AssetManager { ) { let admin = read_administrator(&env.clone()); admin.require_auth(); + let tokens = read_tokens(&env.clone()); + if tokens.contains(&token) { + panic_with_error!(&env.clone(), ContractError::TokenExists) + }else{ + write_tokens(&env, token.clone()); + }; + if percentage > POINTS { - panic_with_error!(&env, ContractError::PercentageShouldBeLessThanOrEqualToPOINTS); + panic_with_error!(&env.clone(), ContractError::PercentageShouldBeLessThanOrEqualToPOINTS); } let token_client = token::Client::new(&env, &token); let contract_token_balance = token_client.balance(&env.current_contract_address()); - write_u128_state(&env, DataKey::Period(token.clone()), &period); - write_u128_state(&env, DataKey::Percentage(token.clone()), &percentage); - write_u64_state(&env, DataKey::LastUpdate(token.clone()), &env.ledger().timestamp()); - write_u128_state(&env, DataKey::CurrentLimit(token.clone()), &((contract_token_balance as u128) * percentage/POINTS)); + write_token_period(&env.clone(), &token.clone(), period); + write_token_percentage(&env.clone(), &token.clone(), percentage); + write_token_last_update(&env.clone(), &token.clone(), env.ledger().timestamp()); + write_token_current_limit(&env.clone(), &token.clone(), (contract_token_balance as u128) * percentage/POINTS); } - pub fn get_rate_limit(env: Env, token: Address ) -> (u128, u128, u128, u128){ + pub fn get_rate_limit(env: Env, token: Address ) -> (u128, u128, u64, u128){ ( - read_u128_state(&env, DataKey::Period(token.clone())), - read_u128_state(&env, DataKey::Percentage(token.clone())), - read_u128_state(&env, DataKey::LastUpdate(token.clone())), - read_u128_state(&env, DataKey::CurrentLimit(token.clone())), + read_token_period(&env, &token.clone()), + read_token_percentage(&env, &token.clone()), + read_token_last_update(&env, &token.clone()), + read_token_last_current_limit(&env, &token.clone()), ) } pub fn reset_limit(env: Env, token: Address){ let token_client = token::Client::new(&env, &token); let contract_token_balance = token_client.balance(&env.current_contract_address()); - let percentage: u128 = read_u128_state(&env, DataKey::Percentage(token.clone())); + let percentage: u128 = read_token_percentage(&env, &token.clone()); env.storage().instance().set(&DataKey::CurrentLimit(token.clone()), &(u128::try_from(contract_token_balance).unwrap()*percentage/POINTS)); } @@ -109,14 +113,14 @@ impl AssetManager { let limit = Self::calculate_limit(env.clone(), token.clone())?; if balance - amount < limit { panic_with_error!(&env, ContractError::ExceedsWithdrawLimit); }; - write_u128_state(&env, DataKey::CurrentLimit(token.clone()), &limit); - write_u64_state(&env, DataKey::LastUpdate(token.clone()), &env.ledger().timestamp()); + write_token_current_limit(&env, &token.clone(), limit); + write_token_last_update(&env, &token.clone(), env.ledger().timestamp()); Ok(true) } pub fn calculate_limit(env: Env, token: Address) -> Result { - let period: u128 = read_u128_state(&env, DataKey::Period(token.clone())); - let percentage: u128 = read_u128_state(&env, DataKey::Percentage(token.clone())); + let period: u128 = read_token_period(&env, &token.clone()); + let percentage: u128 = read_token_percentage(&env, &token.clone()); if period == 0 { return Ok(0); } @@ -127,11 +131,11 @@ impl AssetManager { let max_limit = (balance * percentage) / POINTS; let max_withdraw = balance - max_limit; - let last_update: u64 = read_u64_state(&env, DataKey::LastUpdate(token.clone())); + let last_update: u64 = read_token_last_update(&env, &token.clone()); let time_diff = &env.ledger().timestamp() - last_update; let added_allowed_withdrawal = (max_withdraw * u128::from(time_diff)) / period; - let current_limit: u128 = read_u128_state(&env, DataKey::CurrentLimit(token.clone())); + let current_limit: u128 = read_token_last_current_limit(&env, &token.clone()); let limit: u128 = current_limit - added_allowed_withdrawal; let limit = if balance < limit { balance } else { limit }; @@ -260,7 +264,7 @@ impl AssetManager { } pub fn has_registry(e: Env) -> bool { - has_state(e, DataKey::Registry) + has_registry(&e) } pub fn upgrade(e: Env, new_wasm_hash: BytesN<32>) { @@ -270,4 +274,8 @@ impl AssetManager { e.deployer().update_current_contract_wasm(new_wasm_hash); } + pub fn extend_ttl(e: Env){ + extent_ttl(&e); + } + } \ No newline at end of file diff --git a/contracts/asset_manager/src/errors.rs b/contracts/asset_manager/src/errors.rs index aa3163c..8380dc8 100644 --- a/contracts/asset_manager/src/errors.rs +++ b/contracts/asset_manager/src/errors.rs @@ -14,6 +14,7 @@ pub enum ContractError { OnlyICONAssetManager = 8, OnlyCallService = 9, UnknownMessageType = 10, - AdminRequired = 11 + AdminRequired = 11, + TokenExists = 12 } \ No newline at end of file diff --git a/contracts/asset_manager/src/lib.rs b/contracts/asset_manager/src/lib.rs index 3ff002c..b3ed8bd 100644 --- a/contracts/asset_manager/src/lib.rs +++ b/contracts/asset_manager/src/lib.rs @@ -1,6 +1,5 @@ #![no_std] -pub mod admin; pub mod contract; pub mod storage_types; pub mod tests; diff --git a/contracts/asset_manager/src/states.rs b/contracts/asset_manager/src/states.rs index f879bb3..5816d81 100644 --- a/contracts/asset_manager/src/states.rs +++ b/contracts/asset_manager/src/states.rs @@ -1,51 +1,123 @@ -use soroban_sdk::{Address, Env, String, Vec}; +use soroban_sdk::{Address, Env, Vec}; use crate::storage_types::DataKey; -pub fn has_state(env:Env, key: DataKey) -> bool { - env.storage().instance().has(&key) +pub(crate) const DAY_IN_LEDGERS: u32 = 17280; +pub(crate) const INSTANCE_BUMP_AMOUNT: u32 = 30 * DAY_IN_LEDGERS; +pub(crate) const INSTANCE_LIFETIME_THRESHOLD: u32 = INSTANCE_BUMP_AMOUNT - DAY_IN_LEDGERS; + +pub fn has_administrator(e: &Env) -> bool { + let key: DataKey = DataKey::Admin; + e.storage().instance().has(&key) } -pub fn write_string_state(e: &Env, key: DataKey, id: &String) { - e.storage().instance().set(&key, id); +pub fn read_administrator(e: &Env) -> Address { + let key = DataKey::Admin; + e.storage().instance().get(&key).unwrap() } -pub fn write_address_state(e: &Env, key: DataKey, id: &Address) { +pub fn write_administrator(e: &Env, id: &Address) { + let key = DataKey::Admin; e.storage().instance().set(&key, id); } -pub fn write_u64_state(e: &Env, key: DataKey, id: &u64) { - e.storage().instance().set(&key, id); +pub fn has_registry(e: &Env) -> bool { + let key = DataKey::Registry; + e.storage().instance().has(&key) } -pub fn write_u128_state(e: &Env, key: DataKey, id: &u128) { - e.storage().instance().set(&key, id); +pub fn read_registry(e: &Env) -> Address { + let key = DataKey::Registry; + e.storage().instance().get(&key).unwrap() } -pub fn write_vec_string_state(e: &Env, key: DataKey, id: &Vec) { +pub fn write_registry(e: &Env, id: &Address) { + let key = DataKey::Registry; e.storage().instance().set(&key, id); } -pub fn read_string_state(e: &Env, key: DataKey) -> String { - e.storage().instance().get(&key).unwrap() +pub fn write_token_period(e: &Env, token: &Address, period: u128){ + let key = DataKey::Period(token.clone()); + e.storage().persistent().set(&key, &period); } -pub fn read_address_state(e: &Env, key: DataKey) -> Address { - e.storage().instance().get(&key).unwrap() +pub fn read_token_period(e: &Env, token: &Address)->u128{ + let key = DataKey::Period(token.clone()); + e.storage().persistent().get(&key).unwrap() } -pub fn read_u64_state(e: &Env, key: DataKey) -> u64 { - e.storage().instance().get(&key).unwrap() +pub fn write_token_percentage(e: &Env, token: &Address, period: u128){ + let key = DataKey::Percentage(token.clone()); + e.storage().persistent().set(&key, &period); } -pub fn read_i128_state(e: &Env, key: DataKey) -> i128 { - e.storage().instance().get(&key).unwrap() +pub fn read_token_percentage(e: &Env, token: &Address)->u128{ + let key = DataKey::Percentage(token.clone()); + e.storage().persistent().get(&key).unwrap() } -pub fn read_u128_state(e: &Env, key: DataKey) -> u128 { - e.storage().instance().get(&key).unwrap() +pub fn write_token_last_update(e: &Env, token: &Address, last_update: u64){ + let key = DataKey::LastUpdate(token.clone()); + e.storage().persistent().set(&key, &last_update); } -pub fn read_vec_string_state(e: &Env, key: DataKey) -> Vec { - e.storage().instance().get(&key).unwrap() +pub fn read_token_last_update(e: &Env, token: &Address)->u64{ + let key = DataKey::LastUpdate(token.clone()); + e.storage().persistent().get(&key).unwrap() +} + +pub fn write_token_current_limit(e: &Env, token: &Address, current_limit: u128){ + let key = DataKey::CurrentLimit(token.clone()); + e.storage().persistent().set(&key, ¤t_limit); +} + +pub fn read_token_last_current_limit(e: &Env, token: &Address)->u128{ + let key = DataKey::CurrentLimit(token.clone()); + e.storage().persistent().get(&key).unwrap() +} + +pub fn write_tokens(e: &Env, token: Address){ + let key = DataKey::Tokens; + let mut tokens: Vec
= match e.storage().instance().get(&key) { + Some(names) => names, + None => Vec::new(&e), + }; + + tokens.push_back(token); + e.storage().persistent().set(&key, &tokens); +} + +pub fn read_tokens(e: &Env)->Vec
{ + let key = DataKey::Tokens; + let tokens: Vec
= match e.storage().persistent().get(&key) { + Some(names) => names, + None => Vec::new(&e), + }; + + tokens +} + +pub fn extent_ttl(e: &Env){ + e.storage() + .instance() + .extend_ttl(INSTANCE_LIFETIME_THRESHOLD, INSTANCE_BUMP_AMOUNT); + + let tokens = read_tokens(&e.clone()); + e.storage() + .persistent() + .extend_ttl(&DataKey::Tokens, INSTANCE_LIFETIME_THRESHOLD, INSTANCE_BUMP_AMOUNT); + for token in tokens { + e.storage() + .persistent() + .extend_ttl(&DataKey::Period(token.clone()), INSTANCE_LIFETIME_THRESHOLD, INSTANCE_BUMP_AMOUNT); + e.storage() + .persistent() + .extend_ttl(&DataKey::Percentage(token.clone()), INSTANCE_LIFETIME_THRESHOLD, INSTANCE_BUMP_AMOUNT); + e.storage() + .persistent() + .extend_ttl(&DataKey::LastUpdate(token.clone()), INSTANCE_LIFETIME_THRESHOLD, INSTANCE_BUMP_AMOUNT); + e.storage() + .persistent() + .extend_ttl(&DataKey::CurrentLimit(token.clone()), INSTANCE_LIFETIME_THRESHOLD, INSTANCE_BUMP_AMOUNT); + } } \ No newline at end of file diff --git a/contracts/asset_manager/src/storage_types.rs b/contracts/asset_manager/src/storage_types.rs index 1a89e28..b535eab 100644 --- a/contracts/asset_manager/src/storage_types.rs +++ b/contracts/asset_manager/src/storage_types.rs @@ -1,12 +1,5 @@ use soroban_sdk::{contracttype, Address}; -pub(crate) const DAY_IN_LEDGERS: u32 = 17280; -pub(crate) const INSTANCE_BUMP_AMOUNT: u32 = 7 * DAY_IN_LEDGERS; -pub(crate) const INSTANCE_LIFETIME_THRESHOLD: u32 = INSTANCE_BUMP_AMOUNT - DAY_IN_LEDGERS; - -//pub(crate) const BALANCE_BUMP_AMOUNT: u32 = 30 * DAY_IN_LEDGERS; -//pub(crate) const BALANCE_LIFETIME_THRESHOLD: u32 = BALANCE_BUMP_AMOUNT - DAY_IN_LEDGERS; - pub(crate) const POINTS: u128 = 1000; #[derive(Clone)] @@ -15,8 +8,10 @@ pub enum DataKey{ Registry, Admin, Config, + Tokens, Period(Address), Percentage(Address), LastUpdate(Address), CurrentLimit(Address) -} \ No newline at end of file +} + diff --git a/contracts/asset_manager/src/tests/asset_manager_test.rs b/contracts/asset_manager/src/tests/asset_manager_test.rs index 090df28..db6a700 100644 --- a/contracts/asset_manager/src/tests/asset_manager_test.rs +++ b/contracts/asset_manager/src/tests/asset_manager_test.rs @@ -112,7 +112,6 @@ fn test_veryfy_rate_limit() { let percentage = &300; client.configure_rate_limit( &ctx.token, period, percentage ); - client.configure_rate_limit( &ctx.token, &300, &300 ); let token_client = token::Client::new(&ctx.env, &ctx.token); let stellar_asset_client: token::StellarAssetClient = token::StellarAssetClient::new(&ctx.env, &ctx.token); let amount_i128: i128 = 100000 ; @@ -143,7 +142,6 @@ fn test_veryfy_rate_limit_panic_exceeds_withdraw_limit() { let percentage = &300; client.configure_rate_limit( &ctx.token, period, percentage ); - client.configure_rate_limit( &ctx.token, &300, &300 ); let token_client = token::Client::new(&ctx.env, &ctx.token); let stellar_asset_client: token::StellarAssetClient = token::StellarAssetClient::new(&ctx.env, &ctx.token); let amount_i128: i128 = 100000 ; @@ -378,4 +376,15 @@ fn test_handle_call_message_for_deposit_rollback_panic_with_only_call_service(){ client.handle_call_message(&ctx.xcall, &ctx.xcall_manager.to_string(), &data, &sources); assert_eq!(token_client.balance(&ctx.withdrawer), bnusd_amount as i128) +} + +#[test] +fn test_extend_ttl() { + let ctx = TestContext::default(); + let client = AssetManagerClient::new(&ctx.env, &ctx.registry); + ctx.init_context(&client); + + client.configure_rate_limit( &ctx.token, &300, &300 ); + + client.extend_ttl(); } \ No newline at end of file diff --git a/contracts/balanced_doller/src/contract.rs b/contracts/balanced_doller/src/contract.rs index 4962d1f..319b30f 100644 --- a/contracts/balanced_doller/src/contract.rs +++ b/contracts/balanced_doller/src/contract.rs @@ -1,11 +1,11 @@ //! This contract demonstrates a sample implementation of the Soroban token //! interface. -use crate::admin::{has_administrator, read_administrator, write_administrator}; use crate::allowance::{read_allowance, spend_allowance, write_allowance}; use crate::balance::{read_balance, receive_balance, spend_balance}; use crate::config::ConfigData; use crate::metadata::{read_decimal, read_name, read_symbol, write_metadata}; use crate::storage_types::{INSTANCE_BUMP_AMOUNT, INSTANCE_LIFETIME_THRESHOLD}; +use crate::states::{has_administrator, read_administrator, write_administrator }; use soroban_sdk::token::{self, Interface as _}; use soroban_sdk::{contract, contractimpl, panic_with_error, Address, Bytes, Env, String, Vec}; use soroban_token_sdk::metadata::TokenMetadata; @@ -60,10 +60,6 @@ impl BalancedDollar { let admin = read_administrator(&e); admin.require_auth(); - e.storage() - .instance() - .extend_ttl(INSTANCE_LIFETIME_THRESHOLD, INSTANCE_BUMP_AMOUNT); - write_administrator(&e, &new_admin); TokenUtils::new(&e).events().set_admin(admin, new_admin); } @@ -102,17 +98,20 @@ impl BalancedDollar { balanced_dollar::_handle_call_message(e, from, data, protocols); } - pub fn is_initialized(e: Env) -> Address { - read_administrator(&e) - } + pub fn is_initialized(e: Env) -> bool { + has_administrator(&e) + } + + pub fn extend_ttl(e: Env){ + e.storage() + .instance() + .extend_ttl(INSTANCE_LIFETIME_THRESHOLD, INSTANCE_BUMP_AMOUNT); + } } #[contractimpl] impl token::Interface for BalancedDollar { fn allowance(e: Env, from: Address, spender: Address) -> i128 { - e.storage() - .instance() - .extend_ttl(INSTANCE_LIFETIME_THRESHOLD, INSTANCE_BUMP_AMOUNT); read_allowance(&e, from, spender).amount } @@ -121,10 +120,6 @@ impl token::Interface for BalancedDollar { check_nonnegative_amount(amount); - e.storage() - .instance() - .extend_ttl(INSTANCE_LIFETIME_THRESHOLD, INSTANCE_BUMP_AMOUNT); - write_allowance(&e, from.clone(), spender.clone(), amount, expiration_ledger); TokenUtils::new(&e) .events() @@ -132,9 +127,6 @@ impl token::Interface for BalancedDollar { } fn balance(e: Env, id: Address) -> i128 { - e.storage() - .instance() - .extend_ttl(INSTANCE_LIFETIME_THRESHOLD, INSTANCE_BUMP_AMOUNT); read_balance(&e, id) } @@ -142,11 +134,6 @@ impl token::Interface for BalancedDollar { from.require_auth(); check_nonnegative_amount(amount); - - e.storage() - .instance() - .extend_ttl(INSTANCE_LIFETIME_THRESHOLD, INSTANCE_BUMP_AMOUNT); - spend_balance(&e, from.clone(), amount); receive_balance(&e, to.clone(), amount); TokenUtils::new(&e).events().transfer(from, to, amount); @@ -157,10 +144,6 @@ impl token::Interface for BalancedDollar { check_nonnegative_amount(amount); - e.storage() - .instance() - .extend_ttl(INSTANCE_LIFETIME_THRESHOLD, INSTANCE_BUMP_AMOUNT); - spend_allowance(&e, from.clone(), spender, amount); spend_balance(&e, from.clone(), amount); receive_balance(&e, to.clone(), amount); @@ -176,10 +159,6 @@ impl token::Interface for BalancedDollar { check_nonnegative_amount(amount); - e.storage() - .instance() - .extend_ttl(INSTANCE_LIFETIME_THRESHOLD, INSTANCE_BUMP_AMOUNT); - spend_allowance(&e, from.clone(), spender, amount); spend_balance(&e, from.clone(), amount); TokenUtils::new(&e).events().burn(from, amount) diff --git a/contracts/balanced_doller/src/states.rs b/contracts/balanced_doller/src/states.rs index f879bb3..02c0836 100644 --- a/contracts/balanced_doller/src/states.rs +++ b/contracts/balanced_doller/src/states.rs @@ -2,50 +2,18 @@ use soroban_sdk::{Address, Env, String, Vec}; use crate::storage_types::DataKey; -pub fn has_state(env:Env, key: DataKey) -> bool { - env.storage().instance().has(&key) +pub fn has_administrator(e: &Env) -> bool { + let key = DataKey::Admin; + e.storage().instance().has(&key) } -pub fn write_string_state(e: &Env, key: DataKey, id: &String) { - e.storage().instance().set(&key, id); -} - -pub fn write_address_state(e: &Env, key: DataKey, id: &Address) { - e.storage().instance().set(&key, id); -} - -pub fn write_u64_state(e: &Env, key: DataKey, id: &u64) { - e.storage().instance().set(&key, id); -} - -pub fn write_u128_state(e: &Env, key: DataKey, id: &u128) { - e.storage().instance().set(&key, id); -} - -pub fn write_vec_string_state(e: &Env, key: DataKey, id: &Vec) { - e.storage().instance().set(&key, id); -} - -pub fn read_string_state(e: &Env, key: DataKey) -> String { - e.storage().instance().get(&key).unwrap() -} - -pub fn read_address_state(e: &Env, key: DataKey) -> Address { - e.storage().instance().get(&key).unwrap() -} - -pub fn read_u64_state(e: &Env, key: DataKey) -> u64 { +pub fn read_administrator(e: &Env) -> Address { + let key = DataKey::Admin; e.storage().instance().get(&key).unwrap() } -pub fn read_i128_state(e: &Env, key: DataKey) -> i128 { - e.storage().instance().get(&key).unwrap() -} - -pub fn read_u128_state(e: &Env, key: DataKey) -> u128 { - e.storage().instance().get(&key).unwrap() +pub fn write_administrator(e: &Env, id: &Address) { + let key = DataKey::Admin; + e.storage().instance().set(&key, id); } -pub fn read_vec_string_state(e: &Env, key: DataKey) -> Vec { - e.storage().instance().get(&key).unwrap() -} \ No newline at end of file diff --git a/contracts/balanced_doller/src/storage_types.rs b/contracts/balanced_doller/src/storage_types.rs index e4fccca..f47e2b2 100644 --- a/contracts/balanced_doller/src/storage_types.rs +++ b/contracts/balanced_doller/src/storage_types.rs @@ -23,21 +23,8 @@ pub struct AllowanceValue { #[derive(Clone)] #[contracttype] pub enum DataKey { - Registry, Allowance(AllowanceDataKey), Balance(Address), - Nonce(Address), - State(Address), Admin, Config -} - -#[derive(Clone)] -#[contracttype] -pub enum BnUSDDataKey { - Xcall, - XcallNetworkAddress, - Nid, - IconBnUSD, - XcallManager } \ No newline at end of file diff --git a/contracts/balanced_doller/src/tests/balanced_dollar_test.rs b/contracts/balanced_doller/src/tests/balanced_dollar_test.rs index ff8da24..9f499bb 100644 --- a/contracts/balanced_doller/src/tests/balanced_dollar_test.rs +++ b/contracts/balanced_doller/src/tests/balanced_dollar_test.rs @@ -5,7 +5,7 @@ use crate::contract::BalancedDollarClient; use soroban_rlp::messages::{cross_transfer::CrossTransfer, cross_transfer_revert::CrossTransferRevert}; use soroban_sdk::{ - symbol_short, testutils::{Address as _, AuthorizedFunction, AuthorizedInvocation}, vec, xdr::FromXdr, Address, Bytes, IntoVal, String, Symbol, Val, Vec + symbol_short, testutils::{Address as _, AuthorizedFunction, AuthorizedInvocation}, Address, Bytes, IntoVal, String, Vec }; use super::setup::*; @@ -16,8 +16,8 @@ fn test_initialize() { ctx.init_context(&client); - let registry_exists = client.is_initialized(); - assert_eq!(registry_exists, ctx.admin) + let initialized = client.is_initialized(); + assert_eq!(initialized, true) } @@ -238,3 +238,13 @@ fn test_handle_call_message_for_cross_transfer_revert_panic_for_xcall(){ assert_eq!(client.balance(&ctx.withdrawer), bnusd_amount as i128) } +#[test] +fn test_extend_ttl(){ + let ctx = TestContext::default(); + let client = BalancedDollarClient::new(&ctx.env, &ctx.registry); + ctx.env.mock_all_auths(); + + ctx.init_context(&client); + + client.extend_ttl() +} \ No newline at end of file diff --git a/contracts/xcall_manager/src/contract.rs b/contracts/xcall_manager/src/contract.rs index 2a1f2aa..8f9d2fe 100644 --- a/contracts/xcall_manager/src/contract.rs +++ b/contracts/xcall_manager/src/contract.rs @@ -4,10 +4,9 @@ mod xcall { } use soroban_rlp::messages::{configure_protocols::ConfigureProtocols, execute::Execute }; use crate::{ - admin:: {read_administrator, write_administrator}, config::{get_config, set_config, ConfigData}, - states::{has_state, write_address_state, read_string_state, read_vec_string_state, write_string_state, write_vec_string_state }, - storage_types::{DataKey, INSTANCE_BUMP_AMOUNT, INSTANCE_LIFETIME_THRESHOLD } + states::{has_registry, has_proposed_removed, read_administrator, write_administrator, write_registry, + read_destinations, write_destinations, read_sources, write_sources, read_proposed_removed, write_proposed_removed, extend_ttl}, }; use crate::errors::ContractError; @@ -22,11 +21,11 @@ pub struct XcallManager; impl XcallManager { pub fn initialize(env:Env, registry:Address, admin: Address, config: ConfigData, sources: Vec, destinations: Vec) { - if has_state(env.clone(), DataKey::Registry) { + if has_registry(env.clone()) { panic_with_error!(env, ContractError::ContractAlreadyInitialized) } - write_address_state(&env, DataKey::Registry, ®istry); - write_address_state(&env, DataKey::Admin, &admin); + write_registry(&env, ®istry); + write_administrator(&env, &admin); Self::configure(env, config, sources, destinations ); } @@ -35,8 +34,8 @@ impl XcallManager { admin.require_auth(); set_config(&env, config); - write_vec_string_state(&env, DataKey::Sources, &sources); - write_vec_string_state(&env, DataKey::Destinations, &destinations); + write_sources(&env, &sources); + write_destinations(&env, &destinations); } pub fn get_config(env: Env) -> ConfigData{ @@ -47,10 +46,6 @@ impl XcallManager { let admin = read_administrator(&e); admin.require_auth(); - e.storage() - .instance() - .extend_ttl(INSTANCE_LIFETIME_THRESHOLD, INSTANCE_BUMP_AMOUNT); - write_administrator(&e, &new_admin); } @@ -62,24 +57,24 @@ impl XcallManager { let admin = read_administrator(&e); admin.require_auth(); - write_string_state(&e, DataKey::ProposedProtocolToRemove, &protocol); + write_proposed_removed(&e, &protocol); } pub fn get_proposed_removal(e: Env) -> String { - read_string_state(&e, DataKey::ProposedProtocolToRemove) + read_proposed_removed(&e) } pub fn verify_protocols( e: Env, protocols: Vec ) -> Result { - let sources: Vec = read_vec_string_state(&e, DataKey::Sources); + let sources: Vec = read_sources(&e); return Self::verify_protocols_unordered(e, protocols, sources); } pub fn get_protocols(e: Env) -> Result<(Vec, Vec), ContractError> { - let sources = read_vec_string_state(&e, DataKey::Sources); - let destinations = read_vec_string_state(&e, DataKey::Destinations); + let sources = read_sources(&e); + let destinations = read_destinations(&e); Ok((sources, destinations)) } @@ -127,7 +122,7 @@ impl XcallManager { let method = ConfigureProtocols::get_method(&e.clone(), data.clone()); - let sources = read_vec_string_state(&e, DataKey::Sources); + let sources = read_sources(&e); if !Self::verify_protocols_unordered(e.clone(), protocols.clone(), sources).unwrap() { if method != String::from_str(&e.clone(), CONFIGURE_PROTOCOLS_NAME) { panic_with_error!(e, ContractError::ProtocolMismatch) @@ -144,8 +139,8 @@ impl XcallManager { let message = ConfigureProtocols::decode(&e, data); let sources = message.sources; let destinations = message.destinations; - write_vec_string_state(&e, DataKey::Sources, &sources); - write_vec_string_state(&e, DataKey::Destinations, &destinations); + write_sources(&e, &sources); + write_destinations(&e, &destinations); } else { panic_with_error!(e, ContractError::UnknownMessageType) } @@ -160,12 +155,12 @@ impl XcallManager { } pub fn get_modified_protocols(e: Env) -> Vec{ - if !has_state(e.clone(), DataKey::ProposedProtocolToRemove) { + if !has_proposed_removed(e.clone()) { panic_with_error!(e, ContractError::NoProposalForRemovalExists) } - let sources = read_vec_string_state(&e, DataKey::Sources); - let protocol_to_remove = read_string_state(&e, DataKey::ProposedProtocolToRemove); + let sources = read_sources(&e); + let protocol_to_remove = read_proposed_removed(&e); let mut new_array = Vec::new(&e); for s in sources.iter() { if !s.eq(&protocol_to_remove) { @@ -176,4 +171,7 @@ impl XcallManager { return new_array; } + pub fn extend_ttl(e: Env){ + extend_ttl(&e); + } } \ No newline at end of file diff --git a/contracts/xcall_manager/src/states.rs b/contracts/xcall_manager/src/states.rs index 696d644..9173cb2 100644 --- a/contracts/xcall_manager/src/states.rs +++ b/contracts/xcall_manager/src/states.rs @@ -2,30 +2,71 @@ use soroban_sdk::{Address, Env, String, Vec}; use crate::storage_types::DataKey; -pub fn has_state(env:Env, key: DataKey) -> bool { - env.storage().instance().has(&key) +pub(crate) const DAY_IN_LEDGERS: u32 = 17280; +pub(crate) const INSTANCE_BUMP_AMOUNT: u32 = 30 * DAY_IN_LEDGERS; +pub(crate) const INSTANCE_LIFETIME_THRESHOLD: u32 = INSTANCE_BUMP_AMOUNT - DAY_IN_LEDGERS; + +pub fn read_administrator(e: &Env) -> Address { + let key = DataKey::Admin; + e.storage().instance().get(&key).unwrap() } -pub fn write_string_state(e: &Env, key: DataKey, id: &String) { +pub fn write_administrator(e: &Env, id: &Address) { + let key = DataKey::Admin; e.storage().instance().set(&key, id); } -pub fn write_address_state(e: &Env, key: DataKey, id: &Address) { +pub fn has_registry(env:Env) -> bool { + env.storage().instance().has(&DataKey::Registry) +} + +pub fn write_registry(e: &Env, id: &Address) { + let key = DataKey::Registry; + e.storage().instance().set(&key, id); +} + +pub fn read_registry(e: &Env) -> Address { + let key = DataKey::Registry; + e.storage().instance().get(&key).unwrap() +} + +pub fn has_proposed_removed(env:Env) -> bool { + env.storage().instance().has(&DataKey::ProposedProtocolToRemove) +} + +pub fn write_proposed_removed(e: &Env, id: &String) { + let key = DataKey::ProposedProtocolToRemove; e.storage().instance().set(&key, id); } -pub fn read_address_state(e: &Env, key: DataKey) -> Address { +pub fn read_proposed_removed(e: &Env) -> String { + let key = DataKey::ProposedProtocolToRemove; e.storage().instance().get(&key).unwrap() } -pub fn write_vec_string_state(e: &Env, key: DataKey, id: &Vec) { +pub fn write_sources(e: &Env, id: &Vec) { + let key = DataKey::Sources; e.storage().instance().set(&key, id); } -pub fn read_string_state(e: &Env, key: DataKey) -> String { +pub fn read_sources(e: &Env) -> Vec { + let key = DataKey::Sources; e.storage().instance().get(&key).unwrap() } -pub fn read_vec_string_state(e: &Env, key: DataKey) -> Vec { + +pub fn write_destinations(e: &Env, id: &Vec) { + let key = DataKey::Destinations; + e.storage().instance().set(&key, id); +} + +pub fn read_destinations(e: &Env) -> Vec { + let key = DataKey::Destinations; e.storage().instance().get(&key).unwrap() +} + +pub fn extend_ttl (e: &Env){ + e.storage() + .instance() + .extend_ttl(INSTANCE_LIFETIME_THRESHOLD, INSTANCE_BUMP_AMOUNT); } \ No newline at end of file diff --git a/contracts/xcall_manager/src/storage_types.rs b/contracts/xcall_manager/src/storage_types.rs index c702a64..68ad499 100644 --- a/contracts/xcall_manager/src/storage_types.rs +++ b/contracts/xcall_manager/src/storage_types.rs @@ -1,12 +1,5 @@ use soroban_sdk::contracttype; -pub(crate) const DAY_IN_LEDGERS: u32 = 17280; -pub(crate) const INSTANCE_BUMP_AMOUNT: u32 = 7 * DAY_IN_LEDGERS; -pub(crate) const INSTANCE_LIFETIME_THRESHOLD: u32 = INSTANCE_BUMP_AMOUNT - DAY_IN_LEDGERS; - -pub(crate) const BALANCE_BUMP_AMOUNT: u32 = 30 * DAY_IN_LEDGERS; -pub(crate) const BALANCE_LIFETIME_THRESHOLD: u32 = BALANCE_BUMP_AMOUNT - DAY_IN_LEDGERS; - #[derive(Clone)] #[contracttype] pub enum DataKey{ @@ -16,5 +9,4 @@ pub enum DataKey{ Config, Sources, Destinations - } \ No newline at end of file diff --git a/contracts/xcall_manager/src/test.rs b/contracts/xcall_manager/src/test.rs deleted file mode 100644 index e69de29..0000000 diff --git a/contracts/xcall_manager/src/tests/xcall_manager_test.rs b/contracts/xcall_manager/src/tests/xcall_manager_test.rs index 917a57e..e5337e9 100644 --- a/contracts/xcall_manager/src/tests/xcall_manager_test.rs +++ b/contracts/xcall_manager/src/tests/xcall_manager_test.rs @@ -236,4 +236,14 @@ fn test_handle_call_message_for_configure_protocols_panic_for_unknown_mesage_typ let (s, d) = client.get_protocols(); assert_eq!(s, sources); assert_eq!(d, destinations); +} + +#[test] +fn test_extend_ttl(){ + let ctx = TestContext::default(); + let client = XcallManagerClient::new(&ctx.env, &ctx.registry); + ctx.env.mock_all_auths(); + ctx.init_context(&client); + + client.extend_ttl(); } \ No newline at end of file From 76ede770ef5ffe86e7c4fbde02b924b95312c582 Mon Sep 17 00:00:00 2001 From: sagar sapkota Date: Fri, 31 May 2024 11:09:06 +0545 Subject: [PATCH 06/63] cleanups --- contracts/balanced_doller/src/admin.rs | 18 ------------------ .../balanced_doller/src/balanced_dollar.rs | 2 +- contracts/balanced_doller/src/lib.rs | 1 - contracts/balanced_doller/src/states.rs | 2 +- contracts/xcall_manager/src/admin.rs | 13 ------------- contracts/xcall_manager/src/lib.rs | 2 -- contracts/xcall_manager/src/states.rs | 5 ----- 7 files changed, 2 insertions(+), 41 deletions(-) delete mode 100644 contracts/balanced_doller/src/admin.rs delete mode 100644 contracts/xcall_manager/src/admin.rs diff --git a/contracts/balanced_doller/src/admin.rs b/contracts/balanced_doller/src/admin.rs deleted file mode 100644 index 85f4a52..0000000 --- a/contracts/balanced_doller/src/admin.rs +++ /dev/null @@ -1,18 +0,0 @@ -use soroban_sdk::{Address, Env}; - -use crate::storage_types::DataKey; - -pub fn has_administrator(e: &Env) -> bool { - let key = DataKey::Admin; - e.storage().instance().has(&key) -} - -pub fn read_administrator(e: &Env) -> Address { - let key = DataKey::Admin; - e.storage().instance().get(&key).unwrap() -} - -pub fn write_administrator(e: &Env, id: &Address) { - let key = DataKey::Admin; - e.storage().instance().set(&key, id); -} \ No newline at end of file diff --git a/contracts/balanced_doller/src/balanced_dollar.rs b/contracts/balanced_doller/src/balanced_dollar.rs index 21860d5..9698ad0 100644 --- a/contracts/balanced_doller/src/balanced_dollar.rs +++ b/contracts/balanced_doller/src/balanced_dollar.rs @@ -6,6 +6,7 @@ mod xcall { use soroban_rlp::messages::{cross_transfer::CrossTransfer, cross_transfer_revert::CrossTransferRevert}; use crate::storage_types::{INSTANCE_BUMP_AMOUNT, INSTANCE_LIFETIME_THRESHOLD}; +use crate::states::read_administrator; use crate::{ config::{ get_config, set_config, ConfigData}, xcall_manager_interface::XcallManagerClient @@ -16,7 +17,6 @@ use crate::errors::ContractError; use xcall::{AnyMessage, CallMessageWithRollback, Client, Envelope}; use soroban_token_sdk::TokenUtils; use crate::contract; -use crate::admin::read_administrator; const CROSS_TRANSFER: &str = "xCrossTransfer"; const CROSS_TRANSFER_REVERT: &str = "xCrossTransferRevert"; diff --git a/contracts/balanced_doller/src/lib.rs b/contracts/balanced_doller/src/lib.rs index e07af08..14df839 100644 --- a/contracts/balanced_doller/src/lib.rs +++ b/contracts/balanced_doller/src/lib.rs @@ -1,6 +1,5 @@ #![no_std] -mod admin; mod allowance; mod balance; pub mod contract; diff --git a/contracts/balanced_doller/src/states.rs b/contracts/balanced_doller/src/states.rs index 02c0836..2900b2f 100644 --- a/contracts/balanced_doller/src/states.rs +++ b/contracts/balanced_doller/src/states.rs @@ -1,4 +1,4 @@ -use soroban_sdk::{Address, Env, String, Vec}; +use soroban_sdk::{Address, Env}; use crate::storage_types::DataKey; diff --git a/contracts/xcall_manager/src/admin.rs b/contracts/xcall_manager/src/admin.rs deleted file mode 100644 index f571e95..0000000 --- a/contracts/xcall_manager/src/admin.rs +++ /dev/null @@ -1,13 +0,0 @@ -use soroban_sdk::{Address, Env}; - -use crate::storage_types::DataKey; - -pub fn read_administrator(e: &Env) -> Address { - let key = DataKey::Admin; - e.storage().instance().get(&key).unwrap() -} - -pub fn write_administrator(e: &Env, id: &Address) { - let key = DataKey::Admin; - e.storage().instance().set(&key, id); -} \ No newline at end of file diff --git a/contracts/xcall_manager/src/lib.rs b/contracts/xcall_manager/src/lib.rs index 4d9aa65..68c0567 100644 --- a/contracts/xcall_manager/src/lib.rs +++ b/contracts/xcall_manager/src/lib.rs @@ -1,6 +1,4 @@ #![no_std] - -mod admin; pub mod contract; mod storage_types; mod states; diff --git a/contracts/xcall_manager/src/states.rs b/contracts/xcall_manager/src/states.rs index 9173cb2..5c2f8d8 100644 --- a/contracts/xcall_manager/src/states.rs +++ b/contracts/xcall_manager/src/states.rs @@ -25,11 +25,6 @@ pub fn write_registry(e: &Env, id: &Address) { e.storage().instance().set(&key, id); } -pub fn read_registry(e: &Env) -> Address { - let key = DataKey::Registry; - e.storage().instance().get(&key).unwrap() -} - pub fn has_proposed_removed(env:Env) -> bool { env.storage().instance().has(&DataKey::ProposedProtocolToRemove) } From 573a27bddf6ff3ab34d0730f1edfa639a20fa867 Mon Sep 17 00:00:00 2001 From: sagar sapkota Date: Sun, 2 Jun 2024 08:43:01 +0545 Subject: [PATCH 07/63] unused variables cleanup --- contracts/balanced_doller/src/balanced_dollar.rs | 2 +- contracts/balanced_doller/src/errors.rs | 2 +- contracts/xcall_manager/src/contract.rs | 10 ++-------- contracts/xcall_manager/src/tests/setup.rs | 13 +------------ 4 files changed, 5 insertions(+), 22 deletions(-) diff --git a/contracts/balanced_doller/src/balanced_dollar.rs b/contracts/balanced_doller/src/balanced_dollar.rs index 9698ad0..c0e48c7 100644 --- a/contracts/balanced_doller/src/balanced_dollar.rs +++ b/contracts/balanced_doller/src/balanced_dollar.rs @@ -79,7 +79,7 @@ pub fn _handle_call_message( let icon_bn_usd = get_config(&e).icon_bn_usd; if method == String::from_str(&e, &CROSS_TRANSFER){ if from!=icon_bn_usd { - panic_with_error!(e, ContractError::onlyICONBnUSD) + panic_with_error!(e, ContractError::OnlyIconBnUSD) } let message = CrossTransfer::decode(&e.clone(), data); _mint(e.clone(), Address::from_string( &message.to), u128::try_into(message.amount).unwrap()); diff --git a/contracts/balanced_doller/src/errors.rs b/contracts/balanced_doller/src/errors.rs index 867eb06..84330a2 100644 --- a/contracts/balanced_doller/src/errors.rs +++ b/contracts/balanced_doller/src/errors.rs @@ -8,7 +8,7 @@ pub enum ContractError { ContractAlreadyInitialized = 2, DecimalMustFitInAu8 = 3, ProtocolMismatch = 4, - onlyICONBnUSD = 5, + OnlyIconBnUSD = 5, OnlyCallService = 6, UnknownMessageType = 7, } \ No newline at end of file diff --git a/contracts/xcall_manager/src/contract.rs b/contracts/xcall_manager/src/contract.rs index 8f9d2fe..75d795b 100644 --- a/contracts/xcall_manager/src/contract.rs +++ b/contracts/xcall_manager/src/contract.rs @@ -2,7 +2,7 @@ use soroban_sdk::{contract, contractimpl, Address, Bytes, Env, String, Vec, pani mod xcall { soroban_sdk::contractimport!(file = "../../wasm/xcall.wasm" ); } -use soroban_rlp::messages::{configure_protocols::ConfigureProtocols, execute::Execute }; +use soroban_rlp::messages::configure_protocols::ConfigureProtocols; use crate::{ config::{get_config, set_config, ConfigData}, states::{has_registry, has_proposed_removed, read_administrator, write_administrator, write_registry, @@ -12,7 +12,6 @@ use crate::{ use crate::errors::ContractError; const CONFIGURE_PROTOCOLS_NAME: &str = "ConfigureProtocols"; -const EXECUTE_NAME: &str = "Execute"; #[contract] pub struct XcallManager; @@ -130,12 +129,7 @@ impl XcallManager { Self::verify_protocol_recovery(e.clone(), protocols); } - if method == String::from_str(&e.clone(), EXECUTE_NAME) { - let message = Execute::decode(&e.clone(), data); - // (bool _success, ) = message.contractAddress.call(message.data); - // require(_success, "Failed to excute message"); - //e.invoke_contract(&message.contract_address, &Symbol::new(&e.clone(), "test"), data); - } else if method == String::from_str(&e, CONFIGURE_PROTOCOLS_NAME) { + if method == String::from_str(&e, CONFIGURE_PROTOCOLS_NAME) { let message = ConfigureProtocols::decode(&e, data); let sources = message.sources; let destinations = message.destinations; diff --git a/contracts/xcall_manager/src/tests/setup.rs b/contracts/xcall_manager/src/tests/setup.rs index 5e4157c..e2ac5d4 100644 --- a/contracts/xcall_manager/src/tests/setup.rs +++ b/contracts/xcall_manager/src/tests/setup.rs @@ -11,7 +11,7 @@ use crate::config::ConfigData; use soroban_sdk::Vec; use soroban_sdk::{ testutils::Address as _, - token, Address, Env, String + Address, Env, String }; mod xcall { @@ -101,15 +101,4 @@ impl TestContext { connection_client.set_fee(&self.nid, &message_fee, &response_fee); } - pub fn mint_native_token(&self, address: &Address, amount: u128) { - let native_token_client = token::StellarAssetClient::new(&self.env, &self.native_token); - native_token_client.mint(&address, &(*&amount as i128)); - } - - pub fn get_native_token_balance(&self, address: &Address) -> u128 { - let native_token_client = token::TokenClient::new(&self.env, &self.native_token); - let balance = native_token_client.balance(address); - - *&balance as u128 - } } From 7bf307f03b6af09c69ff389d58d3f2b8b45d1b53 Mon Sep 17 00:00:00 2001 From: sagar sapkota Date: Wed, 5 Jun 2024 18:07:22 +0545 Subject: [PATCH 08/63] integer data types update in unittest --- .../src/tests/asset_manager_test.rs | 92 +++++++++++-------- .../balanced_doller/src/balanced_dollar.rs | 2 +- .../src/tests/balanced_dollar_test.rs | 20 ++-- 3 files changed, 65 insertions(+), 49 deletions(-) diff --git a/contracts/asset_manager/src/tests/asset_manager_test.rs b/contracts/asset_manager/src/tests/asset_manager_test.rs index db6a700..a90bd36 100644 --- a/contracts/asset_manager/src/tests/asset_manager_test.rs +++ b/contracts/asset_manager/src/tests/asset_manager_test.rs @@ -3,7 +3,7 @@ extern crate std; use soroban_sdk::{ - symbol_short, testutils::{Address as _, AuthorizedFunction, AuthorizedInvocation}, token, Address, Bytes, IntoVal, String, Vec + testutils::{Address as _, AuthorizedFunction, AuthorizedInvocation}, token, Address, Bytes, IntoVal, String, Symbol, Vec }; use crate::contract::AssetManagerClient; @@ -38,7 +38,7 @@ fn test_set_admin() { AuthorizedInvocation { function: AuthorizedFunction::Contract(( ctx.registry.clone(), - symbol_short!("set_admin"), + Symbol::new(&ctx.env, "set_admin"), (&new_admin,) .into_val(&ctx.env) )), @@ -56,8 +56,8 @@ fn test_configure_rate_limit_panic() { let ctx = TestContext::default(); let client = AssetManagerClient::new(&ctx.env, &ctx.registry); ctx.init_context(&client); - let period = &300; - let percentage = &1001; + let period = &300u128; + let percentage = &1001u128; client.configure_rate_limit( &ctx.token, period, percentage ); let limit = client.get_withdraw_limit(&ctx.token); @@ -70,10 +70,26 @@ fn test_configure_rate_limit() { let ctx = TestContext::default(); let client = AssetManagerClient::new(&ctx.env, &ctx.registry); ctx.init_context(&client); - let period = &300; - let percentage = &300; + let period = &300u128; + let percentage = &300u128; client.configure_rate_limit( &ctx.token, period, percentage ); - + assert_eq!( + ctx.env.auths(), + std::vec![ + ( + ctx.admin.clone(), + AuthorizedInvocation { + function: AuthorizedFunction::Contract(( + ctx.registry.clone(), + Symbol::new(&ctx.env, "configure_rate_limit"), + (&ctx.token, 300u128, 300u128) + .into_val(&ctx.env) + )), + sub_invocations: std::vec![] + } + ) + ] + ); let limit = client.get_withdraw_limit(&ctx.token); let verified = client.verify_withdraw(&ctx.token, &limit); assert_eq!(verified, true); @@ -85,10 +101,10 @@ fn test_deposit_without_to_and_data(){ let client = AssetManagerClient::new(&ctx.env, &ctx.registry); ctx.init_context(&client); - client.configure_rate_limit( &ctx.token, &300, &300 ); + client.configure_rate_limit( &ctx.token, &300u128, &300u128 ); let token_client = token::Client::new(&ctx.env, &ctx.token); let stellar_asset_client: token::StellarAssetClient = token::StellarAssetClient::new(&ctx.env, &ctx.token); - let amount_i128: i128 = 100000 ; + let amount_i128: i128 = 100000i128; let amount = &(amount_i128 as u128); let mint_amount = &(amount_i128+amount_i128); @@ -108,22 +124,22 @@ fn test_veryfy_rate_limit() { let ctx = TestContext::default(); let client = AssetManagerClient::new(&ctx.env, &ctx.registry); ctx.init_context(&client); - let period = &300; - let percentage = &300; + let period = &300u128; + let percentage = &300u128; client.configure_rate_limit( &ctx.token, period, percentage ); - let token_client = token::Client::new(&ctx.env, &ctx.token); + //let token_client = token::Client::new(&ctx.env, &ctx.token); let stellar_asset_client: token::StellarAssetClient = token::StellarAssetClient::new(&ctx.env, &ctx.token); - let amount_i128: i128 = 100000 ; + let amount_i128: i128 = 100000i128 ; let amount = &(amount_i128 as u128); - let mint_amount = &(amount_i128+amount_i128); + let mint_amount: &i128 = &(amount_i128+amount_i128); stellar_asset_client.mint(&ctx.depositor, mint_amount); - ctx.mint_native_token(&ctx.depositor, 500); - assert_eq!(ctx.get_native_token_balance(&ctx.depositor), 500); + ctx.mint_native_token(&ctx.depositor, 500u128); + assert_eq!(ctx.get_native_token_balance(&ctx.depositor), 500u128); - token_client.approve(&ctx.depositor, &ctx.registry, &(amount_i128+amount_i128), &1312000); + //token_client.approve(&ctx.depositor, &ctx.registry, &(amount_i128+amount_i128), &1312000); client.deposit(&ctx.depositor, &ctx.token, &amount, &Option::Some(String::from_str(&ctx.env, "")), &Option::Some(Bytes::from_array(&ctx.env, &[0u8; 32]))); let limit = client.get_withdraw_limit(&ctx.token); @@ -138,20 +154,20 @@ fn test_veryfy_rate_limit_panic_exceeds_withdraw_limit() { let ctx = TestContext::default(); let client = AssetManagerClient::new(&ctx.env, &ctx.registry); ctx.init_context(&client); - let period = &300; - let percentage = &300; + let period = &300u128; + let percentage = &300u128; client.configure_rate_limit( &ctx.token, period, percentage ); let token_client = token::Client::new(&ctx.env, &ctx.token); let stellar_asset_client: token::StellarAssetClient = token::StellarAssetClient::new(&ctx.env, &ctx.token); - let amount_i128: i128 = 100000 ; + let amount_i128: i128 = 100000i128 ; let amount = &(amount_i128 as u128); let mint_amount = &(amount_i128+amount_i128); stellar_asset_client.mint(&ctx.depositor, mint_amount); - ctx.mint_native_token(&ctx.depositor, 500); - assert_eq!(ctx.get_native_token_balance(&ctx.depositor), 500); + ctx.mint_native_token(&ctx.depositor, 500u128); + assert_eq!(ctx.get_native_token_balance(&ctx.depositor), 500u128); token_client.approve(&ctx.depositor, &ctx.registry, &(amount_i128+amount_i128), &1312000); client.deposit(&ctx.depositor, &ctx.token, &amount, &Option::Some(String::from_str(&ctx.env, "")), &Option::Some(Bytes::from_array(&ctx.env, &[0u8; 32]))); @@ -168,10 +184,10 @@ fn test_deposit_with_to_and_without_data(){ let client = AssetManagerClient::new(&ctx.env, &ctx.registry); ctx.init_context(&client); - client.configure_rate_limit( &ctx.token, &300, &300 ); + client.configure_rate_limit( &ctx.token, &300u128, &300u128); let token_client = token::Client::new(&ctx.env, &ctx.token); let stellar_asset_client: token::StellarAssetClient = token::StellarAssetClient::new(&ctx.env, &ctx.token); - let amount_i128: i128 = 100000 ; + let amount_i128: i128 = 100000i128; let amount = &(amount_i128 as u128); let mint_amount = &(amount_i128+amount_i128); @@ -192,10 +208,10 @@ fn test_deposit_with_to_and_data(){ let client = AssetManagerClient::new(&ctx.env, &ctx.registry); ctx.init_context(&client); - client.configure_rate_limit( &ctx.token, &300, &300 ); + client.configure_rate_limit( &ctx.token, &300u128, &300u128 ); let token_client = token::Client::new(&ctx.env, &ctx.token); let stellar_asset_client: token::StellarAssetClient = token::StellarAssetClient::new(&ctx.env, &ctx.token); - let amount_i128: i128 = 100000 ; + let amount_i128: i128 = 100000i128; let amount = &(amount_i128 as u128); let mint_amount = &(amount_i128+amount_i128); @@ -225,9 +241,9 @@ fn test_handle_call_message_for_withdraw_to(){ ctx.env.mock_all_auths(); ctx.init_context(&client); - client.configure_rate_limit( &ctx.token, &300, &300 ); + client.configure_rate_limit( &ctx.token, &300u128, &300u128); - let bnusd_amount = 100000 as u128; + let bnusd_amount = 100000u128; let token_client = token::Client::new(&ctx.env, &ctx.token); let stellar_asset_client: token::StellarAssetClient = token::StellarAssetClient::new(&ctx.env, &ctx.token); stellar_asset_client.mint(&ctx.registry, &((bnusd_amount*2) as i128)); @@ -252,9 +268,9 @@ fn test_handle_call_message_for_withdraw_to_panic_with_protocal_mismatch(){ ctx.env.mock_all_auths(); ctx.init_context(&client); - client.configure_rate_limit( &ctx.token, &300, &300 ); + client.configure_rate_limit( &ctx.token, &300u128, &300u128); - let bnusd_amount = 100000 as u128; + let bnusd_amount = 100000u128; let token_client = token::Client::new(&ctx.env, &ctx.token); let stellar_asset_client: token::StellarAssetClient = token::StellarAssetClient::new(&ctx.env, &ctx.token); stellar_asset_client.mint(&ctx.registry, &((bnusd_amount*2) as i128)); @@ -279,9 +295,9 @@ fn test_handle_call_message_for_withdraw_to_panic_with_not_icon_asset_manager(){ ctx.env.mock_all_auths(); ctx.init_context(&client); - client.configure_rate_limit( &ctx.token, &300, &300 ); + client.configure_rate_limit( &ctx.token, &300u128, &300u128 ); - let bnusd_amount = 100000 as u128; + let bnusd_amount = 100000u128; let token_client = token::Client::new(&ctx.env, &ctx.token); let stellar_asset_client: token::StellarAssetClient = token::StellarAssetClient::new(&ctx.env, &ctx.token); stellar_asset_client.mint(&ctx.registry, &((bnusd_amount*2) as i128)); @@ -306,9 +322,9 @@ fn test_handle_call_message_for_withdraw_to_panic_with_unknown_message_type(){ ctx.env.mock_all_auths(); ctx.init_context(&client); - client.configure_rate_limit( &ctx.token, &300, &300 ); + client.configure_rate_limit( &ctx.token, &300u128, &300u128 ); - let bnusd_amount = 100000 as u128; + let bnusd_amount = 100000u128; let token_client = token::Client::new(&ctx.env, &ctx.token); let stellar_asset_client: token::StellarAssetClient = token::StellarAssetClient::new(&ctx.env, &ctx.token); stellar_asset_client.mint(&ctx.registry, &((bnusd_amount*2) as i128)); @@ -334,7 +350,7 @@ fn test_handle_call_message_for_deposit_rollback(){ ctx.init_context(&client); client.configure_rate_limit( &ctx.token, &300, &300 ); - let bnusd_amount = 100000 as u128; + let bnusd_amount = 100000u128; let token_client = token::Client::new(&ctx.env, &ctx.token); let stellar_asset_client: token::StellarAssetClient = token::StellarAssetClient::new(&ctx.env, &ctx.token); stellar_asset_client.mint(&ctx.registry, &((bnusd_amount*2) as i128)); @@ -359,9 +375,9 @@ fn test_handle_call_message_for_deposit_rollback_panic_with_only_call_service(){ ctx.env.mock_all_auths(); ctx.init_context(&client); - client.configure_rate_limit( &ctx.token, &300, &300 ); + client.configure_rate_limit( &ctx.token, &300u128, &300u128 ); - let bnusd_amount = 100000 as u128; + let bnusd_amount = 100000u128; let token_client = token::Client::new(&ctx.env, &ctx.token); let stellar_asset_client: token::StellarAssetClient = token::StellarAssetClient::new(&ctx.env, &ctx.token); stellar_asset_client.mint(&ctx.registry, &((bnusd_amount*2) as i128)); @@ -384,7 +400,7 @@ fn test_extend_ttl() { let client = AssetManagerClient::new(&ctx.env, &ctx.registry); ctx.init_context(&client); - client.configure_rate_limit( &ctx.token, &300, &300 ); + client.configure_rate_limit( &ctx.token, &300u128, &300u128); client.extend_ttl(); } \ No newline at end of file diff --git a/contracts/balanced_doller/src/balanced_dollar.rs b/contracts/balanced_doller/src/balanced_dollar.rs index c0e48c7..6ab11b7 100644 --- a/contracts/balanced_doller/src/balanced_dollar.rs +++ b/contracts/balanced_doller/src/balanced_dollar.rs @@ -96,7 +96,7 @@ pub fn _handle_call_message( pub fn _mint(e: Env, to: Address, amount: i128) { contract::check_nonnegative_amount(amount); - let admin = read_administrator(&e); + let admin: Address = read_administrator(&e); e.storage() .instance() diff --git a/contracts/balanced_doller/src/tests/balanced_dollar_test.rs b/contracts/balanced_doller/src/tests/balanced_dollar_test.rs index 9f499bb..2ee97c0 100644 --- a/contracts/balanced_doller/src/tests/balanced_dollar_test.rs +++ b/contracts/balanced_doller/src/tests/balanced_dollar_test.rs @@ -55,14 +55,14 @@ fn test_cross_transfer_with_to_and_data(){ let client = BalancedDollarClient::new(&ctx.env, &ctx.registry); ctx.init_context(&client); - let amount_i128: i128 = 100000 ; + let amount_i128: i128 = 100000i128 ; let amount = &(amount_i128 as u128); let mint_amount = &(amount_i128+amount_i128); client.mint(&ctx.depositor, mint_amount); - ctx.mint_native_token(&ctx.depositor, 500); - assert_eq!(ctx.get_native_token_balance(&ctx.depositor), 500); + ctx.mint_native_token(&ctx.depositor, 500u128); + assert_eq!(ctx.get_native_token_balance(&ctx.depositor), 500u128); client.approve(&ctx.depositor, &ctx.registry, &(amount_i128+amount_i128), &1312000); let data: [u8; 32] = [ @@ -73,7 +73,7 @@ fn test_cross_transfer_with_to_and_data(){ ]; client.cross_transfer_data(&ctx.depositor, &amount, &String::from_str(&ctx.env, "icon01/hxjkdvhui"), &Bytes::from_array(&ctx.env, &data)); std::println!("call"); - assert_eq!(ctx.get_native_token_balance(&ctx.depositor), 400) // why 300? + assert_eq!(ctx.get_native_token_balance(&ctx.depositor), 400u128) // why 300? } @@ -85,7 +85,7 @@ fn test_handle_call_message_for_cross_transfer(){ ctx.init_context(&client); - let bnusd_amount = 100000 as u128; + let bnusd_amount = 100000u128; let items: [u8; 32] = [ 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, @@ -115,7 +115,7 @@ fn test_handle_call_message_for_cross_transfer_panic_for_protocol_mismatch(){ ctx.init_context(&client); - let bnusd_amount = 100000 as u128; + let bnusd_amount = 100000u128; let items: [u8; 32] = [ 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, @@ -144,7 +144,7 @@ fn test_handle_call_message_for_cross_transfer_panic_for_icon_bnusd(){ ctx.init_context(&client); - let bnusd_amount = 100000 as u128; + let bnusd_amount = 100000u128; let items: [u8; 32] = [ 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, @@ -173,7 +173,7 @@ fn test_handle_call_message_for_cross_transfer_panic_for_wront_message_type(){ ctx.init_context(&client); - let bnusd_amount = 100000 as u128; + let bnusd_amount = 100000u128; let items: [u8; 32] = [ 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, @@ -201,7 +201,7 @@ fn test_handle_call_message_for_cross_transfer_revert(){ ctx.init_context(&client); - let bnusd_amount = 100000 as u128; + let bnusd_amount = 100000u128; let data = CrossTransferRevert::new( ctx.withdrawer.clone(), bnusd_amount).encode(&ctx.env, String::from_str(&ctx.env, "xCrossTransferRevert")); let decoded = CrossTransferRevert::decode(&ctx.env, data.clone()); @@ -224,7 +224,7 @@ fn test_handle_call_message_for_cross_transfer_revert_panic_for_xcall(){ ctx.init_context(&client); - let bnusd_amount = 100000 as u128; + let bnusd_amount = 100000u128; let data = CrossTransferRevert::new( ctx.withdrawer.clone(), bnusd_amount).encode(&ctx.env, String::from_str(&ctx.env, "xCrossTransferRevert")); let decoded = CrossTransferRevert::decode(&ctx.env, data.clone()); From a4fbfd6a8367f7bb760f5757d87db92bb0baf071 Mon Sep 17 00:00:00 2001 From: sagar sapkota Date: Thu, 6 Jun 2024 12:10:44 +0545 Subject: [PATCH 09/63] alloc feature removed from asset manager as that is not required and giving issue --- contracts/asset_manager/Cargo.toml | 2 +- contracts/asset_manager/src/contract.rs | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/contracts/asset_manager/Cargo.toml b/contracts/asset_manager/Cargo.toml index 20cb3cd..100da4c 100644 --- a/contracts/asset_manager/Cargo.toml +++ b/contracts/asset_manager/Cargo.toml @@ -10,7 +10,7 @@ crate-type = ["cdylib", "rlib"] testutils = ["soroban-sdk/testutils"] [dependencies] -soroban-sdk = { workspace = true, features = ["alloc"] } +soroban-sdk = { workspace = true } soroban-rlp = { path = "../../libs/soroban-rlp" } [dev_dependencies] diff --git a/contracts/asset_manager/src/contract.rs b/contracts/asset_manager/src/contract.rs index fc733ee..c040d36 100644 --- a/contracts/asset_manager/src/contract.rs +++ b/contracts/asset_manager/src/contract.rs @@ -1,6 +1,5 @@ use soroban_sdk::{contract, contractimpl, token, Address, Bytes, BytesN, Env, String, Vec, panic_with_error}; -extern crate std; mod xcall { soroban_sdk::contractimport!(file = "../../wasm/xcall.wasm"); } From a5900a6e111aa5c6ec9e0a004845e2427fa54fd1 Mon Sep 17 00:00:00 2001 From: sagar sapkota Date: Fri, 7 Jun 2024 11:01:55 +0545 Subject: [PATCH 10/63] removed duplicate reading --- contracts/asset_manager/src/contract.rs | 23 ++++++++++++----------- contracts/xcall_manager/src/states.rs | 2 +- 2 files changed, 13 insertions(+), 12 deletions(-) diff --git a/contracts/asset_manager/src/contract.rs b/contracts/asset_manager/src/contract.rs index c040d36..02adf47 100644 --- a/contracts/asset_manager/src/contract.rs +++ b/contracts/asset_manager/src/contract.rs @@ -95,21 +95,25 @@ impl AssetManager { } pub fn reset_limit(env: Env, token: Address){ - let token_client = token::Client::new(&env, &token); - let contract_token_balance = token_client.balance(&env.current_contract_address()); + let balance = Self::get_token_balance(env.clone(), token.clone()); let percentage: u128 = read_token_percentage(&env, &token.clone()); - env.storage().instance().set(&DataKey::CurrentLimit(token.clone()), &(u128::try_from(contract_token_balance).unwrap()*percentage/POINTS)); + env.storage().instance().set(&DataKey::CurrentLimit(token.clone()), &(balance*percentage/POINTS)); } pub fn get_withdraw_limit(env: Env, token: Address) -> Result { - return Ok(Self::calculate_limit(env, token)?) + let balance = Self::get_token_balance(env.clone(), token.clone()); + return Ok(Self::calculate_limit(env, balance, token)?) } - pub fn verify_withdraw(env: Env, token: Address, amount: u128) -> Result { + fn get_token_balance(env: Env, token: Address) -> u128 { let token_client = token::Client::new(&env, &token); - let balance = token_client.balance(&env.current_contract_address()) as u128; - let limit = Self::calculate_limit(env.clone(), token.clone())?; + return token_client.balance(&env.current_contract_address()) as u128 + } + + pub fn verify_withdraw(env: Env, token: Address, amount: u128) -> Result { + let balance = Self::get_token_balance(env.clone(), token.clone()); + let limit = Self::calculate_limit(env.clone(), balance, token.clone())?; if balance - amount < limit { panic_with_error!(&env, ContractError::ExceedsWithdrawLimit); }; write_token_current_limit(&env, &token.clone(), limit); @@ -117,16 +121,13 @@ impl AssetManager { Ok(true) } - pub fn calculate_limit(env: Env, token: Address) -> Result { + pub fn calculate_limit(env: Env, balance: u128, token: Address) -> Result { let period: u128 = read_token_period(&env, &token.clone()); let percentage: u128 = read_token_percentage(&env, &token.clone()); if period == 0 { return Ok(0); } - let token_client = token::Client::new(&env, &token); - let balance = token_client.balance(&env.current_contract_address()) as u128; - let max_limit = (balance * percentage) / POINTS; let max_withdraw = balance - max_limit; diff --git a/contracts/xcall_manager/src/states.rs b/contracts/xcall_manager/src/states.rs index 5c2f8d8..463aa59 100644 --- a/contracts/xcall_manager/src/states.rs +++ b/contracts/xcall_manager/src/states.rs @@ -23,7 +23,7 @@ pub fn has_registry(env:Env) -> bool { pub fn write_registry(e: &Env, id: &Address) { let key = DataKey::Registry; e.storage().instance().set(&key, id); -} +} pub fn has_proposed_removed(env:Env) -> bool { env.storage().instance().has(&DataKey::ProposedProtocolToRemove) From 36c256443845ba281737b23f9231bf551dcb3a1e Mon Sep 17 00:00:00 2001 From: sagar sapkota Date: Mon, 10 Jun 2024 09:10:41 +0545 Subject: [PATCH 11/63] points changed to 10k, verify limit on withdraw commented for testing --- contracts/asset_manager/src/contract.rs | 3 ++- contracts/asset_manager/src/storage_types.rs | 2 +- .../asset_manager/src/tests/asset_manager_test.rs | 10 +++++----- 3 files changed, 8 insertions(+), 7 deletions(-) diff --git a/contracts/asset_manager/src/contract.rs b/contracts/asset_manager/src/contract.rs index 02adf47..e3cbcf8 100644 --- a/contracts/asset_manager/src/contract.rs +++ b/contracts/asset_manager/src/contract.rs @@ -246,7 +246,8 @@ impl AssetManager { if amount <= 0 { panic_with_error!(&e, ContractError::AmountIsLessThanMinimumAmount); } - let verified = Self::verify_withdraw(e.clone(), token.clone(), amount)?; + // uncomment below code once test completes + let verified = true; //Self::verify_withdraw(e.clone(), token.clone(), amount)?; if verified { Self::transfer_token_to(e, from, token, to, amount); } diff --git a/contracts/asset_manager/src/storage_types.rs b/contracts/asset_manager/src/storage_types.rs index b535eab..a7a11bf 100644 --- a/contracts/asset_manager/src/storage_types.rs +++ b/contracts/asset_manager/src/storage_types.rs @@ -1,6 +1,6 @@ use soroban_sdk::{contracttype, Address}; -pub(crate) const POINTS: u128 = 1000; +pub(crate) const POINTS: u128 = 10000; #[derive(Clone)] #[contracttype] diff --git a/contracts/asset_manager/src/tests/asset_manager_test.rs b/contracts/asset_manager/src/tests/asset_manager_test.rs index a90bd36..a598b12 100644 --- a/contracts/asset_manager/src/tests/asset_manager_test.rs +++ b/contracts/asset_manager/src/tests/asset_manager_test.rs @@ -57,7 +57,7 @@ fn test_configure_rate_limit_panic() { let client = AssetManagerClient::new(&ctx.env, &ctx.registry); ctx.init_context(&client); let period = &300u128; - let percentage = &1001u128; + let percentage = &10001u128; client.configure_rate_limit( &ctx.token, period, percentage ); let limit = client.get_withdraw_limit(&ctx.token); @@ -143,8 +143,8 @@ fn test_veryfy_rate_limit() { client.deposit(&ctx.depositor, &ctx.token, &amount, &Option::Some(String::from_str(&ctx.env, "")), &Option::Some(Bytes::from_array(&ctx.env, &[0u8; 32]))); let limit = client.get_withdraw_limit(&ctx.token); - assert_eq!(limit, 30000); - let verified = client.verify_withdraw(&ctx.token, &(amount-30000-1)); + assert_eq!(limit, 3000); + let verified = client.verify_withdraw(&ctx.token, &(amount-3000-1)); assert_eq!(verified, true); } @@ -173,8 +173,8 @@ fn test_veryfy_rate_limit_panic_exceeds_withdraw_limit() { client.deposit(&ctx.depositor, &ctx.token, &amount, &Option::Some(String::from_str(&ctx.env, "")), &Option::Some(Bytes::from_array(&ctx.env, &[0u8; 32]))); let limit = client.get_withdraw_limit(&ctx.token); - assert_eq!(limit, 30000); - let verified = client.verify_withdraw(&ctx.token, &(amount-30000+1)); + assert_eq!(limit, 3000); + let verified = client.verify_withdraw(&ctx.token, &(amount-3000+1)); assert_eq!(verified, true); } From 4afb72da08932632c74695a1753f7bf3ab15bef3 Mon Sep 17 00:00:00 2001 From: sagar sapkota Date: Mon, 10 Jun 2024 10:13:16 +0545 Subject: [PATCH 12/63] commit for testing --- contracts/asset_manager/src/contract.rs | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/contracts/asset_manager/src/contract.rs b/contracts/asset_manager/src/contract.rs index e3cbcf8..d013f06 100644 --- a/contracts/asset_manager/src/contract.rs +++ b/contracts/asset_manager/src/contract.rs @@ -113,7 +113,8 @@ impl AssetManager { pub fn verify_withdraw(env: Env, token: Address, amount: u128) -> Result { let balance = Self::get_token_balance(env.clone(), token.clone()); - let limit = Self::calculate_limit(env.clone(), balance, token.clone())?; + //uncomment below code once test completes + let limit = balance - amount - 1; //Self::calculate_limit(env.clone(), balance, token.clone())?; if balance - amount < limit { panic_with_error!(&env, ContractError::ExceedsWithdrawLimit); }; write_token_current_limit(&env, &token.clone(), limit); @@ -246,8 +247,8 @@ impl AssetManager { if amount <= 0 { panic_with_error!(&e, ContractError::AmountIsLessThanMinimumAmount); } - // uncomment below code once test completes - let verified = true; //Self::verify_withdraw(e.clone(), token.clone(), amount)?; + + let verified = Self::verify_withdraw(e.clone(), token.clone(), amount)?; if verified { Self::transfer_token_to(e, from, token, to, amount); } From a79f9abbafce47da39567572ccc7946c248400d7 Mon Sep 17 00:00:00 2001 From: sagar sapkota Date: Mon, 10 Jun 2024 10:37:04 +0545 Subject: [PATCH 13/63] commit for testig --- contracts/asset_manager/src/contract.rs | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/contracts/asset_manager/src/contract.rs b/contracts/asset_manager/src/contract.rs index d013f06..0a01319 100644 --- a/contracts/asset_manager/src/contract.rs +++ b/contracts/asset_manager/src/contract.rs @@ -131,18 +131,18 @@ impl AssetManager { let max_limit = (balance * percentage) / POINTS; - let max_withdraw = balance - max_limit; - let last_update: u64 = read_token_last_update(&env, &token.clone()); - let time_diff = &env.ledger().timestamp() - last_update; + // let max_withdraw = balance - max_limit; + // let last_update: u64 = read_token_last_update(&env, &token.clone()); + // let time_diff = &env.ledger().timestamp() - last_update; - let added_allowed_withdrawal = (max_withdraw * u128::from(time_diff)) / period; - let current_limit: u128 = read_token_last_current_limit(&env, &token.clone()); - let limit: u128 = current_limit - added_allowed_withdrawal; + // let added_allowed_withdrawal = (max_withdraw * u128::from(time_diff)) / period; + // let current_limit: u128 = read_token_last_current_limit(&env, &token.clone()); + // let limit: u128 = current_limit - added_allowed_withdrawal; - let limit = if balance < limit { balance } else { limit }; + // let limit = if balance < limit { balance } else { limit }; - let final_limit = if limit > max_limit { limit } else { max_limit }; - Ok(final_limit) + // let final_limit = if limit > max_limit { limit } else { max_limit }; + Ok(max_limit) } pub fn deposit( From 95002e63797a1e79554ceb56a233d1bf454c33ee Mon Sep 17 00:00:00 2001 From: sagar sapkota Date: Mon, 10 Jun 2024 10:37:32 +0545 Subject: [PATCH 14/63] commit for testing --- contracts/asset_manager/src/contract.rs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/contracts/asset_manager/src/contract.rs b/contracts/asset_manager/src/contract.rs index 0a01319..00967b9 100644 --- a/contracts/asset_manager/src/contract.rs +++ b/contracts/asset_manager/src/contract.rs @@ -113,8 +113,7 @@ impl AssetManager { pub fn verify_withdraw(env: Env, token: Address, amount: u128) -> Result { let balance = Self::get_token_balance(env.clone(), token.clone()); - //uncomment below code once test completes - let limit = balance - amount - 1; //Self::calculate_limit(env.clone(), balance, token.clone())?; + let limit = Self::calculate_limit(env.clone(), balance, token.clone())?; if balance - amount < limit { panic_with_error!(&env, ContractError::ExceedsWithdrawLimit); }; write_token_current_limit(&env, &token.clone(), limit); From ec866edc63db613203b22f2cfcb48aac531af624 Mon Sep 17 00:00:00 2001 From: sagar sapkota Date: Mon, 10 Jun 2024 11:25:09 +0545 Subject: [PATCH 15/63] commit for tesitng --- contracts/asset_manager/src/contract.rs | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/contracts/asset_manager/src/contract.rs b/contracts/asset_manager/src/contract.rs index 00967b9..44dc2d1 100644 --- a/contracts/asset_manager/src/contract.rs +++ b/contracts/asset_manager/src/contract.rs @@ -130,18 +130,18 @@ impl AssetManager { let max_limit = (balance * percentage) / POINTS; - // let max_withdraw = balance - max_limit; - // let last_update: u64 = read_token_last_update(&env, &token.clone()); - // let time_diff = &env.ledger().timestamp() - last_update; + let max_withdraw = balance - max_limit; + let last_update: u64 = read_token_last_update(&env, &token.clone()); + let time_diff = &env.ledger().timestamp() - last_update; - // let added_allowed_withdrawal = (max_withdraw * u128::from(time_diff)) / period; - // let current_limit: u128 = read_token_last_current_limit(&env, &token.clone()); - // let limit: u128 = current_limit - added_allowed_withdrawal; + //let added_allowed_withdrawal = (max_withdraw * u128::from(time_diff)) / period; + let current_limit: u128 = read_token_last_current_limit(&env, &token.clone()); + let limit: u128 = current_limit; //- added_allowed_withdrawal; - // let limit = if balance < limit { balance } else { limit }; + let limit = if balance < limit { balance } else { limit }; - // let final_limit = if limit > max_limit { limit } else { max_limit }; - Ok(max_limit) + let final_limit = if limit > max_limit { limit } else { max_limit }; + Ok(final_limit) } pub fn deposit( From 9352a2ae51a2bf0921ce3de1d6e49cc59320d14e Mon Sep 17 00:00:00 2001 From: sagar sapkota Date: Mon, 10 Jun 2024 17:34:44 +0545 Subject: [PATCH 16/63] u64 to u128 conversion approach changed --- contracts/asset_manager/src/contract.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/contracts/asset_manager/src/contract.rs b/contracts/asset_manager/src/contract.rs index 44dc2d1..80640d1 100644 --- a/contracts/asset_manager/src/contract.rs +++ b/contracts/asset_manager/src/contract.rs @@ -134,9 +134,9 @@ impl AssetManager { let last_update: u64 = read_token_last_update(&env, &token.clone()); let time_diff = &env.ledger().timestamp() - last_update; - //let added_allowed_withdrawal = (max_withdraw * u128::from(time_diff)) / period; + let added_allowed_withdrawal = (max_withdraw * time_diff as u128) / period; let current_limit: u128 = read_token_last_current_limit(&env, &token.clone()); - let limit: u128 = current_limit; //- added_allowed_withdrawal; + let limit: u128 = current_limit - added_allowed_withdrawal; let limit = if balance < limit { balance } else { limit }; From ff7be8788d1e561ee8f97c0b21441ae1599bbcdc Mon Sep 17 00:00:00 2001 From: sagar sapkota Date: Mon, 10 Jun 2024 20:11:57 +0545 Subject: [PATCH 17/63] timestamp issue fixed --- contracts/asset_manager/src/contract.rs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/contracts/asset_manager/src/contract.rs b/contracts/asset_manager/src/contract.rs index 80640d1..8b115aa 100644 --- a/contracts/asset_manager/src/contract.rs +++ b/contracts/asset_manager/src/contract.rs @@ -11,7 +11,6 @@ use crate::{ write_token_last_update, write_token_percentage, write_token_period, extent_ttl, read_tokens, write_tokens}, storage_types::{DataKey, POINTS}, xcall_manager_interface::XcallManagerClient }; - use crate::errors::ContractError; use xcall::{AnyMessage, CallMessageWithRollback, Client, Envelope}; @@ -132,7 +131,7 @@ impl AssetManager { let max_withdraw = balance - max_limit; let last_update: u64 = read_token_last_update(&env, &token.clone()); - let time_diff = &env.ledger().timestamp() - last_update; + let time_diff = (&env.ledger().timestamp() - last_update)/1000; let added_allowed_withdrawal = (max_withdraw * time_diff as u128) / period; let current_limit: u128 = read_token_last_current_limit(&env, &token.clone()); From 8542feb6aa48878030b0bf4c78c1498f8fb9fa69 Mon Sep 17 00:00:00 2001 From: sagar sapkota Date: Tue, 11 Jun 2024 13:11:44 +0545 Subject: [PATCH 18/63] balanced dollar message withdraw_to in network address --- .../balanced_doller/src/balanced_dollar.rs | 37 +++++++++++++++- .../src/tests/balanced_dollar_test.rs | 42 +++++++++++-------- 2 files changed, 60 insertions(+), 19 deletions(-) diff --git a/contracts/balanced_doller/src/balanced_dollar.rs b/contracts/balanced_doller/src/balanced_dollar.rs index 6ab11b7..a4c201b 100644 --- a/contracts/balanced_doller/src/balanced_dollar.rs +++ b/contracts/balanced_doller/src/balanced_dollar.rs @@ -1,4 +1,4 @@ -use soroban_sdk::{panic_with_error, Address, Bytes, Env, String, Vec}; +use soroban_sdk::{panic_with_error, Address, Bytes, Env, String, Vec, xdr::ToXdr}; use crate::balance::{spend_balance, receive_balance}; mod xcall { soroban_sdk::contractimport!(file = "../../wasm/xcall.wasm"); @@ -81,8 +81,10 @@ pub fn _handle_call_message( if from!=icon_bn_usd { panic_with_error!(e, ContractError::OnlyIconBnUSD) } + let message = CrossTransfer::decode(&e.clone(), data); - _mint(e.clone(), Address::from_string( &message.to), u128::try_into(message.amount).unwrap()); + let to_network_address = get_address(message.to.clone(), &e.clone()); + _mint(e.clone(), to_network_address, u128::try_into(message.amount).unwrap()); } else if method == String::from_str(&e, &CROSS_TRANSFER_REVERT){ if from!=xcall.to_string() { panic_with_error!(e, ContractError::OnlyCallService) @@ -94,6 +96,37 @@ pub fn _handle_call_message( } } +pub fn get_address(network_address: String, env: &Env) -> Address { + let bytes = network_address.to_xdr(&env); + + if bytes.get(6).unwrap() > 0 { + panic!("Invalid network address length") + } + + let value_len = bytes.get(7).unwrap(); + let slice = bytes.slice(8..value_len as u32 + 8); + let mut nid = Bytes::new(&env); + let mut account = Bytes::new(&env); + + let mut has_seperator = false; + for (index, value) in slice.clone().iter().enumerate() { + if has_seperator { + account.append(&slice.slice(index as u32..slice.len())); + break; + } else if value == 47 { + has_seperator = true; + } else { + nid.push_back(value) + } + } + + if !has_seperator { + panic!("Invalid network address") + } + + Address::from_string_bytes(&account) +} + pub fn _mint(e: Env, to: Address, amount: i128) { contract::check_nonnegative_amount(amount); let admin: Address = read_administrator(&e); diff --git a/contracts/balanced_doller/src/tests/balanced_dollar_test.rs b/contracts/balanced_doller/src/tests/balanced_dollar_test.rs index 2ee97c0..a18f1f8 100644 --- a/contracts/balanced_doller/src/tests/balanced_dollar_test.rs +++ b/contracts/balanced_doller/src/tests/balanced_dollar_test.rs @@ -93,15 +93,17 @@ fn test_handle_call_message_for_cross_transfer(){ 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F, 0x20, ]; - let data = CrossTransfer::new(ctx.depositor.to_string(), ctx.withdrawer.to_string(), bnusd_amount, Bytes::from_array(&ctx.env, &items)).encode(&ctx.env, String::from_str(&ctx.env, "xCrossTransfer")); + let withdrawer = String::from_str(&ctx.env, "stellar/CA36FQITV33RO5SJFPTNLRQBD6ZNAEJG7F7J5KWCV4OP7SQHDMIZCT33"); + let data = CrossTransfer::new(ctx.depositor.to_string(), withdrawer.clone(), bnusd_amount, Bytes::from_array(&ctx.env, &items)).encode(&ctx.env, String::from_str(&ctx.env, "xCrossTransfer")); let decoded = CrossTransfer::decode(&ctx.env, data.clone()); - assert_eq!(decoded.to, ctx.withdrawer.to_string()); + assert_eq!(decoded.to, withdrawer); - assert_eq!(client.balance(&ctx.withdrawer), 0); + let withdrawer_address = &Address::from_string(&String::from_str(&ctx.env, "CA36FQITV33RO5SJFPTNLRQBD6ZNAEJG7F7J5KWCV4OP7SQHDMIZCT33")); + assert_eq!(client.balance(withdrawer_address), 0); let sources = Vec::from_array(&ctx.env, [ctx.centralized_connection.to_string()]); client.handle_call_message( &ctx.icon_bn_usd, &data, &sources); - assert_eq!(client.balance(&ctx.withdrawer), bnusd_amount as i128) + assert_eq!(client.balance(withdrawer_address), bnusd_amount as i128) } @@ -123,16 +125,18 @@ fn test_handle_call_message_for_cross_transfer_panic_for_protocol_mismatch(){ 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F, 0x20, ]; - let data = CrossTransfer::new(ctx.depositor.to_string(), ctx.withdrawer.to_string(), bnusd_amount, Bytes::from_array(&ctx.env, &items)).encode(&ctx.env, String::from_str(&ctx.env, "xCrossTransfer")); + let withdrawer = String::from_str(&ctx.env, "stellar/CA36FQITV33RO5SJFPTNLRQBD6ZNAEJG7F7J5KWCV4OP7SQHDMIZCT33"); + let data = CrossTransfer::new(ctx.depositor.to_string(), withdrawer.clone(), bnusd_amount, Bytes::from_array(&ctx.env, &items)).encode(&ctx.env, String::from_str(&ctx.env, "xCrossTransfer")); let decoded = CrossTransfer::decode(&ctx.env, data.clone()); - assert_eq!(decoded.to, ctx.withdrawer.to_string()); + assert_eq!(decoded.to, withdrawer); - assert_eq!(client.balance(&ctx.withdrawer), 0); + let withdrawer_address = &Address::from_string(&String::from_str(&ctx.env, "CA36FQITV33RO5SJFPTNLRQBD6ZNAEJG7F7J5KWCV4OP7SQHDMIZCT33")); + assert_eq!(client.balance(withdrawer_address), 0); let sources = Vec::from_array(&ctx.env, [ctx.xcall.to_string()]); client.handle_call_message( &ctx.icon_bn_usd, &data, &sources); - assert_eq!(client.balance(&ctx.withdrawer), bnusd_amount as i128) + assert_eq!(client.balance(withdrawer_address), bnusd_amount as i128) } #[test] @@ -152,16 +156,18 @@ fn test_handle_call_message_for_cross_transfer_panic_for_icon_bnusd(){ 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F, 0x20, ]; - let data = CrossTransfer::new(ctx.depositor.to_string(), ctx.withdrawer.to_string(), bnusd_amount, Bytes::from_array(&ctx.env, &items)).encode(&ctx.env, String::from_str(&ctx.env, "xCrossTransfer")); + let withdrawer = String::from_str(&ctx.env, "stellar/CA36FQITV33RO5SJFPTNLRQBD6ZNAEJG7F7J5KWCV4OP7SQHDMIZCT33"); + let data = CrossTransfer::new(ctx.depositor.to_string(), withdrawer.clone(), bnusd_amount, Bytes::from_array(&ctx.env, &items)).encode(&ctx.env, String::from_str(&ctx.env, "xCrossTransfer")); let decoded = CrossTransfer::decode(&ctx.env, data.clone()); - assert_eq!(decoded.to, ctx.withdrawer.to_string()); + assert_eq!(decoded.to, withdrawer); - assert_eq!(client.balance(&ctx.withdrawer), 0); + let withdrawer_address = &Address::from_string(&String::from_str(&ctx.env, "CA36FQITV33RO5SJFPTNLRQBD6ZNAEJG7F7J5KWCV4OP7SQHDMIZCT33")); + assert_eq!(client.balance(withdrawer_address), 0); let sources = Vec::from_array(&ctx.env, [ctx.centralized_connection.to_string()]); client.handle_call_message( &ctx.icon_governance, &data, &sources); - assert_eq!(client.balance(&ctx.withdrawer), bnusd_amount as i128) + assert_eq!(client.balance(withdrawer_address), bnusd_amount as i128) } #[test] @@ -181,16 +187,18 @@ fn test_handle_call_message_for_cross_transfer_panic_for_wront_message_type(){ 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F, 0x20, ]; - let data = CrossTransfer::new(ctx.depositor.to_string(), ctx.withdrawer.to_string(), bnusd_amount, Bytes::from_array(&ctx.env, &items)).encode(&ctx.env, String::from_str(&ctx.env, "xCrossTransferPanic")); - let decoded = CrossTransfer::decode(&ctx.env, data.clone()); - assert_eq!(decoded.to, ctx.withdrawer.to_string()); + let withdrawer = String::from_str(&ctx.env, "stellar/CA36FQITV33RO5SJFPTNLRQBD6ZNAEJG7F7J5KWCV4OP7SQHDMIZCT33"); + let data = CrossTransfer::new(ctx.depositor.to_string(), withdrawer.clone(), bnusd_amount, Bytes::from_array(&ctx.env, &items)).encode(&ctx.env, String::from_str(&ctx.env, "xCrossTransferPanic")); + let decoded: CrossTransfer = CrossTransfer::decode(&ctx.env, data.clone()); + let withdrawer_address = &Address::from_string(&String::from_str(&ctx.env, "CA36FQITV33RO5SJFPTNLRQBD6ZNAEJG7F7J5KWCV4OP7SQHDMIZCT33")); + assert_eq!(decoded.to, withdrawer); - assert_eq!(client.balance(&ctx.withdrawer), 0); + assert_eq!(client.balance(withdrawer_address), 0); let sources = Vec::from_array(&ctx.env, [ctx.centralized_connection.to_string()]); client.handle_call_message( &ctx.icon_bn_usd, &data, &sources); - assert_eq!(client.balance(&ctx.withdrawer), bnusd_amount as i128) + assert_eq!(client.balance(withdrawer_address), bnusd_amount as i128) } #[test] From d1395a58587d2241e324c32c519c565eca1157a2 Mon Sep 17 00:00:00 2001 From: sagar sapkota Date: Tue, 11 Jun 2024 17:48:40 +0545 Subject: [PATCH 19/63] decode length check enabled --- .../balanced_doller/src/tests/balanced_dollar_test.rs | 1 + libs/soroban-rlp/src/messages/cross_transfer.rs | 9 ++++----- libs/soroban-rlp/src/messages/deposit.rs | 2 +- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/contracts/balanced_doller/src/tests/balanced_dollar_test.rs b/contracts/balanced_doller/src/tests/balanced_dollar_test.rs index a18f1f8..c5afa3f 100644 --- a/contracts/balanced_doller/src/tests/balanced_dollar_test.rs +++ b/contracts/balanced_doller/src/tests/balanced_dollar_test.rs @@ -189,6 +189,7 @@ fn test_handle_call_message_for_cross_transfer_panic_for_wront_message_type(){ ]; let withdrawer = String::from_str(&ctx.env, "stellar/CA36FQITV33RO5SJFPTNLRQBD6ZNAEJG7F7J5KWCV4OP7SQHDMIZCT33"); let data = CrossTransfer::new(ctx.depositor.to_string(), withdrawer.clone(), bnusd_amount, Bytes::from_array(&ctx.env, &items)).encode(&ctx.env, String::from_str(&ctx.env, "xCrossTransferPanic")); + let decoded: CrossTransfer = CrossTransfer::decode(&ctx.env, data.clone()); let withdrawer_address = &Address::from_string(&String::from_str(&ctx.env, "CA36FQITV33RO5SJFPTNLRQBD6ZNAEJG7F7J5KWCV4OP7SQHDMIZCT33")); assert_eq!(decoded.to, withdrawer); diff --git a/libs/soroban-rlp/src/messages/cross_transfer.rs b/libs/soroban-rlp/src/messages/cross_transfer.rs index 840a7ca..4472e4f 100644 --- a/libs/soroban-rlp/src/messages/cross_transfer.rs +++ b/libs/soroban-rlp/src/messages/cross_transfer.rs @@ -35,7 +35,7 @@ impl CrossTransfer{ list.push_back(encoder::encode_string(&e, self.from.clone())); list.push_back(encoder::encode_string(&e, self.to.clone())); list.push_back(encoder::encode_u128(&e, self.amount.clone())); - list.push_back(self.data.clone()); + list.push_back(encoder::encode(&e, self.data.clone())); let encoded = encoder::encode_list(&e, list, false); encoded @@ -43,10 +43,9 @@ impl CrossTransfer{ pub fn decode(e: &Env, bytes: Bytes) -> CrossTransfer { let decoded = decoder::decode_list(&e, bytes); - //todo: check length - // if decoded.len() != 5 { - // panic!("InvalidRlpLength"); - // } + if decoded.len() != 5 { + panic!("InvalidRlpLength"); + } let from = decoder::decode_string(e, decoded.get(1).unwrap()); let to = decoder::decode_string(e, decoded.get(2).unwrap()); diff --git a/libs/soroban-rlp/src/messages/deposit.rs b/libs/soroban-rlp/src/messages/deposit.rs index 5a5706c..b0fa639 100644 --- a/libs/soroban-rlp/src/messages/deposit.rs +++ b/libs/soroban-rlp/src/messages/deposit.rs @@ -50,7 +50,7 @@ impl Deposit{ list.push_back(encoder::encode_string(&e, self.from.clone())); list.push_back(encoder::encode_string(&e, self.to.clone())); list.push_back(encoder::encode_u128(&e, self.amount.clone())); - list.push_back(self.data.clone()); + list.push_back(encoder::encode(&e, self.data.clone())); let encoded = encoder::encode_list(&e, list, false); encoded From da7273f9cfc0646c70ae2c3272052054bab3dd93 Mon Sep 17 00:00:00 2001 From: sagar sapkota Date: Wed, 12 Jun 2024 12:15:05 +0545 Subject: [PATCH 20/63] number type conversion update --- contracts/balanced_doller/src/balanced_dollar.rs | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/contracts/balanced_doller/src/balanced_dollar.rs b/contracts/balanced_doller/src/balanced_dollar.rs index a4c201b..4b8e18a 100644 --- a/contracts/balanced_doller/src/balanced_dollar.rs +++ b/contracts/balanced_doller/src/balanced_dollar.rs @@ -7,7 +7,6 @@ mod xcall { use soroban_rlp::messages::{cross_transfer::CrossTransfer, cross_transfer_revert::CrossTransferRevert}; use crate::storage_types::{INSTANCE_BUMP_AMOUNT, INSTANCE_LIFETIME_THRESHOLD}; use crate::states::read_administrator; - use crate::{ config::{ get_config, set_config, ConfigData}, xcall_manager_interface::XcallManagerClient }; @@ -81,19 +80,19 @@ pub fn _handle_call_message( if from!=icon_bn_usd { panic_with_error!(e, ContractError::OnlyIconBnUSD) } - let message = CrossTransfer::decode(&e.clone(), data); let to_network_address = get_address(message.to.clone(), &e.clone()); - _mint(e.clone(), to_network_address, u128::try_into(message.amount).unwrap()); + _mint(e.clone(), to_network_address, message.amount as i128 ); } else if method == String::from_str(&e, &CROSS_TRANSFER_REVERT){ if from!=xcall.to_string() { panic_with_error!(e, ContractError::OnlyCallService) } let message = CrossTransferRevert::decode(&e.clone(), data); - _mint(e.clone(), message.to, u128::try_into(message.amount).unwrap()); + _mint(e.clone(), message.to, message.amount as i128); }else{ panic_with_error!(e, ContractError::UnknownMessageType) } + } pub fn get_address(network_address: String, env: &Env) -> Address { From 384c2a1e70e82082c00cecf00d6ca2e0466719db Mon Sep 17 00:00:00 2001 From: sagar sapkota Date: Wed, 12 Jun 2024 12:44:34 +0545 Subject: [PATCH 21/63] sender params added to handle_call_message method --- contracts/balanced_doller/src/contract.rs | 1 + .../src/tests/balanced_dollar_test.rs | 12 ++++++------ contracts/xcall_manager/src/contract.rs | 1 + .../xcall_manager/src/tests/xcall_manager_test.rs | 12 ++++++------ 4 files changed, 14 insertions(+), 12 deletions(-) diff --git a/contracts/balanced_doller/src/contract.rs b/contracts/balanced_doller/src/contract.rs index 319b30f..16512df 100644 --- a/contracts/balanced_doller/src/contract.rs +++ b/contracts/balanced_doller/src/contract.rs @@ -91,6 +91,7 @@ impl BalancedDollar { pub fn handle_call_message( e: Env, + _xcall: Address, from: String, data: Bytes, protocols: Vec diff --git a/contracts/balanced_doller/src/tests/balanced_dollar_test.rs b/contracts/balanced_doller/src/tests/balanced_dollar_test.rs index c5afa3f..75d5f39 100644 --- a/contracts/balanced_doller/src/tests/balanced_dollar_test.rs +++ b/contracts/balanced_doller/src/tests/balanced_dollar_test.rs @@ -102,7 +102,7 @@ fn test_handle_call_message_for_cross_transfer(){ assert_eq!(client.balance(withdrawer_address), 0); let sources = Vec::from_array(&ctx.env, [ctx.centralized_connection.to_string()]); - client.handle_call_message( &ctx.icon_bn_usd, &data, &sources); + client.handle_call_message(&ctx.xcall, &ctx.icon_bn_usd, &data, &sources); assert_eq!(client.balance(withdrawer_address), bnusd_amount as i128) @@ -134,7 +134,7 @@ fn test_handle_call_message_for_cross_transfer_panic_for_protocol_mismatch(){ assert_eq!(client.balance(withdrawer_address), 0); let sources = Vec::from_array(&ctx.env, [ctx.xcall.to_string()]); - client.handle_call_message( &ctx.icon_bn_usd, &data, &sources); + client.handle_call_message(&ctx.xcall, &ctx.icon_bn_usd, &data, &sources); assert_eq!(client.balance(withdrawer_address), bnusd_amount as i128) } @@ -165,7 +165,7 @@ fn test_handle_call_message_for_cross_transfer_panic_for_icon_bnusd(){ assert_eq!(client.balance(withdrawer_address), 0); let sources = Vec::from_array(&ctx.env, [ctx.centralized_connection.to_string()]); - client.handle_call_message( &ctx.icon_governance, &data, &sources); + client.handle_call_message(&ctx.xcall, &ctx.icon_governance, &data, &sources); assert_eq!(client.balance(withdrawer_address), bnusd_amount as i128) } @@ -197,7 +197,7 @@ fn test_handle_call_message_for_cross_transfer_panic_for_wront_message_type(){ assert_eq!(client.balance(withdrawer_address), 0); let sources = Vec::from_array(&ctx.env, [ctx.centralized_connection.to_string()]); - client.handle_call_message( &ctx.icon_bn_usd, &data, &sources); + client.handle_call_message( &ctx.xcall, &ctx.icon_bn_usd, &data, &sources); assert_eq!(client.balance(withdrawer_address), bnusd_amount as i128) } @@ -219,7 +219,7 @@ fn test_handle_call_message_for_cross_transfer_revert(){ assert_eq!(client.balance(&ctx.withdrawer), 0); let sources = Vec::from_array(&ctx.env, [ctx.centralized_connection.to_string()]); - client.handle_call_message( &ctx.xcall.to_string(), &data, &sources); + client.handle_call_message(&ctx.xcall, &ctx.xcall.to_string(), &data, &sources); assert_eq!(client.balance(&ctx.withdrawer), bnusd_amount as i128) } @@ -242,7 +242,7 @@ fn test_handle_call_message_for_cross_transfer_revert_panic_for_xcall(){ assert_eq!(client.balance(&ctx.withdrawer), 0); let sources = Vec::from_array(&ctx.env, [ctx.centralized_connection.to_string()]); - client.handle_call_message( &ctx.centralized_connection.to_string(), &data, &sources); + client.handle_call_message( &ctx.xcall, &ctx.centralized_connection.to_string(), &data, &sources); assert_eq!(client.balance(&ctx.withdrawer), bnusd_amount as i128) } diff --git a/contracts/xcall_manager/src/contract.rs b/contracts/xcall_manager/src/contract.rs index 75d795b..7dfd16b 100644 --- a/contracts/xcall_manager/src/contract.rs +++ b/contracts/xcall_manager/src/contract.rs @@ -102,6 +102,7 @@ impl XcallManager { pub fn handle_call_message( e: Env, + _xcall: Address, from: String, data: Bytes, protocols: Vec diff --git a/contracts/xcall_manager/src/tests/xcall_manager_test.rs b/contracts/xcall_manager/src/tests/xcall_manager_test.rs index e5337e9..f9450e8 100644 --- a/contracts/xcall_manager/src/tests/xcall_manager_test.rs +++ b/contracts/xcall_manager/src/tests/xcall_manager_test.rs @@ -97,7 +97,7 @@ fn test_handle_call_message_for_configure_protocols(){ assert_eq!(decoded.sources, sources); assert_eq!(decoded.destinations, destinations); let (s, _) = client.get_protocols(); - client.handle_call_message(&ctx.icon_governance, &data, &s); + client.handle_call_message(&ctx.xcall,&ctx.icon_governance, &data, &s); let (s, d) = client.get_protocols(); assert_eq!(s, sources); @@ -129,7 +129,7 @@ fn test_get_modified_proposals(){ let data = ConfigureProtocols::new(sources.clone(), destinations.clone()).encode(&ctx.env, String::from_str(&ctx.env, "ConfigureProtocols")); let (s, _) = client.get_protocols(); - client.handle_call_message(&ctx.icon_governance, &data, &s); + client.handle_call_message(&ctx.xcall,&ctx.icon_governance, &data, &s); client.propose_removal(&String::from_str(&ctx.env, "sui/address")); @@ -152,7 +152,7 @@ fn test_get_modified_proposals_panic_no_proposed_removal(){ let data = ConfigureProtocols::new(sources.clone(), destinations.clone()).encode(&ctx.env, String::from_str(&ctx.env, "ConfigureProtocols")); let (s, _) = client.get_protocols(); - client.handle_call_message(&ctx.icon_governance, &data, &s); + client.handle_call_message(&ctx.xcall,&ctx.icon_governance, &data, &s); //client.propose_removal(&String::from_str(&ctx.env, "sui/address")); @@ -179,7 +179,7 @@ fn test_handle_call_message_for_configure_protocols_panic_for_only_icon_governan assert_eq!(decoded.sources, sources); assert_eq!(decoded.destinations, destinations); let (s, _) = client.get_protocols(); - client.handle_call_message(&ctx.xcall_network_address, &data, &s); + client.handle_call_message(&ctx.xcall, &ctx.xcall_network_address, &data, &s); let (s, d) = client.get_protocols(); assert_eq!(s, sources); @@ -205,7 +205,7 @@ fn test_handle_call_message_for_configure_protocols_panic_for_protocol_mismatch( assert_eq!(decoded.sources, sources); assert_eq!(decoded.destinations, destinations); let s = Vec::from_array(&ctx.env, [ctx.xcall.to_string()]); - client.handle_call_message(&ctx.icon_governance, &data, &s); + client.handle_call_message(&ctx.xcall,&ctx.icon_governance, &data, &s); let (s, d) = client.get_protocols(); assert_eq!(s, sources); @@ -231,7 +231,7 @@ fn test_handle_call_message_for_configure_protocols_panic_for_unknown_mesage_typ assert_eq!(decoded.sources, sources); assert_eq!(decoded.destinations, destinations); let s = Vec::from_array(&ctx.env, [ctx.centralized_connection.to_string()]); - client.handle_call_message(&ctx.icon_governance, &data, &s); + client.handle_call_message(&ctx.xcall,&ctx.icon_governance, &data, &s); let (s, d) = client.get_protocols(); assert_eq!(s, sources); From d68356c6085ee16cef52fa36d33865e9320d047f Mon Sep 17 00:00:00 2001 From: sagar sapkota Date: Wed, 12 Jun 2024 19:22:14 +0545 Subject: [PATCH 22/63] bnusd cross trasfer revert from param update --- contracts/balanced_doller/src/balanced_dollar.rs | 3 ++- contracts/balanced_doller/src/tests/balanced_dollar_test.rs | 2 +- contracts/balanced_doller/src/tests/setup.rs | 6 ++++-- 3 files changed, 7 insertions(+), 4 deletions(-) diff --git a/contracts/balanced_doller/src/balanced_dollar.rs b/contracts/balanced_doller/src/balanced_dollar.rs index 4b8e18a..182d216 100644 --- a/contracts/balanced_doller/src/balanced_dollar.rs +++ b/contracts/balanced_doller/src/balanced_dollar.rs @@ -84,7 +84,8 @@ pub fn _handle_call_message( let to_network_address = get_address(message.to.clone(), &e.clone()); _mint(e.clone(), to_network_address, message.amount as i128 ); } else if method == String::from_str(&e, &CROSS_TRANSFER_REVERT){ - if from!=xcall.to_string() { + let xcall_network_address = self::xcall_client(e.clone()).get_network_address(); + if from!=xcall_network_address { panic_with_error!(e, ContractError::OnlyCallService) } let message = CrossTransferRevert::decode(&e.clone(), data); diff --git a/contracts/balanced_doller/src/tests/balanced_dollar_test.rs b/contracts/balanced_doller/src/tests/balanced_dollar_test.rs index 75d5f39..d716120 100644 --- a/contracts/balanced_doller/src/tests/balanced_dollar_test.rs +++ b/contracts/balanced_doller/src/tests/balanced_dollar_test.rs @@ -219,7 +219,7 @@ fn test_handle_call_message_for_cross_transfer_revert(){ assert_eq!(client.balance(&ctx.withdrawer), 0); let sources = Vec::from_array(&ctx.env, [ctx.centralized_connection.to_string()]); - client.handle_call_message(&ctx.xcall, &ctx.xcall.to_string(), &data, &sources); + client.handle_call_message(&ctx.xcall, &ctx.xcall_client.get_network_address(), &data, &sources); assert_eq!(client.balance(&ctx.withdrawer), bnusd_amount as i128) } diff --git a/contracts/balanced_doller/src/tests/setup.rs b/contracts/balanced_doller/src/tests/setup.rs index 16eacc3..1ca8452 100644 --- a/contracts/balanced_doller/src/tests/setup.rs +++ b/contracts/balanced_doller/src/tests/setup.rs @@ -39,7 +39,8 @@ pub struct TestContext { pub token: Address, pub centralized_connection: Address, pub nid: String, - pub native_token: Address + pub native_token: Address, + pub xcall_client: xcall::Client<'static> } impl TestContext { @@ -61,7 +62,7 @@ impl TestContext { admin: Address::generate(&env), depositor: Address::generate(&env), withdrawer: Address::generate(&env), - xcall: xcall, + xcall: xcall.clone(), xcall_manager: xcall_manager, icon_bn_usd: String::from_str(&env, "icon01/hxjnfh4u"), icon_governance: String::from_str(&env, "icon01/kjdnoi"), @@ -69,6 +70,7 @@ impl TestContext { centralized_connection: centralized_connection, nid: String::from_str(&env, "stellar"), native_token: env.register_stellar_asset_contract(token_admin.clone()), + xcall_client: xcall::Client::new(&env, &xcall), env } } From 4d425c1c547d04e0014f22d4e16840e9b678f806 Mon Sep 17 00:00:00 2001 From: sagar sapkota Date: Fri, 14 Jun 2024 17:12:58 +0545 Subject: [PATCH 23/63] string address validation --- contracts/asset_manager/src/contract.rs | 43 +++++++++++++++++++++++-- contracts/asset_manager/src/errors.rs | 3 +- 2 files changed, 42 insertions(+), 4 deletions(-) diff --git a/contracts/asset_manager/src/contract.rs b/contracts/asset_manager/src/contract.rs index 8b115aa..46075d6 100644 --- a/contracts/asset_manager/src/contract.rs +++ b/contracts/asset_manager/src/contract.rs @@ -1,6 +1,6 @@ -use soroban_sdk::{contract, contractimpl, token, Address, Bytes, BytesN, Env, String, Vec, panic_with_error}; -mod xcall { +use soroban_sdk::{contract, contractimpl, panic_with_error, token, Address, Bytes, BytesN, Env, String, Vec}; +mod xcall { soroban_sdk::contractimport!(file = "../../wasm/xcall.wasm"); } use soroban_rlp::messages::{deposit::Deposit, deposit_revert::DepositRevert, withdraw_to::WithdrawTo}; @@ -215,6 +215,7 @@ impl AssetManager { protocols: Vec ) -> Result<(), ContractError> { get_config(&e).xcall.require_auth(); + if !Self::xcall_manager(e.clone()).verify_protocols(&protocols) { panic_with_error!(&e, ContractError::ProtocolMismatch); }; @@ -225,11 +226,16 @@ impl AssetManager { if from != icon_asset_manager{ panic_with_error!(&e, ContractError::OnlyICONAssetManager); }; + let message = WithdrawTo::decode(&e, data); + if !Self::is_valid_address(&message.to) || !Self::is_valid_address(&message.token_address) { + panic_with_error!(&e, ContractError::InvalidAddress); + } + Self::withdraw(e, current_contract, Address::from_string(&message.token_address), Address::from_string(&message.to), message.amount)?; } else if method == String::from_str(&e, &DEPOSIT_REVERT_NAME){ let xcall_network_address = Self::xcall_client(e.clone()).get_network_address(); - + if from != xcall_network_address { panic_with_error!(&e, ContractError::OnlyCallService) }; @@ -253,6 +259,37 @@ impl AssetManager { Ok(()) } + fn is_valid_address(address: &String) -> bool { + if address.len() != 56 { + return false; + } + + let mut address_bytes = [0u8; 56]; + address.copy_into_slice(&mut address_bytes); + + let mut is_valid = true; + + if address_bytes[0] != b'G' && address_bytes[0] != b'C' { + is_valid = false; + } + + for &byte in &address_bytes { + if !Self::is_valid_base32(byte) { + is_valid = false; + break; + } + } + + is_valid + } + + fn is_valid_base32(byte: u8) -> bool { + match byte { + b'A'..=b'Z' | b'2'..=b'7' => true, + _ => false, + } + } + fn transfer_token_to(e: Env, from: Address, token: Address, to: Address, amount: u128){ let token_client = token::Client::new(&e, &token); token_client.transfer(&from, &to, &(amount as i128)); diff --git a/contracts/asset_manager/src/errors.rs b/contracts/asset_manager/src/errors.rs index 8380dc8..d539591 100644 --- a/contracts/asset_manager/src/errors.rs +++ b/contracts/asset_manager/src/errors.rs @@ -15,6 +15,7 @@ pub enum ContractError { OnlyCallService = 9, UnknownMessageType = 10, AdminRequired = 11, - TokenExists = 12 + TokenExists = 12, + InvalidAddress = 13 } \ No newline at end of file From 6174c57f438f6b0efe2b2f70c1aa87b4e04c366d Mon Sep 17 00:00:00 2001 From: sagar sapkota Date: Fri, 14 Jun 2024 19:23:31 +0545 Subject: [PATCH 24/63] unit test added for invalid adddress --- .../src/tests/asset_manager_test.rs | 27 +++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/contracts/asset_manager/src/tests/asset_manager_test.rs b/contracts/asset_manager/src/tests/asset_manager_test.rs index a598b12..c046062 100644 --- a/contracts/asset_manager/src/tests/asset_manager_test.rs +++ b/contracts/asset_manager/src/tests/asset_manager_test.rs @@ -260,6 +260,33 @@ fn test_handle_call_message_for_withdraw_to(){ assert_eq!(token_client.balance(&ctx.withdrawer), bnusd_amount as i128) } +#[test] +#[should_panic(expected = "HostError: Error(Contract, #13)")] +fn test_handle_call_message_for_withdraw_to_invalid_address(){ + let ctx = TestContext::default(); + let client = AssetManagerClient::new(&ctx.env, &ctx.registry); + ctx.env.mock_all_auths(); + + ctx.init_context(&client); + client.configure_rate_limit( &ctx.token, &300u128, &300u128); + + let bnusd_amount = 100000u128; + let token_client = token::Client::new(&ctx.env, &ctx.token); + let stellar_asset_client: token::StellarAssetClient = token::StellarAssetClient::new(&ctx.env, &ctx.token); + stellar_asset_client.mint(&ctx.registry, &((bnusd_amount*2) as i128)); + + let data = WithdrawTo::new(ctx.token.to_string(), String::from_str(&ctx.env, "InvalidAddress"), bnusd_amount).encode(&ctx.env, String::from_str(&ctx.env, "WithdrawTo")); + let decoded = WithdrawTo::decode(&ctx.env, data.clone()); + assert_eq!(decoded.to, String::from_str(&ctx.env, "InvalidAddress")); + + assert_eq!(token_client.balance(&ctx.withdrawer), 0); + + let sources = Vec::from_array(&ctx.env, [ctx.centralized_connection.to_string()]); + client.handle_call_message(&ctx.xcall, &ctx.icon_asset_manager, &data, &sources); + + assert_eq!(token_client.balance(&ctx.withdrawer), bnusd_amount as i128) +} + #[test] #[should_panic(expected = "HostError: Error(Contract, #7)")] fn test_handle_call_message_for_withdraw_to_panic_with_protocal_mismatch(){ From 71cd7cf09061899e299ac4f784648cb7ab6214b7 Mon Sep 17 00:00:00 2001 From: sagar sapkota Date: Mon, 17 Jun 2024 10:51:00 +0545 Subject: [PATCH 25/63] check valid address for Bytes --- contracts/asset_manager/src/contract.rs | 34 +----------- .../balanced_doller/src/balanced_dollar.rs | 6 ++- contracts/balanced_doller/src/errors.rs | 1 + libs/soroban-rlp/src/address_utils.rs | 52 +++++++++++++++++++ libs/soroban-rlp/src/lib.rs | 1 + 5 files changed, 61 insertions(+), 33 deletions(-) create mode 100644 libs/soroban-rlp/src/address_utils.rs diff --git a/contracts/asset_manager/src/contract.rs b/contracts/asset_manager/src/contract.rs index 46075d6..e6e46c6 100644 --- a/contracts/asset_manager/src/contract.rs +++ b/contracts/asset_manager/src/contract.rs @@ -4,6 +4,7 @@ mod xcall { soroban_sdk::contractimport!(file = "../../wasm/xcall.wasm"); } use soroban_rlp::messages::{deposit::Deposit, deposit_revert::DepositRevert, withdraw_to::WithdrawTo}; +use soroban_rlp::address_utils::is_valid_string_address; use crate::{ config::{get_config, set_config, ConfigData}, states:: {has_registry, read_administrator, read_token_last_current_limit, read_token_last_update, @@ -228,7 +229,7 @@ impl AssetManager { }; let message = WithdrawTo::decode(&e, data); - if !Self::is_valid_address(&message.to) || !Self::is_valid_address(&message.token_address) { + if !is_valid_string_address(&message.to) || !is_valid_string_address(&message.token_address) { panic_with_error!(&e, ContractError::InvalidAddress); } @@ -259,37 +260,6 @@ impl AssetManager { Ok(()) } - fn is_valid_address(address: &String) -> bool { - if address.len() != 56 { - return false; - } - - let mut address_bytes = [0u8; 56]; - address.copy_into_slice(&mut address_bytes); - - let mut is_valid = true; - - if address_bytes[0] != b'G' && address_bytes[0] != b'C' { - is_valid = false; - } - - for &byte in &address_bytes { - if !Self::is_valid_base32(byte) { - is_valid = false; - break; - } - } - - is_valid - } - - fn is_valid_base32(byte: u8) -> bool { - match byte { - b'A'..=b'Z' | b'2'..=b'7' => true, - _ => false, - } - } - fn transfer_token_to(e: Env, from: Address, token: Address, to: Address, amount: u128){ let token_client = token::Client::new(&e, &token); token_client.transfer(&from, &to, &(amount as i128)); diff --git a/contracts/balanced_doller/src/balanced_dollar.rs b/contracts/balanced_doller/src/balanced_dollar.rs index 182d216..8392976 100644 --- a/contracts/balanced_doller/src/balanced_dollar.rs +++ b/contracts/balanced_doller/src/balanced_dollar.rs @@ -10,7 +10,7 @@ use crate::states::read_administrator; use crate::{ config::{ get_config, set_config, ConfigData}, xcall_manager_interface::XcallManagerClient }; - +use soroban_rlp::address_utils::is_valid_bytes_address; use crate::errors::ContractError; use xcall::{AnyMessage, CallMessageWithRollback, Client, Envelope}; @@ -81,6 +81,7 @@ pub fn _handle_call_message( panic_with_error!(e, ContractError::OnlyIconBnUSD) } let message = CrossTransfer::decode(&e.clone(), data); + let to_network_address = get_address(message.to.clone(), &e.clone()); _mint(e.clone(), to_network_address, message.amount as i128 ); } else if method == String::from_str(&e, &CROSS_TRANSFER_REVERT){ @@ -124,6 +125,9 @@ pub fn get_address(network_address: String, env: &Env) -> Address { panic!("Invalid network address") } + if !is_valid_bytes_address(&account) { + panic_with_error!(&env, ContractError::InvalidAddress); + } Address::from_string_bytes(&account) } diff --git a/contracts/balanced_doller/src/errors.rs b/contracts/balanced_doller/src/errors.rs index 84330a2..fc19236 100644 --- a/contracts/balanced_doller/src/errors.rs +++ b/contracts/balanced_doller/src/errors.rs @@ -11,4 +11,5 @@ pub enum ContractError { OnlyIconBnUSD = 5, OnlyCallService = 6, UnknownMessageType = 7, + InvalidAddress = 8 } \ No newline at end of file diff --git a/libs/soroban-rlp/src/address_utils.rs b/libs/soroban-rlp/src/address_utils.rs new file mode 100644 index 0000000..8045a73 --- /dev/null +++ b/libs/soroban-rlp/src/address_utils.rs @@ -0,0 +1,52 @@ +use soroban_sdk::{String, Bytes}; + +pub fn is_valid_string_address(address: &String) -> bool { + if address.len() != 56 { + return false; + } + + let mut address_bytes = [0u8; 56]; + address.copy_into_slice(&mut address_bytes); + + let mut is_valid = true; + + if address_bytes[0] != b'G' && address_bytes[0] != b'C' { + is_valid = false; + } + + for &byte in &address_bytes { + if !is_valid_base32(byte) { + is_valid = false; + break; + } + } + + is_valid +} + +pub fn is_valid_bytes_address(address: &Bytes) -> bool { + if address.len() != 56 { + return false; + } + if address.get(0).unwrap() != b'G' && address.get(0).unwrap() != b'C' { + return false; + } + + for i in 0..56 { + let byte = address.get(i).unwrap(); + if !is_valid_base32(byte) { + return false; + } + } + + true +} + + + +fn is_valid_base32(byte: u8) -> bool { + match byte { + b'A'..=b'Z' | b'2'..=b'7' => true, + _ => false, + } +} \ No newline at end of file diff --git a/libs/soroban-rlp/src/lib.rs b/libs/soroban-rlp/src/lib.rs index 32c2a98..e8158b0 100644 --- a/libs/soroban-rlp/src/lib.rs +++ b/libs/soroban-rlp/src/lib.rs @@ -4,3 +4,4 @@ pub mod decoder; pub mod encoder; mod utils; pub mod messages; +pub mod address_utils; \ No newline at end of file From 85f5742a9bee4a53ac7de43e0f440073b1a213ba Mon Sep 17 00:00:00 2001 From: sagar sapkota Date: Mon, 17 Jun 2024 11:29:28 +0545 Subject: [PATCH 26/63] asset manager rate_limit calc update, bnusd invalid address unittest added --- contracts/asset_manager/src/contract.rs | 19 +++++------ .../balanced_doller/src/balanced_dollar.rs | 2 -- .../src/tests/balanced_dollar_test.rs | 32 +++++++++++++++++++ 3 files changed, 42 insertions(+), 11 deletions(-) diff --git a/contracts/asset_manager/src/contract.rs b/contracts/asset_manager/src/contract.rs index e6e46c6..2cd257d 100644 --- a/contracts/asset_manager/src/contract.rs +++ b/contracts/asset_manager/src/contract.rs @@ -128,20 +128,21 @@ impl AssetManager { return Ok(0); } - let max_limit = (balance * percentage) / POINTS; + let min_reserve = (balance * percentage) / POINTS; - let max_withdraw = balance - max_limit; + let max_withdraw = balance - min_reserve; let last_update: u64 = read_token_last_update(&env, &token.clone()); let time_diff = (&env.ledger().timestamp() - last_update)/1000; - let added_allowed_withdrawal = (max_withdraw * time_diff as u128) / period; - let current_limit: u128 = read_token_last_current_limit(&env, &token.clone()); - let limit: u128 = current_limit - added_allowed_withdrawal; + let allowed_withdrawal = (max_withdraw * time_diff as u128) / period; + let mut reserve: u128 = read_token_last_current_limit(&env, &token.clone()); - let limit = if balance < limit { balance } else { limit }; - - let final_limit = if limit > max_limit { limit } else { max_limit }; - Ok(final_limit) + if reserve > allowed_withdrawal{ + reserve = reserve - allowed_withdrawal; + } + + let reserve = if reserve > min_reserve { reserve } else { min_reserve }; + Ok(reserve) } pub fn deposit( diff --git a/contracts/balanced_doller/src/balanced_dollar.rs b/contracts/balanced_doller/src/balanced_dollar.rs index 8392976..2c34a09 100644 --- a/contracts/balanced_doller/src/balanced_dollar.rs +++ b/contracts/balanced_doller/src/balanced_dollar.rs @@ -12,11 +12,9 @@ use crate::{ }; use soroban_rlp::address_utils::is_valid_bytes_address; use crate::errors::ContractError; - use xcall::{AnyMessage, CallMessageWithRollback, Client, Envelope}; use soroban_token_sdk::TokenUtils; use crate::contract; - const CROSS_TRANSFER: &str = "xCrossTransfer"; const CROSS_TRANSFER_REVERT: &str = "xCrossTransferRevert"; diff --git a/contracts/balanced_doller/src/tests/balanced_dollar_test.rs b/contracts/balanced_doller/src/tests/balanced_dollar_test.rs index d716120..d8730a0 100644 --- a/contracts/balanced_doller/src/tests/balanced_dollar_test.rs +++ b/contracts/balanced_doller/src/tests/balanced_dollar_test.rs @@ -106,6 +106,38 @@ fn test_handle_call_message_for_cross_transfer(){ assert_eq!(client.balance(withdrawer_address), bnusd_amount as i128) +} + +#[test] +#[should_panic(expected = "HostError: Error(Contract, #8)")] +fn test_handle_call_message_for_cross_transfer_invalid_addres_fail(){ + let ctx = TestContext::default(); + let client = BalancedDollarClient::new(&ctx.env, &ctx.registry); + ctx.env.mock_all_auths(); + + ctx.init_context(&client); + + let bnusd_amount = 100000u128; + + let items: [u8; 32] = [ + 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, + 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0x10, + 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, + 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F, 0x20, + ]; + let withdrawer = String::from_str(&ctx.env, "stellar/InvalidAddress"); + let data = CrossTransfer::new(ctx.depositor.to_string(), withdrawer.clone(), bnusd_amount, Bytes::from_array(&ctx.env, &items)).encode(&ctx.env, String::from_str(&ctx.env, "xCrossTransfer")); + let decoded = CrossTransfer::decode(&ctx.env, data.clone()); + assert_eq!(decoded.to, withdrawer); + + // let withdrawer_address = &Address::from_string(&String::from_str(&ctx.env, "InvalidAddress")); + // assert_eq!(client.balance(withdrawer_address), 0); + + let sources = Vec::from_array(&ctx.env, [ctx.centralized_connection.to_string()]); + client.handle_call_message(&ctx.xcall, &ctx.icon_bn_usd, &data, &sources); + // assert_eq!(client.balance(withdrawer_address), bnusd_amount as i128) + + } #[test] From 40ef476f9900a054ba1b0516898b13dc8ffcf6ea Mon Sep 17 00:00:00 2001 From: sagar sapkota Date: Mon, 17 Jun 2024 16:39:44 +0545 Subject: [PATCH 27/63] reentrancy issue fix --- contracts/balanced_doller/src/balanced_dollar.rs | 5 ++--- contracts/balanced_doller/src/contract.rs | 4 ++-- contracts/balanced_doller/src/tests/balanced_dollar_test.rs | 2 +- 3 files changed, 5 insertions(+), 6 deletions(-) diff --git a/contracts/balanced_doller/src/balanced_dollar.rs b/contracts/balanced_doller/src/balanced_dollar.rs index 2c34a09..b5003a6 100644 --- a/contracts/balanced_doller/src/balanced_dollar.rs +++ b/contracts/balanced_doller/src/balanced_dollar.rs @@ -62,6 +62,7 @@ pub fn _cross_transfer( pub fn _handle_call_message( e: Env, + xcall_address : Address, from: String, data: Bytes, protocols: Vec @@ -79,12 +80,10 @@ pub fn _handle_call_message( panic_with_error!(e, ContractError::OnlyIconBnUSD) } let message = CrossTransfer::decode(&e.clone(), data); - let to_network_address = get_address(message.to.clone(), &e.clone()); _mint(e.clone(), to_network_address, message.amount as i128 ); } else if method == String::from_str(&e, &CROSS_TRANSFER_REVERT){ - let xcall_network_address = self::xcall_client(e.clone()).get_network_address(); - if from!=xcall_network_address { + if xcall!=xcall_address { panic_with_error!(e, ContractError::OnlyCallService) } let message = CrossTransferRevert::decode(&e.clone(), data); diff --git a/contracts/balanced_doller/src/contract.rs b/contracts/balanced_doller/src/contract.rs index 16512df..529feed 100644 --- a/contracts/balanced_doller/src/contract.rs +++ b/contracts/balanced_doller/src/contract.rs @@ -91,12 +91,12 @@ impl BalancedDollar { pub fn handle_call_message( e: Env, - _xcall: Address, + xcall: Address, from: String, data: Bytes, protocols: Vec ) { - balanced_dollar::_handle_call_message(e, from, data, protocols); + balanced_dollar::_handle_call_message(e, xcall, from, data, protocols); } pub fn is_initialized(e: Env) -> bool { diff --git a/contracts/balanced_doller/src/tests/balanced_dollar_test.rs b/contracts/balanced_doller/src/tests/balanced_dollar_test.rs index d8730a0..06b1291 100644 --- a/contracts/balanced_doller/src/tests/balanced_dollar_test.rs +++ b/contracts/balanced_doller/src/tests/balanced_dollar_test.rs @@ -274,7 +274,7 @@ fn test_handle_call_message_for_cross_transfer_revert_panic_for_xcall(){ assert_eq!(client.balance(&ctx.withdrawer), 0); let sources = Vec::from_array(&ctx.env, [ctx.centralized_connection.to_string()]); - client.handle_call_message( &ctx.xcall, &ctx.centralized_connection.to_string(), &data, &sources); + client.handle_call_message( &ctx.centralized_connection, &ctx.xcall_client.get_network_address(), &data, &sources); assert_eq!(client.balance(&ctx.withdrawer), bnusd_amount as i128) } From 932201f86258edf06e07c863a321453ba124c1a3 Mon Sep 17 00:00:00 2001 From: sagar sapkota Date: Mon, 17 Jun 2024 18:01:59 +0545 Subject: [PATCH 28/63] error handling fixes --- contracts/asset_manager/src/contract.rs | 10 +++---- .../balanced_doller/src/balanced_dollar.rs | 29 +++++++++---------- contracts/balanced_doller/src/contract.rs | 12 ++++---- contracts/balanced_doller/src/errors.rs | 4 ++- contracts/xcall_manager/src/contract.rs | 26 +++++++++-------- 5 files changed, 42 insertions(+), 39 deletions(-) diff --git a/contracts/asset_manager/src/contract.rs b/contracts/asset_manager/src/contract.rs index 2cd257d..806d941 100644 --- a/contracts/asset_manager/src/contract.rs +++ b/contracts/asset_manager/src/contract.rs @@ -226,12 +226,12 @@ impl AssetManager { let current_contract = e.current_contract_address(); if method == String::from_str(&e, &WITHDRAW_TO_NAME){ if from != icon_asset_manager{ - panic_with_error!(&e, ContractError::OnlyICONAssetManager); + return Err(ContractError::OnlyICONAssetManager); }; let message = WithdrawTo::decode(&e, data); if !is_valid_string_address(&message.to) || !is_valid_string_address(&message.token_address) { - panic_with_error!(&e, ContractError::InvalidAddress); + return Err(ContractError::InvalidAddress); } Self::withdraw(e, current_contract, Address::from_string(&message.token_address), Address::from_string(&message.to), message.amount)?; @@ -239,19 +239,19 @@ impl AssetManager { let xcall_network_address = Self::xcall_client(e.clone()).get_network_address(); if from != xcall_network_address { - panic_with_error!(&e, ContractError::OnlyCallService) + return Err(ContractError::OnlyCallService) }; let message: DepositRevert = DepositRevert::decode(&e.clone(), data); Self::withdraw(e, current_contract, message.token_address, message.to, message.amount)?; } else { - panic_with_error!(&e, ContractError::UnknownMessageType); + return Err(ContractError::UnknownMessageType); } Ok(()) } pub fn withdraw(e: Env, from: Address, token: Address, to: Address, amount: u128) -> Result<(), ContractError> { if amount <= 0 { - panic_with_error!(&e, ContractError::AmountIsLessThanMinimumAmount); + return Err(ContractError::AmountIsLessThanMinimumAmount); } let verified = Self::verify_withdraw(e.clone(), token.clone(), amount)?; diff --git a/contracts/balanced_doller/src/balanced_dollar.rs b/contracts/balanced_doller/src/balanced_dollar.rs index b5003a6..851a473 100644 --- a/contracts/balanced_doller/src/balanced_dollar.rs +++ b/contracts/balanced_doller/src/balanced_dollar.rs @@ -1,4 +1,4 @@ -use soroban_sdk::{panic_with_error, Address, Bytes, Env, String, Vec, xdr::ToXdr}; +use soroban_sdk::{Address, Bytes, Env, String, Vec, xdr::ToXdr}; use crate::balance::{spend_balance, receive_balance}; mod xcall { soroban_sdk::contractimport!(file = "../../wasm/xcall.wasm"); @@ -28,7 +28,7 @@ pub fn _cross_transfer( amount: u128, to: String, data: Bytes -) -> Result<(), ContractError> { +) -> Result<(), ContractError> { _burn(e.clone(), from.clone(), amount as i128); let xcall_message = CrossTransfer::new( from.clone().to_string(), @@ -56,7 +56,6 @@ pub fn _cross_transfer( let current_address = e.clone().current_contract_address(); xcall_client(e).send_call(&from, ¤t_address, envelope, icon_bn_usd ); Ok(()) - } @@ -66,39 +65,39 @@ pub fn _handle_call_message( from: String, data: Bytes, protocols: Vec -) { +) -> Result<(), ContractError> { let xcall = get_config(&e).xcall; xcall.require_auth(); if !xcall_manager_client(e.clone()).verify_protocols(&protocols) { - panic_with_error!(e, ContractError::ProtocolMismatch) + return Err(ContractError::ProtocolMismatch) }; let method = CrossTransfer::get_method(&e, data.clone()); let icon_bn_usd = get_config(&e).icon_bn_usd; if method == String::from_str(&e, &CROSS_TRANSFER){ if from!=icon_bn_usd { - panic_with_error!(e, ContractError::OnlyIconBnUSD) + return Err(ContractError::OnlyIconBnUSD); } let message = CrossTransfer::decode(&e.clone(), data); - let to_network_address = get_address(message.to.clone(), &e.clone()); + let to_network_address: Address = get_address(message.to.clone(), &e.clone())?; _mint(e.clone(), to_network_address, message.amount as i128 ); } else if method == String::from_str(&e, &CROSS_TRANSFER_REVERT){ if xcall!=xcall_address { - panic_with_error!(e, ContractError::OnlyCallService) + return Err(ContractError::OnlyCallService) } let message = CrossTransferRevert::decode(&e.clone(), data); _mint(e.clone(), message.to, message.amount as i128); }else{ - panic_with_error!(e, ContractError::UnknownMessageType) + return Err(ContractError::UnknownMessageType) } - + Ok(()) } -pub fn get_address(network_address: String, env: &Env) -> Address { +pub fn get_address(network_address: String, env: &Env) -> Result { let bytes = network_address.to_xdr(&env); if bytes.get(6).unwrap() > 0 { - panic!("Invalid network address length") + return Err(ContractError::InvalidNetworkAddressLength); } let value_len = bytes.get(7).unwrap(); @@ -119,13 +118,13 @@ pub fn get_address(network_address: String, env: &Env) -> Address { } if !has_seperator { - panic!("Invalid network address") + return Err(ContractError::InvalidNetworkAddress); } if !is_valid_bytes_address(&account) { - panic_with_error!(&env, ContractError::InvalidAddress); + return Err(ContractError::InvalidAddress); } - Address::from_string_bytes(&account) + Ok(Address::from_string_bytes(&account)) } pub fn _mint(e: Env, to: Address, amount: i128) { diff --git a/contracts/balanced_doller/src/contract.rs b/contracts/balanced_doller/src/contract.rs index 529feed..567193c 100644 --- a/contracts/balanced_doller/src/contract.rs +++ b/contracts/balanced_doller/src/contract.rs @@ -73,9 +73,9 @@ impl BalancedDollar { from: Address, amount: u128, to: String, - ) { + ) -> Result<(), ContractError> { from.require_auth(); - balanced_dollar::_cross_transfer(e.clone(), from, amount, to, Bytes::new(&e)).unwrap(); + return balanced_dollar::_cross_transfer(e.clone(), from, amount, to, Bytes::new(&e)); } pub fn cross_transfer_data( @@ -84,9 +84,9 @@ impl BalancedDollar { amount: u128, to: String, data: Bytes - ) { + ) -> Result<(), ContractError> { from.require_auth(); - balanced_dollar::_cross_transfer(e, from, amount, to, data).unwrap(); + return balanced_dollar::_cross_transfer(e, from, amount, to, data); } pub fn handle_call_message( @@ -95,8 +95,8 @@ impl BalancedDollar { from: String, data: Bytes, protocols: Vec - ) { - balanced_dollar::_handle_call_message(e, xcall, from, data, protocols); + ) -> Result<(), ContractError> { + return balanced_dollar::_handle_call_message(e, xcall, from, data, protocols); } pub fn is_initialized(e: Env) -> bool { diff --git a/contracts/balanced_doller/src/errors.rs b/contracts/balanced_doller/src/errors.rs index fc19236..76dcfc2 100644 --- a/contracts/balanced_doller/src/errors.rs +++ b/contracts/balanced_doller/src/errors.rs @@ -11,5 +11,7 @@ pub enum ContractError { OnlyIconBnUSD = 5, OnlyCallService = 6, UnknownMessageType = 7, - InvalidAddress = 8 + InvalidAddress = 8, + InvalidNetworkAddressLength = 9, + InvalidNetworkAddress = 10 } \ No newline at end of file diff --git a/contracts/xcall_manager/src/contract.rs b/contracts/xcall_manager/src/contract.rs index 7dfd16b..dcf8d5a 100644 --- a/contracts/xcall_manager/src/contract.rs +++ b/contracts/xcall_manager/src/contract.rs @@ -106,18 +106,18 @@ impl XcallManager { from: String, data: Bytes, protocols: Vec - ) { + ) -> Result<(), ContractError> { let xcall = get_config(&e.clone()).xcall; xcall.require_auth(); let icon_governance = get_config(&e.clone()).icon_governance; if from != icon_governance { - panic_with_error!(e, ContractError::OnlyICONGovernance) + return Err(ContractError::OnlyICONGovernance); } if !Self::verify_protocols(e.clone(), protocols.clone()).unwrap() { - panic_with_error!(e, ContractError::ProtocolMismatch) + return Err(ContractError::ProtocolMismatch) }; let method = ConfigureProtocols::get_method(&e.clone(), data.clone()); @@ -125,9 +125,9 @@ impl XcallManager { let sources = read_sources(&e); if !Self::verify_protocols_unordered(e.clone(), protocols.clone(), sources).unwrap() { if method != String::from_str(&e.clone(), CONFIGURE_PROTOCOLS_NAME) { - panic_with_error!(e, ContractError::ProtocolMismatch) + return Err(ContractError::ProtocolMismatch) } - Self::verify_protocol_recovery(e.clone(), protocols); + Self::verify_protocol_recovery(e.clone(), protocols)?; } if method == String::from_str(&e, CONFIGURE_PROTOCOLS_NAME) { @@ -137,21 +137,23 @@ impl XcallManager { write_sources(&e, &sources); write_destinations(&e, &destinations); } else { - panic_with_error!(e, ContractError::UnknownMessageType) + return Err(ContractError::UnknownMessageType) } + Ok(()) } - pub fn verify_protocol_recovery(e: Env, protocols: Vec) { - let modified_sources = Self::get_modified_protocols(e.clone()); + pub fn verify_protocol_recovery(e: Env, protocols: Vec) -> Result<(), ContractError> { + let modified_sources = Self::get_modified_protocols(e.clone())?; let verify_unordered = Self::verify_protocols_unordered(e.clone(), modified_sources, protocols).unwrap(); if !verify_unordered { - panic_with_error!(e, ContractError::ProtocolMismatch) + return Err(ContractError::ProtocolMismatch) } + Ok(()) } - pub fn get_modified_protocols(e: Env) -> Vec{ + pub fn get_modified_protocols(e: Env) -> Result, ContractError> { if !has_proposed_removed(e.clone()) { - panic_with_error!(e, ContractError::NoProposalForRemovalExists) + return Err(ContractError::NoProposalForRemovalExists) } let sources = read_sources(&e); @@ -163,7 +165,7 @@ impl XcallManager { } } - return new_array; + return Ok(new_array); } pub fn extend_ttl(e: Env){ From ff15737ea707db290a62b965d069d50e1909ead4 Mon Sep 17 00:00:00 2001 From: sagar sapkota Date: Mon, 17 Jun 2024 19:14:51 +0545 Subject: [PATCH 29/63] bnusd code optimization --- .../balanced_doller/src/balanced_dollar.rs | 63 +++++++++---------- contracts/balanced_doller/src/contract.rs | 4 +- 2 files changed, 31 insertions(+), 36 deletions(-) diff --git a/contracts/balanced_doller/src/balanced_dollar.rs b/contracts/balanced_doller/src/balanced_dollar.rs index 851a473..44ac383 100644 --- a/contracts/balanced_doller/src/balanced_dollar.rs +++ b/contracts/balanced_doller/src/balanced_dollar.rs @@ -5,7 +5,6 @@ mod xcall { } use soroban_rlp::messages::{cross_transfer::CrossTransfer, cross_transfer_revert::CrossTransferRevert}; -use crate::storage_types::{INSTANCE_BUMP_AMOUNT, INSTANCE_LIFETIME_THRESHOLD}; use crate::states::read_administrator; use crate::{ config::{ get_config, set_config, ConfigData}, xcall_manager_interface::XcallManagerClient @@ -29,7 +28,7 @@ pub fn _cross_transfer( to: String, data: Bytes ) -> Result<(), ContractError> { - _burn(e.clone(), from.clone(), amount as i128); + _burn(&e, from.clone(), amount as i128); let xcall_message = CrossTransfer::new( from.clone().to_string(), to, @@ -41,10 +40,13 @@ pub fn _cross_transfer( from.clone(), amount ); + let config = get_config(&e); + let icon_bn_usd = config.icon_bn_usd; - let rollback_bytes = rollback.encode(&e, String::from_str(&e.clone(), CROSS_TRANSFER_REVERT)); - let message_bytes = xcall_message.encode(&e, String::from_str(&e.clone(), CROSS_TRANSFER)); - let (sources, destinations) = xcall_manager_client(e.clone()).get_protocols(); + let rollback_bytes = rollback.encode(&e, String::from_str(&e, CROSS_TRANSFER_REVERT)); + let message_bytes = xcall_message.encode(&e, String::from_str(&e, CROSS_TRANSFER)); + + let (sources, destinations) = xcall_manager_client(&e, &config.xcall_manager).get_protocols(); let message = AnyMessage::CallMessageWithRollback(CallMessageWithRollback { data: message_bytes, rollback: rollback_bytes }); let envelope: &Envelope = &Envelope { @@ -52,9 +54,9 @@ pub fn _cross_transfer( sources, destinations }; - let icon_bn_usd = &get_config(&e).icon_bn_usd; - let current_address = e.clone().current_contract_address(); - xcall_client(e).send_call(&from, ¤t_address, envelope, icon_bn_usd ); + + let current_address = e.current_contract_address(); + xcall_client(&e, &config.xcall).send_call(&from, ¤t_address, envelope, &icon_bn_usd ); Ok(()) } @@ -66,27 +68,28 @@ pub fn _handle_call_message( data: Bytes, protocols: Vec ) -> Result<(), ContractError> { - let xcall = get_config(&e).xcall; + let config: ConfigData = get_config(&e); + let xcall = config.xcall; xcall.require_auth(); - if !xcall_manager_client(e.clone()).verify_protocols(&protocols) { + if !xcall_manager_client(&e, &config.xcall_manager).verify_protocols(&protocols) { return Err(ContractError::ProtocolMismatch) }; let method = CrossTransfer::get_method(&e, data.clone()); - let icon_bn_usd = get_config(&e).icon_bn_usd; + let icon_bn_usd: String = config.icon_bn_usd; if method == String::from_str(&e, &CROSS_TRANSFER){ if from!=icon_bn_usd { return Err(ContractError::OnlyIconBnUSD); } - let message = CrossTransfer::decode(&e.clone(), data); - let to_network_address: Address = get_address(message.to.clone(), &e.clone())?; - _mint(e.clone(), to_network_address, message.amount as i128 ); + let message = CrossTransfer::decode(&e, data); + let to_network_address: Address = get_address(message.to, &e)?; + _mint(&e, to_network_address, message.amount as i128 ); } else if method == String::from_str(&e, &CROSS_TRANSFER_REVERT){ if xcall!=xcall_address { return Err(ContractError::OnlyCallService) } - let message = CrossTransferRevert::decode(&e.clone(), data); - _mint(e.clone(), message.to, message.amount as i128); + let message = CrossTransferRevert::decode(&e, data); + _mint(&e, message.to, message.amount as i128); }else{ return Err(ContractError::UnknownMessageType) } @@ -127,35 +130,27 @@ pub fn get_address(network_address: String, env: &Env) -> Result Client<'static> { - return xcall::Client::new(&e, &get_config(&e).xcall); +fn xcall_client(e: &Env, xcall: &Address) -> Client<'static> { + return xcall::Client::new(e, xcall); } -fn xcall_manager_client(e: Env) -> XcallManagerClient<'static> { - let client = XcallManagerClient::new(&e, &get_config(&e).xcall_manager); +fn xcall_manager_client(e: &Env, xcall_manager: &Address ) -> XcallManagerClient<'static> { + let client = XcallManagerClient::new(e, xcall_manager); return client; } diff --git a/contracts/balanced_doller/src/contract.rs b/contracts/balanced_doller/src/contract.rs index 567193c..9d1547a 100644 --- a/contracts/balanced_doller/src/contract.rs +++ b/contracts/balanced_doller/src/contract.rs @@ -53,7 +53,7 @@ impl BalancedDollar { let admin = read_administrator(&e); admin.require_auth(); - balanced_dollar::_mint(e, to, amount) + balanced_dollar::_mint(&e, to, amount) } pub fn set_admin(e: Env, new_admin: Address) { @@ -152,7 +152,7 @@ impl token::Interface for BalancedDollar { } fn burn(e: Env, from: Address, amount: i128) { - balanced_dollar::_burn(e, from, amount); + balanced_dollar::_burn(&e, from, amount); } fn burn_from(e: Env, spender: Address, from: Address, amount: i128) { From e0ba0663ad5d459a955202a598282276231737d2 Mon Sep 17 00:00:00 2001 From: sagar sapkota Date: Mon, 17 Jun 2024 20:22:20 +0545 Subject: [PATCH 30/63] code optimization --- contracts/asset_manager/src/contract.rs | 119 ++++++++++++------------ contracts/xcall_manager/src/contract.rs | 30 +++--- 2 files changed, 75 insertions(+), 74 deletions(-) diff --git a/contracts/asset_manager/src/contract.rs b/contracts/asset_manager/src/contract.rs index 806d941..9f89ef6 100644 --- a/contracts/asset_manager/src/contract.rs +++ b/contracts/asset_manager/src/contract.rs @@ -40,19 +40,19 @@ impl AssetManager { get_config(&env) } - pub fn set_admin(e: Env, new_admin: Address) { - let admin = read_administrator(&e); + pub fn set_admin(env: Env, new_admin: Address) { + let admin = read_administrator(&env); admin.require_auth(); - write_administrator(&e, &new_admin); + write_administrator(&env, &new_admin); } - pub fn get_admin(e: Env) -> Address{ - read_administrator(&e) + pub fn get_admin(env: Env) -> Address{ + read_administrator(&env) } pub fn configure(env:Env, config: ConfigData){ - let admin = read_administrator(&env.clone()); + let admin = read_administrator(&env); admin.require_auth(); set_config(&env, config); @@ -60,60 +60,61 @@ impl AssetManager { pub fn configure_rate_limit( env: Env, - token: Address, + token_address: Address, period: u128, percentage: u128, - ) { - let admin = read_administrator(&env.clone()); + ) -> Result<(), ContractError> { + let admin = read_administrator(&env); admin.require_auth(); - let tokens = read_tokens(&env.clone()); - if tokens.contains(&token) { - panic_with_error!(&env.clone(), ContractError::TokenExists) + let tokens = read_tokens(&env); + if tokens.contains(&token_address) { + return Err(ContractError::TokenExists) }else{ - write_tokens(&env, token.clone()); + write_tokens(&env, token_address.clone()); }; if percentage > POINTS { - panic_with_error!(&env.clone(), ContractError::PercentageShouldBeLessThanOrEqualToPOINTS); + return Err(ContractError::PercentageShouldBeLessThanOrEqualToPOINTS); } - let token_client = token::Client::new(&env, &token); + let token_client = token::Client::new(&env, &token_address); let contract_token_balance = token_client.balance(&env.current_contract_address()); - write_token_period(&env.clone(), &token.clone(), period); - write_token_percentage(&env.clone(), &token.clone(), percentage); - write_token_last_update(&env.clone(), &token.clone(), env.ledger().timestamp()); - write_token_current_limit(&env.clone(), &token.clone(), (contract_token_balance as u128) * percentage/POINTS); + write_token_period(&env, &token_address, period); + write_token_percentage(&env, &token_address, percentage); + write_token_last_update(&env, &token_address, env.ledger().timestamp()); + write_token_current_limit(&env, &token_address, (contract_token_balance as u128) * percentage/POINTS); + Ok(()) } - pub fn get_rate_limit(env: Env, token: Address ) -> (u128, u128, u64, u128){ + pub fn get_rate_limit(env: Env, token_address: Address ) -> (u128, u128, u64, u128){ ( - read_token_period(&env, &token.clone()), - read_token_percentage(&env, &token.clone()), - read_token_last_update(&env, &token.clone()), - read_token_last_current_limit(&env, &token.clone()), + read_token_period(&env, &token_address), + read_token_percentage(&env, &token_address), + read_token_last_update(&env, &token_address), + read_token_last_current_limit(&env, &token_address), ) } pub fn reset_limit(env: Env, token: Address){ - let balance = Self::get_token_balance(env.clone(), token.clone()); - let percentage: u128 = read_token_percentage(&env, &token.clone()); + let balance = Self::get_token_balance(&env, token.clone()); + let percentage: u128 = read_token_percentage(&env, &token); - env.storage().instance().set(&DataKey::CurrentLimit(token.clone()), &(balance*percentage/POINTS)); + write_token_current_limit(&env, &token, balance*percentage/POINTS); } pub fn get_withdraw_limit(env: Env, token: Address) -> Result { - let balance = Self::get_token_balance(env.clone(), token.clone()); - return Ok(Self::calculate_limit(env, balance, token)?) + let balance = Self::get_token_balance(&env, token.clone()); + return Ok(Self::calculate_limit(&env, balance, token)?) } - fn get_token_balance(env: Env, token: Address) -> u128 { - let token_client = token::Client::new(&env, &token); + fn get_token_balance(env: &Env, token: Address) -> u128 { + let token_client = token::Client::new(env, &token); return token_client.balance(&env.current_contract_address()) as u128 } pub fn verify_withdraw(env: Env, token: Address, amount: u128) -> Result { - let balance = Self::get_token_balance(env.clone(), token.clone()); - let limit = Self::calculate_limit(env.clone(), balance, token.clone())?; + let balance = Self::get_token_balance(&env, token.clone()); + let limit = Self::calculate_limit(&env, balance, token.clone())?; if balance - amount < limit { panic_with_error!(&env, ContractError::ExceedsWithdrawLimit); }; write_token_current_limit(&env, &token.clone(), limit); @@ -121,9 +122,9 @@ impl AssetManager { Ok(true) } - pub fn calculate_limit(env: Env, balance: u128, token: Address) -> Result { - let period: u128 = read_token_period(&env, &token.clone()); - let percentage: u128 = read_token_percentage(&env, &token.clone()); + pub fn calculate_limit(env: &Env, balance: u128, token: Address) -> Result { + let period: u128 = read_token_period(env, &token.clone()); + let percentage: u128 = read_token_percentage(env, &token.clone()); if period == 0 { return Ok(0); } @@ -142,7 +143,7 @@ impl AssetManager { } let reserve = if reserve > min_reserve { reserve } else { min_reserve }; - Ok(reserve) + Ok(reserve) } pub fn deposit( @@ -168,8 +169,8 @@ impl AssetManager { data: Bytes, ) -> Result<(), ContractError> { from.require_auth(); - let current_address = e.clone().current_contract_address(); - Self::transfer_token_to(e.clone(), from.clone(), token.clone(), current_address.clone(), amount); + let current_address = e.current_contract_address(); + Self::transfer_token_to(&e, from.clone(), token.clone(), current_address.clone(), amount); let xcall_message: Deposit = Deposit::new( token.to_string(), @@ -184,29 +185,28 @@ impl AssetManager { from.clone(), amount ); - - let rollback_bytes = rollback.encode(&e, String::from_str(&e.clone(), DEPOSIT_REVERT_NAME)); - let message_bytes = xcall_message.encode(&e, String::from_str(&e.clone(), DEPOSIT_NAME)); - let (sources, destinations) = Self::xcall_manager(e.clone()).get_protocols(); + let config = get_config(&e); + let rollback_bytes = rollback.encode(&e, String::from_str(&e, DEPOSIT_REVERT_NAME)); + let message_bytes = xcall_message.encode(&e, String::from_str(&e, DEPOSIT_NAME)); + let (sources, destinations) = Self::xcall_manager(&e, &config.xcall_manager ).get_protocols(); let message = AnyMessage::CallMessageWithRollback(CallMessageWithRollback { data: message_bytes, rollback: rollback_bytes }); let envelope: &Envelope = &Envelope { destinations, message, sources }; - let icon_asset_manager = &get_config(&e).icon_asset_manager; - Self::xcall_client(e).send_call(&from, ¤t_address, envelope, icon_asset_manager); + Self::xcall_client(&e, &config.xcall).send_call(&from, ¤t_address, envelope, &config.icon_asset_manager); Ok(()) } - fn xcall_manager(e: Env) -> XcallManagerClient<'static> { - let client = XcallManagerClient::new(&e, &get_config(&e).xcall_manager); + fn xcall_manager(e: &Env, xcall_manager: &Address) -> XcallManagerClient<'static> { + let client = XcallManagerClient::new(e, xcall_manager); return client; } - fn xcall_client(e: Env) -> Client<'static> { - return xcall::Client::new(&e, &get_config(&e).xcall); + fn xcall_client(e: &Env, xcall: &Address) -> Client<'static> { + return xcall::Client::new(e, xcall); } pub fn handle_call_message( @@ -216,13 +216,14 @@ impl AssetManager { data: Bytes, protocols: Vec ) -> Result<(), ContractError> { - get_config(&e).xcall.require_auth(); + let config = get_config(&e); + config.xcall.require_auth(); - if !Self::xcall_manager(e.clone()).verify_protocols(&protocols) { - panic_with_error!(&e, ContractError::ProtocolMismatch); + if !Self::xcall_manager(&e, &config.xcall_manager).verify_protocols(&protocols) { + return Err(ContractError::ProtocolMismatch); }; let method = Deposit::get_method(&e, data.clone()); - let icon_asset_manager = get_config(&e).icon_asset_manager; + let icon_asset_manager = config.icon_asset_manager; let current_contract = e.current_contract_address(); if method == String::from_str(&e, &WITHDRAW_TO_NAME){ if from != icon_asset_manager{ @@ -234,22 +235,22 @@ impl AssetManager { return Err(ContractError::InvalidAddress); } - Self::withdraw(e, current_contract, Address::from_string(&message.token_address), Address::from_string(&message.to), message.amount)?; + Self::withdraw(&e, current_contract, Address::from_string(&message.token_address), Address::from_string(&message.to), message.amount)?; } else if method == String::from_str(&e, &DEPOSIT_REVERT_NAME){ - let xcall_network_address = Self::xcall_client(e.clone()).get_network_address(); + let xcall_network_address = Self::xcall_client(&e, &config.xcall).get_network_address(); if from != xcall_network_address { return Err(ContractError::OnlyCallService) }; let message: DepositRevert = DepositRevert::decode(&e.clone(), data); - Self::withdraw(e, current_contract, message.token_address, message.to, message.amount)?; + Self::withdraw(&e, current_contract, message.token_address, message.to, message.amount)?; } else { return Err(ContractError::UnknownMessageType); } Ok(()) } - pub fn withdraw(e: Env, from: Address, token: Address, to: Address, amount: u128) -> Result<(), ContractError> { + pub fn withdraw(e: &Env, from: Address, token: Address, to: Address, amount: u128) -> Result<(), ContractError> { if amount <= 0 { return Err(ContractError::AmountIsLessThanMinimumAmount); } @@ -261,8 +262,8 @@ impl AssetManager { Ok(()) } - fn transfer_token_to(e: Env, from: Address, token: Address, to: Address, amount: u128){ - let token_client = token::Client::new(&e, &token); + fn transfer_token_to(e: &Env, from: Address, token: Address, to: Address, amount: u128){ + let token_client = token::Client::new(e, &token); token_client.transfer(&from, &to, &(amount as i128)); } diff --git a/contracts/xcall_manager/src/contract.rs b/contracts/xcall_manager/src/contract.rs index dcf8d5a..3c45842 100644 --- a/contracts/xcall_manager/src/contract.rs +++ b/contracts/xcall_manager/src/contract.rs @@ -29,7 +29,7 @@ impl XcallManager { } pub fn configure(env:Env, config: ConfigData, sources: Vec, destinations: Vec){ - let admin = read_administrator(&env.clone()); + let admin = read_administrator(&env); admin.require_auth(); set_config(&env, config); @@ -64,11 +64,11 @@ impl XcallManager { } pub fn verify_protocols( - e: Env, + e: &Env, protocols: Vec ) -> Result { - let sources: Vec = read_sources(&e); - return Self::verify_protocols_unordered(e, protocols, sources); + let sources: Vec = read_sources(e); + return Self::verify_protocols_unordered(protocols, sources); } pub fn get_protocols(e: Env) -> Result<(Vec, Vec), ContractError> { @@ -77,7 +77,7 @@ impl XcallManager { Ok((sources, destinations)) } - pub fn verify_protocols_unordered(_e: Env, array1: Vec, array2: Vec) -> Result { + pub fn verify_protocols_unordered(array1: Vec, array2: Vec) -> Result { // Check if the arrays have the same length if array1.len() != array2.len() { return Ok(false); @@ -107,27 +107,27 @@ impl XcallManager { data: Bytes, protocols: Vec ) -> Result<(), ContractError> { - let xcall = get_config(&e.clone()).xcall; + let config = get_config(&e.clone()); + let xcall = config.xcall; xcall.require_auth(); - let icon_governance = get_config(&e.clone()).icon_governance; - if from != icon_governance { + if from != config.icon_governance { return Err(ContractError::OnlyICONGovernance); } - if !Self::verify_protocols(e.clone(), protocols.clone()).unwrap() { + if !Self::verify_protocols(&e, protocols.clone()).unwrap() { return Err(ContractError::ProtocolMismatch) }; let method = ConfigureProtocols::get_method(&e.clone(), data.clone()); let sources = read_sources(&e); - if !Self::verify_protocols_unordered(e.clone(), protocols.clone(), sources).unwrap() { + if !Self::verify_protocols_unordered(protocols.clone(), sources).unwrap() { if method != String::from_str(&e.clone(), CONFIGURE_PROTOCOLS_NAME) { return Err(ContractError::ProtocolMismatch) } - Self::verify_protocol_recovery(e.clone(), protocols)?; + Self::verify_protocol_recovery(&e, protocols)?; } if method == String::from_str(&e, CONFIGURE_PROTOCOLS_NAME) { @@ -142,16 +142,16 @@ impl XcallManager { Ok(()) } - pub fn verify_protocol_recovery(e: Env, protocols: Vec) -> Result<(), ContractError> { - let modified_sources = Self::get_modified_protocols(e.clone())?; - let verify_unordered = Self::verify_protocols_unordered(e.clone(), modified_sources, protocols).unwrap(); + pub fn verify_protocol_recovery(e: &Env, protocols: Vec) -> Result<(), ContractError> { + let modified_sources = Self::get_modified_protocols(e)?; + let verify_unordered = Self::verify_protocols_unordered(modified_sources, protocols).unwrap(); if !verify_unordered { return Err(ContractError::ProtocolMismatch) } Ok(()) } - pub fn get_modified_protocols(e: Env) -> Result, ContractError> { + pub fn get_modified_protocols(e: &Env) -> Result, ContractError> { if !has_proposed_removed(e.clone()) { return Err(ContractError::NoProposalForRemovalExists) } From 6aaf00148c64ef3bcd8fef362cdab77e67355334 Mon Sep 17 00:00:00 2001 From: sagar sapkota Date: Tue, 18 Jun 2024 13:42:14 +0545 Subject: [PATCH 31/63] verify protocal return type issue fixed --- contracts/asset_manager/src/contract.rs | 10 +++++----- contracts/asset_manager/src/xcall_manager_interface.rs | 2 +- contracts/balanced_doller/src/balanced_dollar.rs | 6 ++++-- .../balanced_doller/src/xcall_manager_interface.rs | 2 +- contracts/xcall_manager/src/contract.rs | 10 +++++++--- 5 files changed, 18 insertions(+), 12 deletions(-) diff --git a/contracts/asset_manager/src/contract.rs b/contracts/asset_manager/src/contract.rs index 9f89ef6..0c94c5a 100644 --- a/contracts/asset_manager/src/contract.rs +++ b/contracts/asset_manager/src/contract.rs @@ -71,7 +71,7 @@ impl AssetManager { return Err(ContractError::TokenExists) }else{ write_tokens(&env, token_address.clone()); - }; + } if percentage > POINTS { return Err(ContractError::PercentageShouldBeLessThanOrEqualToPOINTS); @@ -227,8 +227,8 @@ impl AssetManager { let current_contract = e.current_contract_address(); if method == String::from_str(&e, &WITHDRAW_TO_NAME){ if from != icon_asset_manager{ - return Err(ContractError::OnlyICONAssetManager); - }; + return Err(ContractError::OnlyICONAssetManager); + } let message = WithdrawTo::decode(&e, data); if !is_valid_string_address(&message.to) || !is_valid_string_address(&message.token_address) { @@ -240,8 +240,8 @@ impl AssetManager { let xcall_network_address = Self::xcall_client(&e, &config.xcall).get_network_address(); if from != xcall_network_address { - return Err(ContractError::OnlyCallService) - }; + return Err(ContractError::OnlyCallService) + } let message: DepositRevert = DepositRevert::decode(&e.clone(), data); Self::withdraw(&e, current_contract, message.token_address, message.to, message.amount)?; } else { diff --git a/contracts/asset_manager/src/xcall_manager_interface.rs b/contracts/asset_manager/src/xcall_manager_interface.rs index 17c7698..539fbde 100644 --- a/contracts/asset_manager/src/xcall_manager_interface.rs +++ b/contracts/asset_manager/src/xcall_manager_interface.rs @@ -8,7 +8,7 @@ pub trait XcallManagerInterface { fn verify_protocols( e: Env, protocols: Vec - ) -> Result; + ) -> bool; fn get_protocols(e: Env) -> Result<(Vec, Vec), ContractError>; diff --git a/contracts/balanced_doller/src/balanced_dollar.rs b/contracts/balanced_doller/src/balanced_dollar.rs index 44ac383..a159c2d 100644 --- a/contracts/balanced_doller/src/balanced_dollar.rs +++ b/contracts/balanced_doller/src/balanced_dollar.rs @@ -71,9 +71,11 @@ pub fn _handle_call_message( let config: ConfigData = get_config(&e); let xcall = config.xcall; xcall.require_auth(); - if !xcall_manager_client(&e, &config.xcall_manager).verify_protocols(&protocols) { + + let verified = xcall_manager_client(&e, &config.xcall_manager).verify_protocols(&protocols); + if !verified { return Err(ContractError::ProtocolMismatch) - }; + } let method = CrossTransfer::get_method(&e, data.clone()); let icon_bn_usd: String = config.icon_bn_usd; diff --git a/contracts/balanced_doller/src/xcall_manager_interface.rs b/contracts/balanced_doller/src/xcall_manager_interface.rs index 325a064..258787c 100644 --- a/contracts/balanced_doller/src/xcall_manager_interface.rs +++ b/contracts/balanced_doller/src/xcall_manager_interface.rs @@ -8,7 +8,7 @@ pub trait IXcallManager { fn verify_protocols( e: Env, protocols: Vec - ) -> Result; + ) -> bool; fn get_protocols(e: Env) -> Result<(Vec, Vec), ContractError>; diff --git a/contracts/xcall_manager/src/contract.rs b/contracts/xcall_manager/src/contract.rs index 3c45842..cc32447 100644 --- a/contracts/xcall_manager/src/contract.rs +++ b/contracts/xcall_manager/src/contract.rs @@ -66,9 +66,13 @@ impl XcallManager { pub fn verify_protocols( e: &Env, protocols: Vec - ) -> Result { + ) -> bool { let sources: Vec = read_sources(e); - return Self::verify_protocols_unordered(protocols, sources); + let verified = Self::verify_protocols_unordered(protocols, sources); + if !verified.is_ok() { + return false; + } + return verified.unwrap() } pub fn get_protocols(e: Env) -> Result<(Vec, Vec), ContractError> { @@ -116,7 +120,7 @@ impl XcallManager { } - if !Self::verify_protocols(&e, protocols.clone()).unwrap() { + if !Self::verify_protocols(&e, protocols.clone()) { return Err(ContractError::ProtocolMismatch) }; From dc41b14e15e1c9a2efc5864686b654cb1e00d87b Mon Sep 17 00:00:00 2001 From: sagar sapkota Date: Tue, 18 Jun 2024 14:44:00 +0545 Subject: [PATCH 32/63] code optimize for protocal verification --- contracts/asset_manager/src/contract.rs | 6 +++--- .../asset_manager/src/xcall_manager_interface.rs | 2 +- contracts/balanced_doller/src/balanced_dollar.rs | 13 ++++++++----- .../src/xcall_manager_interface.rs | 2 +- contracts/xcall_manager/src/contract.rs | 16 +++++++--------- 5 files changed, 20 insertions(+), 19 deletions(-) diff --git a/contracts/asset_manager/src/contract.rs b/contracts/asset_manager/src/contract.rs index 0c94c5a..cf7164b 100644 --- a/contracts/asset_manager/src/contract.rs +++ b/contracts/asset_manager/src/contract.rs @@ -219,9 +219,6 @@ impl AssetManager { let config = get_config(&e); config.xcall.require_auth(); - if !Self::xcall_manager(&e, &config.xcall_manager).verify_protocols(&protocols) { - return Err(ContractError::ProtocolMismatch); - }; let method = Deposit::get_method(&e, data.clone()); let icon_asset_manager = config.icon_asset_manager; let current_contract = e.current_contract_address(); @@ -247,6 +244,9 @@ impl AssetManager { } else { return Err(ContractError::UnknownMessageType); } + if !Self::xcall_manager(&e, &config.xcall_manager).verify_protocols(&protocols) { + return Err(ContractError::ProtocolMismatch); + } Ok(()) } diff --git a/contracts/asset_manager/src/xcall_manager_interface.rs b/contracts/asset_manager/src/xcall_manager_interface.rs index 539fbde..17c7698 100644 --- a/contracts/asset_manager/src/xcall_manager_interface.rs +++ b/contracts/asset_manager/src/xcall_manager_interface.rs @@ -8,7 +8,7 @@ pub trait XcallManagerInterface { fn verify_protocols( e: Env, protocols: Vec - ) -> bool; + ) -> Result; fn get_protocols(e: Env) -> Result<(Vec, Vec), ContractError>; diff --git a/contracts/balanced_doller/src/balanced_dollar.rs b/contracts/balanced_doller/src/balanced_dollar.rs index a159c2d..9a6a118 100644 --- a/contracts/balanced_doller/src/balanced_dollar.rs +++ b/contracts/balanced_doller/src/balanced_dollar.rs @@ -60,6 +60,13 @@ pub fn _cross_transfer( Ok(()) } +fn verify_protocol(e: &Env, xcall_manager: &Address, protocols: Vec) -> Result<(), ContractError> { + let verified: bool = xcall_manager_client(e, xcall_manager).verify_protocols(&protocols); + if !verified { + return Err(ContractError::ProtocolMismatch) + } + Ok(()) +} pub fn _handle_call_message( e: Env, @@ -72,11 +79,6 @@ pub fn _handle_call_message( let xcall = config.xcall; xcall.require_auth(); - let verified = xcall_manager_client(&e, &config.xcall_manager).verify_protocols(&protocols); - if !verified { - return Err(ContractError::ProtocolMismatch) - } - let method = CrossTransfer::get_method(&e, data.clone()); let icon_bn_usd: String = config.icon_bn_usd; if method == String::from_str(&e, &CROSS_TRANSFER){ @@ -95,6 +97,7 @@ pub fn _handle_call_message( }else{ return Err(ContractError::UnknownMessageType) } + verify_protocol(&e, &config.xcall_manager, protocols)?; Ok(()) } diff --git a/contracts/balanced_doller/src/xcall_manager_interface.rs b/contracts/balanced_doller/src/xcall_manager_interface.rs index 258787c..325a064 100644 --- a/contracts/balanced_doller/src/xcall_manager_interface.rs +++ b/contracts/balanced_doller/src/xcall_manager_interface.rs @@ -8,7 +8,7 @@ pub trait IXcallManager { fn verify_protocols( e: Env, protocols: Vec - ) -> bool; + ) -> Result; fn get_protocols(e: Env) -> Result<(Vec, Vec), ContractError>; diff --git a/contracts/xcall_manager/src/contract.rs b/contracts/xcall_manager/src/contract.rs index cc32447..d8c9bd7 100644 --- a/contracts/xcall_manager/src/contract.rs +++ b/contracts/xcall_manager/src/contract.rs @@ -64,15 +64,13 @@ impl XcallManager { } pub fn verify_protocols( - e: &Env, + e: Env, protocols: Vec - ) -> bool { - let sources: Vec = read_sources(e); - let verified = Self::verify_protocols_unordered(protocols, sources); - if !verified.is_ok() { - return false; - } - return verified.unwrap() + ) -> Result { + let sources: Vec = read_sources(&e); + + let verified = Self::verify_protocols_unordered(protocols, sources)?; + return Ok(verified); } pub fn get_protocols(e: Env) -> Result<(Vec, Vec), ContractError> { @@ -120,7 +118,7 @@ impl XcallManager { } - if !Self::verify_protocols(&e, protocols.clone()) { + if !Self::verify_protocols(e.clone(), protocols.clone())? { return Err(ContractError::ProtocolMismatch) }; From 3ab9aab17648e7b614a05513caac6f0b106675a5 Mon Sep 17 00:00:00 2001 From: sagar sapkota Date: Tue, 18 Jun 2024 15:22:26 +0545 Subject: [PATCH 33/63] reentrancy on asset manager fixed --- contracts/asset_manager/src/contract.rs | 9 ++++----- contracts/asset_manager/src/tests/asset_manager_test.rs | 2 +- contracts/asset_manager/src/tests/setup.rs | 2 +- 3 files changed, 6 insertions(+), 7 deletions(-) diff --git a/contracts/asset_manager/src/contract.rs b/contracts/asset_manager/src/contract.rs index cf7164b..66267d6 100644 --- a/contracts/asset_manager/src/contract.rs +++ b/contracts/asset_manager/src/contract.rs @@ -211,13 +211,14 @@ impl AssetManager { pub fn handle_call_message( e: Env, - _xcall: Address, + xcall_address: Address, from: String, data: Bytes, protocols: Vec ) -> Result<(), ContractError> { let config = get_config(&e); - config.xcall.require_auth(); + let xcall = config.xcall; + xcall.require_auth(); let method = Deposit::get_method(&e, data.clone()); let icon_asset_manager = config.icon_asset_manager; @@ -234,9 +235,7 @@ impl AssetManager { Self::withdraw(&e, current_contract, Address::from_string(&message.token_address), Address::from_string(&message.to), message.amount)?; } else if method == String::from_str(&e, &DEPOSIT_REVERT_NAME){ - let xcall_network_address = Self::xcall_client(&e, &config.xcall).get_network_address(); - - if from != xcall_network_address { + if xcall != xcall_address { return Err(ContractError::OnlyCallService) } let message: DepositRevert = DepositRevert::decode(&e.clone(), data); diff --git a/contracts/asset_manager/src/tests/asset_manager_test.rs b/contracts/asset_manager/src/tests/asset_manager_test.rs index c046062..4f58ca3 100644 --- a/contracts/asset_manager/src/tests/asset_manager_test.rs +++ b/contracts/asset_manager/src/tests/asset_manager_test.rs @@ -416,7 +416,7 @@ fn test_handle_call_message_for_deposit_rollback_panic_with_only_call_service(){ assert_eq!(token_client.balance(&ctx.withdrawer), 0); let sources = Vec::from_array(&ctx.env, [ctx.centralized_connection.to_string()]); - client.handle_call_message(&ctx.xcall, &ctx.xcall_manager.to_string(), &data, &sources); + client.handle_call_message(&ctx.xcall_manager, &ctx.xcall.to_string(), &data, &sources); assert_eq!(token_client.balance(&ctx.withdrawer), bnusd_amount as i128) } diff --git a/contracts/asset_manager/src/tests/setup.rs b/contracts/asset_manager/src/tests/setup.rs index 41308f4..65db020 100644 --- a/contracts/asset_manager/src/tests/setup.rs +++ b/contracts/asset_manager/src/tests/setup.rs @@ -22,7 +22,7 @@ mod connection { } mod xcall_manager { - soroban_sdk::contractimport!(file = "../../target/wasm32-unknown-unknown/release/xcall_manager.wasm" ); + soroban_sdk::contractimport!(file = "../../target/wasm32-unknown-unknown/release/xcall_manager.wasm"); } use xcall_manager::ConfigData as XcallManagerConfigData; From d9e34cf4c15ea20a1688b2c95ead762c6e0377ff Mon Sep 17 00:00:00 2001 From: sagar sapkota Date: Wed, 19 Jun 2024 10:59:44 +0545 Subject: [PATCH 34/63] [dev_dependencies] to [dev-dependencies] --- contracts/asset_manager/Cargo.toml | 2 +- contracts/balanced_doller/Cargo.toml | 2 +- contracts/xcall_manager/Cargo.toml | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/contracts/asset_manager/Cargo.toml b/contracts/asset_manager/Cargo.toml index 100da4c..a23ae57 100644 --- a/contracts/asset_manager/Cargo.toml +++ b/contracts/asset_manager/Cargo.toml @@ -13,5 +13,5 @@ testutils = ["soroban-sdk/testutils"] soroban-sdk = { workspace = true } soroban-rlp = { path = "../../libs/soroban-rlp" } -[dev_dependencies] +[dev-dependencies] soroban-sdk = { workspace = true, features = ["testutils"] } \ No newline at end of file diff --git a/contracts/balanced_doller/Cargo.toml b/contracts/balanced_doller/Cargo.toml index d177567..ed8cfc1 100644 --- a/contracts/balanced_doller/Cargo.toml +++ b/contracts/balanced_doller/Cargo.toml @@ -14,5 +14,5 @@ soroban-sdk = { workspace = true } soroban-token-sdk = { version = "20.3.2" } soroban-rlp = { path = "../../libs/soroban-rlp" } -[dev_dependencies] +[dev-dependencies] soroban-sdk = { workspace = true, features = ["testutils"] } \ No newline at end of file diff --git a/contracts/xcall_manager/Cargo.toml b/contracts/xcall_manager/Cargo.toml index 00380f8..8e93829 100644 --- a/contracts/xcall_manager/Cargo.toml +++ b/contracts/xcall_manager/Cargo.toml @@ -13,5 +13,5 @@ testutils = ["soroban-sdk/testutils"] soroban-sdk = { workspace = true } soroban-rlp = { path = "../../libs/soroban-rlp" } -[dev_dependencies] +[dev-dependencies] soroban-sdk = { workspace = true, features = ["testutils"] } \ No newline at end of file From 6fb275641af53ef7cae1e96401605b7bb2e8d84d Mon Sep 17 00:00:00 2001 From: sagar sapkota Date: Fri, 21 Jun 2024 08:50:56 +0545 Subject: [PATCH 35/63] xcall wasm removed from gitignore, for CI build --- .gitignore | 3 +-- wasm/centralized_connection.wasm | Bin 0 -> 12782 bytes wasm/xcall.wasm | Bin 0 -> 27794 bytes 3 files changed, 1 insertion(+), 2 deletions(-) create mode 100755 wasm/centralized_connection.wasm create mode 100755 wasm/xcall.wasm diff --git a/.gitignore b/.gitignore index 5e72518..9a00312 100644 --- a/.gitignore +++ b/.gitignore @@ -8,5 +8,4 @@ target # macOS-specific files .DS_Store Cargo.lock -test_snapshots -wasm \ No newline at end of file +test_snapshots \ No newline at end of file diff --git a/wasm/centralized_connection.wasm b/wasm/centralized_connection.wasm new file mode 100755 index 0000000000000000000000000000000000000000..9a4fb1c2a6667d57cd9baa43aca6603038349925 GIT binary patch literal 12782 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 literal 0 HcmV?d00001 diff --git a/wasm/xcall.wasm b/wasm/xcall.wasm new file mode 100755 index 0000000000000000000000000000000000000000..40bcf10114dacb121023951358c4f033e217ce14 GIT binary patch literal 27794 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 R4{uoCZ0=fr%dTC){|BptJShMG literal 0 HcmV?d00001 From a78ed46d835c1266d7ea4adc101b852a9d79aaa3 Mon Sep 17 00:00:00 2001 From: Deepak Bomjan Date: Wed, 19 Jun 2024 11:13:42 +0545 Subject: [PATCH 36/63] ci: add cicd --- .github/ISSUE_TEMPLATE/bug_report.md | 24 +++++++++++++ .github/ISSUE_TEMPLATE/feature_request.md | 20 +++++++++++ .github/ISSUE_TEMPLATE/task-template.md | 27 ++++++++++++++ .github/PULL_REQUEST_TEMPLATE.md | 28 +++++++++++++++ .github/labeler.yml | 11 ++++++ .github/workflows/auto-pr-labeler.yml | 32 +++++++++++++++++ .../build-test-soroban-contracts.yml | 35 +++++++++++++++++++ .github/workflows/check-pr-label.yml | 25 +++++++++++++ .github/workflows/lint-pr.yml | 18 ++++++++++ .github/workflows/soroban-codecov.yml | 35 +++++++++++++++++++ 10 files changed, 255 insertions(+) create mode 100644 .github/ISSUE_TEMPLATE/bug_report.md create mode 100644 .github/ISSUE_TEMPLATE/feature_request.md create mode 100644 .github/ISSUE_TEMPLATE/task-template.md create mode 100644 .github/PULL_REQUEST_TEMPLATE.md create mode 100644 .github/labeler.yml create mode 100644 .github/workflows/auto-pr-labeler.yml create mode 100644 .github/workflows/build-test-soroban-contracts.yml create mode 100644 .github/workflows/check-pr-label.yml create mode 100644 .github/workflows/lint-pr.yml create mode 100644 .github/workflows/soroban-codecov.yml diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md new file mode 100644 index 0000000..ddf85ea --- /dev/null +++ b/.github/ISSUE_TEMPLATE/bug_report.md @@ -0,0 +1,24 @@ +--- +name: Bug report +about: Create a report to help us improve +title: '' +labels: iBriz +assignees: '' + +--- + +**Describe the bug** +A clear and concise description of what the bug is. + +**To Reproduce** +Steps to reproduce the behavior: +1. Go to '...' +2. Click on '....' +3. Scroll down to '....' +4. See error + +**Expected behavior** +A clear and concise description of what you expected to happen. + +**Additional context** +Add any other context about the problem here. diff --git a/.github/ISSUE_TEMPLATE/feature_request.md b/.github/ISSUE_TEMPLATE/feature_request.md new file mode 100644 index 0000000..0805004 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/feature_request.md @@ -0,0 +1,20 @@ +--- +name: Feature request +about: Suggest an idea for this project +title: '' +labels: iBriz +assignees: '' + +--- + +**Is your feature request related to a problem? Please describe.** +A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] + +**Describe the solution you'd like** +A clear and concise description of what you want to happen. + +**Describe alternatives you've considered** +A clear and concise description of any alternative solutions or features you've considered. + +**Additional context** +Add any other context or screenshots about the feature request here. diff --git a/.github/ISSUE_TEMPLATE/task-template.md b/.github/ISSUE_TEMPLATE/task-template.md new file mode 100644 index 0000000..901bca6 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/task-template.md @@ -0,0 +1,27 @@ +--- +name: Task Template +about: New tasks created should consist of the following information +title: '' +labels: iBriz +assignees: '' + +--- + +### What needs to be done + +Describe what needs to be done here. +Ex: "Relay synchronization starts from the most recently stored block header" + +### Why it needs to be done + +Describe why it needs to be done here. +Ex: "Reduces the amount of time for the relay to synchronize to the latest block" + +### Acceptance Criteria + +Describe how we can know whether the task is done. +Ex: When restarting the relay, synchronization picks up from the most recently stored block + +### Additional Information + +Describe anything relevant that hasn't been mentioned yet. diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md new file mode 100644 index 0000000..1b818da --- /dev/null +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -0,0 +1,28 @@ +## Description + +### Commit Message + +```bash +type: commit message +``` + +see the [guidelines](https://github.com/icon-project/community/blob/main/guidelines/technical/software-development-guidelines.md#commit-messages) for commit messages. + +### Changelog Entry + +```bash +version: +``` + +## Checklist + +- [ ] I have performed a self-review of my own code +- [ ] I have documented my code in accordance with the [documentation guidelines](https://github.com/icon-project/community/blob/main/guidelines/technical/software-development-guidelines.md#documentation) +- [ ] My changes generate no new warnings +- [ ] I have added tests that prove my fix is effective or that my feature works +- [ ] I have run the unit tests +- [ ] I only have one commit (if not, squash them into one commit). +- [ ] I have a descriptive commit message that adheres to the [commit message guidelines](https://github.com/icon-project/community/blob/main/guidelines/technical/software-development-guidelines.md#commit-messages) +- [ ] I have added version bump label on PR. + +> Please review the [CONTRIBUTING.md](/CONTRIBUTING.md) file for detailed contributing guidelines. diff --git a/.github/labeler.yml b/.github/labeler.yml new file mode 100644 index 0000000..7b083b8 --- /dev/null +++ b/.github/labeler.yml @@ -0,0 +1,11 @@ +cicd: + - '.github/workflows/*' + +scripts: + - 'scripts/*' + +test: + - 'test/**' + +documentation: +- '**/*.md' \ No newline at end of file diff --git a/.github/workflows/auto-pr-labeler.yml b/.github/workflows/auto-pr-labeler.yml new file mode 100644 index 0000000..906947f --- /dev/null +++ b/.github/workflows/auto-pr-labeler.yml @@ -0,0 +1,32 @@ +name: Pull Request Labeler +on: + pull_request: + types: + - opened + - edited + - synchronize +jobs: + auto-label: + permissions: + contents: read + pull-requests: write + runs-on: ubuntu-latest + steps: + - name: Find Current Pull Request + uses: jwalton/gh-find-current-pr@v1.3.2 + id: findPr + with: + # Can be "open", "closed", or "all". Defaults to "open". + state: open + - run: echo "PR Number is ${PR}" + if: success() && steps.findPr.outputs.number + env: + PR: ${{ steps.findPr.outputs.pr }} + + - name: check pr pr-number + run: echo ${{ github.event.number }} + + - uses: actions/labeler@v4 + with: + dot: true + pr-number: ${{ steps.findPr.outputs.pr }} diff --git a/.github/workflows/build-test-soroban-contracts.yml b/.github/workflows/build-test-soroban-contracts.yml new file mode 100644 index 0000000..e81a2ac --- /dev/null +++ b/.github/workflows/build-test-soroban-contracts.yml @@ -0,0 +1,35 @@ +name: Build and Test Balanced Soroban contracts +on: + push: + branches: + - '**' + pull_request: + branches: + - main + +jobs: + Build: + name: Build Soroban Contracts + runs-on: ubuntu-latest + steps: + - name: Checkout sources + uses: actions/checkout@v3 + with: + submodules: true + + - name: Install stable toolchain + uses: actions-rs/toolchain@v1 + with: + toolchain: 1.78.0 + target: wasm32-unknown-unknown + override: true + profile: minimal + + - name: Install wasm32 + run: | + rustup target add wasm32-unknown-unknown + cargo install --locked soroban-cli + + - name: Build & Test soroban Contracts + run: | + soroban contract build diff --git a/.github/workflows/check-pr-label.yml b/.github/workflows/check-pr-label.yml new file mode 100644 index 0000000..330f3d6 --- /dev/null +++ b/.github/workflows/check-pr-label.yml @@ -0,0 +1,25 @@ +name: PR Label Checker +on: + pull_request: + types: + - opened + - synchronize + - reopened + - labeled + - unlabeled + workflow_run: + workflows: + - auto-label + types: + - completed + +jobs: + + check_labels: + name: Check PR labels + runs-on: ubuntu-latest + steps: + - uses: docker://agilepathway/pull-request-label-checker:latest + with: + any_of: documentation,enhancement,bug,cicd,test,breaking-change,feature,scripts,dependencies + repo_token: ${{ secrets.GITHUB_TOKEN }} diff --git a/.github/workflows/lint-pr.yml b/.github/workflows/lint-pr.yml new file mode 100644 index 0000000..dca39a4 --- /dev/null +++ b/.github/workflows/lint-pr.yml @@ -0,0 +1,18 @@ +name: Lint PR +on: + pull_request_target: + types: + - opened + - edited + - synchronize +jobs: + main: + name: Validate PR title + runs-on: ubuntu-latest + steps: + - uses: amannn/action-semantic-pull-request@v5.1.0 + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + with: + validateSingleCommit: true + validateSingleCommitMatchesPrTitle: true diff --git a/.github/workflows/soroban-codecov.yml b/.github/workflows/soroban-codecov.yml new file mode 100644 index 0000000..96dc906 --- /dev/null +++ b/.github/workflows/soroban-codecov.yml @@ -0,0 +1,35 @@ +name: Soroban contracts Codecov + +on: + pull_request: + branches: + - "main" + push: + branches: + - "**" + +jobs: + code-coverage: + runs-on: ubuntu-latest + env: + CARGO_TERM_COLOR: always + steps: + - name: Checkout + uses: actions/checkout@v3 + with: + submodules: true + - name: Install Rust + run: rustup update stable + - name: Cache Rust dependencies + uses: Swatinem/rust-cache@v2 + - name: Install cargo-llvm-cov + uses: taiki-e/install-action@cargo-llvm-cov + - name: Generate code coverage + run: cargo llvm-cov --lcov --output-path lcov.info + - name: Upload coverage to Codecov + uses: codecov/codecov-action@v3 + with: + token: ${{ secrets.CODECOV_TOKEN }} + files: lcov.info + flags: rust + fail_ci_if_error: true \ No newline at end of file From 8c81a3745cb62bffb0cc98e50b7100ddd931acad Mon Sep 17 00:00:00 2001 From: sagar sapkota Date: Thu, 29 Aug 2024 10:55:59 +0545 Subject: [PATCH 37/63] internal audit issues fixes --- contracts/asset_manager/src/config.rs | 11 +- contracts/asset_manager/src/contract.rs | 211 ++++++---- contracts/asset_manager/src/errors.rs | 5 +- contracts/asset_manager/src/event.rs | 0 contracts/asset_manager/src/states.rs | 68 +-- contracts/asset_manager/src/storage_types.rs | 7 +- .../src/tests/asset_manager_test.rs | 393 +++++++++++------- contracts/asset_manager/src/tests/setup.rs | 63 +-- contracts/balanced_doller/src/allowance.rs | 2 +- .../balanced_doller/src/balanced_dollar.rs | 91 ++-- contracts/balanced_doller/src/config.rs | 11 +- contracts/balanced_doller/src/contract.rs | 39 +- contracts/balanced_doller/src/errors.rs | 4 +- contracts/balanced_doller/src/lib.rs | 10 +- contracts/balanced_doller/src/metadata.rs | 2 +- contracts/balanced_doller/src/states.rs | 1 - .../balanced_doller/src/storage_types.rs | 4 +- contracts/balanced_doller/src/test.rs | 37 +- .../src/tests/balanced_dollar_test.rs | 271 +++++++----- contracts/balanced_doller/src/tests/setup.rs | 62 +-- .../src/xcall_manager_interface.rs | 9 +- contracts/xcall_manager/src/config.rs | 11 +- contracts/xcall_manager/src/contract.rs | 115 +++-- contracts/xcall_manager/src/errors.rs | 5 +- contracts/xcall_manager/src/events.rs | 0 contracts/xcall_manager/src/lib.rs | 7 +- contracts/xcall_manager/src/states.rs | 1 - contracts/xcall_manager/src/storage_types.rs | 7 +- contracts/xcall_manager/src/tests/mod.rs | 2 +- .../src/tests/xcall_manager_test.rs | 233 ++++++++--- .../xcall_manager/src/white_list_actions.rs | 37 ++ libs/soroban-rlp/src/address_utils.rs | 50 ++- libs/soroban-rlp/src/decoder.rs | 4 +- libs/soroban-rlp/src/encoder.rs | 2 +- libs/soroban-rlp/src/lib.rs | 5 +- .../src/messages/configure_protocols.rs | 21 +- .../src/messages/cross_transfer.rs | 14 +- libs/soroban-rlp/src/messages/deposit.rs | 16 +- libs/soroban-rlp/src/utils.rs | 2 +- 39 files changed, 1155 insertions(+), 678 deletions(-) delete mode 100644 contracts/asset_manager/src/event.rs delete mode 100644 contracts/xcall_manager/src/events.rs create mode 100644 contracts/xcall_manager/src/white_list_actions.rs diff --git a/contracts/asset_manager/src/config.rs b/contracts/asset_manager/src/config.rs index e924316..6be0240 100644 --- a/contracts/asset_manager/src/config.rs +++ b/contracts/asset_manager/src/config.rs @@ -1,5 +1,5 @@ -use soroban_sdk::{contracttype, unwrap::UnwrapOptimized, Env, String, Address}; use crate::storage_types::DataKey; +use soroban_sdk::{contracttype, unwrap::UnwrapOptimized, Address, Env, String}; #[derive(Clone)] #[contracttype] @@ -10,16 +10,11 @@ pub struct ConfigData { pub icon_asset_manager: String, } -pub fn set_config(e: &Env, config: ConfigData){ +pub fn set_config(e: &Env, config: ConfigData) { e.storage().instance().set(&DataKey::Config, &config); } pub fn get_config(e: &Env) -> ConfigData { let key = DataKey::Config; - e - .storage() - .instance() - .get(&key) - .unwrap_optimized() + e.storage().instance().get(&key).unwrap_optimized() } - diff --git a/contracts/asset_manager/src/contract.rs b/contracts/asset_manager/src/contract.rs index 66267d6..a6c7557 100644 --- a/contracts/asset_manager/src/contract.rs +++ b/contracts/asset_manager/src/contract.rs @@ -1,18 +1,25 @@ - -use soroban_sdk::{contract, contractimpl, panic_with_error, token, Address, Bytes, BytesN, Env, String, Vec}; -mod xcall { +use soroban_sdk::{ + contract, contractimpl, panic_with_error, token, Address, Bytes, BytesN, Env, String, Vec, +}; +mod xcall { soroban_sdk::contractimport!(file = "../../wasm/xcall.wasm"); } -use soroban_rlp::messages::{deposit::Deposit, deposit_revert::DepositRevert, withdraw_to::WithdrawTo}; -use soroban_rlp::address_utils::is_valid_string_address; +use crate::errors::ContractError; use crate::{ - config::{get_config, set_config, ConfigData}, - states:: {has_registry, read_administrator, read_token_last_current_limit, read_token_last_update, - read_token_percentage, read_token_period, write_administrator, write_registry, write_token_current_limit, - write_token_last_update, write_token_percentage, write_token_period, extent_ttl, read_tokens, write_tokens}, - storage_types::{DataKey, POINTS}, xcall_manager_interface::XcallManagerClient + config::{get_config, set_config, ConfigData}, + states::{ + extent_ttl, has_registry, read_administrator, read_token_last_current_limit, + read_token_last_update, read_token_percentage, read_token_period, read_tokens, + write_administrator, write_registry, write_token_current_limit, write_token_last_update, + write_token_percentage, write_token_period, write_tokens, + }, + storage_types::{DataKey, POINTS}, + xcall_manager_interface::XcallManagerClient, +}; +use soroban_rlp::address_utils::{get_address_from, is_valid_string_address}; +use soroban_rlp::messages::{ + deposit::Deposit, deposit_revert::DepositRevert, withdraw_to::WithdrawTo, }; -use crate::errors::ContractError; use xcall::{AnyMessage, CallMessageWithRollback, Client, Envelope}; @@ -25,8 +32,7 @@ pub struct AssetManager; #[contractimpl] impl AssetManager { - - pub fn initialize(env:Env, registry:Address, admin: Address, config: ConfigData) { + pub fn initialize(env: Env, registry: Address, admin: Address, config: ConfigData) { if has_registry(&env.clone()) { panic_with_error!(&env, ContractError::ContractAlreadyInitialized) } @@ -35,7 +41,7 @@ impl AssetManager { write_administrator(&env, &admin); Self::configure(env, config); } - + pub fn get_config(env: Env) -> ConfigData { get_config(&env) } @@ -43,15 +49,16 @@ impl AssetManager { pub fn set_admin(env: Env, new_admin: Address) { let admin = read_administrator(&env); admin.require_auth(); + write_administrator(&env, &new_admin); } - pub fn get_admin(env: Env) -> Address{ + pub fn get_admin(env: Env) -> Address { read_administrator(&env) } - pub fn configure(env:Env, config: ConfigData){ + pub fn configure(env: Env, config: ConfigData) { let admin = read_administrator(&env); admin.require_auth(); @@ -68,25 +75,29 @@ impl AssetManager { admin.require_auth(); let tokens = read_tokens(&env); if tokens.contains(&token_address) { - return Err(ContractError::TokenExists) - }else{ + return Err(ContractError::TokenExists); + } else { write_tokens(&env, token_address.clone()); } if percentage > POINTS { - return Err(ContractError::PercentageShouldBeLessThanOrEqualToPOINTS); + return Err(ContractError::PercentageShouldBeLessThanOrEqualToPOINTS); } let token_client = token::Client::new(&env, &token_address); let contract_token_balance = token_client.balance(&env.current_contract_address()); - + write_token_period(&env, &token_address, period); write_token_percentage(&env, &token_address, percentage); write_token_last_update(&env, &token_address, env.ledger().timestamp()); - write_token_current_limit(&env, &token_address, (contract_token_balance as u128) * percentage/POINTS); + write_token_current_limit( + &env, + &token_address, + (contract_token_balance as u128) * percentage / POINTS, + ); Ok(()) } - pub fn get_rate_limit(env: Env, token_address: Address ) -> (u128, u128, u64, u128){ + pub fn get_rate_limit(env: Env, token_address: Address) -> (u128, u128, u64, u128) { ( read_token_period(&env, &token_address), read_token_percentage(&env, &token_address), @@ -95,36 +106,42 @@ impl AssetManager { ) } - pub fn reset_limit(env: Env, token: Address){ + pub fn reset_limit(env: Env, token: Address) { let balance = Self::get_token_balance(&env, token.clone()); let percentage: u128 = read_token_percentage(&env, &token); - write_token_current_limit(&env, &token, balance*percentage/POINTS); + write_token_current_limit(&env, &token, balance * percentage / POINTS); } - pub fn get_withdraw_limit(env: Env, token: Address) -> Result { + pub fn get_withdraw_limit(env: Env, token: Address) -> Result { let balance = Self::get_token_balance(&env, token.clone()); - return Ok(Self::calculate_limit(&env, balance, token)?) + return Ok(Self::calculate_limit(&env, balance, token)?); } fn get_token_balance(env: &Env, token: Address) -> u128 { let token_client = token::Client::new(env, &token); - return token_client.balance(&env.current_contract_address()) as u128 + return token_client.balance(&env.current_contract_address()) as u128; } pub fn verify_withdraw(env: Env, token: Address, amount: u128) -> Result { let balance = Self::get_token_balance(&env, token.clone()); let limit = Self::calculate_limit(&env, balance, token.clone())?; - if balance - amount < limit { panic_with_error!(&env, ContractError::ExceedsWithdrawLimit); }; + if balance - amount < limit { + panic_with_error!(&env, ContractError::ExceedsWithdrawLimit); + }; write_token_current_limit(&env, &token.clone(), limit); write_token_last_update(&env, &token.clone(), env.ledger().timestamp()); Ok(true) } - pub fn calculate_limit(env: &Env, balance: u128, token: Address) -> Result { + pub fn calculate_limit( + env: &Env, + balance: u128, + token: Address, + ) -> Result { let period: u128 = read_token_period(env, &token.clone()); - let percentage: u128 = read_token_percentage(env, &token.clone()); + let percentage: u128 = read_token_percentage(env, &token.clone()); if period == 0 { return Ok(0); } @@ -133,31 +150,42 @@ impl AssetManager { let max_withdraw = balance - min_reserve; let last_update: u64 = read_token_last_update(&env, &token.clone()); - let time_diff = (&env.ledger().timestamp() - last_update)/1000; + let time_diff = (&env.ledger().timestamp() - last_update) / 1000; - let allowed_withdrawal = (max_withdraw * time_diff as u128) / period; + let allowed_withdrawal = (max_withdraw * time_diff as u128) / period; let mut reserve: u128 = read_token_last_current_limit(&env, &token.clone()); - if reserve > allowed_withdrawal{ + if reserve > allowed_withdrawal { reserve = reserve - allowed_withdrawal; } - let reserve = if reserve > min_reserve { reserve } else { min_reserve }; + let reserve = if reserve > min_reserve { + reserve + } else { + min_reserve + }; Ok(reserve) } pub fn deposit( e: Env, - from: Address, + from: Address, token: Address, amount: u128, to: Option, - data: Option + data: Option, ) -> Result<(), ContractError> { - let deposit_to = to.unwrap_or(String::from_str(&e, "")); - let deposit_data = data.unwrap_or(Bytes::from_array(&e, &[0u8; 32])); + let deposit_to = to.unwrap_or(String::from_str(&e, "")); + let deposit_data = data.unwrap_or(Bytes::from_array(&e, &[0u8; 32])); - Ok(Self::send_deposit_message(e, from, token, amount, deposit_to, deposit_data)?) + Ok(Self::send_deposit_message( + e, + from, + token, + amount, + deposit_to, + deposit_data, + )?) } fn send_deposit_message( @@ -168,41 +196,52 @@ impl AssetManager { to: String, data: Bytes, ) -> Result<(), ContractError> { - from.require_auth(); - let current_address = e.current_contract_address(); - Self::transfer_token_to(&e, from.clone(), token.clone(), current_address.clone(), amount); + from.require_auth(); + let current_address = e.current_contract_address(); + Self::transfer_token_to( + &e, + from.clone(), + token.clone(), + current_address.clone(), + amount, + ); - let xcall_message: Deposit = Deposit::new( + let xcall_message: Deposit = Deposit::new( token.to_string(), from.to_string(), to.clone(), amount, - data + data, ); - let rollback: DepositRevert = DepositRevert::new( - token, - from.clone(), - amount - ); + let rollback: DepositRevert = DepositRevert::new(token, from.clone(), amount); let config = get_config(&e); let rollback_bytes = rollback.encode(&e, String::from_str(&e, DEPOSIT_REVERT_NAME)); let message_bytes = xcall_message.encode(&e, String::from_str(&e, DEPOSIT_NAME)); - let (sources, destinations) = Self::xcall_manager(&e, &config.xcall_manager ).get_protocols(); - let message = AnyMessage::CallMessageWithRollback(CallMessageWithRollback { data: message_bytes, rollback: rollback_bytes }); + let (sources, destinations) = + Self::xcall_manager(&e, &config.xcall_manager).get_protocols(); + let message = AnyMessage::CallMessageWithRollback(CallMessageWithRollback { + data: message_bytes, + rollback: rollback_bytes, + }); let envelope: &Envelope = &Envelope { destinations, message, - sources + sources, }; - - Self::xcall_client(&e, &config.xcall).send_call(&from, ¤t_address, envelope, &config.icon_asset_manager); + + Self::xcall_client(&e, &config.xcall).send_call( + &from, + ¤t_address, + envelope, + &config.icon_asset_manager, + ); Ok(()) } fn xcall_manager(e: &Env, xcall_manager: &Address) -> XcallManagerClient<'static> { - let client = XcallManagerClient::new(e, xcall_manager); - return client; + let client = XcallManagerClient::new(e, xcall_manager); + return client; } fn xcall_client(e: &Env, xcall: &Address) -> Client<'static> { @@ -211,35 +250,50 @@ impl AssetManager { pub fn handle_call_message( e: Env, - xcall_address: Address, from: String, data: Bytes, - protocols: Vec - ) -> Result<(), ContractError> { + protocols: Vec, + ) -> Result<(), ContractError> { let config = get_config(&e); let xcall = config.xcall; xcall.require_auth(); - + let method = Deposit::get_method(&e, data.clone()); let icon_asset_manager = config.icon_asset_manager; let current_contract = e.current_contract_address(); - if method == String::from_str(&e, &WITHDRAW_TO_NAME){ - if from != icon_asset_manager{ - return Err(ContractError::OnlyICONAssetManager); + if method == String::from_str(&e, &WITHDRAW_TO_NAME) { + if from != icon_asset_manager { + return Err(ContractError::OnlyICONAssetManager); } let message = WithdrawTo::decode(&e, data); - if !is_valid_string_address(&message.to) || !is_valid_string_address(&message.token_address) { + if !is_valid_string_address(&message.to) + || !is_valid_string_address(&message.token_address) + { return Err(ContractError::InvalidAddress); } - - Self::withdraw(&e, current_contract, Address::from_string(&message.token_address), Address::from_string(&message.to), message.amount)?; - } else if method == String::from_str(&e, &DEPOSIT_REVERT_NAME){ - if xcall != xcall_address { - return Err(ContractError::OnlyCallService) + + Self::withdraw( + &e, + current_contract, + Address::from_string(&message.token_address), + Address::from_string(&message.to), + message.amount, + )?; + } else if method == String::from_str(&e, &DEPOSIT_REVERT_NAME) { + let from_xcall = get_address_from(&from, &e); + let xcall_address = Address::from_string(&from_xcall.into()); + if xcall != xcall_address { + return Err(ContractError::OnlyCallService); } let message: DepositRevert = DepositRevert::decode(&e.clone(), data); - Self::withdraw(&e, current_contract, message.token_address, message.to, message.amount)?; + Self::withdraw( + &e, + current_contract, + message.token_address, + message.to, + message.amount, + )?; } else { return Err(ContractError::UnknownMessageType); } @@ -249,11 +303,17 @@ impl AssetManager { Ok(()) } - pub fn withdraw(e: &Env, from: Address, token: Address, to: Address, amount: u128) -> Result<(), ContractError> { + pub fn withdraw( + e: &Env, + from: Address, + token: Address, + to: Address, + amount: u128, + ) -> Result<(), ContractError> { if amount <= 0 { return Err(ContractError::AmountIsLessThanMinimumAmount); } - + let verified = Self::verify_withdraw(e.clone(), token.clone(), amount)?; if verified { Self::transfer_token_to(e, from, token, to, amount); @@ -261,7 +321,7 @@ impl AssetManager { Ok(()) } - fn transfer_token_to(e: &Env, from: Address, token: Address, to: Address, amount: u128){ + fn transfer_token_to(e: &Env, from: Address, token: Address, to: Address, amount: u128) { let token_client = token::Client::new(e, &token); token_client.transfer(&from, &to, &(amount as i128)); } @@ -282,8 +342,7 @@ impl AssetManager { e.deployer().update_current_contract_wasm(new_wasm_hash); } - pub fn extend_ttl(e: Env){ + pub fn extend_ttl(e: Env) { extent_ttl(&e); } - -} \ No newline at end of file +} diff --git a/contracts/asset_manager/src/errors.rs b/contracts/asset_manager/src/errors.rs index d539591..535c2da 100644 --- a/contracts/asset_manager/src/errors.rs +++ b/contracts/asset_manager/src/errors.rs @@ -16,6 +16,5 @@ pub enum ContractError { UnknownMessageType = 10, AdminRequired = 11, TokenExists = 12, - InvalidAddress = 13 - -} \ No newline at end of file + InvalidAddress = 13, +} diff --git a/contracts/asset_manager/src/event.rs b/contracts/asset_manager/src/event.rs deleted file mode 100644 index e69de29..0000000 diff --git a/contracts/asset_manager/src/states.rs b/contracts/asset_manager/src/states.rs index 5816d81..eb06737 100644 --- a/contracts/asset_manager/src/states.rs +++ b/contracts/asset_manager/src/states.rs @@ -36,47 +36,47 @@ pub fn write_registry(e: &Env, id: &Address) { e.storage().instance().set(&key, id); } -pub fn write_token_period(e: &Env, token: &Address, period: u128){ +pub fn write_token_period(e: &Env, token: &Address, period: u128) { let key = DataKey::Period(token.clone()); e.storage().persistent().set(&key, &period); } -pub fn read_token_period(e: &Env, token: &Address)->u128{ +pub fn read_token_period(e: &Env, token: &Address) -> u128 { let key = DataKey::Period(token.clone()); e.storage().persistent().get(&key).unwrap() } -pub fn write_token_percentage(e: &Env, token: &Address, period: u128){ +pub fn write_token_percentage(e: &Env, token: &Address, period: u128) { let key = DataKey::Percentage(token.clone()); e.storage().persistent().set(&key, &period); } -pub fn read_token_percentage(e: &Env, token: &Address)->u128{ +pub fn read_token_percentage(e: &Env, token: &Address) -> u128 { let key = DataKey::Percentage(token.clone()); e.storage().persistent().get(&key).unwrap() } -pub fn write_token_last_update(e: &Env, token: &Address, last_update: u64){ +pub fn write_token_last_update(e: &Env, token: &Address, last_update: u64) { let key = DataKey::LastUpdate(token.clone()); e.storage().persistent().set(&key, &last_update); } -pub fn read_token_last_update(e: &Env, token: &Address)->u64{ +pub fn read_token_last_update(e: &Env, token: &Address) -> u64 { let key = DataKey::LastUpdate(token.clone()); e.storage().persistent().get(&key).unwrap() } -pub fn write_token_current_limit(e: &Env, token: &Address, current_limit: u128){ +pub fn write_token_current_limit(e: &Env, token: &Address, current_limit: u128) { let key = DataKey::CurrentLimit(token.clone()); e.storage().persistent().set(&key, ¤t_limit); } -pub fn read_token_last_current_limit(e: &Env, token: &Address)->u128{ +pub fn read_token_last_current_limit(e: &Env, token: &Address) -> u128 { let key = DataKey::CurrentLimit(token.clone()); e.storage().persistent().get(&key).unwrap() } -pub fn write_tokens(e: &Env, token: Address){ +pub fn write_tokens(e: &Env, token: Address) { let key = DataKey::Tokens; let mut tokens: Vec
= match e.storage().instance().get(&key) { Some(names) => names, @@ -87,7 +87,7 @@ pub fn write_tokens(e: &Env, token: Address){ e.storage().persistent().set(&key, &tokens); } -pub fn read_tokens(e: &Env)->Vec
{ +pub fn read_tokens(e: &Env) -> Vec
{ let key = DataKey::Tokens; let tokens: Vec
= match e.storage().persistent().get(&key) { Some(names) => names, @@ -97,27 +97,37 @@ pub fn read_tokens(e: &Env)->Vec
{ tokens } -pub fn extent_ttl(e: &Env){ +pub fn extent_ttl(e: &Env) { e.storage() - .instance() - .extend_ttl(INSTANCE_LIFETIME_THRESHOLD, INSTANCE_BUMP_AMOUNT); + .instance() + .extend_ttl(INSTANCE_LIFETIME_THRESHOLD, INSTANCE_BUMP_AMOUNT); let tokens = read_tokens(&e.clone()); - e.storage() - .persistent() - .extend_ttl(&DataKey::Tokens, INSTANCE_LIFETIME_THRESHOLD, INSTANCE_BUMP_AMOUNT); + e.storage().persistent().extend_ttl( + &DataKey::Tokens, + INSTANCE_LIFETIME_THRESHOLD, + INSTANCE_BUMP_AMOUNT, + ); for token in tokens { - e.storage() - .persistent() - .extend_ttl(&DataKey::Period(token.clone()), INSTANCE_LIFETIME_THRESHOLD, INSTANCE_BUMP_AMOUNT); - e.storage() - .persistent() - .extend_ttl(&DataKey::Percentage(token.clone()), INSTANCE_LIFETIME_THRESHOLD, INSTANCE_BUMP_AMOUNT); - e.storage() - .persistent() - .extend_ttl(&DataKey::LastUpdate(token.clone()), INSTANCE_LIFETIME_THRESHOLD, INSTANCE_BUMP_AMOUNT); - e.storage() - .persistent() - .extend_ttl(&DataKey::CurrentLimit(token.clone()), INSTANCE_LIFETIME_THRESHOLD, INSTANCE_BUMP_AMOUNT); + e.storage().persistent().extend_ttl( + &DataKey::Period(token.clone()), + INSTANCE_LIFETIME_THRESHOLD, + INSTANCE_BUMP_AMOUNT, + ); + e.storage().persistent().extend_ttl( + &DataKey::Percentage(token.clone()), + INSTANCE_LIFETIME_THRESHOLD, + INSTANCE_BUMP_AMOUNT, + ); + e.storage().persistent().extend_ttl( + &DataKey::LastUpdate(token.clone()), + INSTANCE_LIFETIME_THRESHOLD, + INSTANCE_BUMP_AMOUNT, + ); + e.storage().persistent().extend_ttl( + &DataKey::CurrentLimit(token.clone()), + INSTANCE_LIFETIME_THRESHOLD, + INSTANCE_BUMP_AMOUNT, + ); } -} \ No newline at end of file +} diff --git a/contracts/asset_manager/src/storage_types.rs b/contracts/asset_manager/src/storage_types.rs index a7a11bf..4e6d311 100644 --- a/contracts/asset_manager/src/storage_types.rs +++ b/contracts/asset_manager/src/storage_types.rs @@ -1,10 +1,10 @@ use soroban_sdk::{contracttype, Address}; -pub(crate) const POINTS: u128 = 10000; +pub(crate) const POINTS: u128 = 10000; #[derive(Clone)] #[contracttype] -pub enum DataKey{ +pub enum DataKey { Registry, Admin, Config, @@ -12,6 +12,5 @@ pub enum DataKey{ Period(Address), Percentage(Address), LastUpdate(Address), - CurrentLimit(Address) + CurrentLimit(Address), } - diff --git a/contracts/asset_manager/src/tests/asset_manager_test.rs b/contracts/asset_manager/src/tests/asset_manager_test.rs index 4f58ca3..7027437 100644 --- a/contracts/asset_manager/src/tests/asset_manager_test.rs +++ b/contracts/asset_manager/src/tests/asset_manager_test.rs @@ -1,13 +1,13 @@ #![cfg(test)] extern crate std; - +use crate::contract::AssetManagerClient; use soroban_sdk::{ - testutils::{Address as _, AuthorizedFunction, AuthorizedInvocation}, token, Address, Bytes, IntoVal, String, Symbol, Vec + testutils::{Address as _, AuthorizedFunction, AuthorizedInvocation}, + token, Address, Bytes, IntoVal, String, Symbol, Vec, }; -use crate::contract::AssetManagerClient; -use soroban_rlp::messages::{deposit_revert:: DepositRevert, withdraw_to:: WithdrawTo}; +use soroban_rlp::messages::{deposit_revert::DepositRevert, withdraw_to::WithdrawTo}; use super::setup::*; @@ -27,25 +27,22 @@ fn test_set_admin() { let ctx = TestContext::default(); let client = AssetManagerClient::new(&ctx.env, &ctx.registry); ctx.init_context(&client); - + let new_admin: Address = Address::generate(&ctx.env); client.set_admin(&new_admin); assert_eq!( ctx.env.auths(), - std::vec![ - ( - ctx.admin.clone(), - AuthorizedInvocation { - function: AuthorizedFunction::Contract(( - ctx.registry.clone(), - Symbol::new(&ctx.env, "set_admin"), - (&new_admin,) - .into_val(&ctx.env) - )), - sub_invocations: std::vec![] - } - ) - ] + std::vec![( + ctx.admin.clone(), + AuthorizedInvocation { + function: AuthorizedFunction::Contract(( + ctx.registry.clone(), + Symbol::new(&ctx.env, "set_admin"), + (&new_admin,).into_val(&ctx.env) + )), + sub_invocations: std::vec![] + } + )] ); assert_eq!(client.get_admin(), new_admin); } @@ -58,7 +55,7 @@ fn test_configure_rate_limit_panic() { ctx.init_context(&client); let period = &300u128; let percentage = &10001u128; - client.configure_rate_limit( &ctx.token, period, percentage ); + client.configure_rate_limit(&ctx.token, period, percentage); let limit = client.get_withdraw_limit(&ctx.token); let verified = client.verify_withdraw(&ctx.token, &limit); @@ -72,23 +69,20 @@ fn test_configure_rate_limit() { ctx.init_context(&client); let period = &300u128; let percentage = &300u128; - client.configure_rate_limit( &ctx.token, period, percentage ); + client.configure_rate_limit(&ctx.token, period, percentage); assert_eq!( ctx.env.auths(), - std::vec![ - ( - ctx.admin.clone(), - AuthorizedInvocation { - function: AuthorizedFunction::Contract(( - ctx.registry.clone(), - Symbol::new(&ctx.env, "configure_rate_limit"), - (&ctx.token, 300u128, 300u128) - .into_val(&ctx.env) - )), - sub_invocations: std::vec![] - } - ) - ] + std::vec![( + ctx.admin.clone(), + AuthorizedInvocation { + function: AuthorizedFunction::Contract(( + ctx.registry.clone(), + Symbol::new(&ctx.env, "configure_rate_limit"), + (&ctx.token, 300u128, 300u128).into_val(&ctx.env) + )), + sub_invocations: std::vec![] + } + )] ); let limit = client.get_withdraw_limit(&ctx.token); let verified = client.verify_withdraw(&ctx.token, &limit); @@ -96,25 +90,37 @@ fn test_configure_rate_limit() { } #[test] -fn test_deposit_without_to_and_data(){ +fn test_deposit_without_to_and_data() { let ctx = TestContext::default(); let client = AssetManagerClient::new(&ctx.env, &ctx.registry); ctx.init_context(&client); - client.configure_rate_limit( &ctx.token, &300u128, &300u128 ); + client.configure_rate_limit(&ctx.token, &300u128, &300u128); let token_client = token::Client::new(&ctx.env, &ctx.token); - let stellar_asset_client: token::StellarAssetClient = token::StellarAssetClient::new(&ctx.env, &ctx.token); + let stellar_asset_client: token::StellarAssetClient = + token::StellarAssetClient::new(&ctx.env, &ctx.token); let amount_i128: i128 = 100000i128; let amount = &(amount_i128 as u128); - let mint_amount = &(amount_i128+amount_i128); - + let mint_amount = &(amount_i128 + amount_i128); + stellar_asset_client.mint(&ctx.depositor, mint_amount); ctx.mint_native_token(&ctx.depositor, 500); assert_eq!(ctx.get_native_token_balance(&ctx.depositor), 500); - token_client.approve(&ctx.depositor, &ctx.registry, &(amount_i128+amount_i128), &1312000); - client.deposit(&ctx.depositor, &ctx.token, &amount, &Option::Some(String::from_str(&ctx.env, "")), &Option::Some(Bytes::from_array(&ctx.env, &[0u8; 32]))); + token_client.approve( + &ctx.depositor, + &ctx.registry, + &(amount_i128 + amount_i128), + &1312000, + ); + client.deposit( + &ctx.depositor, + &ctx.token, + &amount, + &Option::Some(String::from_str(&ctx.env, "")), + &Option::Some(Bytes::from_array(&ctx.env, &[0u8; 32])), + ); assert_eq!(ctx.get_native_token_balance(&ctx.depositor), 400); // why 300? } @@ -126,25 +132,32 @@ fn test_veryfy_rate_limit() { ctx.init_context(&client); let period = &300u128; let percentage = &300u128; - client.configure_rate_limit( &ctx.token, period, percentage ); + client.configure_rate_limit(&ctx.token, period, percentage); //let token_client = token::Client::new(&ctx.env, &ctx.token); - let stellar_asset_client: token::StellarAssetClient = token::StellarAssetClient::new(&ctx.env, &ctx.token); - let amount_i128: i128 = 100000i128 ; + let stellar_asset_client: token::StellarAssetClient = + token::StellarAssetClient::new(&ctx.env, &ctx.token); + let amount_i128: i128 = 100000i128; let amount = &(amount_i128 as u128); - let mint_amount: &i128 = &(amount_i128+amount_i128); - + let mint_amount: &i128 = &(amount_i128 + amount_i128); + stellar_asset_client.mint(&ctx.depositor, mint_amount); ctx.mint_native_token(&ctx.depositor, 500u128); assert_eq!(ctx.get_native_token_balance(&ctx.depositor), 500u128); //token_client.approve(&ctx.depositor, &ctx.registry, &(amount_i128+amount_i128), &1312000); - client.deposit(&ctx.depositor, &ctx.token, &amount, &Option::Some(String::from_str(&ctx.env, "")), &Option::Some(Bytes::from_array(&ctx.env, &[0u8; 32]))); - + client.deposit( + &ctx.depositor, + &ctx.token, + &amount, + &Option::Some(String::from_str(&ctx.env, "")), + &Option::Some(Bytes::from_array(&ctx.env, &[0u8; 32])), + ); + let limit = client.get_withdraw_limit(&ctx.token); assert_eq!(limit, 3000); - let verified = client.verify_withdraw(&ctx.token, &(amount-3000-1)); + let verified = client.verify_withdraw(&ctx.token, &(amount - 3000 - 1)); assert_eq!(verified, true); } @@ -156,269 +169,349 @@ fn test_veryfy_rate_limit_panic_exceeds_withdraw_limit() { ctx.init_context(&client); let period = &300u128; let percentage = &300u128; - client.configure_rate_limit( &ctx.token, period, percentage ); + client.configure_rate_limit(&ctx.token, period, percentage); let token_client = token::Client::new(&ctx.env, &ctx.token); - let stellar_asset_client: token::StellarAssetClient = token::StellarAssetClient::new(&ctx.env, &ctx.token); - let amount_i128: i128 = 100000i128 ; + let stellar_asset_client: token::StellarAssetClient = + token::StellarAssetClient::new(&ctx.env, &ctx.token); + let amount_i128: i128 = 100000i128; let amount = &(amount_i128 as u128); - let mint_amount = &(amount_i128+amount_i128); - + let mint_amount = &(amount_i128 + amount_i128); + stellar_asset_client.mint(&ctx.depositor, mint_amount); ctx.mint_native_token(&ctx.depositor, 500u128); assert_eq!(ctx.get_native_token_balance(&ctx.depositor), 500u128); - token_client.approve(&ctx.depositor, &ctx.registry, &(amount_i128+amount_i128), &1312000); - client.deposit(&ctx.depositor, &ctx.token, &amount, &Option::Some(String::from_str(&ctx.env, "")), &Option::Some(Bytes::from_array(&ctx.env, &[0u8; 32]))); - + token_client.approve( + &ctx.depositor, + &ctx.registry, + &(amount_i128 + amount_i128), + &1312000, + ); + client.deposit( + &ctx.depositor, + &ctx.token, + &amount, + &Option::Some(String::from_str(&ctx.env, "")), + &Option::Some(Bytes::from_array(&ctx.env, &[0u8; 32])), + ); + let limit = client.get_withdraw_limit(&ctx.token); assert_eq!(limit, 3000); - let verified = client.verify_withdraw(&ctx.token, &(amount-3000+1)); + let verified = client.verify_withdraw(&ctx.token, &(amount - 3000 + 1)); assert_eq!(verified, true); } #[test] -fn test_deposit_with_to_and_without_data(){ +fn test_deposit_with_to_and_without_data() { let ctx = TestContext::default(); let client = AssetManagerClient::new(&ctx.env, &ctx.registry); ctx.init_context(&client); - client.configure_rate_limit( &ctx.token, &300u128, &300u128); + client.configure_rate_limit(&ctx.token, &300u128, &300u128); let token_client = token::Client::new(&ctx.env, &ctx.token); - let stellar_asset_client: token::StellarAssetClient = token::StellarAssetClient::new(&ctx.env, &ctx.token); + let stellar_asset_client: token::StellarAssetClient = + token::StellarAssetClient::new(&ctx.env, &ctx.token); let amount_i128: i128 = 100000i128; let amount = &(amount_i128 as u128); - let mint_amount = &(amount_i128+amount_i128); - + let mint_amount = &(amount_i128 + amount_i128); + stellar_asset_client.mint(&ctx.depositor, mint_amount); ctx.mint_native_token(&ctx.depositor, 500); assert_eq!(ctx.get_native_token_balance(&ctx.depositor), 500); - token_client.approve(&ctx.depositor, &ctx.registry, &(amount_i128+amount_i128), &1312000); - client.deposit(&ctx.depositor, &ctx.token, &amount, &Option::Some(String::from_str(&ctx.env, "icon01/hxjkdvhui")), &Option::Some(Bytes::from_array(&ctx.env, &[0u8; 32]))); + token_client.approve( + &ctx.depositor, + &ctx.registry, + &(amount_i128 + amount_i128), + &1312000, + ); + client.deposit( + &ctx.depositor, + &ctx.token, + &amount, + &Option::Some(String::from_str(&ctx.env, "icon01/hxjkdvhui")), + &Option::Some(Bytes::from_array(&ctx.env, &[0u8; 32])), + ); assert_eq!(ctx.get_native_token_balance(&ctx.depositor), 400) // why 300? } #[test] -fn test_deposit_with_to_and_data(){ +fn test_deposit_with_to_and_data() { let ctx = TestContext::default(); let client = AssetManagerClient::new(&ctx.env, &ctx.registry); ctx.init_context(&client); - client.configure_rate_limit( &ctx.token, &300u128, &300u128 ); + client.configure_rate_limit(&ctx.token, &300u128, &300u128); let token_client = token::Client::new(&ctx.env, &ctx.token); - let stellar_asset_client: token::StellarAssetClient = token::StellarAssetClient::new(&ctx.env, &ctx.token); + let stellar_asset_client: token::StellarAssetClient = + token::StellarAssetClient::new(&ctx.env, &ctx.token); let amount_i128: i128 = 100000i128; let amount = &(amount_i128 as u128); - let mint_amount = &(amount_i128+amount_i128); - + let mint_amount = &(amount_i128 + amount_i128); + stellar_asset_client.mint(&ctx.depositor, mint_amount); ctx.mint_native_token(&ctx.depositor, 500); assert_eq!(ctx.get_native_token_balance(&ctx.depositor), 500); - token_client.approve(&ctx.depositor, &ctx.registry, &(amount_i128+amount_i128), &1312000); + token_client.approve( + &ctx.depositor, + &ctx.registry, + &(amount_i128 + amount_i128), + &1312000, + ); let data: [u8; 32] = [ - 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, - 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0x10, - 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, - 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F, 0x20, + 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, + 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, + 0x1F, 0x20, ]; - client.deposit(&ctx.depositor, &ctx.token, &amount, &Option::Some(String::from_str(&ctx.env, "icon01/hxjkdvhui")), &Option::Some(Bytes::from_array(&ctx.env, &data))); + client.deposit( + &ctx.depositor, + &ctx.token, + &amount, + &Option::Some(String::from_str(&ctx.env, "icon01/hxjkdvhui")), + &Option::Some(Bytes::from_array(&ctx.env, &data)), + ); assert_eq!(ctx.get_native_token_balance(&ctx.depositor), 400); // why 300? - } - #[test] -fn test_handle_call_message_for_withdraw_to(){ +fn test_handle_call_message_for_withdraw_to() { let ctx = TestContext::default(); let client = AssetManagerClient::new(&ctx.env, &ctx.registry); ctx.env.mock_all_auths(); ctx.init_context(&client); - client.configure_rate_limit( &ctx.token, &300u128, &300u128); - + client.configure_rate_limit(&ctx.token, &300u128, &300u128); + let bnusd_amount = 100000u128; let token_client = token::Client::new(&ctx.env, &ctx.token); - let stellar_asset_client: token::StellarAssetClient = token::StellarAssetClient::new(&ctx.env, &ctx.token); - stellar_asset_client.mint(&ctx.registry, &((bnusd_amount*2) as i128)); - - let data = WithdrawTo::new(ctx.token.to_string(), ctx.withdrawer.to_string(), bnusd_amount).encode(&ctx.env, String::from_str(&ctx.env, "WithdrawTo")); + let stellar_asset_client: token::StellarAssetClient = + token::StellarAssetClient::new(&ctx.env, &ctx.token); + stellar_asset_client.mint(&ctx.registry, &((bnusd_amount * 2) as i128)); + + let data = WithdrawTo::new( + ctx.token.to_string(), + ctx.withdrawer.to_string(), + bnusd_amount, + ) + .encode(&ctx.env, String::from_str(&ctx.env, "WithdrawTo")); let decoded = WithdrawTo::decode(&ctx.env, data.clone()); assert_eq!(decoded.to, ctx.withdrawer.to_string()); assert_eq!(token_client.balance(&ctx.withdrawer), 0); let sources = Vec::from_array(&ctx.env, [ctx.centralized_connection.to_string()]); - client.handle_call_message(&ctx.xcall, &ctx.icon_asset_manager, &data, &sources); - - assert_eq!(token_client.balance(&ctx.withdrawer), bnusd_amount as i128) + client.handle_call_message(&ctx.icon_asset_manager, &data, &sources); + + assert_eq!(token_client.balance(&ctx.withdrawer), bnusd_amount as i128) } #[test] #[should_panic(expected = "HostError: Error(Contract, #13)")] -fn test_handle_call_message_for_withdraw_to_invalid_address(){ +fn test_handle_call_message_for_withdraw_to_invalid_address() { let ctx = TestContext::default(); let client = AssetManagerClient::new(&ctx.env, &ctx.registry); ctx.env.mock_all_auths(); ctx.init_context(&client); - client.configure_rate_limit( &ctx.token, &300u128, &300u128); - + client.configure_rate_limit(&ctx.token, &300u128, &300u128); + let bnusd_amount = 100000u128; let token_client = token::Client::new(&ctx.env, &ctx.token); - let stellar_asset_client: token::StellarAssetClient = token::StellarAssetClient::new(&ctx.env, &ctx.token); - stellar_asset_client.mint(&ctx.registry, &((bnusd_amount*2) as i128)); - - let data = WithdrawTo::new(ctx.token.to_string(), String::from_str(&ctx.env, "InvalidAddress"), bnusd_amount).encode(&ctx.env, String::from_str(&ctx.env, "WithdrawTo")); + let stellar_asset_client: token::StellarAssetClient = + token::StellarAssetClient::new(&ctx.env, &ctx.token); + stellar_asset_client.mint(&ctx.registry, &((bnusd_amount * 2) as i128)); + + let data = WithdrawTo::new( + ctx.token.to_string(), + String::from_str(&ctx.env, "InvalidAddress"), + bnusd_amount, + ) + .encode(&ctx.env, String::from_str(&ctx.env, "WithdrawTo")); let decoded = WithdrawTo::decode(&ctx.env, data.clone()); assert_eq!(decoded.to, String::from_str(&ctx.env, "InvalidAddress")); assert_eq!(token_client.balance(&ctx.withdrawer), 0); let sources = Vec::from_array(&ctx.env, [ctx.centralized_connection.to_string()]); - client.handle_call_message(&ctx.xcall, &ctx.icon_asset_manager, &data, &sources); - - assert_eq!(token_client.balance(&ctx.withdrawer), bnusd_amount as i128) + client.handle_call_message(&ctx.icon_asset_manager, &data, &sources); + + assert_eq!(token_client.balance(&ctx.withdrawer), bnusd_amount as i128) } #[test] #[should_panic(expected = "HostError: Error(Contract, #7)")] -fn test_handle_call_message_for_withdraw_to_panic_with_protocal_mismatch(){ +fn test_handle_call_message_for_withdraw_to_panic_with_protocal_mismatch() { let ctx = TestContext::default(); let client = AssetManagerClient::new(&ctx.env, &ctx.registry); ctx.env.mock_all_auths(); ctx.init_context(&client); - client.configure_rate_limit( &ctx.token, &300u128, &300u128); - + client.configure_rate_limit(&ctx.token, &300u128, &300u128); + let bnusd_amount = 100000u128; let token_client = token::Client::new(&ctx.env, &ctx.token); - let stellar_asset_client: token::StellarAssetClient = token::StellarAssetClient::new(&ctx.env, &ctx.token); - stellar_asset_client.mint(&ctx.registry, &((bnusd_amount*2) as i128)); - - let data = WithdrawTo::new(ctx.token.to_string(), ctx.withdrawer.to_string(), bnusd_amount).encode(&ctx.env, String::from_str(&ctx.env, "WithdrawTo")); + let stellar_asset_client: token::StellarAssetClient = + token::StellarAssetClient::new(&ctx.env, &ctx.token); + stellar_asset_client.mint(&ctx.registry, &((bnusd_amount * 2) as i128)); + + let data = WithdrawTo::new( + ctx.token.to_string(), + ctx.withdrawer.to_string(), + bnusd_amount, + ) + .encode(&ctx.env, String::from_str(&ctx.env, "WithdrawTo")); let decoded = WithdrawTo::decode(&ctx.env, data.clone()); assert_eq!(decoded.to, ctx.withdrawer.to_string()); assert_eq!(token_client.balance(&ctx.withdrawer), 0); let sources = Vec::from_array(&ctx.env, [ctx.xcall.to_string()]); - client.handle_call_message(&ctx.xcall, &ctx.icon_asset_manager, &data, &sources); - - assert_eq!(token_client.balance(&ctx.withdrawer), bnusd_amount as i128) + client.handle_call_message(&ctx.icon_asset_manager, &data, &sources); + + assert_eq!(token_client.balance(&ctx.withdrawer), bnusd_amount as i128) } #[test] #[should_panic(expected = "HostError: Error(Contract, #8)")] -fn test_handle_call_message_for_withdraw_to_panic_with_not_icon_asset_manager(){ +fn test_handle_call_message_for_withdraw_to_panic_with_not_icon_asset_manager() { let ctx = TestContext::default(); let client = AssetManagerClient::new(&ctx.env, &ctx.registry); ctx.env.mock_all_auths(); ctx.init_context(&client); - client.configure_rate_limit( &ctx.token, &300u128, &300u128 ); - + client.configure_rate_limit(&ctx.token, &300u128, &300u128); + let bnusd_amount = 100000u128; let token_client = token::Client::new(&ctx.env, &ctx.token); - let stellar_asset_client: token::StellarAssetClient = token::StellarAssetClient::new(&ctx.env, &ctx.token); - stellar_asset_client.mint(&ctx.registry, &((bnusd_amount*2) as i128)); - - let data = WithdrawTo::new(ctx.token.to_string(), ctx.withdrawer.to_string(), bnusd_amount).encode(&ctx.env, String::from_str(&ctx.env, "WithdrawTo")); + let stellar_asset_client: token::StellarAssetClient = + token::StellarAssetClient::new(&ctx.env, &ctx.token); + stellar_asset_client.mint(&ctx.registry, &((bnusd_amount * 2) as i128)); + + let data = WithdrawTo::new( + ctx.token.to_string(), + ctx.withdrawer.to_string(), + bnusd_amount, + ) + .encode(&ctx.env, String::from_str(&ctx.env, "WithdrawTo")); let decoded = WithdrawTo::decode(&ctx.env, data.clone()); assert_eq!(decoded.to, ctx.withdrawer.to_string()); assert_eq!(token_client.balance(&ctx.withdrawer), 0); let sources = Vec::from_array(&ctx.env, [ctx.centralized_connection.to_string()]); - client.handle_call_message(&ctx.xcall, &ctx.centralized_connection.to_string(), &data, &sources); - - assert_eq!(token_client.balance(&ctx.withdrawer), bnusd_amount as i128) + client.handle_call_message(&ctx.centralized_connection.to_string(), &data, &sources); + + assert_eq!(token_client.balance(&ctx.withdrawer), bnusd_amount as i128) } #[test] #[should_panic(expected = "HostError: Error(Contract, #10)")] -fn test_handle_call_message_for_withdraw_to_panic_with_unknown_message_type(){ +fn test_handle_call_message_for_withdraw_to_panic_with_unknown_message_type() { let ctx = TestContext::default(); let client = AssetManagerClient::new(&ctx.env, &ctx.registry); ctx.env.mock_all_auths(); ctx.init_context(&client); - client.configure_rate_limit( &ctx.token, &300u128, &300u128 ); - + client.configure_rate_limit(&ctx.token, &300u128, &300u128); + let bnusd_amount = 100000u128; let token_client = token::Client::new(&ctx.env, &ctx.token); - let stellar_asset_client: token::StellarAssetClient = token::StellarAssetClient::new(&ctx.env, &ctx.token); - stellar_asset_client.mint(&ctx.registry, &((bnusd_amount*2) as i128)); - - let data = WithdrawTo::new(ctx.token.to_string(), ctx.withdrawer.to_string(), bnusd_amount).encode(&ctx.env, String::from_str(&ctx.env, "WithdrawToUnknown")); + let stellar_asset_client: token::StellarAssetClient = + token::StellarAssetClient::new(&ctx.env, &ctx.token); + stellar_asset_client.mint(&ctx.registry, &((bnusd_amount * 2) as i128)); + + let data = WithdrawTo::new( + ctx.token.to_string(), + ctx.withdrawer.to_string(), + bnusd_amount, + ) + .encode(&ctx.env, String::from_str(&ctx.env, "WithdrawToUnknown")); let decoded = WithdrawTo::decode(&ctx.env, data.clone()); assert_eq!(decoded.to, ctx.withdrawer.to_string()); assert_eq!(token_client.balance(&ctx.withdrawer), 0); let sources = Vec::from_array(&ctx.env, [ctx.centralized_connection.to_string()]); - client.handle_call_message(&ctx.xcall, &ctx.icon_asset_manager, &data, &sources); - - assert_eq!(token_client.balance(&ctx.withdrawer), bnusd_amount as i128) + client.handle_call_message(&ctx.icon_asset_manager, &data, &sources); + + assert_eq!(token_client.balance(&ctx.withdrawer), bnusd_amount as i128) } #[test] -fn test_handle_call_message_for_deposit_rollback(){ +fn test_handle_call_message_for_deposit_rollback() { let ctx = TestContext::default(); let client = AssetManagerClient::new(&ctx.env, &ctx.registry); ctx.env.mock_all_auths(); ctx.init_context(&client); - client.configure_rate_limit( &ctx.token, &300, &300 ); - + client.configure_rate_limit(&ctx.token, &300, &300); + let bnusd_amount = 100000u128; let token_client = token::Client::new(&ctx.env, &ctx.token); - let stellar_asset_client: token::StellarAssetClient = token::StellarAssetClient::new(&ctx.env, &ctx.token); - stellar_asset_client.mint(&ctx.registry, &((bnusd_amount*2) as i128)); + let stellar_asset_client: token::StellarAssetClient = + token::StellarAssetClient::new(&ctx.env, &ctx.token); + stellar_asset_client.mint(&ctx.registry, &((bnusd_amount * 2) as i128)); - let data = DepositRevert::new(ctx.token, ctx.withdrawer.clone(), bnusd_amount).encode(&ctx.env, String::from_str(&ctx.env, "DepositRevert")); + let data = DepositRevert::new(ctx.token, ctx.withdrawer.clone(), bnusd_amount) + .encode(&ctx.env, String::from_str(&ctx.env, "DepositRevert")); let decoded = DepositRevert::decode(&ctx.env, data.clone()); assert_eq!(decoded.to, ctx.withdrawer); assert_eq!(token_client.balance(&ctx.withdrawer), 0); let sources = Vec::from_array(&ctx.env, [ctx.centralized_connection.to_string()]); - client.handle_call_message(&ctx.xcall, &ctx.xcall_client.get_network_address(), &data, &sources); - - assert_eq!(token_client.balance(&ctx.withdrawer), bnusd_amount as i128) + client.handle_call_message(&ctx.xcall_client.get_network_address(), &data, &sources); + + assert_eq!(token_client.balance(&ctx.withdrawer), bnusd_amount as i128) } #[test] #[should_panic(expected = "HostError: Error(Contract, #9)")] -fn test_handle_call_message_for_deposit_rollback_panic_with_only_call_service(){ +fn test_handle_call_message_for_deposit_rollback_panic_with_only_call_service() { let ctx = TestContext::default(); let client = AssetManagerClient::new(&ctx.env, &ctx.registry); ctx.env.mock_all_auths(); ctx.init_context(&client); - client.configure_rate_limit( &ctx.token, &300u128, &300u128 ); - + client.configure_rate_limit(&ctx.token, &300u128, &300u128); + let bnusd_amount = 100000u128; let token_client = token::Client::new(&ctx.env, &ctx.token); - let stellar_asset_client: token::StellarAssetClient = token::StellarAssetClient::new(&ctx.env, &ctx.token); - stellar_asset_client.mint(&ctx.registry, &((bnusd_amount*2) as i128)); + let stellar_asset_client: token::StellarAssetClient = + token::StellarAssetClient::new(&ctx.env, &ctx.token); + stellar_asset_client.mint(&ctx.registry, &((bnusd_amount * 2) as i128)); - let data = DepositRevert::new(ctx.token, ctx.withdrawer.clone(), bnusd_amount).encode(&ctx.env, String::from_str(&ctx.env, "DepositRevert")); + let data = DepositRevert::new(ctx.token, ctx.withdrawer.clone(), bnusd_amount) + .encode(&ctx.env, String::from_str(&ctx.env, "DepositRevert")); let decoded = DepositRevert::decode(&ctx.env, data.clone()); assert_eq!(decoded.to, ctx.withdrawer); assert_eq!(token_client.balance(&ctx.withdrawer), 0); let sources = Vec::from_array(&ctx.env, [ctx.centralized_connection.to_string()]); - client.handle_call_message(&ctx.xcall_manager, &ctx.xcall.to_string(), &data, &sources); - - assert_eq!(token_client.balance(&ctx.withdrawer), bnusd_amount as i128) + let wrong_network_address: String = String::from_str( + &ctx.env, + &std::format!( + "{}/{}", + "soroban", + "CBEPDNVYXQGWB5YUBXKJWYJA7OXTZW5LFLNO5JRRGE6Z6C5OSUZPCCEL" + ), + ); + + std::println!( + "{}", + std::string::ToString::to_string(&wrong_network_address) + ); + client.handle_call_message(&wrong_network_address, &data, &sources); + + assert_eq!(token_client.balance(&ctx.withdrawer), bnusd_amount as i128) } #[test] @@ -427,7 +520,7 @@ fn test_extend_ttl() { let client = AssetManagerClient::new(&ctx.env, &ctx.registry); ctx.init_context(&client); - client.configure_rate_limit( &ctx.token, &300u128, &300u128); - + client.configure_rate_limit(&ctx.token, &300u128, &300u128); + client.extend_ttl(); -} \ No newline at end of file +} diff --git a/contracts/asset_manager/src/tests/setup.rs b/contracts/asset_manager/src/tests/setup.rs index 65db020..99241fa 100644 --- a/contracts/asset_manager/src/tests/setup.rs +++ b/contracts/asset_manager/src/tests/setup.rs @@ -1,20 +1,15 @@ #![cfg(test)] extern crate std; -use crate::contract::{ - AssetManager, AssetManagerClient -}; +use crate::contract::{AssetManager, AssetManagerClient}; use crate::config::ConfigData; use soroban_sdk::Vec; -use soroban_sdk::{ - testutils::Address as _, - token, Address, Env, String, -}; +use soroban_sdk::{testutils::Address as _, token, Address, Env, String}; mod xcall { - soroban_sdk::contractimport!(file = "../../wasm/xcall.wasm" ); + soroban_sdk::contractimport!(file = "../../wasm/xcall.wasm"); } mod connection { @@ -22,26 +17,28 @@ mod connection { } mod xcall_manager { - soroban_sdk::contractimport!(file = "../../target/wasm32-unknown-unknown/release/xcall_manager.wasm"); + soroban_sdk::contractimport!( + file = "../../target/wasm32-unknown-unknown/release/xcall_manager.wasm" + ); } use xcall_manager::ConfigData as XcallManagerConfigData; pub struct TestContext { - pub env: Env, - pub registry:Address, - pub admin: Address, + pub env: Env, + pub registry: Address, + pub admin: Address, pub depositor: Address, pub withdrawer: Address, - pub xcall: Address, - pub xcall_manager: Address, - pub icon_asset_manager: String, + pub xcall: Address, + pub xcall_manager: Address, + pub icon_asset_manager: String, pub icon_governance: String, pub token: Address, pub centralized_connection: Address, pub nid: String, pub native_token: Address, - pub xcall_client: xcall::Client<'static> + pub xcall_client: xcall::Client<'static>, } impl TestContext { @@ -59,7 +56,7 @@ impl TestContext { admin: Address::generate(&env), depositor: Address::generate(&env), withdrawer: Address::generate(&env), - xcall: xcall.clone(), + xcall: xcall.clone(), xcall_manager: xcall_manager, icon_asset_manager: String::from_str(&env, "icon01/hxjnfh4u"), icon_governance: String::from_str(&env, "icon01/kjdnoi"), @@ -68,13 +65,18 @@ impl TestContext { nid: String::from_str(&env, "stellar"), native_token: env.register_stellar_asset_contract(token_admin.clone()), xcall_client: xcall::Client::new(&env, &xcall), - env + env, } } pub fn init_context(&self, client: &AssetManagerClient<'static>) { self.env.mock_all_auths(); - let config = ConfigData {xcall: self.xcall.clone(), xcall_manager: self.xcall_manager.clone(), native_address: self.native_token.clone(), icon_asset_manager: self.icon_asset_manager.clone()}; + let config = ConfigData { + xcall: self.xcall.clone(), + xcall_manager: self.xcall_manager.clone(), + native_address: self.native_token.clone(), + icon_asset_manager: self.icon_asset_manager.clone(), + }; client.initialize(&self.registry, &self.admin, &config); self.init_xcall_manager_context(); self.init_xcall_state(); @@ -82,13 +84,23 @@ impl TestContext { pub fn init_xcall_manager_context(&self) { let client = self::xcall_manager::Client::new(&self.env, &self.xcall_manager); - let config = XcallManagerConfigData {xcall: self.xcall.clone(), icon_governance: self.icon_governance.clone()}; + let config = XcallManagerConfigData { + xcall: self.xcall.clone(), + icon_governance: self.icon_governance.clone(), + }; let sources = Vec::from_array(&self.env, [self.centralized_connection.to_string()]); - let destinations = Vec::from_array(&self.env, [String::from_str(&self.env, "icon/address")]); - client.initialize(&self.xcall_manager, &self.admin, &config, &sources, &destinations); + let destinations = + Vec::from_array(&self.env, [String::from_str(&self.env, "icon/address")]); + client.initialize( + &self.xcall_manager, + &self.admin, + &config, + &sources, + &destinations, + ); } - pub fn init_xcall_state(&self){ + pub fn init_xcall_state(&self) { self.xcall_client.initialize(&xcall::InitializeMsg { sender: self.admin.clone(), network_id: self.nid.clone(), @@ -97,7 +109,8 @@ impl TestContext { self.init_connection_state(); self.xcall_client.set_protocol_fee(&100); - self.xcall_client.set_default_connection(&self.nid, &self.centralized_connection); + self.xcall_client + .set_default_connection(&self.nid, &self.centralized_connection); } pub fn init_connection_state(&self) { @@ -114,7 +127,7 @@ impl TestContext { let response_fee = 100; connection_client.set_fee(&self.nid, &message_fee, &response_fee); } - + pub fn mint_native_token(&self, address: &Address, amount: u128) { let native_token_client = token::StellarAssetClient::new(&self.env, &self.native_token); native_token_client.mint(&address, &(*&amount as i128)); diff --git a/contracts/balanced_doller/src/allowance.rs b/contracts/balanced_doller/src/allowance.rs index 603ff09..ad74687 100644 --- a/contracts/balanced_doller/src/allowance.rs +++ b/contracts/balanced_doller/src/allowance.rs @@ -60,4 +60,4 @@ pub fn spend_allowance(e: &Env, from: Address, spender: Address, amount: i128) { allowance.amount - amount, allowance.expiration_ledger, ); -} \ No newline at end of file +} diff --git a/contracts/balanced_doller/src/balanced_dollar.rs b/contracts/balanced_doller/src/balanced_dollar.rs index 9a6a118..e2135bb 100644 --- a/contracts/balanced_doller/src/balanced_dollar.rs +++ b/contracts/balanced_doller/src/balanced_dollar.rs @@ -1,23 +1,26 @@ -use soroban_sdk::{Address, Bytes, Env, String, Vec, xdr::ToXdr}; -use crate::balance::{spend_balance, receive_balance}; +use crate::balance::{receive_balance, spend_balance}; +use soroban_sdk::{xdr::ToXdr, Address, Bytes, Env, String, Vec}; mod xcall { soroban_sdk::contractimport!(file = "../../wasm/xcall.wasm"); } -use soroban_rlp::messages::{cross_transfer::CrossTransfer, cross_transfer_revert::CrossTransferRevert}; +use crate::contract; +use crate::errors::ContractError; use crate::states::read_administrator; use crate::{ - config::{ get_config, set_config, ConfigData}, xcall_manager_interface::XcallManagerClient + config::{get_config, set_config, ConfigData}, + xcall_manager_interface::XcallManagerClient, }; use soroban_rlp::address_utils::is_valid_bytes_address; -use crate::errors::ContractError; -use xcall::{AnyMessage, CallMessageWithRollback, Client, Envelope}; +use soroban_rlp::messages::{ + cross_transfer::CrossTransfer, cross_transfer_revert::CrossTransferRevert, +}; use soroban_token_sdk::TokenUtils; -use crate::contract; +use xcall::{AnyMessage, CallMessageWithRollback, Client, Envelope}; const CROSS_TRANSFER: &str = "xCrossTransfer"; const CROSS_TRANSFER_REVERT: &str = "xCrossTransferRevert"; - -pub fn configure(env:Env, config: ConfigData){ + +pub fn configure(env: Env, config: ConfigData) { set_config(&env, config); } @@ -26,54 +29,53 @@ pub fn _cross_transfer( from: Address, amount: u128, to: String, - data: Bytes + data: Bytes, ) -> Result<(), ContractError> { _burn(&e, from.clone(), amount as i128); - let xcall_message = CrossTransfer::new( - from.clone().to_string(), - to, - amount, - data - ); - - let rollback = CrossTransferRevert::new( - from.clone(), - amount - ); + let xcall_message = CrossTransfer::new(from.clone().to_string(), to, amount, data); + + let rollback = CrossTransferRevert::new(from.clone(), amount); let config = get_config(&e); let icon_bn_usd = config.icon_bn_usd; let rollback_bytes = rollback.encode(&e, String::from_str(&e, CROSS_TRANSFER_REVERT)); let message_bytes = xcall_message.encode(&e, String::from_str(&e, CROSS_TRANSFER)); - - let (sources, destinations) = xcall_manager_client(&e, &config.xcall_manager).get_protocols(); - let message = AnyMessage::CallMessageWithRollback(CallMessageWithRollback { data: message_bytes, rollback: rollback_bytes }); + let (sources, destinations) = xcall_manager_client(&e, &config.xcall_manager).get_protocols(); + + let message = AnyMessage::CallMessageWithRollback(CallMessageWithRollback { + data: message_bytes, + rollback: rollback_bytes, + }); let envelope: &Envelope = &Envelope { message, sources, - destinations + destinations, }; - + let current_address = e.current_contract_address(); - xcall_client(&e, &config.xcall).send_call(&from, ¤t_address, envelope, &icon_bn_usd ); + xcall_client(&e, &config.xcall).send_call(&from, ¤t_address, envelope, &icon_bn_usd); Ok(()) } -fn verify_protocol(e: &Env, xcall_manager: &Address, protocols: Vec) -> Result<(), ContractError> { +fn verify_protocol( + e: &Env, + xcall_manager: &Address, + protocols: Vec, +) -> Result<(), ContractError> { let verified: bool = xcall_manager_client(e, xcall_manager).verify_protocols(&protocols); if !verified { - return Err(ContractError::ProtocolMismatch) + return Err(ContractError::ProtocolMismatch); } Ok(()) } pub fn _handle_call_message( e: Env, - xcall_address : Address, + xcall_address: Address, from: String, data: Bytes, - protocols: Vec + protocols: Vec, ) -> Result<(), ContractError> { let config: ConfigData = get_config(&e); let xcall = config.xcall; @@ -81,31 +83,31 @@ pub fn _handle_call_message( let method = CrossTransfer::get_method(&e, data.clone()); let icon_bn_usd: String = config.icon_bn_usd; - if method == String::from_str(&e, &CROSS_TRANSFER){ - if from!=icon_bn_usd { - return Err(ContractError::OnlyIconBnUSD); + if method == String::from_str(&e, &CROSS_TRANSFER) { + if from != icon_bn_usd { + return Err(ContractError::OnlyIconBnUSD); } let message = CrossTransfer::decode(&e, data); let to_network_address: Address = get_address(message.to, &e)?; - _mint(&e, to_network_address, message.amount as i128 ); - } else if method == String::from_str(&e, &CROSS_TRANSFER_REVERT){ - if xcall!=xcall_address { - return Err(ContractError::OnlyCallService) + _mint(&e, to_network_address, message.amount as i128); + } else if method == String::from_str(&e, &CROSS_TRANSFER_REVERT) { + if xcall != xcall_address { + return Err(ContractError::OnlyCallService); } let message = CrossTransferRevert::decode(&e, data); _mint(&e, message.to, message.amount as i128); - }else{ - return Err(ContractError::UnknownMessageType) + } else { + return Err(ContractError::UnknownMessageType); } verify_protocol(&e, &config.xcall_manager, protocols)?; Ok(()) } -pub fn get_address(network_address: String, env: &Env) -> Result { +pub fn get_address(network_address: String, env: &Env) -> Result { let bytes = network_address.to_xdr(&env); if bytes.get(6).unwrap() > 0 { - return Err(ContractError::InvalidNetworkAddressLength); + return Err(ContractError::InvalidNetworkAddressLength); } let value_len = bytes.get(7).unwrap(); @@ -139,7 +141,7 @@ pub fn _mint(e: &Env, to: Address, amount: i128) { contract::check_nonnegative_amount(amount); let admin: Address = read_administrator(&e); - receive_balance(e , to.clone(), amount); + receive_balance(e, to.clone(), amount); TokenUtils::new(e).events().mint(admin, to, amount); } @@ -150,12 +152,11 @@ pub fn _burn(e: &Env, from: Address, amount: i128) { TokenUtils::new(e).events().burn(from, amount); } - fn xcall_client(e: &Env, xcall: &Address) -> Client<'static> { return xcall::Client::new(e, xcall); } -fn xcall_manager_client(e: &Env, xcall_manager: &Address ) -> XcallManagerClient<'static> { +fn xcall_manager_client(e: &Env, xcall_manager: &Address) -> XcallManagerClient<'static> { let client = XcallManagerClient::new(e, xcall_manager); return client; } diff --git a/contracts/balanced_doller/src/config.rs b/contracts/balanced_doller/src/config.rs index 9d9c36e..8c0b0b0 100644 --- a/contracts/balanced_doller/src/config.rs +++ b/contracts/balanced_doller/src/config.rs @@ -1,5 +1,5 @@ -use soroban_sdk::{contracttype, unwrap::UnwrapOptimized, Env, String, Address}; use crate::storage_types::DataKey; +use soroban_sdk::{contracttype, unwrap::UnwrapOptimized, Address, Env, String}; #[derive(Clone)] #[contracttype] @@ -10,16 +10,11 @@ pub struct ConfigData { pub icon_bn_usd: String, } -pub fn set_config(e: &Env, config: ConfigData){ +pub fn set_config(e: &Env, config: ConfigData) { e.storage().instance().set(&DataKey::Config, &config); } pub fn get_config(e: &Env) -> ConfigData { let key = DataKey::Config; - e - .storage() - .instance() - .get(&key) - .unwrap_optimized() + e.storage().instance().get(&key).unwrap_optimized() } - diff --git a/contracts/balanced_doller/src/contract.rs b/contracts/balanced_doller/src/contract.rs index 9d1547a..bafd90a 100644 --- a/contracts/balanced_doller/src/contract.rs +++ b/contracts/balanced_doller/src/contract.rs @@ -2,16 +2,16 @@ //! interface. use crate::allowance::{read_allowance, spend_allowance, write_allowance}; use crate::balance::{read_balance, receive_balance, spend_balance}; +use crate::balanced_dollar; use crate::config::ConfigData; +use crate::errors::ContractError; use crate::metadata::{read_decimal, read_name, read_symbol, write_metadata}; -use crate::storage_types::{INSTANCE_BUMP_AMOUNT, INSTANCE_LIFETIME_THRESHOLD}; -use crate::states::{has_administrator, read_administrator, write_administrator }; +use crate::states::{has_administrator, read_administrator, write_administrator}; +use crate::storage_types::{DataKey, INSTANCE_BUMP_AMOUNT, INSTANCE_LIFETIME_THRESHOLD}; use soroban_sdk::token::{self, Interface as _}; -use soroban_sdk::{contract, contractimpl, panic_with_error, Address, Bytes, Env, String, Vec}; +use soroban_sdk::{contract, contractimpl, panic_with_error, Address, Bytes, BytesN, Env, String, Vec}; use soroban_token_sdk::metadata::TokenMetadata; use soroban_token_sdk::TokenUtils; -use crate::balanced_dollar; -use crate::errors::ContractError; pub fn check_nonnegative_amount(amount: i128) { if amount < 0 { panic!("negative amount is not allowed: {}", amount) @@ -28,7 +28,7 @@ impl BalancedDollar { panic_with_error!(e, ContractError::ContractAlreadyInitialized) } write_administrator(&e, &admin); - + //initialize token properties let decimal = 18; let name = String::from_str(&e, "Balanced Dollar"); @@ -46,13 +46,13 @@ impl BalancedDollar { symbol, }, ); - balanced_dollar::configure(e, config ); + balanced_dollar::configure(e, config); } pub fn mint(e: Env, to: Address, amount: i128) { let admin = read_administrator(&e); admin.require_auth(); - + balanced_dollar::_mint(&e, to, amount) } @@ -73,7 +73,7 @@ impl BalancedDollar { from: Address, amount: u128, to: String, - ) -> Result<(), ContractError> { + ) -> Result<(), ContractError> { from.require_auth(); return balanced_dollar::_cross_transfer(e.clone(), from, amount, to, Bytes::new(&e)); } @@ -83,8 +83,8 @@ impl BalancedDollar { from: Address, amount: u128, to: String, - data: Bytes - ) -> Result<(), ContractError> { + data: Bytes, + ) -> Result<(), ContractError> { from.require_auth(); return balanced_dollar::_cross_transfer(e, from, amount, to, data); } @@ -94,8 +94,8 @@ impl BalancedDollar { xcall: Address, from: String, data: Bytes, - protocols: Vec - ) -> Result<(), ContractError> { + protocols: Vec, + ) -> Result<(), ContractError> { return balanced_dollar::_handle_call_message(e, xcall, from, data, protocols); } @@ -103,7 +103,14 @@ impl BalancedDollar { has_administrator(&e) } - pub fn extend_ttl(e: Env){ + pub fn upgrade(e: Env, new_wasm_hash: BytesN<32>) { + let admin: Address = e.storage().instance().get(&DataKey::Admin).unwrap(); + admin.require_auth(); + + e.deployer().update_current_contract_wasm(new_wasm_hash); + } + + pub fn extend_ttl(e: Env) { e.storage() .instance() .extend_ttl(INSTANCE_LIFETIME_THRESHOLD, INSTANCE_BUMP_AMOUNT); @@ -176,7 +183,5 @@ impl token::Interface for BalancedDollar { fn symbol(e: Env) -> String { read_symbol(&e) } +} - - -} \ No newline at end of file diff --git a/contracts/balanced_doller/src/errors.rs b/contracts/balanced_doller/src/errors.rs index 76dcfc2..a1cc30b 100644 --- a/contracts/balanced_doller/src/errors.rs +++ b/contracts/balanced_doller/src/errors.rs @@ -13,5 +13,5 @@ pub enum ContractError { UnknownMessageType = 7, InvalidAddress = 8, InvalidNetworkAddressLength = 9, - InvalidNetworkAddress = 10 -} \ No newline at end of file + InvalidNetworkAddress = 10, +} diff --git a/contracts/balanced_doller/src/lib.rs b/contracts/balanced_doller/src/lib.rs index 14df839..7948e23 100644 --- a/contracts/balanced_doller/src/lib.rs +++ b/contracts/balanced_doller/src/lib.rs @@ -2,12 +2,12 @@ mod allowance; mod balance; +pub mod balanced_dollar; +mod config; pub mod contract; +mod errors; mod metadata; -mod storage_types; mod states; +mod storage_types; mod tests; -mod config; -pub mod balanced_dollar; -mod errors; -mod xcall_manager_interface; \ No newline at end of file +mod xcall_manager_interface; diff --git a/contracts/balanced_doller/src/metadata.rs b/contracts/balanced_doller/src/metadata.rs index 7977778..715feee 100644 --- a/contracts/balanced_doller/src/metadata.rs +++ b/contracts/balanced_doller/src/metadata.rs @@ -19,4 +19,4 @@ pub fn read_symbol(e: &Env) -> String { pub fn write_metadata(e: &Env, metadata: TokenMetadata) { let util = TokenUtils::new(e); util.metadata().set_metadata(&metadata); -} \ No newline at end of file +} diff --git a/contracts/balanced_doller/src/states.rs b/contracts/balanced_doller/src/states.rs index 2900b2f..a820bf0 100644 --- a/contracts/balanced_doller/src/states.rs +++ b/contracts/balanced_doller/src/states.rs @@ -16,4 +16,3 @@ pub fn write_administrator(e: &Env, id: &Address) { let key = DataKey::Admin; e.storage().instance().set(&key, id); } - diff --git a/contracts/balanced_doller/src/storage_types.rs b/contracts/balanced_doller/src/storage_types.rs index f47e2b2..069bbab 100644 --- a/contracts/balanced_doller/src/storage_types.rs +++ b/contracts/balanced_doller/src/storage_types.rs @@ -26,5 +26,5 @@ pub enum DataKey { Allowance(AllowanceDataKey), Balance(Address), Admin, - Config -} \ No newline at end of file + Config, +} diff --git a/contracts/balanced_doller/src/test.rs b/contracts/balanced_doller/src/test.rs index 108f22f..77e6a47 100644 --- a/contracts/balanced_doller/src/test.rs +++ b/contracts/balanced_doller/src/test.rs @@ -3,19 +3,28 @@ extern crate std; use crate::{contract::BalancedDollar, BalancedDollarClient}; use soroban_sdk::{ - symbol_short, testutils::{Address as _, AuthorizedFunction, AuthorizedInvocation}, Address, Env, IntoVal, String, Symbol + symbol_short, + testutils::{Address as _, AuthorizedFunction, AuthorizedInvocation}, + Address, Env, IntoVal, String, Symbol, }; fn create_token<'a>(e: &Env, admin: &Address) -> BalancedDollarClient<'a> { let token = BalancedDollarClient::new(e, &e.register_contract(None, BalancedDollar {})); let xcall = Address::generate(&e.clone()); - let xcall_manager = Address::generate(&e.clone()); + let xcall_manager = Address::generate(&e.clone()); let xcall_network_address = String::from_str(&e.clone(), "ste/address"); let icon_bn_usd = String::from_str(&e.clone(), "icon/hxeoriweo"); let nid = String::from_str(&e.clone(), "ste"); - token.initialize(&admin, &xcall, &xcall_manager, &xcall_network_address, &icon_bn_usd, &nid); + token.initialize( + &admin, + &xcall, + &xcall_manager, + &xcall_network_address, + &icon_bn_usd, + &nid, + ); token } @@ -244,12 +253,26 @@ fn initialize_already_initialized() { let token = create_token(&e, &admin); let xcall = Address::generate(&e.clone()); - let xcall_manager = Address::generate(&e.clone()); + let xcall_manager = Address::generate(&e.clone()); let xcall_network_address = String::from_str(&e.clone(), "ste/address"); let icon_bn_usd = String::from_str(&e.clone(), "icon/hxeoriweo"); let nid = String::from_str(&e.clone(), "ste"); - token.initialize(&admin, &xcall, &xcall_manager, &xcall_network_address, &icon_bn_usd, &nid); + token.initialize( + &admin, + &xcall, + &xcall_manager, + &xcall_network_address, + &icon_bn_usd, + &nid, + ); - token.initialize(&admin, &xcall, &xcall_manager, &xcall_network_address, &icon_bn_usd, &nid); -} \ No newline at end of file + token.initialize( + &admin, + &xcall, + &xcall_manager, + &xcall_network_address, + &icon_bn_usd, + &nid, + ); +} diff --git a/contracts/balanced_doller/src/tests/balanced_dollar_test.rs b/contracts/balanced_doller/src/tests/balanced_dollar_test.rs index 06b1291..a5185ff 100644 --- a/contracts/balanced_doller/src/tests/balanced_dollar_test.rs +++ b/contracts/balanced_doller/src/tests/balanced_dollar_test.rs @@ -3,11 +3,15 @@ extern crate std; use crate::contract::BalancedDollarClient; -use soroban_rlp::messages::{cross_transfer::CrossTransfer, cross_transfer_revert::CrossTransferRevert}; +use super::setup::*; +use soroban_rlp::messages::{ + cross_transfer::CrossTransfer, cross_transfer_revert::CrossTransferRevert, +}; use soroban_sdk::{ - symbol_short, testutils::{Address as _, AuthorizedFunction, AuthorizedInvocation}, Address, Bytes, IntoVal, String, Vec + symbol_short, + testutils::{Address as _, AuthorizedFunction, AuthorizedInvocation}, + Address, Bytes, IntoVal, String, Vec, }; -use super::setup::*; #[test] fn test_initialize() { @@ -18,7 +22,6 @@ fn test_initialize() { let initialized = client.is_initialized(); assert_eq!(initialized, true) - } #[test] @@ -26,107 +29,126 @@ fn test_set_admin() { let ctx = TestContext::default(); let client = BalancedDollarClient::new(&ctx.env, &ctx.registry); ctx.init_context(&client); - + let new_admin: Address = Address::generate(&ctx.env); client.set_admin(&new_admin); assert_eq!( ctx.env.auths(), - std::vec![ - ( - ctx.admin.clone(), - AuthorizedInvocation { - function: AuthorizedFunction::Contract(( - ctx.registry.clone(), - symbol_short!("set_admin"), - (&new_admin,) - .into_val(&ctx.env) - )), - sub_invocations: std::vec![] - } - ) - ] + std::vec![( + ctx.admin.clone(), + AuthorizedInvocation { + function: AuthorizedFunction::Contract(( + ctx.registry.clone(), + symbol_short!("set_admin"), + (&new_admin,).into_val(&ctx.env) + )), + sub_invocations: std::vec![] + } + )] ); assert_eq!(client.get_admin(), new_admin); } #[test] -fn test_cross_transfer_with_to_and_data(){ +fn test_cross_transfer_with_to_and_data() { let ctx = TestContext::default(); let client = BalancedDollarClient::new(&ctx.env, &ctx.registry); ctx.init_context(&client); - let amount_i128: i128 = 100000i128 ; + let amount_i128: i128 = 100000i128; let amount = &(amount_i128 as u128); - let mint_amount = &(amount_i128+amount_i128); - + let mint_amount = &(amount_i128 + amount_i128); + client.mint(&ctx.depositor, mint_amount); ctx.mint_native_token(&ctx.depositor, 500u128); assert_eq!(ctx.get_native_token_balance(&ctx.depositor), 500u128); - client.approve(&ctx.depositor, &ctx.registry, &(amount_i128+amount_i128), &1312000); + client.approve( + &ctx.depositor, + &ctx.registry, + &(amount_i128 + amount_i128), + &1312000, + ); let data: [u8; 32] = [ - 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, - 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0x10, - 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, - 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F, 0x20, + 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, + 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, + 0x1F, 0x20, ]; - client.cross_transfer_data(&ctx.depositor, &amount, &String::from_str(&ctx.env, "icon01/hxjkdvhui"), &Bytes::from_array(&ctx.env, &data)); + client.cross_transfer_data( + &ctx.depositor, + &amount, + &String::from_str(&ctx.env, "icon01/hxjkdvhui"), + &Bytes::from_array(&ctx.env, &data), + ); std::println!("call"); assert_eq!(ctx.get_native_token_balance(&ctx.depositor), 400u128) // why 300? } - #[test] -fn test_handle_call_message_for_cross_transfer(){ +fn test_handle_call_message_for_cross_transfer() { let ctx = TestContext::default(); let client = BalancedDollarClient::new(&ctx.env, &ctx.registry); ctx.env.mock_all_auths(); ctx.init_context(&client); - + let bnusd_amount = 100000u128; let items: [u8; 32] = [ - 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, - 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0x10, - 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, - 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F, 0x20, + 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, + 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, + 0x1F, 0x20, ]; - let withdrawer = String::from_str(&ctx.env, "stellar/CA36FQITV33RO5SJFPTNLRQBD6ZNAEJG7F7J5KWCV4OP7SQHDMIZCT33"); - let data = CrossTransfer::new(ctx.depositor.to_string(), withdrawer.clone(), bnusd_amount, Bytes::from_array(&ctx.env, &items)).encode(&ctx.env, String::from_str(&ctx.env, "xCrossTransfer")); + let withdrawer = String::from_str( + &ctx.env, + "stellar/CA36FQITV33RO5SJFPTNLRQBD6ZNAEJG7F7J5KWCV4OP7SQHDMIZCT33", + ); + let data = CrossTransfer::new( + ctx.depositor.to_string(), + withdrawer.clone(), + bnusd_amount, + Bytes::from_array(&ctx.env, &items), + ) + .encode(&ctx.env, String::from_str(&ctx.env, "xCrossTransfer")); let decoded = CrossTransfer::decode(&ctx.env, data.clone()); assert_eq!(decoded.to, withdrawer); - let withdrawer_address = &Address::from_string(&String::from_str(&ctx.env, "CA36FQITV33RO5SJFPTNLRQBD6ZNAEJG7F7J5KWCV4OP7SQHDMIZCT33")); + let withdrawer_address = &Address::from_string(&String::from_str( + &ctx.env, + "CA36FQITV33RO5SJFPTNLRQBD6ZNAEJG7F7J5KWCV4OP7SQHDMIZCT33", + )); assert_eq!(client.balance(withdrawer_address), 0); let sources = Vec::from_array(&ctx.env, [ctx.centralized_connection.to_string()]); client.handle_call_message(&ctx.xcall, &ctx.icon_bn_usd, &data, &sources); - assert_eq!(client.balance(withdrawer_address), bnusd_amount as i128) - - + assert_eq!(client.balance(withdrawer_address), bnusd_amount as i128) } #[test] #[should_panic(expected = "HostError: Error(Contract, #8)")] -fn test_handle_call_message_for_cross_transfer_invalid_addres_fail(){ +fn test_handle_call_message_for_cross_transfer_invalid_addres_fail() { let ctx = TestContext::default(); let client = BalancedDollarClient::new(&ctx.env, &ctx.registry); ctx.env.mock_all_auths(); ctx.init_context(&client); - + let bnusd_amount = 100000u128; let items: [u8; 32] = [ - 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, - 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0x10, - 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, - 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F, 0x20, + 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, + 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, + 0x1F, 0x20, ]; let withdrawer = String::from_str(&ctx.env, "stellar/InvalidAddress"); - let data = CrossTransfer::new(ctx.depositor.to_string(), withdrawer.clone(), bnusd_amount, Bytes::from_array(&ctx.env, &items)).encode(&ctx.env, String::from_str(&ctx.env, "xCrossTransfer")); + let data = CrossTransfer::new( + ctx.depositor.to_string(), + withdrawer.clone(), + bnusd_amount, + Bytes::from_array(&ctx.env, &items), + ) + .encode(&ctx.env, String::from_str(&ctx.env, "xCrossTransfer")); let decoded = CrossTransfer::decode(&ctx.env, data.clone()); assert_eq!(decoded.to, withdrawer); @@ -135,152 +157,195 @@ fn test_handle_call_message_for_cross_transfer_invalid_addres_fail(){ let sources = Vec::from_array(&ctx.env, [ctx.centralized_connection.to_string()]); client.handle_call_message(&ctx.xcall, &ctx.icon_bn_usd, &data, &sources); - // assert_eq!(client.balance(withdrawer_address), bnusd_amount as i128) - - + // assert_eq!(client.balance(withdrawer_address), bnusd_amount as i128) } #[test] #[should_panic(expected = "HostError: Error(Contract, #4)")] -fn test_handle_call_message_for_cross_transfer_panic_for_protocol_mismatch(){ +fn test_handle_call_message_for_cross_transfer_panic_for_protocol_mismatch() { let ctx = TestContext::default(); let client = BalancedDollarClient::new(&ctx.env, &ctx.registry); ctx.env.mock_all_auths(); ctx.init_context(&client); - + let bnusd_amount = 100000u128; let items: [u8; 32] = [ - 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, - 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0x10, - 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, - 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F, 0x20, + 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, + 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, + 0x1F, 0x20, ]; - let withdrawer = String::from_str(&ctx.env, "stellar/CA36FQITV33RO5SJFPTNLRQBD6ZNAEJG7F7J5KWCV4OP7SQHDMIZCT33"); - let data = CrossTransfer::new(ctx.depositor.to_string(), withdrawer.clone(), bnusd_amount, Bytes::from_array(&ctx.env, &items)).encode(&ctx.env, String::from_str(&ctx.env, "xCrossTransfer")); + let withdrawer = String::from_str( + &ctx.env, + "stellar/CA36FQITV33RO5SJFPTNLRQBD6ZNAEJG7F7J5KWCV4OP7SQHDMIZCT33", + ); + let data = CrossTransfer::new( + ctx.depositor.to_string(), + withdrawer.clone(), + bnusd_amount, + Bytes::from_array(&ctx.env, &items), + ) + .encode(&ctx.env, String::from_str(&ctx.env, "xCrossTransfer")); let decoded = CrossTransfer::decode(&ctx.env, data.clone()); assert_eq!(decoded.to, withdrawer); - let withdrawer_address = &Address::from_string(&String::from_str(&ctx.env, "CA36FQITV33RO5SJFPTNLRQBD6ZNAEJG7F7J5KWCV4OP7SQHDMIZCT33")); + let withdrawer_address = &Address::from_string(&String::from_str( + &ctx.env, + "CA36FQITV33RO5SJFPTNLRQBD6ZNAEJG7F7J5KWCV4OP7SQHDMIZCT33", + )); assert_eq!(client.balance(withdrawer_address), 0); let sources = Vec::from_array(&ctx.env, [ctx.xcall.to_string()]); - client.handle_call_message(&ctx.xcall, &ctx.icon_bn_usd, &data, &sources); - - assert_eq!(client.balance(withdrawer_address), bnusd_amount as i128) + client.handle_call_message(&ctx.xcall, &ctx.icon_bn_usd, &data, &sources); + + assert_eq!(client.balance(withdrawer_address), bnusd_amount as i128) } #[test] #[should_panic(expected = "HostError: Error(Contract, #5)")] -fn test_handle_call_message_for_cross_transfer_panic_for_icon_bnusd(){ +fn test_handle_call_message_for_cross_transfer_panic_for_icon_bnusd() { let ctx = TestContext::default(); let client = BalancedDollarClient::new(&ctx.env, &ctx.registry); ctx.env.mock_all_auths(); ctx.init_context(&client); - + let bnusd_amount = 100000u128; let items: [u8; 32] = [ - 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, - 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0x10, - 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, - 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F, 0x20, + 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, + 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, + 0x1F, 0x20, ]; - let withdrawer = String::from_str(&ctx.env, "stellar/CA36FQITV33RO5SJFPTNLRQBD6ZNAEJG7F7J5KWCV4OP7SQHDMIZCT33"); - let data = CrossTransfer::new(ctx.depositor.to_string(), withdrawer.clone(), bnusd_amount, Bytes::from_array(&ctx.env, &items)).encode(&ctx.env, String::from_str(&ctx.env, "xCrossTransfer")); + let withdrawer = String::from_str( + &ctx.env, + "stellar/CA36FQITV33RO5SJFPTNLRQBD6ZNAEJG7F7J5KWCV4OP7SQHDMIZCT33", + ); + let data = CrossTransfer::new( + ctx.depositor.to_string(), + withdrawer.clone(), + bnusd_amount, + Bytes::from_array(&ctx.env, &items), + ) + .encode(&ctx.env, String::from_str(&ctx.env, "xCrossTransfer")); let decoded = CrossTransfer::decode(&ctx.env, data.clone()); assert_eq!(decoded.to, withdrawer); - let withdrawer_address = &Address::from_string(&String::from_str(&ctx.env, "CA36FQITV33RO5SJFPTNLRQBD6ZNAEJG7F7J5KWCV4OP7SQHDMIZCT33")); + let withdrawer_address = &Address::from_string(&String::from_str( + &ctx.env, + "CA36FQITV33RO5SJFPTNLRQBD6ZNAEJG7F7J5KWCV4OP7SQHDMIZCT33", + )); assert_eq!(client.balance(withdrawer_address), 0); let sources = Vec::from_array(&ctx.env, [ctx.centralized_connection.to_string()]); - client.handle_call_message(&ctx.xcall, &ctx.icon_governance, &data, &sources); - - assert_eq!(client.balance(withdrawer_address), bnusd_amount as i128) + client.handle_call_message(&ctx.xcall, &ctx.icon_governance, &data, &sources); + + assert_eq!(client.balance(withdrawer_address), bnusd_amount as i128) } #[test] #[should_panic(expected = "HostError: Error(Contract, #7)")] -fn test_handle_call_message_for_cross_transfer_panic_for_wront_message_type(){ +fn test_handle_call_message_for_cross_transfer_panic_for_wront_message_type() { let ctx = TestContext::default(); let client = BalancedDollarClient::new(&ctx.env, &ctx.registry); ctx.env.mock_all_auths(); ctx.init_context(&client); - + let bnusd_amount = 100000u128; let items: [u8; 32] = [ - 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, - 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0x10, - 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, - 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F, 0x20, + 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, + 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, + 0x1F, 0x20, ]; - let withdrawer = String::from_str(&ctx.env, "stellar/CA36FQITV33RO5SJFPTNLRQBD6ZNAEJG7F7J5KWCV4OP7SQHDMIZCT33"); - let data = CrossTransfer::new(ctx.depositor.to_string(), withdrawer.clone(), bnusd_amount, Bytes::from_array(&ctx.env, &items)).encode(&ctx.env, String::from_str(&ctx.env, "xCrossTransferPanic")); - + let withdrawer = String::from_str( + &ctx.env, + "stellar/CA36FQITV33RO5SJFPTNLRQBD6ZNAEJG7F7J5KWCV4OP7SQHDMIZCT33", + ); + let data = CrossTransfer::new( + ctx.depositor.to_string(), + withdrawer.clone(), + bnusd_amount, + Bytes::from_array(&ctx.env, &items), + ) + .encode(&ctx.env, String::from_str(&ctx.env, "xCrossTransferPanic")); + let decoded: CrossTransfer = CrossTransfer::decode(&ctx.env, data.clone()); - let withdrawer_address = &Address::from_string(&String::from_str(&ctx.env, "CA36FQITV33RO5SJFPTNLRQBD6ZNAEJG7F7J5KWCV4OP7SQHDMIZCT33")); + let withdrawer_address = &Address::from_string(&String::from_str( + &ctx.env, + "CA36FQITV33RO5SJFPTNLRQBD6ZNAEJG7F7J5KWCV4OP7SQHDMIZCT33", + )); assert_eq!(decoded.to, withdrawer); assert_eq!(client.balance(withdrawer_address), 0); let sources = Vec::from_array(&ctx.env, [ctx.centralized_connection.to_string()]); - client.handle_call_message( &ctx.xcall, &ctx.icon_bn_usd, &data, &sources); - - assert_eq!(client.balance(withdrawer_address), bnusd_amount as i128) + client.handle_call_message(&ctx.xcall, &ctx.icon_bn_usd, &data, &sources); + + assert_eq!(client.balance(withdrawer_address), bnusd_amount as i128) } #[test] -fn test_handle_call_message_for_cross_transfer_revert(){ +fn test_handle_call_message_for_cross_transfer_revert() { let ctx = TestContext::default(); let client = BalancedDollarClient::new(&ctx.env, &ctx.registry); ctx.env.mock_all_auths(); ctx.init_context(&client); - + let bnusd_amount = 100000u128; - let data = CrossTransferRevert::new( ctx.withdrawer.clone(), bnusd_amount).encode(&ctx.env, String::from_str(&ctx.env, "xCrossTransferRevert")); + let data = CrossTransferRevert::new(ctx.withdrawer.clone(), bnusd_amount) + .encode(&ctx.env, String::from_str(&ctx.env, "xCrossTransferRevert")); let decoded = CrossTransferRevert::decode(&ctx.env, data.clone()); assert_eq!(decoded.to, ctx.withdrawer); assert_eq!(client.balance(&ctx.withdrawer), 0); let sources = Vec::from_array(&ctx.env, [ctx.centralized_connection.to_string()]); - client.handle_call_message(&ctx.xcall, &ctx.xcall_client.get_network_address(), &data, &sources); - - assert_eq!(client.balance(&ctx.withdrawer), bnusd_amount as i128) + client.handle_call_message( + &ctx.xcall, + &ctx.xcall_client.get_network_address(), + &data, + &sources, + ); + + assert_eq!(client.balance(&ctx.withdrawer), bnusd_amount as i128) } #[test] #[should_panic(expected = "HostError: Error(Contract, #6)")] -fn test_handle_call_message_for_cross_transfer_revert_panic_for_xcall(){ +fn test_handle_call_message_for_cross_transfer_revert_panic_for_xcall() { let ctx = TestContext::default(); let client = BalancedDollarClient::new(&ctx.env, &ctx.registry); ctx.env.mock_all_auths(); ctx.init_context(&client); - + let bnusd_amount = 100000u128; - let data = CrossTransferRevert::new( ctx.withdrawer.clone(), bnusd_amount).encode(&ctx.env, String::from_str(&ctx.env, "xCrossTransferRevert")); + let data = CrossTransferRevert::new(ctx.withdrawer.clone(), bnusd_amount) + .encode(&ctx.env, String::from_str(&ctx.env, "xCrossTransferRevert")); let decoded = CrossTransferRevert::decode(&ctx.env, data.clone()); assert_eq!(decoded.to, ctx.withdrawer); assert_eq!(client.balance(&ctx.withdrawer), 0); let sources = Vec::from_array(&ctx.env, [ctx.centralized_connection.to_string()]); - client.handle_call_message( &ctx.centralized_connection, &ctx.xcall_client.get_network_address(), &data, &sources); - - assert_eq!(client.balance(&ctx.withdrawer), bnusd_amount as i128) + client.handle_call_message( + &ctx.centralized_connection, + &ctx.xcall_client.get_network_address(), + &data, + &sources, + ); + + assert_eq!(client.balance(&ctx.withdrawer), bnusd_amount as i128) } #[test] -fn test_extend_ttl(){ +fn test_extend_ttl() { let ctx = TestContext::default(); let client = BalancedDollarClient::new(&ctx.env, &ctx.registry); ctx.env.mock_all_auths(); @@ -288,4 +353,4 @@ fn test_extend_ttl(){ ctx.init_context(&client); client.extend_ttl() -} \ No newline at end of file +} diff --git a/contracts/balanced_doller/src/tests/setup.rs b/contracts/balanced_doller/src/tests/setup.rs index 1ca8452..844a54d 100644 --- a/contracts/balanced_doller/src/tests/setup.rs +++ b/contracts/balanced_doller/src/tests/setup.rs @@ -1,19 +1,14 @@ #![cfg(test)] extern crate std; -use crate::contract::{ - BalancedDollar, BalancedDollarClient -}; +use crate::contract::{BalancedDollar, BalancedDollarClient}; use crate::config::ConfigData; -use soroban_sdk::{ - testutils::Address as _, - token, Vec, Address, Env, String, -}; +use soroban_sdk::{testutils::Address as _, token, Address, Env, String, Vec}; mod xcall { - soroban_sdk::contractimport!(file = "../../wasm/xcall.wasm" ); + soroban_sdk::contractimport!(file = "../../wasm/xcall.wasm"); } mod connection { @@ -21,26 +16,28 @@ mod connection { } mod xcall_manager { - soroban_sdk::contractimport!(file = "../../target/wasm32-unknown-unknown/release/xcall_manager.wasm" ); + soroban_sdk::contractimport!( + file = "../../target/wasm32-unknown-unknown/release/xcall_manager.wasm" + ); } use xcall_manager::ConfigData as XcallManagerConfigData; pub struct TestContext { - pub env: Env, - pub registry:Address, - pub admin: Address, + pub env: Env, + pub registry: Address, + pub admin: Address, pub depositor: Address, pub withdrawer: Address, - pub xcall: Address, - pub xcall_manager: Address, - pub icon_bn_usd: String, + pub xcall: Address, + pub xcall_manager: Address, + pub icon_bn_usd: String, pub icon_governance: String, pub token: Address, pub centralized_connection: Address, pub nid: String, pub native_token: Address, - pub xcall_client: xcall::Client<'static> + pub xcall_client: xcall::Client<'static>, } impl TestContext { @@ -62,7 +59,7 @@ impl TestContext { admin: Address::generate(&env), depositor: Address::generate(&env), withdrawer: Address::generate(&env), - xcall: xcall.clone(), + xcall: xcall.clone(), xcall_manager: xcall_manager, icon_bn_usd: String::from_str(&env, "icon01/hxjnfh4u"), icon_governance: String::from_str(&env, "icon01/kjdnoi"), @@ -71,27 +68,42 @@ impl TestContext { nid: String::from_str(&env, "stellar"), native_token: env.register_stellar_asset_contract(token_admin.clone()), xcall_client: xcall::Client::new(&env, &xcall), - env + env, } } pub fn init_context(&self, client: &BalancedDollarClient<'static>) { self.env.mock_all_auths(); - let config = ConfigData {xcall: self.xcall.clone(), xcall_manager: self.xcall_manager.clone(), nid: self.nid.clone(), icon_bn_usd: self.icon_bn_usd.clone()}; - client.initialize( &self.admin, &config); + let config = ConfigData { + xcall: self.xcall.clone(), + xcall_manager: self.xcall_manager.clone(), + nid: self.nid.clone(), + icon_bn_usd: self.icon_bn_usd.clone(), + }; + client.initialize(&self.admin, &config); self.init_xcall_manager_context(); self.init_xcall_state(); } pub fn init_xcall_manager_context(&self) { let client = self::xcall_manager::Client::new(&self.env, &self.xcall_manager); - let config = XcallManagerConfigData {xcall: self.xcall.clone(), icon_governance: self.icon_governance.clone()}; + let config = XcallManagerConfigData { + xcall: self.xcall.clone(), + icon_governance: self.icon_governance.clone(), + }; let sources = Vec::from_array(&self.env, [self.centralized_connection.to_string()]); - let destinations = Vec::from_array(&self.env, [String::from_str(&self.env, "icon/address")]); - client.initialize(&self.xcall_manager, &self.admin, &config, &sources, &destinations); + let destinations = + Vec::from_array(&self.env, [String::from_str(&self.env, "icon/address")]); + client.initialize( + &self.xcall_manager, + &self.admin, + &config, + &sources, + &destinations, + ); } - pub fn init_xcall_state(&self){ + pub fn init_xcall_state(&self) { let xcall_client = xcall::Client::new(&self.env, &self.xcall); xcall_client.initialize(&xcall::InitializeMsg { @@ -119,7 +131,7 @@ impl TestContext { let response_fee = 100; connection_client.set_fee(&self.nid, &message_fee, &response_fee); } - + pub fn mint_native_token(&self, address: &Address, amount: u128) { let native_token_client = token::StellarAssetClient::new(&self.env, &self.native_token); native_token_client.mint(&address, &(*&amount as i128)); diff --git a/contracts/balanced_doller/src/xcall_manager_interface.rs b/contracts/balanced_doller/src/xcall_manager_interface.rs index 325a064..224bb14 100644 --- a/contracts/balanced_doller/src/xcall_manager_interface.rs +++ b/contracts/balanced_doller/src/xcall_manager_interface.rs @@ -4,12 +4,7 @@ use crate::errors::ContractError; #[contractclient(name = "XcallManagerClient")] pub trait IXcallManager { - - fn verify_protocols( - e: Env, - protocols: Vec - ) -> Result; + fn verify_protocols(e: Env, protocols: Vec) -> Result; fn get_protocols(e: Env) -> Result<(Vec, Vec), ContractError>; - -} \ No newline at end of file +} diff --git a/contracts/xcall_manager/src/config.rs b/contracts/xcall_manager/src/config.rs index cd1b43e..57e34bd 100644 --- a/contracts/xcall_manager/src/config.rs +++ b/contracts/xcall_manager/src/config.rs @@ -1,5 +1,5 @@ -use soroban_sdk::{contracttype, unwrap::UnwrapOptimized, Env, String, Address}; use crate::storage_types::DataKey; +use soroban_sdk::{contracttype, unwrap::UnwrapOptimized, Address, Env, String}; #[derive(Clone)] #[contracttype] @@ -8,16 +8,11 @@ pub struct ConfigData { pub icon_governance: String, } -pub fn set_config(e: &Env, config: ConfigData){ +pub fn set_config(e: &Env, config: ConfigData) { e.storage().instance().set(&DataKey::Config, &config); } pub fn get_config(e: &Env) -> ConfigData { let key = DataKey::Config; - e - .storage() - .instance() - .get(&key) - .unwrap_optimized() + e.storage().instance().get(&key).unwrap_optimized() } - diff --git a/contracts/xcall_manager/src/contract.rs b/contracts/xcall_manager/src/contract.rs index d8c9bd7..e674f36 100644 --- a/contracts/xcall_manager/src/contract.rs +++ b/contracts/xcall_manager/src/contract.rs @@ -1,13 +1,16 @@ -use soroban_sdk::{contract, contractimpl, Address, Bytes, Env, String, Vec, panic_with_error}; +use soroban_sdk::{contract, contractimpl, panic_with_error, Address, Bytes, BytesN, Env, String, Vec}; mod xcall { - soroban_sdk::contractimport!(file = "../../wasm/xcall.wasm" ); + soroban_sdk::contractimport!(file = "../../wasm/xcall.wasm"); } -use soroban_rlp::messages::configure_protocols::ConfigureProtocols; use crate::{ - config::{get_config, set_config, ConfigData}, - states::{has_registry, has_proposed_removed, read_administrator, write_administrator, write_registry, - read_destinations, write_destinations, read_sources, write_sources, read_proposed_removed, write_proposed_removed, extend_ttl}, + config::{get_config, set_config, ConfigData}, + states::{ + extend_ttl, has_proposed_removed, has_registry, read_administrator, read_destinations, + read_proposed_removed, read_sources, write_administrator, write_destinations, + write_proposed_removed, write_registry, write_sources, + }, storage_types::DataKey, white_list_actions::WhiteListActions }; +use soroban_rlp::messages::configure_protocols::ConfigureProtocols; use crate::errors::ContractError; @@ -18,17 +21,28 @@ pub struct XcallManager; #[contractimpl] impl XcallManager { - - pub fn initialize(env:Env, registry:Address, admin: Address, config: ConfigData, sources: Vec, destinations: Vec) { + pub fn initialize( + env: Env, + registry: Address, + admin: Address, + config: ConfigData, + sources: Vec, + destinations: Vec, + ) { if has_registry(env.clone()) { panic_with_error!(env, ContractError::ContractAlreadyInitialized) } write_registry(&env, ®istry); write_administrator(&env, &admin); - Self::configure(env, config, sources, destinations ); + Self::configure(env, config, sources, destinations); } - pub fn configure(env:Env, config: ConfigData, sources: Vec, destinations: Vec){ + pub fn configure( + env: Env, + config: ConfigData, + sources: Vec, + destinations: Vec, + ) { let admin = read_administrator(&env); admin.require_auth(); @@ -37,7 +51,7 @@ impl XcallManager { write_destinations(&env, &destinations); } - pub fn get_config(env: Env) -> ConfigData{ + pub fn get_config(env: Env) -> ConfigData { get_config(&env) } @@ -55,18 +69,29 @@ impl XcallManager { pub fn propose_removal(e: Env, protocol: String) { let admin = read_administrator(&e); admin.require_auth(); - - write_proposed_removed(&e, &protocol); + + write_proposed_removed(&e, &protocol); } pub fn get_proposed_removal(e: Env) -> String { read_proposed_removed(&e) } - pub fn verify_protocols( - e: Env, - protocols: Vec - ) -> Result { + pub fn white_list_actions(e: Env, action: Bytes) { + let actions = WhiteListActions::new(DataKey::WhiteListedActions); + actions.add(&e, action); + } + + pub fn remove_action(e: Env, action: Bytes) -> Result { + let actions = WhiteListActions::new(DataKey::WhiteListedActions); + if !actions.contains(&e, action.clone()){ + return Err(ContractError::NotWhiteListed); + } + actions.remove(&e, action); + Ok(true) + } + + pub fn verify_protocols(e: Env, protocols: Vec) -> Result { let sources: Vec = read_sources(&e); let verified = Self::verify_protocols_unordered(protocols, sources)?; @@ -79,7 +104,10 @@ impl XcallManager { Ok((sources, destinations)) } - pub fn verify_protocols_unordered(array1: Vec, array2: Vec) -> Result { + pub fn verify_protocols_unordered( + array1: Vec, + array2: Vec, + ) -> Result { // Check if the arrays have the same length if array1.len() != array2.len() { return Ok(false); @@ -87,16 +115,15 @@ impl XcallManager { for p in array1.iter() { let mut j = 0; for s in array2.iter() { - j = j+1; + j = j + 1; if p.eq(&s) { break; } else { - if j == array2.len() { - return Ok(false); + if j == array2.len() { + return Ok(false); } continue; } - } } return Ok(true); @@ -107,8 +134,8 @@ impl XcallManager { _xcall: Address, from: String, data: Bytes, - protocols: Vec - ) -> Result<(), ContractError> { + protocols: Vec, + ) -> Result<(), ContractError> { let config = get_config(&e.clone()); let xcall = config.xcall; xcall.require_auth(); @@ -117,18 +144,23 @@ impl XcallManager { return Err(ContractError::OnlyICONGovernance); } - + let actions = WhiteListActions::new(DataKey::WhiteListedActions); + if !actions.contains(&e, data.clone()){ + return Err(ContractError::NotWhiteListed); + } + actions.remove(&e, data.clone()); + if !Self::verify_protocols(e.clone(), protocols.clone())? { - return Err(ContractError::ProtocolMismatch) + return Err(ContractError::ProtocolMismatch); }; let method = ConfigureProtocols::get_method(&e.clone(), data.clone()); let sources = read_sources(&e); if !Self::verify_protocols_unordered(protocols.clone(), sources).unwrap() { - if method != String::from_str(&e.clone(), CONFIGURE_PROTOCOLS_NAME) { - return Err(ContractError::ProtocolMismatch) - } + if method != String::from_str(&e.clone(), CONFIGURE_PROTOCOLS_NAME) { + return Err(ContractError::ProtocolMismatch); + } Self::verify_protocol_recovery(&e, protocols)?; } @@ -139,23 +171,24 @@ impl XcallManager { write_sources(&e, &sources); write_destinations(&e, &destinations); } else { - return Err(ContractError::UnknownMessageType) + return Err(ContractError::UnknownMessageType); } Ok(()) } pub fn verify_protocol_recovery(e: &Env, protocols: Vec) -> Result<(), ContractError> { let modified_sources = Self::get_modified_protocols(e)?; - let verify_unordered = Self::verify_protocols_unordered(modified_sources, protocols).unwrap(); + let verify_unordered = + Self::verify_protocols_unordered(modified_sources, protocols).unwrap(); if !verify_unordered { - return Err(ContractError::ProtocolMismatch) + return Err(ContractError::ProtocolMismatch); } Ok(()) } pub fn get_modified_protocols(e: &Env) -> Result, ContractError> { if !has_proposed_removed(e.clone()) { - return Err(ContractError::NoProposalForRemovalExists) + return Err(ContractError::NoProposalForRemovalExists); } let sources = read_sources(&e); @@ -166,11 +199,19 @@ impl XcallManager { new_array.push_back(s); } } - + return Ok(new_array); - } + } - pub fn extend_ttl(e: Env){ + pub fn upgrade(e: Env, new_wasm_hash: BytesN<32>) { + let admin: Address = e.storage().instance().get(&DataKey::Admin).unwrap(); + admin.require_auth(); + + e.deployer().update_current_contract_wasm(new_wasm_hash); + } + + pub fn extend_ttl(e: Env) { extend_ttl(&e); } -} \ No newline at end of file + +} diff --git a/contracts/xcall_manager/src/errors.rs b/contracts/xcall_manager/src/errors.rs index 61cb64f..deeba2b 100644 --- a/contracts/xcall_manager/src/errors.rs +++ b/contracts/xcall_manager/src/errors.rs @@ -12,5 +12,6 @@ pub enum ContractError { OnlyCallService = 9, UnknownMessageType = 10, AdminRequired = 11, - NoProposalForRemovalExists = 12 -} \ No newline at end of file + NoProposalForRemovalExists = 12, + NotWhiteListed = 13, +} diff --git a/contracts/xcall_manager/src/events.rs b/contracts/xcall_manager/src/events.rs deleted file mode 100644 index e69de29..0000000 diff --git a/contracts/xcall_manager/src/lib.rs b/contracts/xcall_manager/src/lib.rs index 68c0567..d000c39 100644 --- a/contracts/xcall_manager/src/lib.rs +++ b/contracts/xcall_manager/src/lib.rs @@ -1,7 +1,8 @@ #![no_std] +mod config; pub mod contract; -mod storage_types; +mod errors; mod states; +mod storage_types; mod tests; -mod errors; -mod config; \ No newline at end of file +mod white_list_actions; diff --git a/contracts/xcall_manager/src/states.rs b/contracts/xcall_manager/src/states.rs index 463aa59..7947f4f 100644 --- a/contracts/xcall_manager/src/states.rs +++ b/contracts/xcall_manager/src/states.rs @@ -49,7 +49,6 @@ pub fn read_sources(e: &Env) -> Vec { e.storage().instance().get(&key).unwrap() } - pub fn write_destinations(e: &Env, id: &Vec) { let key = DataKey::Destinations; e.storage().instance().set(&key, id); diff --git a/contracts/xcall_manager/src/storage_types.rs b/contracts/xcall_manager/src/storage_types.rs index 68ad499..ab85e14 100644 --- a/contracts/xcall_manager/src/storage_types.rs +++ b/contracts/xcall_manager/src/storage_types.rs @@ -2,11 +2,12 @@ use soroban_sdk::contracttype; #[derive(Clone)] #[contracttype] -pub enum DataKey{ +pub enum DataKey { Registry, Admin, ProposedProtocolToRemove, Config, Sources, - Destinations -} \ No newline at end of file + Destinations, + WhiteListedActions +} diff --git a/contracts/xcall_manager/src/tests/mod.rs b/contracts/xcall_manager/src/tests/mod.rs index 08c141b..2def534 100644 --- a/contracts/xcall_manager/src/tests/mod.rs +++ b/contracts/xcall_manager/src/tests/mod.rs @@ -1,2 +1,2 @@ pub mod setup; -pub mod xcall_manager_test; \ No newline at end of file +pub mod xcall_manager_test; diff --git a/contracts/xcall_manager/src/tests/xcall_manager_test.rs b/contracts/xcall_manager/src/tests/xcall_manager_test.rs index f9450e8..33813e5 100644 --- a/contracts/xcall_manager/src/tests/xcall_manager_test.rs +++ b/contracts/xcall_manager/src/tests/xcall_manager_test.rs @@ -3,11 +3,13 @@ extern crate std; use crate::contract::XcallManagerClient; +use super::setup::*; +use soroban_rlp::messages::configure_protocols::ConfigureProtocols; use soroban_sdk::{ - symbol_short, testutils::{Address as _, AuthorizedFunction, AuthorizedInvocation}, Address, IntoVal, String, Vec, vec + symbol_short, + testutils::{Address as _, AuthorizedFunction, AuthorizedInvocation}, + vec, Address, IntoVal, String, Vec, }; -use soroban_rlp::messages::configure_protocols::ConfigureProtocols; -use super::setup::*; #[test] fn test_initialize() { @@ -21,7 +23,6 @@ fn test_initialize() { let (s, d) = client.get_protocols(); assert_eq!(s, sources); assert_eq!(d, destinations); - } #[test] @@ -29,25 +30,22 @@ fn test_set_admin() { let ctx = TestContext::default(); let client = XcallManagerClient::new(&ctx.env, &ctx.registry); ctx.init_context(&client); - + let new_admin: Address = Address::generate(&ctx.env); client.set_admin(&new_admin); assert_eq!( ctx.env.auths(), - std::vec![ - ( - ctx.admin.clone(), - AuthorizedInvocation { - function: AuthorizedFunction::Contract(( - ctx.registry.clone(), - symbol_short!("set_admin"), - (&new_admin,) - .into_val(&ctx.env) - )), - sub_invocations: std::vec![] - } - ) - ] + std::vec![( + ctx.admin.clone(), + AuthorizedInvocation { + function: AuthorizedFunction::Contract(( + ctx.registry.clone(), + symbol_short!("set_admin"), + (&new_admin,).into_val(&ctx.env) + )), + sub_invocations: std::vec![] + } + )] ); assert_eq!(client.get_admin(), new_admin); } @@ -66,11 +64,37 @@ fn test_initialize_panic_already_initialized() { let (s, d) = client.get_protocols(); assert_eq!(s, sources); assert_eq!(d, destinations); +} + +#[test] +fn test_whitelist_action() { + let ctx = TestContext::default(); + let client = XcallManagerClient::new(&ctx.env, &ctx.registry); + + ctx.env.mock_all_auths(); + ctx.init_context(&client); + let source_items = [ + String::from_str(&ctx.env, "stellar/address"), + String::from_str(&ctx.env, "stellar/address1"), + ]; + let destination_items = [ + String::from_str(&ctx.env, "icon/address"), + String::from_str(&ctx.env, "icon/address1"), + ]; + + let sources = Vec::from_array(&ctx.env, source_items); + let destinations = Vec::from_array(&ctx.env, destination_items); + let data = ConfigureProtocols::new(sources.clone(), destinations.clone()) + .encode(&ctx.env, String::from_str(&ctx.env, "ConfigureProtocols")); + client.white_list_actions(&data); + + let result = client.remove_action(&data); + assert!(result==true) } #[test] -fn test_verify_protocols(){ +fn test_verify_protocols() { let ctx = TestContext::default(); let client = XcallManagerClient::new(&ctx.env, &ctx.registry); @@ -80,24 +104,61 @@ fn test_verify_protocols(){ } #[test] -fn test_handle_call_message_for_configure_protocols(){ +#[should_panic(expected = "HostError: Error(Contract, #13)")] +fn test_handle_call_message_for_configure_protocols_panic_for_action_not_whitelisted() { let ctx = TestContext::default(); let client = XcallManagerClient::new(&ctx.env, &ctx.registry); ctx.env.mock_all_auths(); ctx.init_context(&client); - - let source_items = [String::from_str(&ctx.env, "sui/address"), String::from_str(&ctx.env, "sui/address1")]; - let destination_items = [String::from_str(&ctx.env, "icon/address"), String::from_str(&ctx.env, "icon/address1")]; + let source_items = [ + String::from_str(&ctx.env, "stellar/address"), + String::from_str(&ctx.env, "stellar/address1"), + ]; + let destination_items = [ + String::from_str(&ctx.env, "icon/address"), + String::from_str(&ctx.env, "icon/address1"), + ]; let sources = Vec::from_array(&ctx.env, source_items); let destinations = Vec::from_array(&ctx.env, destination_items); - let data = ConfigureProtocols::new(sources.clone(), destinations.clone()).encode(&ctx.env, String::from_str(&ctx.env, "ConfigureProtocols")); + let data = ConfigureProtocols::new(sources.clone(), destinations.clone()) + .encode(&ctx.env, String::from_str(&ctx.env, "ConfigureProtocols")); let decoded: ConfigureProtocols = ConfigureProtocols::decode(&ctx.env, data.clone()); + assert_eq!(decoded.sources, sources); + assert_eq!(decoded.destinations, destinations); + let (s, _) = client.get_protocols(); + client.handle_call_message(&ctx.xcall, &ctx.icon_governance, &data, &s); + + let (s, d) = client.get_protocols(); + assert_eq!(s, sources); + assert_eq!(d, destinations); +} + +#[test] +fn test_handle_call_message_for_configure_protocols() { + let ctx = TestContext::default(); + let client = XcallManagerClient::new(&ctx.env, &ctx.registry); + ctx.env.mock_all_auths(); + ctx.init_context(&client); + let source_items = [ + String::from_str(&ctx.env, "stellar/address"), + String::from_str(&ctx.env, "stellar/address1"), + ]; + let destination_items = [ + String::from_str(&ctx.env, "icon/address"), + String::from_str(&ctx.env, "icon/address1"), + ]; + let sources = Vec::from_array(&ctx.env, source_items); + let destinations = Vec::from_array(&ctx.env, destination_items); + let data = ConfigureProtocols::new(sources.clone(), destinations.clone()) + .encode(&ctx.env, String::from_str(&ctx.env, "ConfigureProtocols")); + let decoded: ConfigureProtocols = ConfigureProtocols::decode(&ctx.env, data.clone()); + client.white_list_actions(&data); assert_eq!(decoded.sources, sources); assert_eq!(decoded.destinations, destinations); let (s, _) = client.get_protocols(); - client.handle_call_message(&ctx.xcall,&ctx.icon_governance, &data, &s); + client.handle_call_message(&ctx.xcall, &ctx.icon_governance, &data, &s); let (s, d) = client.get_protocols(); assert_eq!(s, sources); @@ -105,81 +166,102 @@ fn test_handle_call_message_for_configure_protocols(){ } #[test] -fn test_proposal_removal(){ +fn test_proposal_removal() { let ctx = TestContext::default(); let client = XcallManagerClient::new(&ctx.env, &ctx.registry); ctx.env.mock_all_auths(); ctx.init_context(&client); - client.propose_removal(&String::from_str(&ctx.env, "sui/address")); - assert_eq!(String::from_str(&ctx.env, "sui/address"), client.get_proposed_removal()) + client.propose_removal(&String::from_str(&ctx.env, "stellar/address")); + assert_eq!( + String::from_str(&ctx.env, "stellar/address"), + client.get_proposed_removal() + ) } #[test] -fn test_get_modified_proposals(){ +fn test_get_modified_proposals() { let ctx = TestContext::default(); let client = XcallManagerClient::new(&ctx.env, &ctx.registry); ctx.env.mock_all_auths(); ctx.init_context(&client); - let source_items = [String::from_str(&ctx.env, "sui/address"), String::from_str(&ctx.env, "sui/address1")]; - let destination_items = [String::from_str(&ctx.env, "icon/address"), String::from_str(&ctx.env, "icon/address1")]; + let source_items = [ + String::from_str(&ctx.env, "stellar/address"), + String::from_str(&ctx.env, "stellar/address1"), + ]; + let destination_items = [ + String::from_str(&ctx.env, "icon/address"), + String::from_str(&ctx.env, "icon/address1"), + ]; let sources = Vec::from_array(&ctx.env, source_items); let destinations = Vec::from_array(&ctx.env, destination_items); - let data = ConfigureProtocols::new(sources.clone(), destinations.clone()).encode(&ctx.env, String::from_str(&ctx.env, "ConfigureProtocols")); - + let data = ConfigureProtocols::new(sources.clone(), destinations.clone()) + .encode(&ctx.env, String::from_str(&ctx.env, "ConfigureProtocols")); + client.white_list_actions(&data); let (s, _) = client.get_protocols(); - client.handle_call_message(&ctx.xcall,&ctx.icon_governance, &data, &s); + client.handle_call_message(&ctx.xcall, &ctx.icon_governance, &data, &s); - client.propose_removal(&String::from_str(&ctx.env, "sui/address")); + client.propose_removal(&String::from_str(&ctx.env, "stellar/address")); - let updated_protocal = vec![&ctx.env, String::from_str(&ctx.env, "sui/address1")]; + let updated_protocal = vec![&ctx.env, String::from_str(&ctx.env, "stellar/address1")]; assert_eq!(updated_protocal, client.get_modified_protocols()); } #[test] #[should_panic(expected = "HostError: Error(Contract, #12)")] -fn test_get_modified_proposals_panic_no_proposed_removal(){ +fn test_get_modified_proposals_panic_no_proposed_removal() { let ctx = TestContext::default(); let client = XcallManagerClient::new(&ctx.env, &ctx.registry); ctx.env.mock_all_auths(); ctx.init_context(&client); - let source_items = [String::from_str(&ctx.env, "sui/address"), String::from_str(&ctx.env, "sui/address1")]; - let destination_items = [String::from_str(&ctx.env, "icon/address"), String::from_str(&ctx.env, "icon/address1")]; + let source_items = [ + String::from_str(&ctx.env, "stellar/address"), + String::from_str(&ctx.env, "stellar/address1"), + ]; + let destination_items = [ + String::from_str(&ctx.env, "icon/address"), + String::from_str(&ctx.env, "icon/address1"), + ]; let sources = Vec::from_array(&ctx.env, source_items); let destinations = Vec::from_array(&ctx.env, destination_items); - let data = ConfigureProtocols::new(sources.clone(), destinations.clone()).encode(&ctx.env, String::from_str(&ctx.env, "ConfigureProtocols")); - + let data = ConfigureProtocols::new(sources.clone(), destinations.clone()) + .encode(&ctx.env, String::from_str(&ctx.env, "ConfigureProtocols")); + client.white_list_actions(&data); let (s, _) = client.get_protocols(); - client.handle_call_message(&ctx.xcall,&ctx.icon_governance, &data, &s); - - //client.propose_removal(&String::from_str(&ctx.env, "sui/address")); + client.handle_call_message(&ctx.xcall, &ctx.icon_governance, &data, &s); - let updated_protocal = vec![&ctx.env, String::from_str(&ctx.env, "sui/address1")]; + let updated_protocal = vec![&ctx.env, String::from_str(&ctx.env, "stellar/address1")]; assert_eq!(updated_protocal, client.get_modified_protocols()); } #[test] #[should_panic(expected = "HostError: Error(Contract, #8)")] -fn test_handle_call_message_for_configure_protocols_panic_for_only_icon_governance(){ +fn test_handle_call_message_for_configure_protocols_panic_for_only_icon_governance() { let ctx = TestContext::default(); let client = XcallManagerClient::new(&ctx.env, &ctx.registry); ctx.env.mock_all_auths(); ctx.init_context(&client); - - let source_items = [String::from_str(&ctx.env, "sui/address"), String::from_str(&ctx.env, "sui/address1")]; - let destination_items = [String::from_str(&ctx.env, "icon/address"), String::from_str(&ctx.env, "icon/address1")]; + let source_items = [ + String::from_str(&ctx.env, "stellar/address"), + String::from_str(&ctx.env, "stellar/address1"), + ]; + let destination_items = [ + String::from_str(&ctx.env, "icon/address"), + String::from_str(&ctx.env, "icon/address1"), + ]; let sources = Vec::from_array(&ctx.env, source_items); let destinations = Vec::from_array(&ctx.env, destination_items); - let data = ConfigureProtocols::new(sources.clone(), destinations.clone()).encode(&ctx.env, String::from_str(&ctx.env, "ConfigureProtocols")); + let data = ConfigureProtocols::new(sources.clone(), destinations.clone()) + .encode(&ctx.env, String::from_str(&ctx.env, "ConfigureProtocols")); let decoded: ConfigureProtocols = ConfigureProtocols::decode(&ctx.env, data.clone()); - + client.white_list_actions(&data); assert_eq!(decoded.sources, sources); assert_eq!(decoded.destinations, destinations); let (s, _) = client.get_protocols(); - client.handle_call_message(&ctx.xcall, &ctx.xcall_network_address, &data, &s); + client.handle_call_message(&ctx.xcall, &ctx.xcall_network_address, &data, &s); let (s, d) = client.get_protocols(); assert_eq!(s, sources); @@ -188,24 +270,30 @@ fn test_handle_call_message_for_configure_protocols_panic_for_only_icon_governan #[test] #[should_panic(expected = "HostError: Error(Contract, #7)")] -fn test_handle_call_message_for_configure_protocols_panic_for_protocol_mismatch(){ +fn test_handle_call_message_for_configure_protocols_panic_for_protocol_mismatch() { let ctx = TestContext::default(); let client = XcallManagerClient::new(&ctx.env, &ctx.registry); ctx.env.mock_all_auths(); ctx.init_context(&client); - - let source_items = [String::from_str(&ctx.env, "sui/address"), String::from_str(&ctx.env, "sui/address1")]; - let destination_items = [String::from_str(&ctx.env, "icon/address"), String::from_str(&ctx.env, "icon/address1")]; + let source_items = [ + String::from_str(&ctx.env, "stellar/address"), + String::from_str(&ctx.env, "stellar/address1"), + ]; + let destination_items = [ + String::from_str(&ctx.env, "icon/address"), + String::from_str(&ctx.env, "icon/address1"), + ]; let sources = Vec::from_array(&ctx.env, source_items); let destinations = Vec::from_array(&ctx.env, destination_items); - let data = ConfigureProtocols::new(sources.clone(), destinations.clone()).encode(&ctx.env, String::from_str(&ctx.env, "ConfigureProtocols")); + let data = ConfigureProtocols::new(sources.clone(), destinations.clone()) + .encode(&ctx.env, String::from_str(&ctx.env, "ConfigureProtocols")); let decoded: ConfigureProtocols = ConfigureProtocols::decode(&ctx.env, data.clone()); - + client.white_list_actions(&data); assert_eq!(decoded.sources, sources); assert_eq!(decoded.destinations, destinations); let s = Vec::from_array(&ctx.env, [ctx.xcall.to_string()]); - client.handle_call_message(&ctx.xcall,&ctx.icon_governance, &data, &s); + client.handle_call_message(&ctx.xcall, &ctx.icon_governance, &data, &s); let (s, d) = client.get_protocols(); assert_eq!(s, sources); @@ -214,24 +302,33 @@ fn test_handle_call_message_for_configure_protocols_panic_for_protocol_mismatch( #[test] #[should_panic(expected = "HostError: Error(Contract, #10)")] -fn test_handle_call_message_for_configure_protocols_panic_for_unknown_mesage_type(){ +fn test_handle_call_message_for_configure_protocols_panic_for_unknown_mesage_type() { let ctx = TestContext::default(); let client = XcallManagerClient::new(&ctx.env, &ctx.registry); ctx.env.mock_all_auths(); ctx.init_context(&client); - - let source_items = [String::from_str(&ctx.env, "sui/address"), String::from_str(&ctx.env, "sui/address1")]; - let destination_items = [String::from_str(&ctx.env, "icon/address"), String::from_str(&ctx.env, "icon/address1")]; + let source_items = [ + String::from_str(&ctx.env, "stellar/address"), + String::from_str(&ctx.env, "stellar/address1"), + ]; + let destination_items = [ + String::from_str(&ctx.env, "icon/address"), + String::from_str(&ctx.env, "icon/address1"), + ]; let sources = Vec::from_array(&ctx.env, source_items); let destinations = Vec::from_array(&ctx.env, destination_items); - let data = ConfigureProtocols::new(sources.clone(), destinations.clone()).encode(&ctx.env, String::from_str(&ctx.env, "ConfigureProtocolsPanic")); + let data = ConfigureProtocols::new(sources.clone(), destinations.clone()).encode( + &ctx.env, + String::from_str(&ctx.env, "ConfigureProtocolsPanic"), + ); + client.white_list_actions(&data); let decoded: ConfigureProtocols = ConfigureProtocols::decode(&ctx.env, data.clone()); assert_eq!(decoded.sources, sources); assert_eq!(decoded.destinations, destinations); let s = Vec::from_array(&ctx.env, [ctx.centralized_connection.to_string()]); - client.handle_call_message(&ctx.xcall,&ctx.icon_governance, &data, &s); + client.handle_call_message(&ctx.xcall, &ctx.icon_governance, &data, &s); let (s, d) = client.get_protocols(); assert_eq!(s, sources); @@ -239,11 +336,11 @@ fn test_handle_call_message_for_configure_protocols_panic_for_unknown_mesage_typ } #[test] -fn test_extend_ttl(){ +fn test_extend_ttl() { let ctx = TestContext::default(); let client = XcallManagerClient::new(&ctx.env, &ctx.registry); ctx.env.mock_all_auths(); ctx.init_context(&client); client.extend_ttl(); -} \ No newline at end of file +} diff --git a/contracts/xcall_manager/src/white_list_actions.rs b/contracts/xcall_manager/src/white_list_actions.rs new file mode 100644 index 0000000..36d1759 --- /dev/null +++ b/contracts/xcall_manager/src/white_list_actions.rs @@ -0,0 +1,37 @@ +use soroban_sdk::{Bytes, Env, Vec}; + +use crate::storage_types::DataKey; + +#[derive(Clone)] +pub struct WhiteListActions { + pub key: DataKey, +} + +impl WhiteListActions { + pub fn new(key: DataKey) -> Self { + Self { key } + } + + pub fn add(&self, env: &Env, value: Bytes) { + let mut list = self.get(env); + list.push_back(value); + env.storage().instance().set(&self.key, &list); + } + + pub fn remove(&self, env: &Env, value: Bytes) { + let mut list = self.get(env); + if let Some(pos) = list.iter().position(|x| x == value) { + list.remove(pos as u32); + env.storage().instance().set(&self.key, &list); + } + } + + pub fn contains(&self, env: &Env, value: Bytes) -> bool { + let list = self.get(env); + list.contains(&value) + } + + fn get(&self, env: &Env) -> Vec { + env.storage().instance().get(&self.key).unwrap_or_else(|| Vec::new(env)) + } +} diff --git a/libs/soroban-rlp/src/address_utils.rs b/libs/soroban-rlp/src/address_utils.rs index 8045a73..e45995d 100644 --- a/libs/soroban-rlp/src/address_utils.rs +++ b/libs/soroban-rlp/src/address_utils.rs @@ -1,4 +1,4 @@ -use soroban_sdk::{String, Bytes}; +use soroban_sdk::{xdr::ToXdr, xdr::FromXdr, Bytes, Env, String}; pub fn is_valid_string_address(address: &String) -> bool { if address.len() != 56 { @@ -42,11 +42,55 @@ pub fn is_valid_bytes_address(address: &Bytes) -> bool { true } - - fn is_valid_base32(byte: u8) -> bool { match byte { b'A'..=b'Z' | b'2'..=b'7' => true, _ => false, } +} + +pub fn get_address_from(network_address: &String, env: &Env) -> String { + let mut nid = Bytes::new(&env); + let mut account = Bytes::new(&env); + + let addr_slice = get_bytes_from_string(&env,network_address.clone()); + + let mut has_seperator = false; + for (index, value) in addr_slice.clone().iter().enumerate() { + if has_seperator { + account.append(&addr_slice.slice(index as u32..addr_slice.len())); + break; + } else if value == 47 { + has_seperator = true; + } else { + nid.push_back(value) + } + } + + if !has_seperator { + panic!("Invalid network address") + } + + + get_string_from_bytes(&env, account) + +} + +pub fn get_bytes_from_string(env: &Env, value: String) -> Bytes { + let bytes = value.to_xdr(&env); + + if bytes.get(6).unwrap() > 0 { + panic!("Invalid network address length") + } + + let value_len = bytes.get(7).unwrap(); + let slice = bytes.slice(8..value_len as u32 + 8); + slice +} + +pub fn get_string_from_bytes(e: &Env, bytes: Bytes) -> String { + let mut bytes_xdr = bytes.to_xdr(&e); + bytes_xdr.set(3, 14); + + String::from_xdr(&e, &bytes_xdr).unwrap() } \ No newline at end of file diff --git a/libs/soroban-rlp/src/decoder.rs b/libs/soroban-rlp/src/decoder.rs index f9b67ce..92c2959 100644 --- a/libs/soroban-rlp/src/decoder.rs +++ b/libs/soroban-rlp/src/decoder.rs @@ -65,7 +65,7 @@ pub fn decode_list(env: &Env, list: Bytes) -> Vec { i = i + (len as u32 + 1); } else if byte > 0xc0 && byte < 0xf7 { let len = (byte - 0xc0) as u64; - decoded.push_back(slice_vector(&env, encoded.clone(), i as u64, len+1)); + decoded.push_back(slice_vector(&env, encoded.clone(), i as u64, len + 1)); i = i + (len as u32 + 1) } else if byte > 0xb7 && byte < 0xc0 { let data_bytes_len = (byte - 0xb7) as u64; @@ -146,4 +146,4 @@ pub fn decode_strings(env: &Env, bytes: Bytes) -> Vec { } strings -} \ No newline at end of file +} diff --git a/libs/soroban-rlp/src/encoder.rs b/libs/soroban-rlp/src/encoder.rs index ade67a9..3b55bf7 100644 --- a/libs/soroban-rlp/src/encoder.rs +++ b/libs/soroban-rlp/src/encoder.rs @@ -89,4 +89,4 @@ pub fn encode_strings(env: &Env, values: Vec) -> Bytes { } encode_list(&env, list, false) -} \ No newline at end of file +} diff --git a/libs/soroban-rlp/src/lib.rs b/libs/soroban-rlp/src/lib.rs index e8158b0..ab2eac6 100644 --- a/libs/soroban-rlp/src/lib.rs +++ b/libs/soroban-rlp/src/lib.rs @@ -1,7 +1,6 @@ #![no_std] - +pub mod address_utils; pub mod decoder; pub mod encoder; -mod utils; pub mod messages; -pub mod address_utils; \ No newline at end of file +mod utils; diff --git a/libs/soroban-rlp/src/messages/configure_protocols.rs b/libs/soroban-rlp/src/messages/configure_protocols.rs index 425d119..2c7505c 100644 --- a/libs/soroban-rlp/src/messages/configure_protocols.rs +++ b/libs/soroban-rlp/src/messages/configure_protocols.rs @@ -1,20 +1,19 @@ -use soroban_sdk::{contracttype, Env, String, Bytes, Vec}; -use crate::encoder; use crate::decoder; +use crate::encoder; +use soroban_sdk::{contracttype, Bytes, Env, String, Vec}; #[derive(Clone)] #[contracttype] pub struct ConfigureProtocols { - pub sources: Vec, - pub destinations: Vec -} + pub sources: Vec, + pub destinations: Vec, +} - -impl ConfigureProtocols{ +impl ConfigureProtocols { pub fn new(sources: Vec, destinations: Vec) -> Self { Self { sources, - destinations + destinations, } } @@ -41,12 +40,12 @@ impl ConfigureProtocols{ if decoded.len() != 3 { panic!("InvalidRlpLength"); } - + let sources = decoder::decode_strings(e, decoded.get(1).unwrap()); let destinations = decoder::decode_strings(e, decoded.get(2).unwrap()); Self { sources, - destinations + destinations, } } @@ -55,4 +54,4 @@ impl ConfigureProtocols{ let method = decoder::decode_string(e, decoded.get(0).unwrap()); method } -} \ No newline at end of file +} diff --git a/libs/soroban-rlp/src/messages/cross_transfer.rs b/libs/soroban-rlp/src/messages/cross_transfer.rs index 4472e4f..743277e 100644 --- a/libs/soroban-rlp/src/messages/cross_transfer.rs +++ b/libs/soroban-rlp/src/messages/cross_transfer.rs @@ -1,6 +1,6 @@ -use soroban_sdk::{contracttype, Env, String, Bytes, Vec}; -use crate::encoder; use crate::decoder; +use crate::encoder; +use soroban_sdk::{contracttype, Bytes, Env, String, Vec}; #[derive(Clone)] #[contracttype] @@ -8,16 +8,16 @@ pub struct CrossTransfer { pub from: String, pub to: String, pub amount: u128, - pub data: Bytes + pub data: Bytes, } -impl CrossTransfer{ +impl CrossTransfer { pub fn new(from: String, to: String, amount: u128, data: Bytes) -> Self { Self { from, to, amount, - data + data, } } @@ -55,7 +55,7 @@ impl CrossTransfer{ from, to, amount, - data + data, } } @@ -64,4 +64,4 @@ impl CrossTransfer{ let method = decoder::decode_string(e, decoded.get(0).unwrap()); method } -} \ No newline at end of file +} diff --git a/libs/soroban-rlp/src/messages/deposit.rs b/libs/soroban-rlp/src/messages/deposit.rs index b0fa639..720db75 100644 --- a/libs/soroban-rlp/src/messages/deposit.rs +++ b/libs/soroban-rlp/src/messages/deposit.rs @@ -1,6 +1,6 @@ -use soroban_sdk::{contracttype, Env, String, Bytes, Vec}; -use crate::encoder; use crate::decoder; +use crate::encoder; +use soroban_sdk::{contracttype, Bytes, Env, String, Vec}; #[derive(Clone)] #[contracttype] @@ -9,17 +9,17 @@ pub struct Deposit { pub from: String, pub to: String, pub amount: u128, - pub data: Bytes + pub data: Bytes, } -impl Deposit{ +impl Deposit { pub fn new(token_address: String, from: String, to: String, amount: u128, data: Bytes) -> Self { Self { token_address, from, to, amount, - data + data, } } @@ -73,13 +73,13 @@ impl Deposit{ from, to, amount, - data + data, } } - pub fn get_method(e: &Env, bytes: Bytes)-> String { + pub fn get_method(e: &Env, bytes: Bytes) -> String { let decoded = decoder::decode_list(&e, bytes); let method = decoder::decode_string(e, decoded.get(0).unwrap()); method } -} \ No newline at end of file +} diff --git a/libs/soroban-rlp/src/utils.rs b/libs/soroban-rlp/src/utils.rs index 69d91d0..90b000d 100644 --- a/libs/soroban-rlp/src/utils.rs +++ b/libs/soroban-rlp/src/utils.rs @@ -101,4 +101,4 @@ pub fn bytes_to_string(env: &Env, bytes: Bytes) -> String { bytes_xdr.set(3, 14); String::from_xdr(&env, &bytes_xdr).unwrap() -} \ No newline at end of file +} From cdeb4ef9e090ce6aad627a8edc10c7fdec83edee Mon Sep 17 00:00:00 2001 From: Deepak Bomjan Date: Fri, 21 Jun 2024 11:33:47 +0545 Subject: [PATCH 38/63] ci: add codecov bandge --- .github/workflows/build-test-soroban-contracts.yml | 2 +- README.md | 5 +++++ 2 files changed, 6 insertions(+), 1 deletion(-) create mode 100644 README.md diff --git a/.github/workflows/build-test-soroban-contracts.yml b/.github/workflows/build-test-soroban-contracts.yml index e81a2ac..dfa7d76 100644 --- a/.github/workflows/build-test-soroban-contracts.yml +++ b/.github/workflows/build-test-soroban-contracts.yml @@ -1,4 +1,4 @@ -name: Build and Test Balanced Soroban contracts +name: Build on: push: branches: diff --git a/README.md b/README.md new file mode 100644 index 0000000..fe2d6ae --- /dev/null +++ b/README.md @@ -0,0 +1,5 @@ +[![codecov](https://codecov.io/gh/balancednetwork/balanced-soroban-contracts/graph/badge.svg?token=6Epcv9Uek5)](https://codecov.io/gh/balancednetwork/balanced-soroban-contracts) +![build](https://github.com/balancednetwork/balanced-soroban-contracts/actions/workflows/build-test-soroban-contracts.yml/badge.svg) + +## Balanced Soroban Contracts + From 2972b6cdad13754a0094f2175be81df3ee43f9d8 Mon Sep 17 00:00:00 2001 From: Deepak Bomjan Date: Fri, 21 Jun 2024 12:15:40 +0545 Subject: [PATCH 39/63] ci: configure condecov --- .github/workflows/soroban-codecov.yml | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/.github/workflows/soroban-codecov.yml b/.github/workflows/soroban-codecov.yml index 96dc906..8ca37f4 100644 --- a/.github/workflows/soroban-codecov.yml +++ b/.github/workflows/soroban-codecov.yml @@ -24,8 +24,16 @@ jobs: uses: Swatinem/rust-cache@v2 - name: Install cargo-llvm-cov uses: taiki-e/install-action@cargo-llvm-cov + - name: Install wasm32 + run: | + rustup target add wasm32-unknown-unknown + cargo install --locked soroban-cli + - name: Build & Test soroban Contracts + run: | + soroban contract build - name: Generate code coverage - run: cargo llvm-cov --lcov --output-path lcov.info + run: + cargo llvm-cov --lcov --output-path lcov.info - name: Upload coverage to Codecov uses: codecov/codecov-action@v3 with: From 24ab23a2c2e818f4edcdc6068b83a128432aa512 Mon Sep 17 00:00:00 2001 From: sagar sapkota Date: Thu, 29 Aug 2024 11:42:43 +0545 Subject: [PATCH 40/63] version updated and tested --- Cargo.toml | 2 +- contracts/balanced_doller/Cargo.toml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index e030416..77b02ae 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -6,7 +6,7 @@ members = [ ] [workspace.dependencies] -soroban-sdk = "20.3.2" +soroban-sdk = "21.6.0" [profile.release] opt-level = "z" diff --git a/contracts/balanced_doller/Cargo.toml b/contracts/balanced_doller/Cargo.toml index ed8cfc1..efa6b9f 100644 --- a/contracts/balanced_doller/Cargo.toml +++ b/contracts/balanced_doller/Cargo.toml @@ -11,7 +11,7 @@ testutils = ["soroban-sdk/testutils"] [dependencies] soroban-sdk = { workspace = true } -soroban-token-sdk = { version = "20.3.2" } +soroban-token-sdk = { version = "21.6.0" } soroban-rlp = { path = "../../libs/soroban-rlp" } [dev-dependencies] From fb06c3fc03ee7dd289fc2ffc0615d7d0c484df05 Mon Sep 17 00:00:00 2001 From: sagar sapkota Date: Tue, 3 Sep 2024 13:28:25 +0545 Subject: [PATCH 41/63] token unittests for balanced dollar updated and enabled --- contracts/asset_manager/src/contract.rs | 1 - .../Cargo.toml | 0 .../src/allowance.rs | 0 .../src/balance.rs | 0 .../src/balanced_dollar.rs | 0 .../src/config.rs | 0 .../src/contract.rs | 0 .../src/errors.rs | 0 .../src/lib.rs | 0 .../src/metadata.rs | 0 .../src/states.rs | 0 .../src/storage_types.rs | 0 .../src/tests/balanced_dollar_test.rs | 0 contracts/balanced_dollar/src/tests/mod.rs | 3 + .../src/tests/setup.rs | 10 +- contracts/balanced_dollar/src/tests/test.rs | 219 ++++++++++++++ .../src/xcall_manager_interface.rs | 0 contracts/balanced_doller/src/test.rs | 278 ------------------ contracts/balanced_doller/src/tests/mod.rs | 2 - wasm/centralized_connection.wasm | Bin 12782 -> 12662 bytes wasm/xcall.wasm | Bin 27794 -> 27372 bytes 21 files changed, 227 insertions(+), 286 deletions(-) rename contracts/{balanced_doller => balanced_dollar}/Cargo.toml (100%) rename contracts/{balanced_doller => balanced_dollar}/src/allowance.rs (100%) rename contracts/{balanced_doller => balanced_dollar}/src/balance.rs (100%) rename contracts/{balanced_doller => balanced_dollar}/src/balanced_dollar.rs (100%) rename contracts/{balanced_doller => balanced_dollar}/src/config.rs (100%) rename contracts/{balanced_doller => balanced_dollar}/src/contract.rs (100%) rename contracts/{balanced_doller => balanced_dollar}/src/errors.rs (100%) rename contracts/{balanced_doller => balanced_dollar}/src/lib.rs (100%) rename contracts/{balanced_doller => balanced_dollar}/src/metadata.rs (100%) rename contracts/{balanced_doller => balanced_dollar}/src/states.rs (100%) rename contracts/{balanced_doller => balanced_dollar}/src/storage_types.rs (100%) rename contracts/{balanced_doller => balanced_dollar}/src/tests/balanced_dollar_test.rs (100%) create mode 100644 contracts/balanced_dollar/src/tests/mod.rs rename contracts/{balanced_doller => balanced_dollar}/src/tests/setup.rs (94%) create mode 100644 contracts/balanced_dollar/src/tests/test.rs rename contracts/{balanced_doller => balanced_dollar}/src/xcall_manager_interface.rs (100%) delete mode 100644 contracts/balanced_doller/src/test.rs delete mode 100644 contracts/balanced_doller/src/tests/mod.rs diff --git a/contracts/asset_manager/src/contract.rs b/contracts/asset_manager/src/contract.rs index a6c7557..803f77a 100644 --- a/contracts/asset_manager/src/contract.rs +++ b/contracts/asset_manager/src/contract.rs @@ -50,7 +50,6 @@ impl AssetManager { let admin = read_administrator(&env); admin.require_auth(); - write_administrator(&env, &new_admin); } diff --git a/contracts/balanced_doller/Cargo.toml b/contracts/balanced_dollar/Cargo.toml similarity index 100% rename from contracts/balanced_doller/Cargo.toml rename to contracts/balanced_dollar/Cargo.toml diff --git a/contracts/balanced_doller/src/allowance.rs b/contracts/balanced_dollar/src/allowance.rs similarity index 100% rename from contracts/balanced_doller/src/allowance.rs rename to contracts/balanced_dollar/src/allowance.rs diff --git a/contracts/balanced_doller/src/balance.rs b/contracts/balanced_dollar/src/balance.rs similarity index 100% rename from contracts/balanced_doller/src/balance.rs rename to contracts/balanced_dollar/src/balance.rs diff --git a/contracts/balanced_doller/src/balanced_dollar.rs b/contracts/balanced_dollar/src/balanced_dollar.rs similarity index 100% rename from contracts/balanced_doller/src/balanced_dollar.rs rename to contracts/balanced_dollar/src/balanced_dollar.rs diff --git a/contracts/balanced_doller/src/config.rs b/contracts/balanced_dollar/src/config.rs similarity index 100% rename from contracts/balanced_doller/src/config.rs rename to contracts/balanced_dollar/src/config.rs diff --git a/contracts/balanced_doller/src/contract.rs b/contracts/balanced_dollar/src/contract.rs similarity index 100% rename from contracts/balanced_doller/src/contract.rs rename to contracts/balanced_dollar/src/contract.rs diff --git a/contracts/balanced_doller/src/errors.rs b/contracts/balanced_dollar/src/errors.rs similarity index 100% rename from contracts/balanced_doller/src/errors.rs rename to contracts/balanced_dollar/src/errors.rs diff --git a/contracts/balanced_doller/src/lib.rs b/contracts/balanced_dollar/src/lib.rs similarity index 100% rename from contracts/balanced_doller/src/lib.rs rename to contracts/balanced_dollar/src/lib.rs diff --git a/contracts/balanced_doller/src/metadata.rs b/contracts/balanced_dollar/src/metadata.rs similarity index 100% rename from contracts/balanced_doller/src/metadata.rs rename to contracts/balanced_dollar/src/metadata.rs diff --git a/contracts/balanced_doller/src/states.rs b/contracts/balanced_dollar/src/states.rs similarity index 100% rename from contracts/balanced_doller/src/states.rs rename to contracts/balanced_dollar/src/states.rs diff --git a/contracts/balanced_doller/src/storage_types.rs b/contracts/balanced_dollar/src/storage_types.rs similarity index 100% rename from contracts/balanced_doller/src/storage_types.rs rename to contracts/balanced_dollar/src/storage_types.rs diff --git a/contracts/balanced_doller/src/tests/balanced_dollar_test.rs b/contracts/balanced_dollar/src/tests/balanced_dollar_test.rs similarity index 100% rename from contracts/balanced_doller/src/tests/balanced_dollar_test.rs rename to contracts/balanced_dollar/src/tests/balanced_dollar_test.rs diff --git a/contracts/balanced_dollar/src/tests/mod.rs b/contracts/balanced_dollar/src/tests/mod.rs new file mode 100644 index 0000000..557345c --- /dev/null +++ b/contracts/balanced_dollar/src/tests/mod.rs @@ -0,0 +1,3 @@ +pub mod setup; +pub mod balanced_dollar_test; +pub mod test; \ No newline at end of file diff --git a/contracts/balanced_doller/src/tests/setup.rs b/contracts/balanced_dollar/src/tests/setup.rs similarity index 94% rename from contracts/balanced_doller/src/tests/setup.rs rename to contracts/balanced_dollar/src/tests/setup.rs index 844a54d..1155128 100644 --- a/contracts/balanced_doller/src/tests/setup.rs +++ b/contracts/balanced_dollar/src/tests/setup.rs @@ -44,7 +44,7 @@ impl TestContext { pub fn default() -> Self { let env = Env::default(); let token_admin = Address::generate(&env); - let token = env.register_stellar_asset_contract(token_admin.clone()); + let token = env.register_stellar_asset_contract_v2(token_admin.clone()).address(); let balanced_dollar = env.register_contract(None, BalancedDollar); let centralized_connection = env.register_contract_wasm(None, connection::WASM); let xcall_manager = env.register_contract_wasm(None, xcall_manager::WASM); @@ -60,13 +60,13 @@ impl TestContext { depositor: Address::generate(&env), withdrawer: Address::generate(&env), xcall: xcall.clone(), - xcall_manager: xcall_manager, + xcall_manager, icon_bn_usd: String::from_str(&env, "icon01/hxjnfh4u"), icon_governance: String::from_str(&env, "icon01/kjdnoi"), - token: token, - centralized_connection: centralized_connection, + token, + centralized_connection, nid: String::from_str(&env, "stellar"), - native_token: env.register_stellar_asset_contract(token_admin.clone()), + native_token: env.register_stellar_asset_contract_v2(token_admin.clone()).address(), xcall_client: xcall::Client::new(&env, &xcall), env, } diff --git a/contracts/balanced_dollar/src/tests/test.rs b/contracts/balanced_dollar/src/tests/test.rs new file mode 100644 index 0000000..dc38f25 --- /dev/null +++ b/contracts/balanced_dollar/src/tests/test.rs @@ -0,0 +1,219 @@ +#![cfg(test)] +extern crate std; + +use crate::contract::BalancedDollarClient; + +use soroban_sdk::{ + symbol_short, + testutils::{Address as _, AuthorizedFunction, AuthorizedInvocation}, + Address, IntoVal, Symbol, +}; + +use super::setup::*; + +#[test] +fn test() { + let ctx = TestContext::default(); + let client = BalancedDollarClient::new(&ctx.env, &ctx.registry); + let e = &ctx.env; + e.mock_all_auths(); + ctx.init_context(&client); + + + let admin2 = Address::generate(&e); + let user1 = Address::generate(&e); + let user2 = Address::generate(&e); + let user3 = Address::generate(&e); + + client.mint(&ctx.admin, &1000); + assert_eq!( + e.auths(), + std::vec![( + ctx.admin.clone(), + AuthorizedInvocation { + function: AuthorizedFunction::Contract(( + client.address.clone(), + symbol_short!("mint"), + (&ctx.admin, 1000_i128).into_val(e), + )), + sub_invocations: std::vec![] + } + )] + ); + assert_eq!(client.balance(&ctx.admin), 1000); + + client.approve(&ctx.admin, &user3, &500, &200); + assert_eq!( + e.auths(), + std::vec![( + ctx.admin.clone(), + AuthorizedInvocation { + function: AuthorizedFunction::Contract(( + client.address.clone(), + symbol_short!("approve"), + (&ctx.admin, &user3, 500_i128, 200_u32).into_val(e), + )), + sub_invocations: std::vec![] + } + )] + ); + assert_eq!(client.allowance(&ctx.admin, &user3), 500); + + client.transfer(&ctx.admin, &user2, &600); + assert_eq!( + e.auths(), + std::vec![( + ctx.admin.clone(), + AuthorizedInvocation { + function: AuthorizedFunction::Contract(( + client.address.clone(), + symbol_short!("transfer"), + (&ctx.admin, &user2, 600_i128).into_val(e), + )), + sub_invocations: std::vec![] + } + )] + ); + assert_eq!(client.balance(&ctx.admin), 400); + assert_eq!(client.balance(&user2), 600); + + client.transfer_from(&user3, &ctx.admin, &user1, &400); + assert_eq!( + e.auths(), + std::vec![( + user3.clone(), + AuthorizedInvocation { + function: AuthorizedFunction::Contract(( + client.address.clone(), + Symbol::new(&e, "transfer_from"), + (&user3, &ctx.admin, &user1, 400_i128).into_val(e), + )), + sub_invocations: std::vec![] + } + )] + ); + assert_eq!(client.balance(&user1), 400); + assert_eq!(client.balance(&user2), 600); + + client.transfer(&user1, &user3, &300); + assert_eq!(client.balance(&user1), 100); + assert_eq!(client.balance(&user3), 300); + + client.set_admin(&admin2); + assert_eq!( + e.auths(), + std::vec![( + ctx.admin.clone(), + AuthorizedInvocation { + function: AuthorizedFunction::Contract(( + client.address.clone(), + symbol_short!("set_admin"), + (&admin2,).into_val(e), + )), + sub_invocations: std::vec![] + } + )] + ); + + // Increase to 500 + client.approve(&user2, &user3, &500, &200); + assert_eq!(client.allowance(&user2, &user3), 500); + client.approve(&user2, &user3, &0, &200); + assert_eq!( + e.auths(), + std::vec![( + user2.clone(), + AuthorizedInvocation { + function: AuthorizedFunction::Contract(( + client.address.clone(), + symbol_short!("approve"), + (&user2, &user3, 0_i128, 200_u32).into_val(e), + )), + sub_invocations: std::vec![] + } + )] + ); + assert_eq!(client.allowance(&user2, &user3), 0); +} + +#[test] +fn test_burn() { + let ctx = TestContext::default(); + let client = BalancedDollarClient::new(&ctx.env, &ctx.registry); + let e = &ctx.env; + e.mock_all_auths(); + ctx.init_context(&client); + + + let user2 = Address::generate(&e); + //let token = create_token(&e, &admin); + + client.mint(&ctx.admin, &1000); + assert_eq!(client.balance(&ctx.admin), 1000); + + client.approve(&ctx.admin, &user2, &500, &200); + assert_eq!(client.allowance(&ctx.admin, &user2), 500); + + client.burn_from(&user2, &ctx.admin, &500); + assert_eq!( + e.auths(), + std::vec![( + user2.clone(), + AuthorizedInvocation { + function: AuthorizedFunction::Contract(( + client.address.clone(), + symbol_short!("burn_from"), + (&user2, &ctx.admin, 500_i128).into_val(e), + )), + sub_invocations: std::vec![] + } + )] + ); + + assert_eq!(client.allowance(&ctx.admin, &user2), 0); + assert_eq!(client.balance(&ctx.admin), 500); + assert_eq!(client.balance(&user2), 0); + + client.burn(&ctx.admin, &500); + + assert_eq!(client.balance(&ctx.admin), 0); + assert_eq!(client.balance(&user2), 0); +} + +#[test] +#[should_panic(expected = "insufficient balance")] +fn transfer_insufficient_balance() { + let ctx = TestContext::default(); + let client = BalancedDollarClient::new(&ctx.env, &ctx.registry); + let e = &ctx.env; + e.mock_all_auths(); + ctx.init_context(&client); + e.mock_all_auths(); + let user2 = Address::generate(&e); + + client.mint(&ctx.admin, &1000); + assert_eq!(client.balance(&ctx.admin), 1000); + + client.transfer(&ctx.admin, &user2, &1001); +} + +#[test] +#[should_panic(expected = "insufficient allowance")] +fn transfer_from_insufficient_allowance() { + let ctx = TestContext::default(); + let client = BalancedDollarClient::new(&ctx.env, &ctx.registry); + let e = &ctx.env; + e.mock_all_auths(); + ctx.init_context(&client); + let user2 = Address::generate(&e); + let user3 = Address::generate(&e); + + client.mint(&ctx.admin, &1000); + assert_eq!(client.balance(&ctx.admin), 1000); + + client.approve(&ctx.admin, &user3, &100, &200); + assert_eq!(client.allowance(&ctx.admin, &user3), 100); + + client.transfer_from(&user3, &ctx.admin, &user2, &101); +} + diff --git a/contracts/balanced_doller/src/xcall_manager_interface.rs b/contracts/balanced_dollar/src/xcall_manager_interface.rs similarity index 100% rename from contracts/balanced_doller/src/xcall_manager_interface.rs rename to contracts/balanced_dollar/src/xcall_manager_interface.rs diff --git a/contracts/balanced_doller/src/test.rs b/contracts/balanced_doller/src/test.rs deleted file mode 100644 index 77e6a47..0000000 --- a/contracts/balanced_doller/src/test.rs +++ /dev/null @@ -1,278 +0,0 @@ -#![cfg(test)] -extern crate std; - -use crate::{contract::BalancedDollar, BalancedDollarClient}; -use soroban_sdk::{ - symbol_short, - testutils::{Address as _, AuthorizedFunction, AuthorizedInvocation}, - Address, Env, IntoVal, String, Symbol, -}; - -fn create_token<'a>(e: &Env, admin: &Address) -> BalancedDollarClient<'a> { - let token = BalancedDollarClient::new(e, &e.register_contract(None, BalancedDollar {})); - - let xcall = Address::generate(&e.clone()); - let xcall_manager = Address::generate(&e.clone()); - let xcall_network_address = String::from_str(&e.clone(), "ste/address"); - let icon_bn_usd = String::from_str(&e.clone(), "icon/hxeoriweo"); - let nid = String::from_str(&e.clone(), "ste"); - - token.initialize( - &admin, - &xcall, - &xcall_manager, - &xcall_network_address, - &icon_bn_usd, - &nid, - ); - token -} - -#[test] -fn test() { - let e = Env::default(); - e.mock_all_auths(); - - let admin1 = Address::generate(&e); - let admin2 = Address::generate(&e); - let user1 = Address::generate(&e); - let user2 = Address::generate(&e); - let user3 = Address::generate(&e); - let token = create_token(&e, &admin1); - - token.mint(&user1, &1000); - assert_eq!( - e.auths(), - std::vec![( - admin1.clone(), - AuthorizedInvocation { - function: AuthorizedFunction::Contract(( - token.address.clone(), - symbol_short!("mint"), - (&user1, 1000_i128).into_val(&e), - )), - sub_invocations: std::vec![] - } - )] - ); - assert_eq!(token.balance(&user1), 1000); - - token.approve(&user2, &user3, &500, &200); - assert_eq!( - e.auths(), - std::vec![( - user2.clone(), - AuthorizedInvocation { - function: AuthorizedFunction::Contract(( - token.address.clone(), - symbol_short!("approve"), - (&user2, &user3, 500_i128, 200_u32).into_val(&e), - )), - sub_invocations: std::vec![] - } - )] - ); - assert_eq!(token.allowance(&user2, &user3), 500); - - token.transfer(&user1, &user2, &600); - assert_eq!( - e.auths(), - std::vec![( - user1.clone(), - AuthorizedInvocation { - function: AuthorizedFunction::Contract(( - token.address.clone(), - symbol_short!("transfer"), - (&user1, &user2, 600_i128).into_val(&e), - )), - sub_invocations: std::vec![] - } - )] - ); - assert_eq!(token.balance(&user1), 400); - assert_eq!(token.balance(&user2), 600); - - token.transfer_from(&user3, &user2, &user1, &400); - assert_eq!( - e.auths(), - std::vec![( - user3.clone(), - AuthorizedInvocation { - function: AuthorizedFunction::Contract(( - token.address.clone(), - Symbol::new(&e, "transfer_from"), - (&user3, &user2, &user1, 400_i128).into_val(&e), - )), - sub_invocations: std::vec![] - } - )] - ); - assert_eq!(token.balance(&user1), 800); - assert_eq!(token.balance(&user2), 200); - - token.transfer(&user1, &user3, &300); - assert_eq!(token.balance(&user1), 500); - assert_eq!(token.balance(&user3), 300); - - token.set_admin(&admin2); - assert_eq!( - e.auths(), - std::vec![( - admin1.clone(), - AuthorizedInvocation { - function: AuthorizedFunction::Contract(( - token.address.clone(), - symbol_short!("set_admin"), - (&admin2,).into_val(&e), - )), - sub_invocations: std::vec![] - } - )] - ); - - // Increase to 500 - token.approve(&user2, &user3, &500, &200); - assert_eq!(token.allowance(&user2, &user3), 500); - token.approve(&user2, &user3, &0, &200); - assert_eq!( - e.auths(), - std::vec![( - user2.clone(), - AuthorizedInvocation { - function: AuthorizedFunction::Contract(( - token.address.clone(), - symbol_short!("approve"), - (&user2, &user3, 0_i128, 200_u32).into_val(&e), - )), - sub_invocations: std::vec![] - } - )] - ); - assert_eq!(token.allowance(&user2, &user3), 0); -} - -#[test] -fn test_burn() { - let e = Env::default(); - e.mock_all_auths(); - - let admin = Address::generate(&e); - let user1 = Address::generate(&e); - let user2 = Address::generate(&e); - let token = create_token(&e, &admin); - - token.mint(&user1, &1000); - assert_eq!(token.balance(&user1), 1000); - - token.approve(&user1, &user2, &500, &200); - assert_eq!(token.allowance(&user1, &user2), 500); - - token.burn_from(&user2, &user1, &500); - assert_eq!( - e.auths(), - std::vec![( - user2.clone(), - AuthorizedInvocation { - function: AuthorizedFunction::Contract(( - token.address.clone(), - symbol_short!("burn_from"), - (&user2, &user1, 500_i128).into_val(&e), - )), - sub_invocations: std::vec![] - } - )] - ); - - assert_eq!(token.allowance(&user1, &user2), 0); - assert_eq!(token.balance(&user1), 500); - assert_eq!(token.balance(&user2), 0); - - token.burn(&user1, &500); - assert_eq!( - e.auths(), - std::vec![( - user1.clone(), - AuthorizedInvocation { - function: AuthorizedFunction::Contract(( - token.address.clone(), - symbol_short!("burn"), - (&user1, 500_i128).into_val(&e), - )), - sub_invocations: std::vec![] - } - )] - ); - - assert_eq!(token.balance(&user1), 0); - assert_eq!(token.balance(&user2), 0); -} - -#[test] -#[should_panic(expected = "insufficient balance")] -fn transfer_insufficient_balance() { - let e = Env::default(); - e.mock_all_auths(); - - let admin = Address::generate(&e); - let user1 = Address::generate(&e); - let user2 = Address::generate(&e); - let token = create_token(&e, &admin); - - token.mint(&user1, &1000); - assert_eq!(token.balance(&user1), 1000); - - token.transfer(&user1, &user2, &1001); -} - -#[test] -#[should_panic(expected = "insufficient allowance")] -fn transfer_from_insufficient_allowance() { - let e = Env::default(); - e.mock_all_auths(); - - let admin = Address::generate(&e); - let user1 = Address::generate(&e); - let user2 = Address::generate(&e); - let user3 = Address::generate(&e); - let token = create_token(&e, &admin); - - token.mint(&user1, &1000); - assert_eq!(token.balance(&user1), 1000); - - token.approve(&user1, &user3, &100, &200); - assert_eq!(token.allowance(&user1, &user3), 100); - - token.transfer_from(&user3, &user1, &user2, &101); -} - -#[test] -#[should_panic(expected = "already initialized")] -fn initialize_already_initialized() { - let e = Env::default(); - let admin = Address::generate(&e); - let token = create_token(&e, &admin); - - let xcall = Address::generate(&e.clone()); - let xcall_manager = Address::generate(&e.clone()); - let xcall_network_address = String::from_str(&e.clone(), "ste/address"); - let icon_bn_usd = String::from_str(&e.clone(), "icon/hxeoriweo"); - let nid = String::from_str(&e.clone(), "ste"); - - token.initialize( - &admin, - &xcall, - &xcall_manager, - &xcall_network_address, - &icon_bn_usd, - &nid, - ); - - token.initialize( - &admin, - &xcall, - &xcall_manager, - &xcall_network_address, - &icon_bn_usd, - &nid, - ); -} diff --git a/contracts/balanced_doller/src/tests/mod.rs b/contracts/balanced_doller/src/tests/mod.rs deleted file mode 100644 index 7918a54..0000000 --- a/contracts/balanced_doller/src/tests/mod.rs +++ /dev/null @@ -1,2 +0,0 @@ -pub mod setup; -pub mod balanced_dollar_test; \ No newline at end of file diff --git a/wasm/centralized_connection.wasm b/wasm/centralized_connection.wasm index 9a4fb1c2a6667d57cd9baa43aca6603038349925..23a847612803f9dcdbfc77a471ef23c9a3baf15f 100755 GIT binary patch delta 2145 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 R4{uoCZ0=fr%dTC){|BptJShMG From e07f372f7b8979eb5e1a91d54d09330224af18ab Mon Sep 17 00:00:00 2001 From: sagar sapkota Date: Wed, 4 Sep 2024 19:28:29 +0545 Subject: [PATCH 42/63] xcall param removed from handle call message of bnUSD and xcall manager --- .../balanced_dollar/src/balanced_dollar.rs | 5 +++-- contracts/balanced_dollar/src/contract.rs | 3 +-- .../src/tests/balanced_dollar_test.rs | 22 ++++++++++++------- contracts/xcall_manager/src/contract.rs | 1 - .../src/tests/xcall_manager_test.rs | 14 ++++++------ 5 files changed, 25 insertions(+), 20 deletions(-) diff --git a/contracts/balanced_dollar/src/balanced_dollar.rs b/contracts/balanced_dollar/src/balanced_dollar.rs index e2135bb..5c297d6 100644 --- a/contracts/balanced_dollar/src/balanced_dollar.rs +++ b/contracts/balanced_dollar/src/balanced_dollar.rs @@ -11,7 +11,7 @@ use crate::{ config::{get_config, set_config, ConfigData}, xcall_manager_interface::XcallManagerClient, }; -use soroban_rlp::address_utils::is_valid_bytes_address; +use soroban_rlp::address_utils::{get_address_from, is_valid_bytes_address}; use soroban_rlp::messages::{ cross_transfer::CrossTransfer, cross_transfer_revert::CrossTransferRevert, }; @@ -72,7 +72,6 @@ fn verify_protocol( pub fn _handle_call_message( e: Env, - xcall_address: Address, from: String, data: Bytes, protocols: Vec, @@ -91,6 +90,8 @@ pub fn _handle_call_message( let to_network_address: Address = get_address(message.to, &e)?; _mint(&e, to_network_address, message.amount as i128); } else if method == String::from_str(&e, &CROSS_TRANSFER_REVERT) { + let from_xcall = get_address_from(&from, &e); + let xcall_address = Address::from_string(&from_xcall.into()); if xcall != xcall_address { return Err(ContractError::OnlyCallService); } diff --git a/contracts/balanced_dollar/src/contract.rs b/contracts/balanced_dollar/src/contract.rs index bafd90a..0143c99 100644 --- a/contracts/balanced_dollar/src/contract.rs +++ b/contracts/balanced_dollar/src/contract.rs @@ -91,12 +91,11 @@ impl BalancedDollar { pub fn handle_call_message( e: Env, - xcall: Address, from: String, data: Bytes, protocols: Vec, ) -> Result<(), ContractError> { - return balanced_dollar::_handle_call_message(e, xcall, from, data, protocols); + return balanced_dollar::_handle_call_message(e, from, data, protocols); } pub fn is_initialized(e: Env) -> bool { diff --git a/contracts/balanced_dollar/src/tests/balanced_dollar_test.rs b/contracts/balanced_dollar/src/tests/balanced_dollar_test.rs index a5185ff..c60dc43 100644 --- a/contracts/balanced_dollar/src/tests/balanced_dollar_test.rs +++ b/contracts/balanced_dollar/src/tests/balanced_dollar_test.rs @@ -121,7 +121,7 @@ fn test_handle_call_message_for_cross_transfer() { assert_eq!(client.balance(withdrawer_address), 0); let sources = Vec::from_array(&ctx.env, [ctx.centralized_connection.to_string()]); - client.handle_call_message(&ctx.xcall, &ctx.icon_bn_usd, &data, &sources); + client.handle_call_message( &ctx.icon_bn_usd, &data, &sources); assert_eq!(client.balance(withdrawer_address), bnusd_amount as i128) } @@ -156,7 +156,7 @@ fn test_handle_call_message_for_cross_transfer_invalid_addres_fail() { // assert_eq!(client.balance(withdrawer_address), 0); let sources = Vec::from_array(&ctx.env, [ctx.centralized_connection.to_string()]); - client.handle_call_message(&ctx.xcall, &ctx.icon_bn_usd, &data, &sources); + client.handle_call_message(&ctx.icon_bn_usd, &data, &sources); // assert_eq!(client.balance(withdrawer_address), bnusd_amount as i128) } @@ -197,7 +197,7 @@ fn test_handle_call_message_for_cross_transfer_panic_for_protocol_mismatch() { assert_eq!(client.balance(withdrawer_address), 0); let sources = Vec::from_array(&ctx.env, [ctx.xcall.to_string()]); - client.handle_call_message(&ctx.xcall, &ctx.icon_bn_usd, &data, &sources); + client.handle_call_message( &ctx.icon_bn_usd, &data, &sources); assert_eq!(client.balance(withdrawer_address), bnusd_amount as i128) } @@ -239,7 +239,7 @@ fn test_handle_call_message_for_cross_transfer_panic_for_icon_bnusd() { assert_eq!(client.balance(withdrawer_address), 0); let sources = Vec::from_array(&ctx.env, [ctx.centralized_connection.to_string()]); - client.handle_call_message(&ctx.xcall, &ctx.icon_governance, &data, &sources); + client.handle_call_message( &ctx.icon_governance, &data, &sources); assert_eq!(client.balance(withdrawer_address), bnusd_amount as i128) } @@ -282,7 +282,7 @@ fn test_handle_call_message_for_cross_transfer_panic_for_wront_message_type() { assert_eq!(client.balance(withdrawer_address), 0); let sources = Vec::from_array(&ctx.env, [ctx.centralized_connection.to_string()]); - client.handle_call_message(&ctx.xcall, &ctx.icon_bn_usd, &data, &sources); + client.handle_call_message( &ctx.icon_bn_usd, &data, &sources); assert_eq!(client.balance(withdrawer_address), bnusd_amount as i128) } @@ -306,7 +306,6 @@ fn test_handle_call_message_for_cross_transfer_revert() { let sources = Vec::from_array(&ctx.env, [ctx.centralized_connection.to_string()]); client.handle_call_message( - &ctx.xcall, &ctx.xcall_client.get_network_address(), &data, &sources, @@ -334,9 +333,16 @@ fn test_handle_call_message_for_cross_transfer_revert_panic_for_xcall() { assert_eq!(client.balance(&ctx.withdrawer), 0); let sources = Vec::from_array(&ctx.env, [ctx.centralized_connection.to_string()]); + let wrong_network_address: String = String::from_str( + &ctx.env, + &std::format!( + "{}/{}", + "soroban", + "CBEPDNVYXQGWB5YUBXKJWYJA7OXTZW5LFLNO5JRRGE6Z6C5OSUZPCCEL" + ), + ); client.handle_call_message( - &ctx.centralized_connection, - &ctx.xcall_client.get_network_address(), + &wrong_network_address, &data, &sources, ); diff --git a/contracts/xcall_manager/src/contract.rs b/contracts/xcall_manager/src/contract.rs index e674f36..90fc63c 100644 --- a/contracts/xcall_manager/src/contract.rs +++ b/contracts/xcall_manager/src/contract.rs @@ -131,7 +131,6 @@ impl XcallManager { pub fn handle_call_message( e: Env, - _xcall: Address, from: String, data: Bytes, protocols: Vec, diff --git a/contracts/xcall_manager/src/tests/xcall_manager_test.rs b/contracts/xcall_manager/src/tests/xcall_manager_test.rs index 33813e5..2083eef 100644 --- a/contracts/xcall_manager/src/tests/xcall_manager_test.rs +++ b/contracts/xcall_manager/src/tests/xcall_manager_test.rs @@ -127,7 +127,7 @@ fn test_handle_call_message_for_configure_protocols_panic_for_action_not_whiteli assert_eq!(decoded.sources, sources); assert_eq!(decoded.destinations, destinations); let (s, _) = client.get_protocols(); - client.handle_call_message(&ctx.xcall, &ctx.icon_governance, &data, &s); + client.handle_call_message( &ctx.icon_governance, &data, &s); let (s, d) = client.get_protocols(); assert_eq!(s, sources); @@ -158,7 +158,7 @@ fn test_handle_call_message_for_configure_protocols() { assert_eq!(decoded.sources, sources); assert_eq!(decoded.destinations, destinations); let (s, _) = client.get_protocols(); - client.handle_call_message(&ctx.xcall, &ctx.icon_governance, &data, &s); + client.handle_call_message( &ctx.icon_governance, &data, &s); let (s, d) = client.get_protocols(); assert_eq!(s, sources); @@ -200,7 +200,7 @@ fn test_get_modified_proposals() { .encode(&ctx.env, String::from_str(&ctx.env, "ConfigureProtocols")); client.white_list_actions(&data); let (s, _) = client.get_protocols(); - client.handle_call_message(&ctx.xcall, &ctx.icon_governance, &data, &s); + client.handle_call_message( &ctx.icon_governance, &data, &s); client.propose_removal(&String::from_str(&ctx.env, "stellar/address")); @@ -230,7 +230,7 @@ fn test_get_modified_proposals_panic_no_proposed_removal() { .encode(&ctx.env, String::from_str(&ctx.env, "ConfigureProtocols")); client.white_list_actions(&data); let (s, _) = client.get_protocols(); - client.handle_call_message(&ctx.xcall, &ctx.icon_governance, &data, &s); + client.handle_call_message(&ctx.icon_governance, &data, &s); let updated_protocal = vec![&ctx.env, String::from_str(&ctx.env, "stellar/address1")]; assert_eq!(updated_protocal, client.get_modified_protocols()); @@ -261,7 +261,7 @@ fn test_handle_call_message_for_configure_protocols_panic_for_only_icon_governan assert_eq!(decoded.sources, sources); assert_eq!(decoded.destinations, destinations); let (s, _) = client.get_protocols(); - client.handle_call_message(&ctx.xcall, &ctx.xcall_network_address, &data, &s); + client.handle_call_message(&ctx.xcall_network_address, &data, &s); let (s, d) = client.get_protocols(); assert_eq!(s, sources); @@ -293,7 +293,7 @@ fn test_handle_call_message_for_configure_protocols_panic_for_protocol_mismatch( assert_eq!(decoded.sources, sources); assert_eq!(decoded.destinations, destinations); let s = Vec::from_array(&ctx.env, [ctx.xcall.to_string()]); - client.handle_call_message(&ctx.xcall, &ctx.icon_governance, &data, &s); + client.handle_call_message( &ctx.icon_governance, &data, &s); let (s, d) = client.get_protocols(); assert_eq!(s, sources); @@ -328,7 +328,7 @@ fn test_handle_call_message_for_configure_protocols_panic_for_unknown_mesage_typ assert_eq!(decoded.sources, sources); assert_eq!(decoded.destinations, destinations); let s = Vec::from_array(&ctx.env, [ctx.centralized_connection.to_string()]); - client.handle_call_message(&ctx.xcall, &ctx.icon_governance, &data, &s); + client.handle_call_message(&ctx.icon_governance, &data, &s); let (s, d) = client.get_protocols(); assert_eq!(s, sources); From 67ef0ec7afb1eba5b57a83331c035c5c7155f81e Mon Sep 17 00:00:00 2001 From: sagar sapkota Date: Fri, 6 Sep 2024 13:26:19 +0545 Subject: [PATCH 43/63] balanced messages separated from rlp lib --- .gitignore | 3 +- contracts/asset_manager/src/contract.rs | 4 +- .../src/tests/asset_manager_test.rs | 2 +- .../Cargo.toml | 0 .../src/allowance.rs | 0 .../src/balance.rs | 0 .../src/balanced_dollar.rs | 4 +- .../src/config.rs | 0 .../src/contract.rs | 0 .../src/errors.rs | 0 .../src/lib.rs | 0 .../src/metadata.rs | 0 .../src/states.rs | 0 .../src/storage_types.rs | 0 .../src/tests/balanced_dollar_test.rs | 2 +- .../src/tests/mod.rs | 0 .../src/tests/setup.rs | 0 .../src/tests/test.rs | 2 +- .../src/xcall_manager_interface.rs | 0 contracts/xcall_manager/src/contract.rs | 15 +---- .../src/tests/xcall_manager_test.rs | 2 +- .../src/{ => balanced}/address_utils.rs | 0 .../messages/configure_protocols.rs | 0 .../{ => balanced}/messages/cross_transfer.rs | 0 .../messages/cross_transfer_revert.rs | 0 .../src/{ => balanced}/messages/deposit.rs | 0 .../{ => balanced}/messages/deposit_revert.rs | 0 .../src/{ => balanced}/messages/mod.rs | 1 - .../{ => balanced}/messages/withdraw_to.rs | 0 libs/soroban-rlp/src/balanced/mod.rs | 2 + libs/soroban-rlp/src/lib.rs | 3 +- libs/soroban-rlp/src/messages/execute.rs | 52 ------------------ wasm/centralized_connection.wasm | Bin 12662 -> 12782 bytes wasm/xcall.wasm | Bin 27372 -> 27794 bytes 34 files changed, 15 insertions(+), 77 deletions(-) rename contracts/{balanced_dollar => balanced_doller}/Cargo.toml (100%) rename contracts/{balanced_dollar => balanced_doller}/src/allowance.rs (100%) rename contracts/{balanced_dollar => balanced_doller}/src/balance.rs (100%) rename contracts/{balanced_dollar => balanced_doller}/src/balanced_dollar.rs (97%) rename contracts/{balanced_dollar => balanced_doller}/src/config.rs (100%) rename contracts/{balanced_dollar => balanced_doller}/src/contract.rs (100%) rename contracts/{balanced_dollar => balanced_doller}/src/errors.rs (100%) rename contracts/{balanced_dollar => balanced_doller}/src/lib.rs (100%) rename contracts/{balanced_dollar => balanced_doller}/src/metadata.rs (100%) rename contracts/{balanced_dollar => balanced_doller}/src/states.rs (100%) rename contracts/{balanced_dollar => balanced_doller}/src/storage_types.rs (100%) rename contracts/{balanced_dollar => balanced_doller}/src/tests/balanced_dollar_test.rs (99%) rename contracts/{balanced_dollar => balanced_doller}/src/tests/mod.rs (100%) rename contracts/{balanced_dollar => balanced_doller}/src/tests/setup.rs (100%) rename contracts/{balanced_dollar => balanced_doller}/src/tests/test.rs (99%) rename contracts/{balanced_dollar => balanced_doller}/src/xcall_manager_interface.rs (100%) rename libs/soroban-rlp/src/{ => balanced}/address_utils.rs (100%) rename libs/soroban-rlp/src/{ => balanced}/messages/configure_protocols.rs (100%) rename libs/soroban-rlp/src/{ => balanced}/messages/cross_transfer.rs (100%) rename libs/soroban-rlp/src/{ => balanced}/messages/cross_transfer_revert.rs (100%) rename libs/soroban-rlp/src/{ => balanced}/messages/deposit.rs (100%) rename libs/soroban-rlp/src/{ => balanced}/messages/deposit_revert.rs (100%) rename libs/soroban-rlp/src/{ => balanced}/messages/mod.rs (89%) rename libs/soroban-rlp/src/{ => balanced}/messages/withdraw_to.rs (100%) create mode 100644 libs/soroban-rlp/src/balanced/mod.rs delete mode 100644 libs/soroban-rlp/src/messages/execute.rs mode change 100755 => 100644 wasm/centralized_connection.wasm mode change 100755 => 100644 wasm/xcall.wasm diff --git a/.gitignore b/.gitignore index 9a00312..2be4200 100644 --- a/.gitignore +++ b/.gitignore @@ -8,4 +8,5 @@ target # macOS-specific files .DS_Store Cargo.lock -test_snapshots \ No newline at end of file +test_snapshots +.VSCodeCounter \ No newline at end of file diff --git a/contracts/asset_manager/src/contract.rs b/contracts/asset_manager/src/contract.rs index 803f77a..791e460 100644 --- a/contracts/asset_manager/src/contract.rs +++ b/contracts/asset_manager/src/contract.rs @@ -16,8 +16,8 @@ use crate::{ storage_types::{DataKey, POINTS}, xcall_manager_interface::XcallManagerClient, }; -use soroban_rlp::address_utils::{get_address_from, is_valid_string_address}; -use soroban_rlp::messages::{ +use soroban_rlp::balanced::address_utils::{get_address_from, is_valid_string_address}; +use soroban_rlp::balanced::messages::{ deposit::Deposit, deposit_revert::DepositRevert, withdraw_to::WithdrawTo, }; diff --git a/contracts/asset_manager/src/tests/asset_manager_test.rs b/contracts/asset_manager/src/tests/asset_manager_test.rs index 7027437..a90416d 100644 --- a/contracts/asset_manager/src/tests/asset_manager_test.rs +++ b/contracts/asset_manager/src/tests/asset_manager_test.rs @@ -7,7 +7,7 @@ use soroban_sdk::{ token, Address, Bytes, IntoVal, String, Symbol, Vec, }; -use soroban_rlp::messages::{deposit_revert::DepositRevert, withdraw_to::WithdrawTo}; +use soroban_rlp::balanced::messages::{deposit_revert::DepositRevert, withdraw_to::WithdrawTo}; use super::setup::*; diff --git a/contracts/balanced_dollar/Cargo.toml b/contracts/balanced_doller/Cargo.toml similarity index 100% rename from contracts/balanced_dollar/Cargo.toml rename to contracts/balanced_doller/Cargo.toml diff --git a/contracts/balanced_dollar/src/allowance.rs b/contracts/balanced_doller/src/allowance.rs similarity index 100% rename from contracts/balanced_dollar/src/allowance.rs rename to contracts/balanced_doller/src/allowance.rs diff --git a/contracts/balanced_dollar/src/balance.rs b/contracts/balanced_doller/src/balance.rs similarity index 100% rename from contracts/balanced_dollar/src/balance.rs rename to contracts/balanced_doller/src/balance.rs diff --git a/contracts/balanced_dollar/src/balanced_dollar.rs b/contracts/balanced_doller/src/balanced_dollar.rs similarity index 97% rename from contracts/balanced_dollar/src/balanced_dollar.rs rename to contracts/balanced_doller/src/balanced_dollar.rs index 5c297d6..9aa2231 100644 --- a/contracts/balanced_dollar/src/balanced_dollar.rs +++ b/contracts/balanced_doller/src/balanced_dollar.rs @@ -11,8 +11,8 @@ use crate::{ config::{get_config, set_config, ConfigData}, xcall_manager_interface::XcallManagerClient, }; -use soroban_rlp::address_utils::{get_address_from, is_valid_bytes_address}; -use soroban_rlp::messages::{ +use soroban_rlp::balanced::address_utils::{get_address_from, is_valid_bytes_address}; +use soroban_rlp::balanced::messages::{ cross_transfer::CrossTransfer, cross_transfer_revert::CrossTransferRevert, }; use soroban_token_sdk::TokenUtils; diff --git a/contracts/balanced_dollar/src/config.rs b/contracts/balanced_doller/src/config.rs similarity index 100% rename from contracts/balanced_dollar/src/config.rs rename to contracts/balanced_doller/src/config.rs diff --git a/contracts/balanced_dollar/src/contract.rs b/contracts/balanced_doller/src/contract.rs similarity index 100% rename from contracts/balanced_dollar/src/contract.rs rename to contracts/balanced_doller/src/contract.rs diff --git a/contracts/balanced_dollar/src/errors.rs b/contracts/balanced_doller/src/errors.rs similarity index 100% rename from contracts/balanced_dollar/src/errors.rs rename to contracts/balanced_doller/src/errors.rs diff --git a/contracts/balanced_dollar/src/lib.rs b/contracts/balanced_doller/src/lib.rs similarity index 100% rename from contracts/balanced_dollar/src/lib.rs rename to contracts/balanced_doller/src/lib.rs diff --git a/contracts/balanced_dollar/src/metadata.rs b/contracts/balanced_doller/src/metadata.rs similarity index 100% rename from contracts/balanced_dollar/src/metadata.rs rename to contracts/balanced_doller/src/metadata.rs diff --git a/contracts/balanced_dollar/src/states.rs b/contracts/balanced_doller/src/states.rs similarity index 100% rename from contracts/balanced_dollar/src/states.rs rename to contracts/balanced_doller/src/states.rs diff --git a/contracts/balanced_dollar/src/storage_types.rs b/contracts/balanced_doller/src/storage_types.rs similarity index 100% rename from contracts/balanced_dollar/src/storage_types.rs rename to contracts/balanced_doller/src/storage_types.rs diff --git a/contracts/balanced_dollar/src/tests/balanced_dollar_test.rs b/contracts/balanced_doller/src/tests/balanced_dollar_test.rs similarity index 99% rename from contracts/balanced_dollar/src/tests/balanced_dollar_test.rs rename to contracts/balanced_doller/src/tests/balanced_dollar_test.rs index c60dc43..7f966ce 100644 --- a/contracts/balanced_dollar/src/tests/balanced_dollar_test.rs +++ b/contracts/balanced_doller/src/tests/balanced_dollar_test.rs @@ -4,7 +4,7 @@ extern crate std; use crate::contract::BalancedDollarClient; use super::setup::*; -use soroban_rlp::messages::{ +use soroban_rlp::balanced::messages::{ cross_transfer::CrossTransfer, cross_transfer_revert::CrossTransferRevert, }; use soroban_sdk::{ diff --git a/contracts/balanced_dollar/src/tests/mod.rs b/contracts/balanced_doller/src/tests/mod.rs similarity index 100% rename from contracts/balanced_dollar/src/tests/mod.rs rename to contracts/balanced_doller/src/tests/mod.rs diff --git a/contracts/balanced_dollar/src/tests/setup.rs b/contracts/balanced_doller/src/tests/setup.rs similarity index 100% rename from contracts/balanced_dollar/src/tests/setup.rs rename to contracts/balanced_doller/src/tests/setup.rs diff --git a/contracts/balanced_dollar/src/tests/test.rs b/contracts/balanced_doller/src/tests/test.rs similarity index 99% rename from contracts/balanced_dollar/src/tests/test.rs rename to contracts/balanced_doller/src/tests/test.rs index dc38f25..692479f 100644 --- a/contracts/balanced_dollar/src/tests/test.rs +++ b/contracts/balanced_doller/src/tests/test.rs @@ -3,6 +3,7 @@ extern crate std; use crate::contract::BalancedDollarClient; + use soroban_sdk::{ symbol_short, testutils::{Address as _, AuthorizedFunction, AuthorizedInvocation}, @@ -146,7 +147,6 @@ fn test_burn() { let user2 = Address::generate(&e); - //let token = create_token(&e, &admin); client.mint(&ctx.admin, &1000); assert_eq!(client.balance(&ctx.admin), 1000); diff --git a/contracts/balanced_dollar/src/xcall_manager_interface.rs b/contracts/balanced_doller/src/xcall_manager_interface.rs similarity index 100% rename from contracts/balanced_dollar/src/xcall_manager_interface.rs rename to contracts/balanced_doller/src/xcall_manager_interface.rs diff --git a/contracts/xcall_manager/src/contract.rs b/contracts/xcall_manager/src/contract.rs index 90fc63c..0eb8f1d 100644 --- a/contracts/xcall_manager/src/contract.rs +++ b/contracts/xcall_manager/src/contract.rs @@ -10,7 +10,7 @@ use crate::{ write_proposed_removed, write_registry, write_sources, }, storage_types::DataKey, white_list_actions::WhiteListActions }; -use soroban_rlp::messages::configure_protocols::ConfigureProtocols; +use soroban_rlp::balanced::messages::configure_protocols::ConfigureProtocols; use crate::errors::ContractError; @@ -34,21 +34,10 @@ impl XcallManager { } write_registry(&env, ®istry); write_administrator(&env, &admin); - Self::configure(env, config, sources, destinations); - } - - pub fn configure( - env: Env, - config: ConfigData, - sources: Vec, - destinations: Vec, - ) { - let admin = read_administrator(&env); - admin.require_auth(); - set_config(&env, config); write_sources(&env, &sources); write_destinations(&env, &destinations); + } pub fn get_config(env: Env) -> ConfigData { diff --git a/contracts/xcall_manager/src/tests/xcall_manager_test.rs b/contracts/xcall_manager/src/tests/xcall_manager_test.rs index 2083eef..0466451 100644 --- a/contracts/xcall_manager/src/tests/xcall_manager_test.rs +++ b/contracts/xcall_manager/src/tests/xcall_manager_test.rs @@ -4,7 +4,7 @@ extern crate std; use crate::contract::XcallManagerClient; use super::setup::*; -use soroban_rlp::messages::configure_protocols::ConfigureProtocols; +use soroban_rlp::balanced::messages::configure_protocols::ConfigureProtocols; use soroban_sdk::{ symbol_short, testutils::{Address as _, AuthorizedFunction, AuthorizedInvocation}, diff --git a/libs/soroban-rlp/src/address_utils.rs b/libs/soroban-rlp/src/balanced/address_utils.rs similarity index 100% rename from libs/soroban-rlp/src/address_utils.rs rename to libs/soroban-rlp/src/balanced/address_utils.rs diff --git a/libs/soroban-rlp/src/messages/configure_protocols.rs b/libs/soroban-rlp/src/balanced/messages/configure_protocols.rs similarity index 100% rename from libs/soroban-rlp/src/messages/configure_protocols.rs rename to libs/soroban-rlp/src/balanced/messages/configure_protocols.rs diff --git a/libs/soroban-rlp/src/messages/cross_transfer.rs b/libs/soroban-rlp/src/balanced/messages/cross_transfer.rs similarity index 100% rename from libs/soroban-rlp/src/messages/cross_transfer.rs rename to libs/soroban-rlp/src/balanced/messages/cross_transfer.rs diff --git a/libs/soroban-rlp/src/messages/cross_transfer_revert.rs b/libs/soroban-rlp/src/balanced/messages/cross_transfer_revert.rs similarity index 100% rename from libs/soroban-rlp/src/messages/cross_transfer_revert.rs rename to libs/soroban-rlp/src/balanced/messages/cross_transfer_revert.rs diff --git a/libs/soroban-rlp/src/messages/deposit.rs b/libs/soroban-rlp/src/balanced/messages/deposit.rs similarity index 100% rename from libs/soroban-rlp/src/messages/deposit.rs rename to libs/soroban-rlp/src/balanced/messages/deposit.rs diff --git a/libs/soroban-rlp/src/messages/deposit_revert.rs b/libs/soroban-rlp/src/balanced/messages/deposit_revert.rs similarity index 100% rename from libs/soroban-rlp/src/messages/deposit_revert.rs rename to libs/soroban-rlp/src/balanced/messages/deposit_revert.rs diff --git a/libs/soroban-rlp/src/messages/mod.rs b/libs/soroban-rlp/src/balanced/messages/mod.rs similarity index 89% rename from libs/soroban-rlp/src/messages/mod.rs rename to libs/soroban-rlp/src/balanced/messages/mod.rs index d47f963..c11ac92 100644 --- a/libs/soroban-rlp/src/messages/mod.rs +++ b/libs/soroban-rlp/src/balanced/messages/mod.rs @@ -4,5 +4,4 @@ pub mod withdraw_to; pub mod cross_transfer; pub mod cross_transfer_revert; pub mod configure_protocols; -pub mod execute; diff --git a/libs/soroban-rlp/src/messages/withdraw_to.rs b/libs/soroban-rlp/src/balanced/messages/withdraw_to.rs similarity index 100% rename from libs/soroban-rlp/src/messages/withdraw_to.rs rename to libs/soroban-rlp/src/balanced/messages/withdraw_to.rs diff --git a/libs/soroban-rlp/src/balanced/mod.rs b/libs/soroban-rlp/src/balanced/mod.rs new file mode 100644 index 0000000..2f5876d --- /dev/null +++ b/libs/soroban-rlp/src/balanced/mod.rs @@ -0,0 +1,2 @@ +pub mod address_utils; +pub mod messages; diff --git a/libs/soroban-rlp/src/lib.rs b/libs/soroban-rlp/src/lib.rs index ab2eac6..514036a 100644 --- a/libs/soroban-rlp/src/lib.rs +++ b/libs/soroban-rlp/src/lib.rs @@ -1,6 +1,5 @@ #![no_std] -pub mod address_utils; pub mod decoder; pub mod encoder; -pub mod messages; mod utils; +pub mod balanced; diff --git a/libs/soroban-rlp/src/messages/execute.rs b/libs/soroban-rlp/src/messages/execute.rs deleted file mode 100644 index 4af0ea8..0000000 --- a/libs/soroban-rlp/src/messages/execute.rs +++ /dev/null @@ -1,52 +0,0 @@ -use soroban_sdk::{contracttype, Env, String, Bytes, Vec, Address}; -use crate::encoder; -use crate::decoder; - -#[derive(Clone)] -#[contracttype] -pub struct Execute { - pub contract_address: Address, - pub data: Bytes -} - -impl Execute{ - pub fn new(contract_address: Address, data: Bytes) -> Self { - Self { - contract_address, - data - } - } - - pub fn contract_address(&self) -> &Address { - &self.contract_address - } - - pub fn data(&self) -> &Bytes { - &self.data - } - - pub fn encode(&self, e: &Env, method: String) -> Bytes { - let mut list: Vec = Vec::new(&e); - list.push_back(encoder::encode_string(&e, method)); - list.push_back(encoder::encode_string(&e, self.contract_address.clone().to_string() )); - list.push_back(encoder::encode(&e, self.data.clone())); - - let encoded = encoder::encode_list(&e, list, false); - encoded - } - - pub fn decode(e: &Env, bytes: Bytes) -> Execute { - let decoded = decoder::decode_list(&e, bytes); - if decoded.len() != 3 { - panic!("InvalidRlpLength"); - } - - let contract_address = Address::from_string(&decoder::decode_string(e, decoded.get(1).unwrap())); - let data = decoded.get(2).unwrap(); - - Self { - contract_address, - data - } - } -} \ No newline at end of file diff --git a/wasm/centralized_connection.wasm b/wasm/centralized_connection.wasm old mode 100755 new mode 100644 index 23a847612803f9dcdbfc77a471ef23c9a3baf15f..9a4fb1c2a6667d57cd9baa43aca6603038349925 GIT binary patch delta 2375 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 R4{uoCZ0=fr%dTC){|BptJShMG literal 27372 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 Date: Fri, 6 Sep 2024 15:38:57 +0545 Subject: [PATCH 44/63] stellar deviation doc added --- docs.md | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) create mode 100644 docs.md diff --git a/docs.md b/docs.md new file mode 100644 index 0000000..73c1457 --- /dev/null +++ b/docs.md @@ -0,0 +1,27 @@ + +**Balanced Stellar spoke contracts** + +This document outlines the major changes in the implementation of Balanced in the Stellar blockchain and the rationale behind these changes. Key updates includes the merge of `deposit native` and `deposit` method on AssetManager contract, introduction of `extend_ttl` method on all contracts, introduction of `upgrade` method to upgrade the contract etc + +For more details on each spoke contracts see: [Balanced Crosschain Docs](https://github.com/balancednetwork/balanced-java-contracts/blob/420-balanced-docs/docs/crosschain.md) + + +For more details on the Balanced Protocol see [Balanced Docs](https://github.com/balancednetwork/balanced-java-contracts/blob/420-balanced-docs/docs/docs.md) or [Balanced Network](https://balanced.network/) + + + +1. **Merge of `deposit native` and `deposit` method** +**Change:** The methods deposit and deposit native are commonly available on AssetManager contract in other languages, but in stellar(also in SUI) both are merge and deposit method has been used as merged method. + +**Rationale:** +* The stellar native token can be accessed by Stellar Asset Contract (SAC) and the SAC contract address can be used for the token activities, the same way the Stellar Token Contract (STC) is used for the token activities + +2. **Introduction of `extend_ttl` method** +**Change:** New method extend_ttl has been introduced on stellar contracts, which will be used to extend ttl of the storages by the contract admin by paying the required rent periodically (however there is not authentication, anyone can extend the ttl) + +**Rationale:** There are three types of the storages in stellar, Temporary Storage, Instance Storage and Persistence Storage. Balanced has used Instance Storage and Persistence Storage, Temporary Storage has not been required in balanced. The rent paying by user does not seem logical as the applicability of rent is not per transaction but for specified period, In which many users can make transactions. For the reason, it is designed in the balanced such that rent will be paid by the admin periodically + +3. **Introduction of `upgrade` method** +**Change:** `upgrade` method has been introduced in the balanced stellar contracts + +**Rationale:** The upgrade mechanism of stellar contract is different from upgrade mechanism of contracts written on other languages. Stellar contracts can be upgraded simply sending the reference of the hash of the newly installed WASM to the `upgrade` method of the stellar contract. \ No newline at end of file From ab42a3f05c1620da02541213fd2d358adcfa1b77 Mon Sep 17 00:00:00 2001 From: sagar sapkota Date: Fri, 6 Sep 2024 16:14:11 +0545 Subject: [PATCH 45/63] rlp decoder issue fixed for empty byte array --- libs/soroban-rlp/src/decoder.rs | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/libs/soroban-rlp/src/decoder.rs b/libs/soroban-rlp/src/decoder.rs index 92c2959..37b8340 100644 --- a/libs/soroban-rlp/src/decoder.rs +++ b/libs/soroban-rlp/src/decoder.rs @@ -82,13 +82,16 @@ pub fn decode_list(env: &Env, list: Bytes) -> Vec { let data_bytes_len = (byte - 0xf7) as u64; let len_bytes = slice_vector(&env, encoded.clone(), i as u64 + 1, data_bytes_len); let len = bytes_to_u64(len_bytes); - - decoded.push_back(slice_vector( - &env, - encoded.clone(), - i as u64, - data_bytes_len + len + 1, - )); + if byte == 0xf8 && len == 0 { + decoded.push_back(Bytes::new(&env)); + } else { + decoded.push_back(slice_vector( + &env, + encoded.clone(), + i as u64, + data_bytes_len + len + 1, + )); + } i = i + (data_bytes_len + len + 1) as u32 } else { panic!("invalid rlp byte length") From 1a1c5837f5383eaa425385a055588b4914359f51 Mon Sep 17 00:00:00 2001 From: sagar sapkota Date: Sun, 8 Sep 2024 14:43:16 +0545 Subject: [PATCH 46/63] token data data structure optimized and tested --- contracts/asset_manager/src/contract.rs | 57 +++++++---------- contracts/asset_manager/src/states.rs | 63 +++---------------- contracts/asset_manager/src/storage_types.rs | 14 +++-- .../src/tests/asset_manager_test.rs | 38 +++++------ contracts/asset_manager/src/tests/setup.rs | 6 +- contracts/xcall_manager/src/contract.rs | 4 +- 6 files changed, 68 insertions(+), 114 deletions(-) diff --git a/contracts/asset_manager/src/contract.rs b/contracts/asset_manager/src/contract.rs index 791e460..64862ec 100644 --- a/contracts/asset_manager/src/contract.rs +++ b/contracts/asset_manager/src/contract.rs @@ -5,13 +5,12 @@ mod xcall { soroban_sdk::contractimport!(file = "../../wasm/xcall.wasm"); } use crate::errors::ContractError; +use crate::storage_types::TokenData; use crate::{ config::{get_config, set_config, ConfigData}, states::{ - extent_ttl, has_registry, read_administrator, read_token_last_current_limit, - read_token_last_update, read_token_percentage, read_token_period, read_tokens, - write_administrator, write_registry, write_token_current_limit, write_token_last_update, - write_token_percentage, write_token_period, write_tokens, + extent_ttl, has_registry, read_administrator, read_token_data, read_tokens, + write_administrator, write_registry, write_token_data, write_tokens, }, storage_types::{DataKey, POINTS}, xcall_manager_interface::XcallManagerClient, @@ -67,8 +66,8 @@ impl AssetManager { pub fn configure_rate_limit( env: Env, token_address: Address, - period: u128, - percentage: u128, + period: u64, + percentage: u32, ) -> Result<(), ContractError> { let admin = read_administrator(&env); admin.require_auth(); @@ -79,37 +78,28 @@ impl AssetManager { write_tokens(&env, token_address.clone()); } - if percentage > POINTS { + if percentage > POINTS as u32 { return Err(ContractError::PercentageShouldBeLessThanOrEqualToPOINTS); } - let token_client = token::Client::new(&env, &token_address); - let contract_token_balance = token_client.balance(&env.current_contract_address()); - - write_token_period(&env, &token_address, period); - write_token_percentage(&env, &token_address, percentage); - write_token_last_update(&env, &token_address, env.ledger().timestamp()); - write_token_current_limit( - &env, - &token_address, - (contract_token_balance as u128) * percentage / POINTS, - ); + + write_token_data(&env, token_address, TokenData{period, percentage, last_update: env.ledger().timestamp(), current_limit: 0}); Ok(()) } - pub fn get_rate_limit(env: Env, token_address: Address) -> (u128, u128, u64, u128) { + pub fn get_rate_limit(env: Env, token_address: Address) -> (u64, u32, u64, u64) { + let data: TokenData = read_token_data(&env, token_address).unwrap(); ( - read_token_period(&env, &token_address), - read_token_percentage(&env, &token_address), - read_token_last_update(&env, &token_address), - read_token_last_current_limit(&env, &token_address), + data.period, + data.percentage, + data.last_update, + data.current_limit ) } pub fn reset_limit(env: Env, token: Address) { let balance = Self::get_token_balance(&env, token.clone()); - let percentage: u128 = read_token_percentage(&env, &token); - - write_token_current_limit(&env, &token, balance * percentage / POINTS); + let mut data: TokenData = read_token_data(&env, token).unwrap(); + data.current_limit = (balance * data.percentage as u128 / POINTS) as u64; } pub fn get_withdraw_limit(env: Env, token: Address) -> Result { @@ -128,9 +118,9 @@ impl AssetManager { if balance - amount < limit { panic_with_error!(&env, ContractError::ExceedsWithdrawLimit); }; - - write_token_current_limit(&env, &token.clone(), limit); - write_token_last_update(&env, &token.clone(), env.ledger().timestamp()); + let mut data: TokenData = read_token_data(&env, token).unwrap(); + data.current_limit = limit as u64; + data.last_update = env.ledger().timestamp(); Ok(true) } @@ -139,8 +129,9 @@ impl AssetManager { balance: u128, token: Address, ) -> Result { - let period: u128 = read_token_period(env, &token.clone()); - let percentage: u128 = read_token_percentage(env, &token.clone()); + let data: TokenData = read_token_data(&env, token).unwrap(); + let period: u128 = data.period as u128; + let percentage: u128 = data.percentage as u128; if period == 0 { return Ok(0); } @@ -148,11 +139,11 @@ impl AssetManager { let min_reserve = (balance * percentage) / POINTS; let max_withdraw = balance - min_reserve; - let last_update: u64 = read_token_last_update(&env, &token.clone()); + let last_update: u64 = data.last_update; let time_diff = (&env.ledger().timestamp() - last_update) / 1000; let allowed_withdrawal = (max_withdraw * time_diff as u128) / period; - let mut reserve: u128 = read_token_last_current_limit(&env, &token.clone()); + let mut reserve: u128 = data.current_limit as u128; if reserve > allowed_withdrawal { reserve = reserve - allowed_withdrawal; diff --git a/contracts/asset_manager/src/states.rs b/contracts/asset_manager/src/states.rs index eb06737..bfc7ee4 100644 --- a/contracts/asset_manager/src/states.rs +++ b/contracts/asset_manager/src/states.rs @@ -1,6 +1,6 @@ use soroban_sdk::{Address, Env, Vec}; -use crate::storage_types::DataKey; +use crate::storage_types::{DataKey, TokenData}; pub(crate) const DAY_IN_LEDGERS: u32 = 17280; pub(crate) const INSTANCE_BUMP_AMOUNT: u32 = 30 * DAY_IN_LEDGERS; @@ -36,44 +36,14 @@ pub fn write_registry(e: &Env, id: &Address) { e.storage().instance().set(&key, id); } -pub fn write_token_period(e: &Env, token: &Address, period: u128) { - let key = DataKey::Period(token.clone()); - e.storage().persistent().set(&key, &period); +pub fn write_token_data(env: &Env, token_address: Address, data: TokenData) { + let key = DataKey::TokenData(token_address); + env.storage().persistent().set(&key, &data); } -pub fn read_token_period(e: &Env, token: &Address) -> u128 { - let key = DataKey::Period(token.clone()); - e.storage().persistent().get(&key).unwrap() -} - -pub fn write_token_percentage(e: &Env, token: &Address, period: u128) { - let key = DataKey::Percentage(token.clone()); - e.storage().persistent().set(&key, &period); -} - -pub fn read_token_percentage(e: &Env, token: &Address) -> u128 { - let key = DataKey::Percentage(token.clone()); - e.storage().persistent().get(&key).unwrap() -} - -pub fn write_token_last_update(e: &Env, token: &Address, last_update: u64) { - let key = DataKey::LastUpdate(token.clone()); - e.storage().persistent().set(&key, &last_update); -} - -pub fn read_token_last_update(e: &Env, token: &Address) -> u64 { - let key = DataKey::LastUpdate(token.clone()); - e.storage().persistent().get(&key).unwrap() -} - -pub fn write_token_current_limit(e: &Env, token: &Address, current_limit: u128) { - let key = DataKey::CurrentLimit(token.clone()); - e.storage().persistent().set(&key, ¤t_limit); -} - -pub fn read_token_last_current_limit(e: &Env, token: &Address) -> u128 { - let key = DataKey::CurrentLimit(token.clone()); - e.storage().persistent().get(&key).unwrap() +pub fn read_token_data(env: &Env, token_address: Address) -> Option { + let key = DataKey::TokenData(token_address); + env.storage().persistent().get(&key) } pub fn write_tokens(e: &Env, token: Address) { @@ -109,25 +79,12 @@ pub fn extent_ttl(e: &Env) { INSTANCE_BUMP_AMOUNT, ); for token in tokens { + e.storage().persistent().extend_ttl( - &DataKey::Period(token.clone()), - INSTANCE_LIFETIME_THRESHOLD, - INSTANCE_BUMP_AMOUNT, - ); - e.storage().persistent().extend_ttl( - &DataKey::Percentage(token.clone()), - INSTANCE_LIFETIME_THRESHOLD, - INSTANCE_BUMP_AMOUNT, - ); - e.storage().persistent().extend_ttl( - &DataKey::LastUpdate(token.clone()), - INSTANCE_LIFETIME_THRESHOLD, - INSTANCE_BUMP_AMOUNT, - ); - e.storage().persistent().extend_ttl( - &DataKey::CurrentLimit(token.clone()), + &DataKey::TokenData(token.clone()), INSTANCE_LIFETIME_THRESHOLD, INSTANCE_BUMP_AMOUNT, ); + } } diff --git a/contracts/asset_manager/src/storage_types.rs b/contracts/asset_manager/src/storage_types.rs index 4e6d311..db2e779 100644 --- a/contracts/asset_manager/src/storage_types.rs +++ b/contracts/asset_manager/src/storage_types.rs @@ -9,8 +9,14 @@ pub enum DataKey { Admin, Config, Tokens, - Period(Address), - Percentage(Address), - LastUpdate(Address), - CurrentLimit(Address), + TokenData(Address), +} + +#[derive(Clone)] +#[contracttype] +pub struct TokenData { + pub period: u64, + pub percentage: u32, + pub last_update: u64, + pub current_limit: u64, } diff --git a/contracts/asset_manager/src/tests/asset_manager_test.rs b/contracts/asset_manager/src/tests/asset_manager_test.rs index a90416d..dcfb29f 100644 --- a/contracts/asset_manager/src/tests/asset_manager_test.rs +++ b/contracts/asset_manager/src/tests/asset_manager_test.rs @@ -53,8 +53,8 @@ fn test_configure_rate_limit_panic() { let ctx = TestContext::default(); let client = AssetManagerClient::new(&ctx.env, &ctx.registry); ctx.init_context(&client); - let period = &300u128; - let percentage = &10001u128; + let period = &300; + let percentage = &10001; client.configure_rate_limit(&ctx.token, period, percentage); let limit = client.get_withdraw_limit(&ctx.token); @@ -67,8 +67,8 @@ fn test_configure_rate_limit() { let ctx = TestContext::default(); let client = AssetManagerClient::new(&ctx.env, &ctx.registry); ctx.init_context(&client); - let period = &300u128; - let percentage = &300u128; + let period = &300; + let percentage = &300; client.configure_rate_limit(&ctx.token, period, percentage); assert_eq!( ctx.env.auths(), @@ -78,7 +78,7 @@ fn test_configure_rate_limit() { function: AuthorizedFunction::Contract(( ctx.registry.clone(), Symbol::new(&ctx.env, "configure_rate_limit"), - (&ctx.token, 300u128, 300u128).into_val(&ctx.env) + (&ctx.token, 300u64, 300u32).into_val(&ctx.env) )), sub_invocations: std::vec![] } @@ -95,7 +95,7 @@ fn test_deposit_without_to_and_data() { let client = AssetManagerClient::new(&ctx.env, &ctx.registry); ctx.init_context(&client); - client.configure_rate_limit(&ctx.token, &300u128, &300u128); + client.configure_rate_limit(&ctx.token, &300, &300); let token_client = token::Client::new(&ctx.env, &ctx.token); let stellar_asset_client: token::StellarAssetClient = token::StellarAssetClient::new(&ctx.env, &ctx.token); @@ -130,8 +130,8 @@ fn test_veryfy_rate_limit() { let ctx = TestContext::default(); let client = AssetManagerClient::new(&ctx.env, &ctx.registry); ctx.init_context(&client); - let period = &300u128; - let percentage = &300u128; + let period = &300; + let percentage = &300; client.configure_rate_limit(&ctx.token, period, percentage); //let token_client = token::Client::new(&ctx.env, &ctx.token); @@ -167,8 +167,8 @@ fn test_veryfy_rate_limit_panic_exceeds_withdraw_limit() { let ctx = TestContext::default(); let client = AssetManagerClient::new(&ctx.env, &ctx.registry); ctx.init_context(&client); - let period = &300u128; - let percentage = &300u128; + let period = &300; + let percentage = &300; client.configure_rate_limit(&ctx.token, period, percentage); let token_client = token::Client::new(&ctx.env, &ctx.token); @@ -209,7 +209,7 @@ fn test_deposit_with_to_and_without_data() { let client = AssetManagerClient::new(&ctx.env, &ctx.registry); ctx.init_context(&client); - client.configure_rate_limit(&ctx.token, &300u128, &300u128); + client.configure_rate_limit(&ctx.token, &300, &300); let token_client = token::Client::new(&ctx.env, &ctx.token); let stellar_asset_client: token::StellarAssetClient = token::StellarAssetClient::new(&ctx.env, &ctx.token); @@ -245,7 +245,7 @@ fn test_deposit_with_to_and_data() { let client = AssetManagerClient::new(&ctx.env, &ctx.registry); ctx.init_context(&client); - client.configure_rate_limit(&ctx.token, &300u128, &300u128); + client.configure_rate_limit(&ctx.token, &300, &300); let token_client = token::Client::new(&ctx.env, &ctx.token); let stellar_asset_client: token::StellarAssetClient = token::StellarAssetClient::new(&ctx.env, &ctx.token); @@ -287,7 +287,7 @@ fn test_handle_call_message_for_withdraw_to() { ctx.env.mock_all_auths(); ctx.init_context(&client); - client.configure_rate_limit(&ctx.token, &300u128, &300u128); + client.configure_rate_limit(&ctx.token, &300, &300); let bnusd_amount = 100000u128; let token_client = token::Client::new(&ctx.env, &ctx.token); @@ -320,7 +320,7 @@ fn test_handle_call_message_for_withdraw_to_invalid_address() { ctx.env.mock_all_auths(); ctx.init_context(&client); - client.configure_rate_limit(&ctx.token, &300u128, &300u128); + client.configure_rate_limit(&ctx.token, &300, &300); let bnusd_amount = 100000u128; let token_client = token::Client::new(&ctx.env, &ctx.token); @@ -353,7 +353,7 @@ fn test_handle_call_message_for_withdraw_to_panic_with_protocal_mismatch() { ctx.env.mock_all_auths(); ctx.init_context(&client); - client.configure_rate_limit(&ctx.token, &300u128, &300u128); + client.configure_rate_limit(&ctx.token, &300, &300); let bnusd_amount = 100000u128; let token_client = token::Client::new(&ctx.env, &ctx.token); @@ -386,7 +386,7 @@ fn test_handle_call_message_for_withdraw_to_panic_with_not_icon_asset_manager() ctx.env.mock_all_auths(); ctx.init_context(&client); - client.configure_rate_limit(&ctx.token, &300u128, &300u128); + client.configure_rate_limit(&ctx.token, &300, &300); let bnusd_amount = 100000u128; let token_client = token::Client::new(&ctx.env, &ctx.token); @@ -419,7 +419,7 @@ fn test_handle_call_message_for_withdraw_to_panic_with_unknown_message_type() { ctx.env.mock_all_auths(); ctx.init_context(&client); - client.configure_rate_limit(&ctx.token, &300u128, &300u128); + client.configure_rate_limit(&ctx.token, &300, &300); let bnusd_amount = 100000u128; let token_client = token::Client::new(&ctx.env, &ctx.token); @@ -480,7 +480,7 @@ fn test_handle_call_message_for_deposit_rollback_panic_with_only_call_service() ctx.env.mock_all_auths(); ctx.init_context(&client); - client.configure_rate_limit(&ctx.token, &300u128, &300u128); + client.configure_rate_limit(&ctx.token, &300, &300); let bnusd_amount = 100000u128; let token_client = token::Client::new(&ctx.env, &ctx.token); @@ -520,7 +520,7 @@ fn test_extend_ttl() { let client = AssetManagerClient::new(&ctx.env, &ctx.registry); ctx.init_context(&client); - client.configure_rate_limit(&ctx.token, &300u128, &300u128); + client.configure_rate_limit(&ctx.token, &300, &300); client.extend_ttl(); } diff --git a/contracts/asset_manager/src/tests/setup.rs b/contracts/asset_manager/src/tests/setup.rs index 99241fa..5510507 100644 --- a/contracts/asset_manager/src/tests/setup.rs +++ b/contracts/asset_manager/src/tests/setup.rs @@ -45,7 +45,7 @@ impl TestContext { pub fn default() -> Self { let env = Env::default(); let token_admin = Address::generate(&env); - let token = env.register_stellar_asset_contract(token_admin.clone()); + let token = env.register_stellar_asset_contract_v2(token_admin.clone()); let asset_manager = env.register_contract(None, AssetManager); let centralized_connection = env.register_contract_wasm(None, connection::WASM); let xcall_manager = env.register_contract_wasm(None, xcall_manager::WASM); @@ -60,10 +60,10 @@ impl TestContext { xcall_manager: xcall_manager, icon_asset_manager: String::from_str(&env, "icon01/hxjnfh4u"), icon_governance: String::from_str(&env, "icon01/kjdnoi"), - token: token, + token: token.address(), centralized_connection: centralized_connection, nid: String::from_str(&env, "stellar"), - native_token: env.register_stellar_asset_contract(token_admin.clone()), + native_token: env.register_stellar_asset_contract_v2(token_admin.clone()).address(), xcall_client: xcall::Client::new(&env, &xcall), env, } diff --git a/contracts/xcall_manager/src/contract.rs b/contracts/xcall_manager/src/contract.rs index 0eb8f1d..99e1ece 100644 --- a/contracts/xcall_manager/src/contract.rs +++ b/contracts/xcall_manager/src/contract.rs @@ -88,7 +88,7 @@ impl XcallManager { } pub fn get_protocols(e: Env) -> Result<(Vec, Vec), ContractError> { - let sources = read_sources(&e); + let sources: Vec = read_sources(&e); let destinations = read_destinations(&e); Ok((sources, destinations)) } @@ -147,7 +147,7 @@ impl XcallManager { let sources = read_sources(&e); if !Self::verify_protocols_unordered(protocols.clone(), sources).unwrap() { if method != String::from_str(&e.clone(), CONFIGURE_PROTOCOLS_NAME) { - return Err(ContractError::ProtocolMismatch); + return Err(ContractError::UnknownMessageType); } Self::verify_protocol_recovery(&e, protocols)?; } From e9530f7ed53be27458d7f4706234f5e4dd2f2b65 Mon Sep 17 00:00:00 2001 From: sagar sapkota Date: Mon, 9 Sep 2024 09:56:10 +0545 Subject: [PATCH 47/63] test events removed, token data saved --- contracts/asset_manager/src/contract.rs | 9 +++++---- contracts/asset_manager/src/tests/asset_manager_test.rs | 2 ++ contracts/balanced_doller/src/balanced_dollar.rs | 1 - 3 files changed, 7 insertions(+), 5 deletions(-) diff --git a/contracts/asset_manager/src/contract.rs b/contracts/asset_manager/src/contract.rs index 64862ec..5108966 100644 --- a/contracts/asset_manager/src/contract.rs +++ b/contracts/asset_manager/src/contract.rs @@ -98,8 +98,9 @@ impl AssetManager { pub fn reset_limit(env: Env, token: Address) { let balance = Self::get_token_balance(&env, token.clone()); - let mut data: TokenData = read_token_data(&env, token).unwrap(); + let mut data: TokenData = read_token_data(&env, token.clone()).unwrap(); data.current_limit = (balance * data.percentage as u128 / POINTS) as u64; + write_token_data(&env, token, data); } pub fn get_withdraw_limit(env: Env, token: Address) -> Result { @@ -118,9 +119,10 @@ impl AssetManager { if balance - amount < limit { panic_with_error!(&env, ContractError::ExceedsWithdrawLimit); }; - let mut data: TokenData = read_token_data(&env, token).unwrap(); + let mut data: TokenData = read_token_data(&env, token.clone()).unwrap(); data.current_limit = limit as u64; data.last_update = env.ledger().timestamp(); + write_token_data(&env, token, data); Ok(true) } @@ -249,20 +251,19 @@ impl AssetManager { xcall.require_auth(); let method = Deposit::get_method(&e, data.clone()); + let icon_asset_manager = config.icon_asset_manager; let current_contract = e.current_contract_address(); if method == String::from_str(&e, &WITHDRAW_TO_NAME) { if from != icon_asset_manager { return Err(ContractError::OnlyICONAssetManager); } - let message = WithdrawTo::decode(&e, data); if !is_valid_string_address(&message.to) || !is_valid_string_address(&message.token_address) { return Err(ContractError::InvalidAddress); } - Self::withdraw( &e, current_contract, diff --git a/contracts/asset_manager/src/tests/asset_manager_test.rs b/contracts/asset_manager/src/tests/asset_manager_test.rs index dcfb29f..a3111ff 100644 --- a/contracts/asset_manager/src/tests/asset_manager_test.rs +++ b/contracts/asset_manager/src/tests/asset_manager_test.rs @@ -84,6 +84,8 @@ fn test_configure_rate_limit() { } )] ); + let token_data = client.get_rate_limit(&ctx.token); + assert_eq!(token_data.3, 0); let limit = client.get_withdraw_limit(&ctx.token); let verified = client.verify_withdraw(&ctx.token, &limit); assert_eq!(verified, true); diff --git a/contracts/balanced_doller/src/balanced_dollar.rs b/contracts/balanced_doller/src/balanced_dollar.rs index 9aa2231..d2299b8 100644 --- a/contracts/balanced_doller/src/balanced_dollar.rs +++ b/contracts/balanced_doller/src/balanced_dollar.rs @@ -33,7 +33,6 @@ pub fn _cross_transfer( ) -> Result<(), ContractError> { _burn(&e, from.clone(), amount as i128); let xcall_message = CrossTransfer::new(from.clone().to_string(), to, amount, data); - let rollback = CrossTransferRevert::new(from.clone(), amount); let config = get_config(&e); let icon_bn_usd = config.icon_bn_usd; From f2d5c875e07e692ec7142d5b027116667c167379 Mon Sep 17 00:00:00 2001 From: sagar sapkota Date: Mon, 9 Sep 2024 15:54:16 +0545 Subject: [PATCH 48/63] storage type mismatch issue fixed, ttl_extend verification on unit test --- contracts/asset_manager/src/contract.rs | 3 ++- contracts/asset_manager/src/states.rs | 4 ++-- .../asset_manager/src/tests/asset_manager_test.rs | 15 +++++++++++---- 3 files changed, 15 insertions(+), 7 deletions(-) diff --git a/contracts/asset_manager/src/contract.rs b/contracts/asset_manager/src/contract.rs index 5108966..5ff6d43 100644 --- a/contracts/asset_manager/src/contract.rs +++ b/contracts/asset_manager/src/contract.rs @@ -1,5 +1,5 @@ use soroban_sdk::{ - contract, contractimpl, panic_with_error, token, Address, Bytes, BytesN, Env, String, Vec, + contract, contractimpl, panic_with_error, token, Address, Bytes, BytesN, Env, String, Vec }; mod xcall { soroban_sdk::contractimport!(file = "../../wasm/xcall.wasm"); @@ -108,6 +108,7 @@ impl AssetManager { return Ok(Self::calculate_limit(&env, balance, token)?); } + fn get_token_balance(env: &Env, token: Address) -> u128 { let token_client = token::Client::new(env, &token); return token_client.balance(&env.current_contract_address()) as u128; diff --git a/contracts/asset_manager/src/states.rs b/contracts/asset_manager/src/states.rs index bfc7ee4..7bf1a60 100644 --- a/contracts/asset_manager/src/states.rs +++ b/contracts/asset_manager/src/states.rs @@ -48,7 +48,7 @@ pub fn read_token_data(env: &Env, token_address: Address) -> Option { pub fn write_tokens(e: &Env, token: Address) { let key = DataKey::Tokens; - let mut tokens: Vec
= match e.storage().instance().get(&key) { + let mut tokens: Vec
= match e.storage().persistent().get(&key) { Some(names) => names, None => Vec::new(&e), }; @@ -72,7 +72,7 @@ pub fn extent_ttl(e: &Env) { .instance() .extend_ttl(INSTANCE_LIFETIME_THRESHOLD, INSTANCE_BUMP_AMOUNT); - let tokens = read_tokens(&e.clone()); + let tokens = read_tokens(&e); e.storage().persistent().extend_ttl( &DataKey::Tokens, INSTANCE_LIFETIME_THRESHOLD, diff --git a/contracts/asset_manager/src/tests/asset_manager_test.rs b/contracts/asset_manager/src/tests/asset_manager_test.rs index a3111ff..afb2654 100644 --- a/contracts/asset_manager/src/tests/asset_manager_test.rs +++ b/contracts/asset_manager/src/tests/asset_manager_test.rs @@ -1,10 +1,9 @@ #![cfg(test)] extern crate std; -use crate::contract::AssetManagerClient; +use crate::{contract::AssetManagerClient, storage_types::DataKey}; use soroban_sdk::{ - testutils::{Address as _, AuthorizedFunction, AuthorizedInvocation}, - token, Address, Bytes, IntoVal, String, Symbol, Vec, + testutils::{storage::Persistent, Address as _, AuthorizedFunction, AuthorizedInvocation}, token, Address, Bytes, IntoVal, String, Symbol, Vec }; use soroban_rlp::balanced::messages::{deposit_revert::DepositRevert, withdraw_to::WithdrawTo}; @@ -523,6 +522,14 @@ fn test_extend_ttl() { ctx.init_context(&client); client.configure_rate_limit(&ctx.token, &300, &300); - + let token = ctx.token; + client.extend_ttl(); + + ctx.env.as_contract(&client.address, || { + let key = DataKey::TokenData(token.clone()); + let before_ttl = ctx.env.storage().persistent().get_ttl(&key); + std::println!("before ttl is: {:?}", before_ttl); + }); + } From 2edba2b8a1d9434d655f7750d2a4ee312850de81 Mon Sep 17 00:00:00 2001 From: sagar sapkota Date: Tue, 10 Sep 2024 08:54:26 +0545 Subject: [PATCH 49/63] cross_transfer and cross_transfer_data methods merged --- contracts/balanced_doller/src/contract.rs | 15 +++------------ .../src/tests/balanced_dollar_test.rs | 4 ++-- contracts/xcall_manager/src/tests/setup.rs | 10 +++++----- 3 files changed, 10 insertions(+), 19 deletions(-) diff --git a/contracts/balanced_doller/src/contract.rs b/contracts/balanced_doller/src/contract.rs index 0143c99..dfa7145 100644 --- a/contracts/balanced_doller/src/contract.rs +++ b/contracts/balanced_doller/src/contract.rs @@ -73,20 +73,11 @@ impl BalancedDollar { from: Address, amount: u128, to: String, + data: Option ) -> Result<(), ContractError> { from.require_auth(); - return balanced_dollar::_cross_transfer(e.clone(), from, amount, to, Bytes::new(&e)); - } - - pub fn cross_transfer_data( - e: Env, - from: Address, - amount: u128, - to: String, - data: Bytes, - ) -> Result<(), ContractError> { - from.require_auth(); - return balanced_dollar::_cross_transfer(e, from, amount, to, data); + let transfer_data = data.unwrap_or(Bytes::from_array(&e, &[0u8; 32])); + return balanced_dollar::_cross_transfer(e.clone(), from, amount, to, transfer_data); } pub fn handle_call_message( diff --git a/contracts/balanced_doller/src/tests/balanced_dollar_test.rs b/contracts/balanced_doller/src/tests/balanced_dollar_test.rs index 7f966ce..245ddc5 100644 --- a/contracts/balanced_doller/src/tests/balanced_dollar_test.rs +++ b/contracts/balanced_doller/src/tests/balanced_dollar_test.rs @@ -75,11 +75,11 @@ fn test_cross_transfer_with_to_and_data() { 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F, 0x20, ]; - client.cross_transfer_data( + client.cross_transfer( &ctx.depositor, &amount, &String::from_str(&ctx.env, "icon01/hxjkdvhui"), - &Bytes::from_array(&ctx.env, &data), + &Option::Some(Bytes::from_array(&ctx.env, &data)), ); std::println!("call"); assert_eq!(ctx.get_native_token_balance(&ctx.depositor), 400u128) // why 300? diff --git a/contracts/xcall_manager/src/tests/setup.rs b/contracts/xcall_manager/src/tests/setup.rs index e2ac5d4..8b7ad4b 100644 --- a/contracts/xcall_manager/src/tests/setup.rs +++ b/contracts/xcall_manager/src/tests/setup.rs @@ -40,7 +40,7 @@ impl TestContext { pub fn default() -> Self { let env = Env::default(); let token_admin = Address::generate(&env); - let token = env.register_stellar_asset_contract(token_admin.clone()); + let token = env.register_stellar_asset_contract_v2(token_admin.clone()); let xcall_manager = env.register_contract(None, XcallManager); let centralized_connection = env.register_contract_wasm(None, connection::WASM); let xcall = env.register_contract_wasm(None, xcall::WASM); @@ -52,13 +52,13 @@ impl TestContext { registry: xcall_manager, admin: Address::generate(&env), depositor: Address::generate(&env), - xcall: xcall, + xcall, icon_governance: String::from_str(&env, "icon01/kjdnoi"), xcall_network_address: String::from_str(&env, "stellar/address"), - token: token, - centralized_connection: centralized_connection, + token: token.address(), + centralized_connection, nid: String::from_str(&env, "stellar"), - native_token: env.register_stellar_asset_contract(token_admin.clone()), + native_token: env.register_stellar_asset_contract_v2(token_admin.clone()).address(), env } } From 59393842c0156d3fccb1beef7fbe1eefd87e5299 Mon Sep 17 00:00:00 2001 From: sagar sapkota Date: Tue, 10 Sep 2024 09:08:14 +0545 Subject: [PATCH 50/63] the readme document added --- README.md | 104 ++++++++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 101 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index fe2d6ae..881ecfc 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,103 @@ -[![codecov](https://codecov.io/gh/balancednetwork/balanced-soroban-contracts/graph/badge.svg?token=6Epcv9Uek5)](https://codecov.io/gh/balancednetwork/balanced-soroban-contracts) -![build](https://github.com/balancednetwork/balanced-soroban-contracts/actions/workflows/build-test-soroban-contracts.yml/badge.svg) -## Balanced Soroban Contracts +# Balanced Package Structure +## Overview + +The Balanced contracts within the Stellar blockchain ecosystem is designed to manage various aspects of the decentralized application (dApp) including asset management, cross-chain communication, and stable coin operations. This structure ensures efficient handling of these operations through well-defined smart contracts and unique contract addresses. The smart contracts are written using Soroban framework of Rust programming language + +## Contracts + +The Balanced Stellar Spoke have three main smart contracts, each responsible for specific functionalities: + +### 1. Asset Manager: asset_manager +- **Purpose**: Manages assets within the Balanced ecosystem. + +### 2. xCall Manager: xcall_manager +- **Purpose**: Facilitates cross-chain administration from the icon side. + +### 3. Balanced Dollar: balanced_dollar +- **Purpose**: Includes the bnUSD token contract and Manages the crosschain bnUSD operations within the Balanced ecosystem. + +## Identifiers + +### Contract Addresses +- **Definition**: Addresses of each each smart contract on the stellar blockchain +- **Usage**: Used while called using RPC and cross contract calls, also used in cross-chain configuration + +```shell +soroban contract invoke --id $contract_address \ +--source-account $ACCOUNT --rpc-url $ENDPOINT \ +--network-passphrase "$PASSPHRASE" -- \ +#method_name --arg1 $arg1 --arg2 $arg2 +``` + +## Frontend Integration Interfaces + +This guide provides an overview of the key functions for interacting with the Stellar blockchain within your frontend application. These functions are part of the Asset Manager, Balanced Dollar, and XCall smart contracts, which allow for token deposits, cross-chain transfers, and cross-chain calls. + +### Important Note: Renting mechanism in Stellar Blockchain and TTL of storage + +Stellar has unique renting mechanism implemented on its smart contracts.. + +--- + +### Asset Manager Smart contract + +The Asset Manager Contract handles depositing Stellar tokens in balanced. + +#### `deposit` + +Deposits a specified amount of a token into the Sui blockchain. +``` typescript + deposit( + from: Address, //Address from which the transaction is initiated + token: Address, // Address of the token being deposited + amount: u128, // Amount of the token being deposited + to: Option,// (Optional) The recipient's address if needed. + data: Option, // (Optional) Any additional data you want to attach to the deposit. + ); +``` +The above method can be RPC called using the shell script with the following code: +```shell + soroban contract invoke --id $assetManagerContractAddress \ + --source-account $ACCOUNT --rpc-url $ENDPOINT \ + --network-passphrase "$PASSPHRASE" -- \ + deposit --from $fromAddress --token $tokenAddress \ + --amount $amount --to $toNetworkAddress +``` +Both native token and Other fungible tokens can be deposited using the `deposit` method + +### Balanced Dollar Module + +The Balanced Dollar Contract facilitates the transfer of `BALANCED_DOLLAR` tokens across chains. + +#### `cross_transfer` + +Transfers `BALANCED_DOLLAR` tokens across chains. +```typescript + function cross_transfer( + from: Address, //Address from which the transaction is initiated + amount: u128, // Amount of the balanced dollar being deposited + to: String, // The recipient's address on the destination chain. + data: Option // (Optional) Any additional data to attach to the transfer. + ) +``` +The above method can be called using following shell script: +```shell + soroban contract invoke --id $bnUSDContractAddress \ + --rpc-url $ENDPOINT --network-passphrase "$PASSPHRASE" \ + --source-account $ACCOUNT -- cross_transfer --from $fromAddress -- amount $amount --to $toNetworkAddress +``` + +### XCallManager Contract + +#### get_protocols +The `get_protocols` function retrieves the sources and destinations associated with a given configuration. + +```typescript +function get_protocols( +) -> Result<( // Returns a tuple containing two arrays: sources and destinations or error if occurred + Vec, + Vec +), ContractError> +``` \ No newline at end of file From d9638379de7dd154d0bb2770333011fb66fc8181 Mon Sep 17 00:00:00 2001 From: sagar sapkota Date: Wed, 11 Sep 2024 08:39:12 +0545 Subject: [PATCH 51/63] xcall address validation issue and verify_protocols issue fixed, tests added --- contracts/asset_manager/src/contract.rs | 7 +- .../balanced_doller/src/balanced_dollar.rs | 5 +- contracts/xcall_manager/src/contract.rs | 6 +- .../src/tests/xcall_manager_test.rs | 71 +++++++++++++++++++ 4 files changed, 79 insertions(+), 10 deletions(-) diff --git a/contracts/asset_manager/src/contract.rs b/contracts/asset_manager/src/contract.rs index 5ff6d43..e2839a6 100644 --- a/contracts/asset_manager/src/contract.rs +++ b/contracts/asset_manager/src/contract.rs @@ -20,7 +20,7 @@ use soroban_rlp::balanced::messages::{ deposit::Deposit, deposit_revert::DepositRevert, withdraw_to::WithdrawTo, }; -use xcall::{AnyMessage, CallMessageWithRollback, Client, Envelope}; +use xcall::{AnyMessage, CallMessageWithRollback, Client, Envelope, NetworkAddress}; const DEPOSIT_NAME: &str = "Deposit"; const WITHDRAW_TO_NAME: &str = "WithdrawTo"; @@ -273,9 +273,8 @@ impl AssetManager { message.amount, )?; } else if method == String::from_str(&e, &DEPOSIT_REVERT_NAME) { - let from_xcall = get_address_from(&from, &e); - let xcall_address = Address::from_string(&from_xcall.into()); - if xcall != xcall_address { + let xcall_network_address = Self::xcall_client(&e, &xcall).get_network_address(); + if xcall_network_address != from { return Err(ContractError::OnlyCallService); } let message: DepositRevert = DepositRevert::decode(&e.clone(), data); diff --git a/contracts/balanced_doller/src/balanced_dollar.rs b/contracts/balanced_doller/src/balanced_dollar.rs index d2299b8..46470d6 100644 --- a/contracts/balanced_doller/src/balanced_dollar.rs +++ b/contracts/balanced_doller/src/balanced_dollar.rs @@ -89,9 +89,8 @@ pub fn _handle_call_message( let to_network_address: Address = get_address(message.to, &e)?; _mint(&e, to_network_address, message.amount as i128); } else if method == String::from_str(&e, &CROSS_TRANSFER_REVERT) { - let from_xcall = get_address_from(&from, &e); - let xcall_address = Address::from_string(&from_xcall.into()); - if xcall != xcall_address { + let xcall_network_address = xcall_client(&e, &xcall).get_network_address(); + if xcall_network_address != from { return Err(ContractError::OnlyCallService); } let message = CrossTransferRevert::decode(&e, data); diff --git a/contracts/xcall_manager/src/contract.rs b/contracts/xcall_manager/src/contract.rs index 99e1ece..121674e 100644 --- a/contracts/xcall_manager/src/contract.rs +++ b/contracts/xcall_manager/src/contract.rs @@ -101,14 +101,14 @@ impl XcallManager { if array1.len() != array2.len() { return Ok(false); } - for p in array1.iter() { + for p in array2.iter() { let mut j = 0; - for s in array2.iter() { + for s in array1.iter() { j = j + 1; if p.eq(&s) { break; } else { - if j == array2.len() { + if j == array1.len() { return Ok(false); } continue; diff --git a/contracts/xcall_manager/src/tests/xcall_manager_test.rs b/contracts/xcall_manager/src/tests/xcall_manager_test.rs index 0466451..87a595f 100644 --- a/contracts/xcall_manager/src/tests/xcall_manager_test.rs +++ b/contracts/xcall_manager/src/tests/xcall_manager_test.rs @@ -163,6 +163,77 @@ fn test_handle_call_message_for_configure_protocols() { let (s, d) = client.get_protocols(); assert_eq!(s, sources); assert_eq!(d, destinations); + + //verify multiple protocols + let wrong_sources = [ + String::from_str(&ctx.env, "stellar/address"), + String::from_str(&ctx.env, "stellar/address"), + ]; + let verifiy_false = client.verify_protocols(&Vec::from_array(&ctx.env, wrong_sources)); + assert_eq!(verifiy_false, false); + + let wrong_sources_second = [ + String::from_str(&ctx.env, "stellar/address1"), + String::from_str(&ctx.env, "stellar/address1"), + ]; + let verifiy_false_second = client.verify_protocols(&Vec::from_array(&ctx.env, wrong_sources_second)); + assert_eq!(verifiy_false_second, false); + + let correct_sources = [ + String::from_str(&ctx.env, "stellar/address"), + String::from_str(&ctx.env, "stellar/address1"), + ]; + let verifiy_true = client.verify_protocols(&Vec::from_array(&ctx.env, correct_sources)); + assert_eq!(verifiy_true, true); + + let correct_sources_second: [String; 2] = [ + String::from_str(&ctx.env, "stellar/address1"), + String::from_str(&ctx.env, "stellar/address"), + ]; + let verifiy_true = client.verify_protocols(&Vec::from_array(&ctx.env, correct_sources_second)); + assert_eq!(verifiy_true, true); + + //verify protocol recovery + client.propose_removal(&String::from_str(&ctx.env, "stellar/address1")); + let with_protocol_remove: [String; 1] = [ + String::from_str(&ctx.env, "stellar/address"), + ]; + client.verify_protocol_recovery(&Vec::from_array(&ctx.env, with_protocol_remove)); +} + +#[test] +#[should_panic(expected = "HostError: Error(Contract, #12)")] +fn test_verify_protocol_recovery_without_removing_protocol() { + let ctx = TestContext::default(); + let client = XcallManagerClient::new(&ctx.env, &ctx.registry); + ctx.env.mock_all_auths(); + ctx.init_context(&client); + + let source_items = [ + String::from_str(&ctx.env, "stellar/address"), + String::from_str(&ctx.env, "stellar/address1"), + ]; + let destination_items = [ + String::from_str(&ctx.env, "icon/address"), + String::from_str(&ctx.env, "icon/address1"), + ]; + let sources = Vec::from_array(&ctx.env, source_items); + let destinations = Vec::from_array(&ctx.env, destination_items); + let data = ConfigureProtocols::new(sources.clone(), destinations.clone()) + .encode(&ctx.env, String::from_str(&ctx.env, "ConfigureProtocols")); + let decoded: ConfigureProtocols = ConfigureProtocols::decode(&ctx.env, data.clone()); + client.white_list_actions(&data); + assert_eq!(decoded.sources, sources); + assert_eq!(decoded.destinations, destinations); + let (s, _) = client.get_protocols(); + client.handle_call_message( &ctx.icon_governance, &data, &s); + + //verify protocol recovery + let without_protocol_remove: [String; 2] = [ + String::from_str(&ctx.env, "stellar/address1"), + String::from_str(&ctx.env, "stellar/address"), + ]; + client.verify_protocol_recovery(&Vec::from_array(&ctx.env, without_protocol_remove)); } #[test] From e50ba1293d90219ef780578838e8ce0b6cb656d1 Mon Sep 17 00:00:00 2001 From: sagar sapkota Date: Wed, 11 Sep 2024 16:18:16 +0545 Subject: [PATCH 52/63] re-entry issue fixed --- contracts/asset_manager/src/config.rs | 1 + contracts/asset_manager/src/contract.rs | 8 +++----- contracts/asset_manager/src/storage_types.rs | 2 +- contracts/asset_manager/src/tests/setup.rs | 6 ++++-- contracts/balanced_doller/src/balanced_dollar.rs | 3 +-- contracts/balanced_doller/src/config.rs | 1 + contracts/balanced_doller/src/tests/setup.rs | 6 ++++-- 7 files changed, 15 insertions(+), 12 deletions(-) diff --git a/contracts/asset_manager/src/config.rs b/contracts/asset_manager/src/config.rs index 6be0240..524b978 100644 --- a/contracts/asset_manager/src/config.rs +++ b/contracts/asset_manager/src/config.rs @@ -8,6 +8,7 @@ pub struct ConfigData { pub xcall_manager: Address, pub native_address: Address, pub icon_asset_manager: String, + pub xcall_network_address: String, } pub fn set_config(e: &Env, config: ConfigData) { diff --git a/contracts/asset_manager/src/contract.rs b/contracts/asset_manager/src/contract.rs index e2839a6..d83ca1d 100644 --- a/contracts/asset_manager/src/contract.rs +++ b/contracts/asset_manager/src/contract.rs @@ -15,12 +15,12 @@ use crate::{ storage_types::{DataKey, POINTS}, xcall_manager_interface::XcallManagerClient, }; -use soroban_rlp::balanced::address_utils::{get_address_from, is_valid_string_address}; +use soroban_rlp::balanced::address_utils::is_valid_string_address; use soroban_rlp::balanced::messages::{ deposit::Deposit, deposit_revert::DepositRevert, withdraw_to::WithdrawTo, }; -use xcall::{AnyMessage, CallMessageWithRollback, Client, Envelope, NetworkAddress}; +use xcall::{AnyMessage, CallMessageWithRollback, Client, Envelope}; const DEPOSIT_NAME: &str = "Deposit"; const WITHDRAW_TO_NAME: &str = "WithdrawTo"; @@ -35,7 +35,6 @@ impl AssetManager { if has_registry(&env.clone()) { panic_with_error!(&env, ContractError::ContractAlreadyInitialized) } - write_registry(&env, ®istry); write_administrator(&env, &admin); Self::configure(env, config); @@ -273,8 +272,7 @@ impl AssetManager { message.amount, )?; } else if method == String::from_str(&e, &DEPOSIT_REVERT_NAME) { - let xcall_network_address = Self::xcall_client(&e, &xcall).get_network_address(); - if xcall_network_address != from { + if config.xcall_network_address != from { return Err(ContractError::OnlyCallService); } let message: DepositRevert = DepositRevert::decode(&e.clone(), data); diff --git a/contracts/asset_manager/src/storage_types.rs b/contracts/asset_manager/src/storage_types.rs index db2e779..2e1997b 100644 --- a/contracts/asset_manager/src/storage_types.rs +++ b/contracts/asset_manager/src/storage_types.rs @@ -9,7 +9,7 @@ pub enum DataKey { Admin, Config, Tokens, - TokenData(Address), + TokenData(Address) } #[derive(Clone)] diff --git a/contracts/asset_manager/src/tests/setup.rs b/contracts/asset_manager/src/tests/setup.rs index 5510507..f29dfff 100644 --- a/contracts/asset_manager/src/tests/setup.rs +++ b/contracts/asset_manager/src/tests/setup.rs @@ -71,15 +71,17 @@ impl TestContext { pub fn init_context(&self, client: &AssetManagerClient<'static>) { self.env.mock_all_auths(); + self.init_xcall_manager_context(); + self.init_xcall_state(); let config = ConfigData { xcall: self.xcall.clone(), xcall_manager: self.xcall_manager.clone(), native_address: self.native_token.clone(), icon_asset_manager: self.icon_asset_manager.clone(), + xcall_network_address: self.xcall_client.get_network_address() }; client.initialize(&self.registry, &self.admin, &config); - self.init_xcall_manager_context(); - self.init_xcall_state(); + } pub fn init_xcall_manager_context(&self) { diff --git a/contracts/balanced_doller/src/balanced_dollar.rs b/contracts/balanced_doller/src/balanced_dollar.rs index 46470d6..cb2fdc4 100644 --- a/contracts/balanced_doller/src/balanced_dollar.rs +++ b/contracts/balanced_doller/src/balanced_dollar.rs @@ -89,8 +89,7 @@ pub fn _handle_call_message( let to_network_address: Address = get_address(message.to, &e)?; _mint(&e, to_network_address, message.amount as i128); } else if method == String::from_str(&e, &CROSS_TRANSFER_REVERT) { - let xcall_network_address = xcall_client(&e, &xcall).get_network_address(); - if xcall_network_address != from { + if config.xcall_network_address != from { return Err(ContractError::OnlyCallService); } let message = CrossTransferRevert::decode(&e, data); diff --git a/contracts/balanced_doller/src/config.rs b/contracts/balanced_doller/src/config.rs index 8c0b0b0..13b88b8 100644 --- a/contracts/balanced_doller/src/config.rs +++ b/contracts/balanced_doller/src/config.rs @@ -8,6 +8,7 @@ pub struct ConfigData { pub xcall_manager: Address, pub nid: String, pub icon_bn_usd: String, + pub xcall_network_address: String } pub fn set_config(e: &Env, config: ConfigData) { diff --git a/contracts/balanced_doller/src/tests/setup.rs b/contracts/balanced_doller/src/tests/setup.rs index 1155128..f6a0616 100644 --- a/contracts/balanced_doller/src/tests/setup.rs +++ b/contracts/balanced_doller/src/tests/setup.rs @@ -74,15 +74,17 @@ impl TestContext { pub fn init_context(&self, client: &BalancedDollarClient<'static>) { self.env.mock_all_auths(); + self.init_xcall_manager_context(); + self.init_xcall_state(); let config = ConfigData { xcall: self.xcall.clone(), xcall_manager: self.xcall_manager.clone(), nid: self.nid.clone(), icon_bn_usd: self.icon_bn_usd.clone(), + xcall_network_address: self.xcall_client.get_network_address() }; client.initialize(&self.admin, &config); - self.init_xcall_manager_context(); - self.init_xcall_state(); + } pub fn init_xcall_manager_context(&self) { From 080f650bcacb743f9cf0ee1159a280b3b5dde3cb Mon Sep 17 00:00:00 2001 From: sagar sapkota Date: Wed, 18 Sep 2024 17:22:57 +0545 Subject: [PATCH 53/63] mint method removed and tests updated --- .../balanced_doller/src/balanced_dollar.rs | 2 +- contracts/balanced_doller/src/contract.rs | 7 - .../src/tests/balanced_dollar_test.rs | 45 +++- contracts/balanced_doller/src/tests/mod.rs | 3 +- contracts/balanced_doller/src/tests/test.rs | 219 ------------------ 5 files changed, 36 insertions(+), 240 deletions(-) delete mode 100644 contracts/balanced_doller/src/tests/test.rs diff --git a/contracts/balanced_doller/src/balanced_dollar.rs b/contracts/balanced_doller/src/balanced_dollar.rs index cb2fdc4..6f7df89 100644 --- a/contracts/balanced_doller/src/balanced_dollar.rs +++ b/contracts/balanced_doller/src/balanced_dollar.rs @@ -135,7 +135,7 @@ pub fn get_address(network_address: String, env: &Env) -> Result Date: Tue, 19 Mar 2024 12:27:06 +1100 Subject: [PATCH 54/63] Initial commit --- .../.github/ISSUE_TEMPLATE/feature_request.md | 0 .../.github/PULL_REQUEST_TEMPLATE.md | 28 +++ .github/ISSUE_TEMPLATE/.github/labeler.yml | 11 + .github/ISSUE_TEMPLATE/.github/release.yml | 25 +++ .../.github/workflows/auto-pr-labeler.yml | 32 +++ .../.github/workflows/check-pr-label.yml | 25 +++ .../.github/workflows/lint-pr.yml | 18 ++ CODEOWNERS | 0 CODE_OF_CONDUCT.md | 132 +++++++++++ CONTRIBUTING.md | 55 +++++ LICENSE | 201 +++++++++++++++++ NOTICE | 210 ++++++++++++++++++ codecov.yml | 37 +++ 13 files changed, 774 insertions(+) create mode 100644 .github/ISSUE_TEMPLATE/.github/ISSUE_TEMPLATE/feature_request.md create mode 100644 .github/ISSUE_TEMPLATE/.github/PULL_REQUEST_TEMPLATE.md create mode 100644 .github/ISSUE_TEMPLATE/.github/labeler.yml create mode 100644 .github/ISSUE_TEMPLATE/.github/release.yml create mode 100644 .github/ISSUE_TEMPLATE/.github/workflows/auto-pr-labeler.yml create mode 100644 .github/ISSUE_TEMPLATE/.github/workflows/check-pr-label.yml create mode 100644 .github/ISSUE_TEMPLATE/.github/workflows/lint-pr.yml create mode 100644 CODEOWNERS create mode 100644 CODE_OF_CONDUCT.md create mode 100644 CONTRIBUTING.md create mode 100644 LICENSE create mode 100644 NOTICE create mode 100644 codecov.yml diff --git a/.github/ISSUE_TEMPLATE/.github/ISSUE_TEMPLATE/feature_request.md b/.github/ISSUE_TEMPLATE/.github/ISSUE_TEMPLATE/feature_request.md new file mode 100644 index 0000000..e69de29 diff --git a/.github/ISSUE_TEMPLATE/.github/PULL_REQUEST_TEMPLATE.md b/.github/ISSUE_TEMPLATE/.github/PULL_REQUEST_TEMPLATE.md new file mode 100644 index 0000000..75e813b --- /dev/null +++ b/.github/ISSUE_TEMPLATE/.github/PULL_REQUEST_TEMPLATE.md @@ -0,0 +1,28 @@ +## Description + +### Commit Message + +```bash +type: commit message +``` + +see the [guidelines](https://github.com/icon-project/community/blob/main/guidelines/technical/software-development-guidelines.md#commit-messages) for commit messages. + +### Changelog Entry + +```bash +version: +``` + +## Checklist + +- [ ] I have performed a self-review of my own code +- [ ] I have documented my code in accordance with the [documentation guidelines](https://github.com/icon-project/community/blob/main/guidelines/technical/software-development-guidelines.md#documentation) +- [ ] My changes generate no new warnings +- [ ] I have added tests that prove my fix is effective or that my feature works +- [ ] I have run the unit tests +- [ ] I only have one commit (if not, squash them into one commit). +- [ ] I have a descriptive commit message that adheres to the [commit message guidelines](https://github.com/icon-project/community/blob/main/guidelines/technical/software-development-guidelines.md#commit-messages) +- [ ] I have added version bump label on PR. + +> Please review the [CONTRIBUTING.md](/CONTRIBUTING.md) file for detailed contributing guidelines. \ No newline at end of file diff --git a/.github/ISSUE_TEMPLATE/.github/labeler.yml b/.github/ISSUE_TEMPLATE/.github/labeler.yml new file mode 100644 index 0000000..0c61d38 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/.github/labeler.yml @@ -0,0 +1,11 @@ +cicd: + - '.github/workflows/*' + +scripts: + - 'scripts/*' + +test: + - 'test/**' + +documentation: +- '**/*.md' diff --git a/.github/ISSUE_TEMPLATE/.github/release.yml b/.github/ISSUE_TEMPLATE/.github/release.yml new file mode 100644 index 0000000..95830b2 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/.github/release.yml @@ -0,0 +1,25 @@ +# .github/release.yml + +changelog: + exclude: + labels: + - cicd + - scripts + - test + categories: + - title: Breaking Changes 🛠 + labels: + - Major + - breaking-change + - title: New Features 🎉 + labels: + - Minor + - enhancement + - Feature + - title: Bug Fixes 🐛 + labels: + - Patch + - bug + - title: Other Changes 📝 + labels: + - "*" diff --git a/.github/ISSUE_TEMPLATE/.github/workflows/auto-pr-labeler.yml b/.github/ISSUE_TEMPLATE/.github/workflows/auto-pr-labeler.yml new file mode 100644 index 0000000..906947f --- /dev/null +++ b/.github/ISSUE_TEMPLATE/.github/workflows/auto-pr-labeler.yml @@ -0,0 +1,32 @@ +name: Pull Request Labeler +on: + pull_request: + types: + - opened + - edited + - synchronize +jobs: + auto-label: + permissions: + contents: read + pull-requests: write + runs-on: ubuntu-latest + steps: + - name: Find Current Pull Request + uses: jwalton/gh-find-current-pr@v1.3.2 + id: findPr + with: + # Can be "open", "closed", or "all". Defaults to "open". + state: open + - run: echo "PR Number is ${PR}" + if: success() && steps.findPr.outputs.number + env: + PR: ${{ steps.findPr.outputs.pr }} + + - name: check pr pr-number + run: echo ${{ github.event.number }} + + - uses: actions/labeler@v4 + with: + dot: true + pr-number: ${{ steps.findPr.outputs.pr }} diff --git a/.github/ISSUE_TEMPLATE/.github/workflows/check-pr-label.yml b/.github/ISSUE_TEMPLATE/.github/workflows/check-pr-label.yml new file mode 100644 index 0000000..330f3d6 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/.github/workflows/check-pr-label.yml @@ -0,0 +1,25 @@ +name: PR Label Checker +on: + pull_request: + types: + - opened + - synchronize + - reopened + - labeled + - unlabeled + workflow_run: + workflows: + - auto-label + types: + - completed + +jobs: + + check_labels: + name: Check PR labels + runs-on: ubuntu-latest + steps: + - uses: docker://agilepathway/pull-request-label-checker:latest + with: + any_of: documentation,enhancement,bug,cicd,test,breaking-change,feature,scripts,dependencies + repo_token: ${{ secrets.GITHUB_TOKEN }} diff --git a/.github/ISSUE_TEMPLATE/.github/workflows/lint-pr.yml b/.github/ISSUE_TEMPLATE/.github/workflows/lint-pr.yml new file mode 100644 index 0000000..dca39a4 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/.github/workflows/lint-pr.yml @@ -0,0 +1,18 @@ +name: Lint PR +on: + pull_request_target: + types: + - opened + - edited + - synchronize +jobs: + main: + name: Validate PR title + runs-on: ubuntu-latest + steps: + - uses: amannn/action-semantic-pull-request@v5.1.0 + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + with: + validateSingleCommit: true + validateSingleCommitMatchesPrTitle: true diff --git a/CODEOWNERS b/CODEOWNERS new file mode 100644 index 0000000..e69de29 diff --git a/CODE_OF_CONDUCT.md b/CODE_OF_CONDUCT.md new file mode 100644 index 0000000..a691bfd --- /dev/null +++ b/CODE_OF_CONDUCT.md @@ -0,0 +1,132 @@ +# Contributor Covenant Code of Conduct + +## Our Pledge + +We as members, contributors, and leaders pledge to make participation in our +community a harassment-free experience for everyone, regardless of age, body +size, visible or invisible disability, ethnicity, sex characteristics, gender +identity and expression, level of experience, education, socio-economic status, +nationality, personal appearance, race, caste, color, religion, or sexual +identity and orientation. + +We pledge to act and interact in ways that contribute to an open, welcoming, +diverse, inclusive, and healthy community. + +## Our Standards + +Examples of behavior that contributes to a positive environment for our +community include: + +- Demonstrating empathy and kindness toward other people +- Being respectful of differing opinions, viewpoints, and experiences +- Giving and gracefully accepting constructive feedback +- Accepting responsibility and apologizing to those affected by our mistakes, + and learning from the experience +- Focusing on what is best not just for us as individuals, but for the overall + community + +Examples of unacceptable behavior include: + +- The use of sexualized language or imagery, and sexual attention or advances of + any kind +- Trolling, insulting or derogatory comments, and personal or political attacks +- Public or private harassment +- Publishing others' private information, such as a physical or email address, + without their explicit permission +- Other conduct which could reasonably be considered inappropriate in a + professional setting + +## Enforcement Responsibilities + +Community leaders are responsible for clarifying and enforcing our standards of +acceptable behavior and will take appropriate and fair corrective action in +response to any behavior that they deem inappropriate, threatening, offensive, +or harmful. + +Community leaders have the right and responsibility to remove, edit, or reject +comments, commits, code, wiki edits, issues, and other contributions that are +not aligned to this Code of Conduct, and will communicate reasons for moderation +decisions when appropriate. + +## Scope + +This Code of Conduct applies within all community spaces, and also applies when +an individual is officially representing the community in public spaces. +Examples of representing our community include using an official e-mail address, +posting via an official social media account, or acting as an appointed +representative at an online or offline event. + +## Enforcement + +Instances of abusive, harassing, or otherwise unacceptable behavior may be +reported to the community leaders responsible for enforcement at +[INSERT CONTACT METHOD]. +All complaints will be reviewed and investigated promptly and fairly. + +All community leaders are obligated to respect the privacy and security of the +reporter of any incident. + +## Enforcement Guidelines + +Community leaders will follow these Community Impact Guidelines in determining +the consequences for any action they deem in violation of this Code of Conduct: + +### 1. Correction + +**Community Impact**: Use of inappropriate language or other behavior deemed +unprofessional or unwelcome in the community. + +**Consequence**: A private, written warning from community leaders, providing +clarity around the nature of the violation and an explanation of why the +behavior was inappropriate. A public apology may be requested. + +### 2. Warning + +**Community Impact**: A violation through a single incident or series of +actions. + +**Consequence**: A warning with consequences for continued behavior. No +interaction with the people involved, including unsolicited interaction with +those enforcing the Code of Conduct, for a specified period of time. This +includes avoiding interactions in community spaces as well as external channels +like social media. Violating these terms may lead to a temporary or permanent +ban. + +### 3. Temporary Ban + +**Community Impact**: A serious violation of community standards, including +sustained inappropriate behavior. + +**Consequence**: A temporary ban from any sort of interaction or public +communication with the community for a specified period of time. No public or +private interaction with the people involved, including unsolicited interaction +with those enforcing the Code of Conduct, is allowed during this period. +Violating these terms may lead to a permanent ban. + +### 4. Permanent Ban + +**Community Impact**: Demonstrating a pattern of violation of community +standards, including sustained inappropriate behavior, harassment of an +individual, or aggression toward or disparagement of classes of individuals. + +**Consequence**: A permanent ban from any sort of public interaction within the +community. + +## Attribution + +This Code of Conduct is adapted from the [Contributor Covenant][homepage], +version 2.1, available at +[https://www.contributor-covenant.org/version/2/1/code_of_conduct.html][v2.1]. + +Community Impact Guidelines were inspired by +[Mozilla's code of conduct enforcement ladder][mozilla coc]. + +For answers to common questions about this code of conduct, see the FAQ at +[https://www.contributor-covenant.org/faq][faq]. Translations are available at +[https://www.contributor-covenant.org/translations][translations]. + +[homepage]: https://www.contributor-covenant.org +[v2.1]: https://www.contributor-covenant.org/version/2/1/code_of_conduct.html +[mozilla coc]: https://github.com/mozilla/diversity +[faq]: https://www.contributor-covenant.org/faq +[translations]: https://www.contributor-covenant.org/translations \ No newline at end of file diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 0000000..635a76d --- /dev/null +++ b/CONTRIBUTING.md @@ -0,0 +1,55 @@ +# Contributing to + +The following is a set of guidelines for contributing to IBC-Integration. + +These guidelines are subject to change. Feel free to propose changes to this document in a pull request. + +## Pull Request Checklist + +Before sending your pull requests, make sure you do the following: + +- Read the [contributing guidelines](CONTRIBUTING.md). +- Check if your changes adhere to the [guidelines](https://github.com/icon-project/community/blob/main/guidelines/technical-development/development-guidelines.md). +- Run the [unit tests](#running-unit-tests). + +## Code of Conduct + +The project is governed by the [Contributor Covenant Code of Conduct](https://www.contributor-covenant.org/version/2/1/code_of_conduct/code_of_conduct.md). Participants are expected to uphold this code. + +## Questions + +> **Note:** Github Issues are reserved for feature requests and bug reporting. Please don't create a new Github issue to ask a question. + +We have a vibrant developer community and several community resources to ask questions in. + +### Community Resources + +- [Github Discussions](https://github.com/icon-project//discussions) +- [ICON Official Discord](https://discord.gg/qa9m4bgKHE) + +## How Can I Contribute? + +### Reporting Bugs + +Before creating bug reports, please check **[our list of issues](https://github.com/icon-project//issues)** to see if an +issue already exists. + +> **Note:** For existing issues, please add a comment to the existing issue instead of opening a new issue. If the issue is closed and +> the problem persists, please open a new issue and include a link to the original issue in the body of your new one. + +When you are creating a bug report, please fill out [the required template](https://github.com/icon-project//blob/main/.github/ISSUE_TEMPLATE/bug.md) and include as many details as possible. + +### Contributing Code + +If you want to contribute, start working through the IBC-Integration repository, navigate to the Github "issues" tab and start looking through issues. We recommed issues labeled "good first issue". These are issues that we believe are particularly well suited for newcomers. If you decide to start on an issue, leave a comment so that other people know that you're working on it. If you want to help out, but not alone, use the issue comment thread to coordinate. + +Please see the [ICON Foundation Development Guidelines](https://github.com/icon-project/community/blob/main/guidelines/technical-development/development-guidelines.md) +for information regarding our development standards and practices. + +### IBC-Integration Core Development Process + +This section is intended for developers and project managers that are involved with core IBC-Integration. + +After the developer working on the branch determines the feature (or fix) branch satisfies the acceptance criteria of the associated issue and has sufficiently tested the added code, the developer should submit a pull request with at least 1 reviewer assigned for the feature branch to be merged into the main branch. + +After the pull request has been merged, the feature branch should be deleted and the issue should be closed. \ No newline at end of file diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..f49a4e1 --- /dev/null +++ b/LICENSE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. \ No newline at end of file diff --git a/NOTICE b/NOTICE new file mode 100644 index 0000000..93cdf97 --- /dev/null +++ b/NOTICE @@ -0,0 +1,210 @@ +THIRD PARTY SOFTWARE NOTICES AND INFORMATION + +This software incorporates material from third parties. + +_____ + +strangelove-ventures/interchaintest + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + \ No newline at end of file diff --git a/codecov.yml b/codecov.yml new file mode 100644 index 0000000..20176fb --- /dev/null +++ b/codecov.yml @@ -0,0 +1,37 @@ +codecov: + require_ci_to_pass: false +comment: + behavior: default + layout: "reach, diff, flags, files" + +ignore: + - "**/test_*" + - "**/*_test.*" + - "**/mocks/*" + - "**/mock/*" + - "libraries/rust/common/src/icon/*" + +flag_management: + default_rules: # the rules that will be followed for any flag added, generally + carryforward: true + statuses: + - type: project + target: auto + threshold: 1% + - type: patch + target: 80% + +coverage: + precision: 2 + range: "50...100" + round: down + status: + project: no + patch: # patch status only measures lines adjusted in the pull request or single commit + default: + target: 80% # target of an exact coverage number such as 75% or 100% + threshold: 2% # Allow the coverage to drop by X%, and posting a success status. + base: auto + changes: false # Codecov will detect changes in coverage that are NOT included in the commit/pull diff +github_checks: + annotations: true \ No newline at end of file From 7c029baa79dd322bd95744d926be66a3e85a8a33 Mon Sep 17 00:00:00 2001 From: Deepak Bomjan Date: Tue, 18 Jun 2024 13:46:58 +0545 Subject: [PATCH 55/63] ci: add hygiene ci checks --- .../.github/ISSUE_TEMPLATE/feature_request.md | 0 .../.github/PULL_REQUEST_TEMPLATE.md | 28 ---------------- .github/ISSUE_TEMPLATE/.github/labeler.yml | 11 ------- .github/ISSUE_TEMPLATE/.github/release.yml | 25 --------------- .../.github/workflows/auto-pr-labeler.yml | 32 ------------------- .../.github/workflows/check-pr-label.yml | 25 --------------- .../.github/workflows/lint-pr.yml | 18 ----------- 7 files changed, 139 deletions(-) delete mode 100644 .github/ISSUE_TEMPLATE/.github/ISSUE_TEMPLATE/feature_request.md delete mode 100644 .github/ISSUE_TEMPLATE/.github/PULL_REQUEST_TEMPLATE.md delete mode 100644 .github/ISSUE_TEMPLATE/.github/labeler.yml delete mode 100644 .github/ISSUE_TEMPLATE/.github/release.yml delete mode 100644 .github/ISSUE_TEMPLATE/.github/workflows/auto-pr-labeler.yml delete mode 100644 .github/ISSUE_TEMPLATE/.github/workflows/check-pr-label.yml delete mode 100644 .github/ISSUE_TEMPLATE/.github/workflows/lint-pr.yml diff --git a/.github/ISSUE_TEMPLATE/.github/ISSUE_TEMPLATE/feature_request.md b/.github/ISSUE_TEMPLATE/.github/ISSUE_TEMPLATE/feature_request.md deleted file mode 100644 index e69de29..0000000 diff --git a/.github/ISSUE_TEMPLATE/.github/PULL_REQUEST_TEMPLATE.md b/.github/ISSUE_TEMPLATE/.github/PULL_REQUEST_TEMPLATE.md deleted file mode 100644 index 75e813b..0000000 --- a/.github/ISSUE_TEMPLATE/.github/PULL_REQUEST_TEMPLATE.md +++ /dev/null @@ -1,28 +0,0 @@ -## Description - -### Commit Message - -```bash -type: commit message -``` - -see the [guidelines](https://github.com/icon-project/community/blob/main/guidelines/technical/software-development-guidelines.md#commit-messages) for commit messages. - -### Changelog Entry - -```bash -version: -``` - -## Checklist - -- [ ] I have performed a self-review of my own code -- [ ] I have documented my code in accordance with the [documentation guidelines](https://github.com/icon-project/community/blob/main/guidelines/technical/software-development-guidelines.md#documentation) -- [ ] My changes generate no new warnings -- [ ] I have added tests that prove my fix is effective or that my feature works -- [ ] I have run the unit tests -- [ ] I only have one commit (if not, squash them into one commit). -- [ ] I have a descriptive commit message that adheres to the [commit message guidelines](https://github.com/icon-project/community/blob/main/guidelines/technical/software-development-guidelines.md#commit-messages) -- [ ] I have added version bump label on PR. - -> Please review the [CONTRIBUTING.md](/CONTRIBUTING.md) file for detailed contributing guidelines. \ No newline at end of file diff --git a/.github/ISSUE_TEMPLATE/.github/labeler.yml b/.github/ISSUE_TEMPLATE/.github/labeler.yml deleted file mode 100644 index 0c61d38..0000000 --- a/.github/ISSUE_TEMPLATE/.github/labeler.yml +++ /dev/null @@ -1,11 +0,0 @@ -cicd: - - '.github/workflows/*' - -scripts: - - 'scripts/*' - -test: - - 'test/**' - -documentation: -- '**/*.md' diff --git a/.github/ISSUE_TEMPLATE/.github/release.yml b/.github/ISSUE_TEMPLATE/.github/release.yml deleted file mode 100644 index 95830b2..0000000 --- a/.github/ISSUE_TEMPLATE/.github/release.yml +++ /dev/null @@ -1,25 +0,0 @@ -# .github/release.yml - -changelog: - exclude: - labels: - - cicd - - scripts - - test - categories: - - title: Breaking Changes 🛠 - labels: - - Major - - breaking-change - - title: New Features 🎉 - labels: - - Minor - - enhancement - - Feature - - title: Bug Fixes 🐛 - labels: - - Patch - - bug - - title: Other Changes 📝 - labels: - - "*" diff --git a/.github/ISSUE_TEMPLATE/.github/workflows/auto-pr-labeler.yml b/.github/ISSUE_TEMPLATE/.github/workflows/auto-pr-labeler.yml deleted file mode 100644 index 906947f..0000000 --- a/.github/ISSUE_TEMPLATE/.github/workflows/auto-pr-labeler.yml +++ /dev/null @@ -1,32 +0,0 @@ -name: Pull Request Labeler -on: - pull_request: - types: - - opened - - edited - - synchronize -jobs: - auto-label: - permissions: - contents: read - pull-requests: write - runs-on: ubuntu-latest - steps: - - name: Find Current Pull Request - uses: jwalton/gh-find-current-pr@v1.3.2 - id: findPr - with: - # Can be "open", "closed", or "all". Defaults to "open". - state: open - - run: echo "PR Number is ${PR}" - if: success() && steps.findPr.outputs.number - env: - PR: ${{ steps.findPr.outputs.pr }} - - - name: check pr pr-number - run: echo ${{ github.event.number }} - - - uses: actions/labeler@v4 - with: - dot: true - pr-number: ${{ steps.findPr.outputs.pr }} diff --git a/.github/ISSUE_TEMPLATE/.github/workflows/check-pr-label.yml b/.github/ISSUE_TEMPLATE/.github/workflows/check-pr-label.yml deleted file mode 100644 index 330f3d6..0000000 --- a/.github/ISSUE_TEMPLATE/.github/workflows/check-pr-label.yml +++ /dev/null @@ -1,25 +0,0 @@ -name: PR Label Checker -on: - pull_request: - types: - - opened - - synchronize - - reopened - - labeled - - unlabeled - workflow_run: - workflows: - - auto-label - types: - - completed - -jobs: - - check_labels: - name: Check PR labels - runs-on: ubuntu-latest - steps: - - uses: docker://agilepathway/pull-request-label-checker:latest - with: - any_of: documentation,enhancement,bug,cicd,test,breaking-change,feature,scripts,dependencies - repo_token: ${{ secrets.GITHUB_TOKEN }} diff --git a/.github/ISSUE_TEMPLATE/.github/workflows/lint-pr.yml b/.github/ISSUE_TEMPLATE/.github/workflows/lint-pr.yml deleted file mode 100644 index dca39a4..0000000 --- a/.github/ISSUE_TEMPLATE/.github/workflows/lint-pr.yml +++ /dev/null @@ -1,18 +0,0 @@ -name: Lint PR -on: - pull_request_target: - types: - - opened - - edited - - synchronize -jobs: - main: - name: Validate PR title - runs-on: ubuntu-latest - steps: - - uses: amannn/action-semantic-pull-request@v5.1.0 - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - with: - validateSingleCommit: true - validateSingleCommitMatchesPrTitle: true From 903041bed6c13bd8f661142275cd1e5a239a0971 Mon Sep 17 00:00:00 2001 From: Deepak Bomjan Date: Thu, 20 Jun 2024 11:01:07 +0545 Subject: [PATCH 56/63] ci: add pull request template --- .gitignore | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/.gitignore b/.gitignore index 2be4200..75ea5e0 100644 --- a/.gitignore +++ b/.gitignore @@ -9,4 +9,6 @@ target .DS_Store Cargo.lock test_snapshots -.VSCodeCounter \ No newline at end of file +.VSCodeCounter + +artifacts/ \ No newline at end of file From 65c82f35de0ac1d3fb365e58b6959f0ade668786 Mon Sep 17 00:00:00 2001 From: DeepakBomjan <44976635+DeepakBomjan@users.noreply.github.com> Date: Wed, 18 Sep 2024 08:16:20 +0545 Subject: [PATCH 57/63] docs: add Codecov badges --- README.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 881ecfc..d371897 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,4 @@ +[![codecov](https://codecov.io/gh/balancednetwork/balanced-soroban-contracts/graph/badge.svg?token=6Epcv9Uek5)](https://codecov.io/gh/balancednetwork/balanced-soroban-contracts) ![build](https://github.com/balancednetwork/balanced-soroban-contracts/actions/workflows/build-test-soroban-contracts.yml/badge.svg) # Balanced Package Structure @@ -100,4 +101,4 @@ function get_protocols( Vec, Vec ), ContractError> -``` \ No newline at end of file +``` From a983075133e42ec3194e3285d0f21f6aabaf8dff Mon Sep 17 00:00:00 2001 From: DeepakBomjan <44976635+DeepakBomjan@users.noreply.github.com> Date: Wed, 18 Sep 2024 13:55:52 +0545 Subject: [PATCH 58/63] ci: upgrade rust toolchain version to 1.79.0 --- .github/workflows/build-test-soroban-contracts.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/build-test-soroban-contracts.yml b/.github/workflows/build-test-soroban-contracts.yml index dfa7d76..560223d 100644 --- a/.github/workflows/build-test-soroban-contracts.yml +++ b/.github/workflows/build-test-soroban-contracts.yml @@ -20,7 +20,7 @@ jobs: - name: Install stable toolchain uses: actions-rs/toolchain@v1 with: - toolchain: 1.78.0 + toolchain: 1.79.0 target: wasm32-unknown-unknown override: true profile: minimal From f72296fb8328742c9740c55cdfc4c58fbe177745 Mon Sep 17 00:00:00 2001 From: sagar sapkota Date: Wed, 18 Sep 2024 18:05:41 +0545 Subject: [PATCH 59/63] rate limit default value set --- contracts/asset_manager/src/contract.rs | 8 +- contracts/asset_manager/src/states.rs | 5 +- .../src/tests/asset_manager_test.rs | 2 +- contracts/balanced_doller/src/tests/test.rs | 219 ++++++++++++++++++ 4 files changed, 227 insertions(+), 7 deletions(-) create mode 100644 contracts/balanced_doller/src/tests/test.rs diff --git a/contracts/asset_manager/src/contract.rs b/contracts/asset_manager/src/contract.rs index d83ca1d..7be1a75 100644 --- a/contracts/asset_manager/src/contract.rs +++ b/contracts/asset_manager/src/contract.rs @@ -86,7 +86,7 @@ impl AssetManager { } pub fn get_rate_limit(env: Env, token_address: Address) -> (u64, u32, u64, u64) { - let data: TokenData = read_token_data(&env, token_address).unwrap(); + let data: TokenData = read_token_data(&env, token_address); ( data.period, data.percentage, @@ -97,7 +97,7 @@ impl AssetManager { pub fn reset_limit(env: Env, token: Address) { let balance = Self::get_token_balance(&env, token.clone()); - let mut data: TokenData = read_token_data(&env, token.clone()).unwrap(); + let mut data: TokenData = read_token_data(&env, token.clone()); data.current_limit = (balance * data.percentage as u128 / POINTS) as u64; write_token_data(&env, token, data); } @@ -119,7 +119,7 @@ impl AssetManager { if balance - amount < limit { panic_with_error!(&env, ContractError::ExceedsWithdrawLimit); }; - let mut data: TokenData = read_token_data(&env, token.clone()).unwrap(); + let mut data: TokenData = read_token_data(&env, token.clone()); data.current_limit = limit as u64; data.last_update = env.ledger().timestamp(); write_token_data(&env, token, data); @@ -131,7 +131,7 @@ impl AssetManager { balance: u128, token: Address, ) -> Result { - let data: TokenData = read_token_data(&env, token).unwrap(); + let data: TokenData = read_token_data(&env, token); let period: u128 = data.period as u128; let percentage: u128 = data.percentage as u128; if period == 0 { diff --git a/contracts/asset_manager/src/states.rs b/contracts/asset_manager/src/states.rs index 7bf1a60..e6fbd80 100644 --- a/contracts/asset_manager/src/states.rs +++ b/contracts/asset_manager/src/states.rs @@ -41,9 +41,10 @@ pub fn write_token_data(env: &Env, token_address: Address, data: TokenData) { env.storage().persistent().set(&key, &data); } -pub fn read_token_data(env: &Env, token_address: Address) -> Option { +pub fn read_token_data(env: &Env, token_address: Address) -> TokenData { + let default = TokenData{percentage: 0, period: 0, last_update: 0, current_limit: 0 }; let key = DataKey::TokenData(token_address); - env.storage().persistent().get(&key) + env.storage().persistent().get(&key).unwrap_or(default) } pub fn write_tokens(e: &Env, token: Address) { diff --git a/contracts/asset_manager/src/tests/asset_manager_test.rs b/contracts/asset_manager/src/tests/asset_manager_test.rs index afb2654..e4d6fd8 100644 --- a/contracts/asset_manager/src/tests/asset_manager_test.rs +++ b/contracts/asset_manager/src/tests/asset_manager_test.rs @@ -288,7 +288,7 @@ fn test_handle_call_message_for_withdraw_to() { ctx.env.mock_all_auths(); ctx.init_context(&client); - client.configure_rate_limit(&ctx.token, &300, &300); + //client.configure_rate_limit(&ctx.token, &300, &300); let bnusd_amount = 100000u128; let token_client = token::Client::new(&ctx.env, &ctx.token); diff --git a/contracts/balanced_doller/src/tests/test.rs b/contracts/balanced_doller/src/tests/test.rs new file mode 100644 index 0000000..264425a --- /dev/null +++ b/contracts/balanced_doller/src/tests/test.rs @@ -0,0 +1,219 @@ +// #![cfg(test)] +// extern crate std; + +// use crate::contract::BalancedDollarClient; + + +// use soroban_sdk::{ +// symbol_short, +// testutils::{Address as _, AuthorizedFunction, AuthorizedInvocation}, +// Address, IntoVal, Symbol, +// }; + +// use super::setup::*; + +// #[test] +// fn test() { +// let ctx = TestContext::default(); +// let client = BalancedDollarClient::new(&ctx.env, &ctx.registry); +// let e = &ctx.env; +// e.mock_all_auths(); +// ctx.init_context(&client); + + +// let admin2 = Address::generate(&e); +// let user1 = Address::generate(&e); +// let user2 = Address::generate(&e); +// let user3 = Address::generate(&e); + +// client.mint(&ctx.admin, &1000); +// assert_eq!( +// e.auths(), +// std::vec![( +// ctx.admin.clone(), +// AuthorizedInvocation { +// function: AuthorizedFunction::Contract(( +// client.address.clone(), +// symbol_short!("mint"), +// (&ctx.admin, 1000_i128).into_val(e), +// )), +// sub_invocations: std::vec![] +// } +// )] +// ); +// assert_eq!(client.balance(&ctx.admin), 1000); + +// client.approve(&ctx.admin, &user3, &500, &200); +// assert_eq!( +// e.auths(), +// std::vec![( +// ctx.admin.clone(), +// AuthorizedInvocation { +// function: AuthorizedFunction::Contract(( +// client.address.clone(), +// symbol_short!("approve"), +// (&ctx.admin, &user3, 500_i128, 200_u32).into_val(e), +// )), +// sub_invocations: std::vec![] +// } +// )] +// ); +// assert_eq!(client.allowance(&ctx.admin, &user3), 500); + +// client.transfer(&ctx.admin, &user2, &600); +// assert_eq!( +// e.auths(), +// std::vec![( +// ctx.admin.clone(), +// AuthorizedInvocation { +// function: AuthorizedFunction::Contract(( +// client.address.clone(), +// symbol_short!("transfer"), +// (&ctx.admin, &user2, 600_i128).into_val(e), +// )), +// sub_invocations: std::vec![] +// } +// )] +// ); +// assert_eq!(client.balance(&ctx.admin), 400); +// assert_eq!(client.balance(&user2), 600); + +// client.transfer_from(&user3, &ctx.admin, &user1, &400); +// assert_eq!( +// e.auths(), +// std::vec![( +// user3.clone(), +// AuthorizedInvocation { +// function: AuthorizedFunction::Contract(( +// client.address.clone(), +// Symbol::new(&e, "transfer_from"), +// (&user3, &ctx.admin, &user1, 400_i128).into_val(e), +// )), +// sub_invocations: std::vec![] +// } +// )] +// ); +// assert_eq!(client.balance(&user1), 400); +// assert_eq!(client.balance(&user2), 600); + +// client.transfer(&user1, &user3, &300); +// assert_eq!(client.balance(&user1), 100); +// assert_eq!(client.balance(&user3), 300); + +// client.set_admin(&admin2); +// assert_eq!( +// e.auths(), +// std::vec![( +// ctx.admin.clone(), +// AuthorizedInvocation { +// function: AuthorizedFunction::Contract(( +// client.address.clone(), +// symbol_short!("set_admin"), +// (&admin2,).into_val(e), +// )), +// sub_invocations: std::vec![] +// } +// )] +// ); + +// // Increase to 500 +// client.approve(&user2, &user3, &500, &200); +// assert_eq!(client.allowance(&user2, &user3), 500); +// client.approve(&user2, &user3, &0, &200); +// assert_eq!( +// e.auths(), +// std::vec![( +// user2.clone(), +// AuthorizedInvocation { +// function: AuthorizedFunction::Contract(( +// client.address.clone(), +// symbol_short!("approve"), +// (&user2, &user3, 0_i128, 200_u32).into_val(e), +// )), +// sub_invocations: std::vec![] +// } +// )] +// ); +// assert_eq!(client.allowance(&user2, &user3), 0); +// } + +// #[test] +// fn test_burn() { +// let ctx = TestContext::default(); +// let client = BalancedDollarClient::new(&ctx.env, &ctx.registry); +// let e = &ctx.env; +// e.mock_all_auths(); +// ctx.init_context(&client); + + +// let user2 = Address::generate(&e); + +// client.mint(&ctx.admin, &1000); +// assert_eq!(client.balance(&ctx.admin), 1000); + +// client.approve(&ctx.admin, &user2, &500, &200); +// assert_eq!(client.allowance(&ctx.admin, &user2), 500); + +// client.burn_from(&user2, &ctx.admin, &500); +// assert_eq!( +// e.auths(), +// std::vec![( +// user2.clone(), +// AuthorizedInvocation { +// function: AuthorizedFunction::Contract(( +// client.address.clone(), +// symbol_short!("burn_from"), +// (&user2, &ctx.admin, 500_i128).into_val(e), +// )), +// sub_invocations: std::vec![] +// } +// )] +// ); + +// assert_eq!(client.allowance(&ctx.admin, &user2), 0); +// assert_eq!(client.balance(&ctx.admin), 500); +// assert_eq!(client.balance(&user2), 0); + +// client.burn(&ctx.admin, &500); + +// assert_eq!(client.balance(&ctx.admin), 0); +// assert_eq!(client.balance(&user2), 0); +// } + +// #[test] +// #[should_panic(expected = "insufficient balance")] +// fn transfer_insufficient_balance() { +// let ctx = TestContext::default(); +// let client = BalancedDollarClient::new(&ctx.env, &ctx.registry); +// let e = &ctx.env; +// e.mock_all_auths(); +// ctx.init_context(&client); +// e.mock_all_auths(); +// let user2 = Address::generate(&e); + +// client.mint(&ctx.admin, &1000); +// assert_eq!(client.balance(&ctx.admin), 1000); + +// client.transfer(&ctx.admin, &user2, &1001); +// } + +// #[test] +// #[should_panic(expected = "insufficient allowance")] +// fn transfer_from_insufficient_allowance() { +// let ctx = TestContext::default(); +// let client = BalancedDollarClient::new(&ctx.env, &ctx.registry); +// let e = &ctx.env; +// e.mock_all_auths(); +// ctx.init_context(&client); +// let user2 = Address::generate(&e); +// let user3 = Address::generate(&e); + +// client.mint(&ctx.admin, &1000); +// assert_eq!(client.balance(&ctx.admin), 1000); + +// client.approve(&ctx.admin, &user3, &100, &200); +// assert_eq!(client.allowance(&ctx.admin, &user3), 100); + +// client.transfer_from(&user3, &ctx.admin, &user2, &101); +// } + From 18d197e8cd312d94776c9b802eeed92762a1f8e5 Mon Sep 17 00:00:00 2001 From: sagar sapkota Date: Thu, 19 Sep 2024 13:48:46 +0545 Subject: [PATCH 60/63] burn method removed -> token interface removed --- contracts/balanced_doller/src/contract.rs | 34 ++++++----------------- 1 file changed, 8 insertions(+), 26 deletions(-) diff --git a/contracts/balanced_doller/src/contract.rs b/contracts/balanced_doller/src/contract.rs index 79b6bef..8f855d5 100644 --- a/contracts/balanced_doller/src/contract.rs +++ b/contracts/balanced_doller/src/contract.rs @@ -8,7 +8,6 @@ use crate::errors::ContractError; use crate::metadata::{read_decimal, read_name, read_symbol, write_metadata}; use crate::states::{has_administrator, read_administrator, write_administrator}; use crate::storage_types::{DataKey, INSTANCE_BUMP_AMOUNT, INSTANCE_LIFETIME_THRESHOLD}; -use soroban_sdk::token::{self, Interface as _}; use soroban_sdk::{contract, contractimpl, panic_with_error, Address, Bytes, BytesN, Env, String, Vec}; use soroban_token_sdk::metadata::TokenMetadata; use soroban_token_sdk::TokenUtils; @@ -98,15 +97,12 @@ impl BalancedDollar { .instance() .extend_ttl(INSTANCE_LIFETIME_THRESHOLD, INSTANCE_BUMP_AMOUNT); } -} -#[contractimpl] -impl token::Interface for BalancedDollar { - fn allowance(e: Env, from: Address, spender: Address) -> i128 { + pub fn allowance(e: Env, from: Address, spender: Address) -> i128 { read_allowance(&e, from, spender).amount } - fn approve(e: Env, from: Address, spender: Address, amount: i128, expiration_ledger: u32) { + pub fn approve(e: Env, from: Address, spender: Address, amount: i128, expiration_ledger: u32) { from.require_auth(); check_nonnegative_amount(amount); @@ -117,11 +113,11 @@ impl token::Interface for BalancedDollar { .approve(from, spender, amount, expiration_ledger); } - fn balance(e: Env, id: Address) -> i128 { + pub fn balance(e: Env, id: Address) -> i128 { read_balance(&e, id) } - fn transfer(e: Env, from: Address, to: Address, amount: i128) { + pub fn transfer(e: Env, from: Address, to: Address, amount: i128) { from.require_auth(); check_nonnegative_amount(amount); @@ -130,7 +126,7 @@ impl token::Interface for BalancedDollar { TokenUtils::new(&e).events().transfer(from, to, amount); } - fn transfer_from(e: Env, spender: Address, from: Address, to: Address, amount: i128) { + pub fn transfer_from(e: Env, spender: Address, from: Address, to: Address, amount: i128) { spender.require_auth(); check_nonnegative_amount(amount); @@ -141,29 +137,15 @@ impl token::Interface for BalancedDollar { TokenUtils::new(&e).events().transfer(from, to, amount) } - fn burn(e: Env, from: Address, amount: i128) { - balanced_dollar::_burn(&e, from, amount); - } - - fn burn_from(e: Env, spender: Address, from: Address, amount: i128) { - spender.require_auth(); - - check_nonnegative_amount(amount); - - spend_allowance(&e, from.clone(), spender, amount); - spend_balance(&e, from.clone(), amount); - TokenUtils::new(&e).events().burn(from, amount) - } - - fn decimals(e: Env) -> u32 { + pub fn decimals(e: Env) -> u32 { read_decimal(&e) } - fn name(e: Env) -> String { + pub fn name(e: Env) -> String { read_name(&e) } - fn symbol(e: Env) -> String { + pub fn symbol(e: Env) -> String { read_symbol(&e) } } From 53c0b7838e34522a036bd1a51e680eb1fd7c9488 Mon Sep 17 00:00:00 2001 From: sagar sapkota Date: Thu, 19 Sep 2024 15:03:34 +0545 Subject: [PATCH 61/63] rlp issue fix --- libs/soroban-rlp/src/utils.rs | 21 ++++++++++++++------- 1 file changed, 14 insertions(+), 7 deletions(-) diff --git a/libs/soroban-rlp/src/utils.rs b/libs/soroban-rlp/src/utils.rs index 90b000d..366309d 100644 --- a/libs/soroban-rlp/src/utils.rs +++ b/libs/soroban-rlp/src/utils.rs @@ -1,14 +1,17 @@ use soroban_sdk::{ + bytes, xdr::{FromXdr, ToXdr}, Bytes, Env, String, }; pub fn u32_to_bytes(env: &Env, number: u32) -> Bytes { - let mut bytes = Bytes::new(&env); + let mut bytes = bytes!(&env, 0x00); let mut i = 3; + let mut leading_zero = true; while i >= 0 { let val = (number >> (i * 8) & 0xff) as u8; - if val > 0 { + if val > 0 || !leading_zero { + leading_zero = false; bytes.push_back(val); } @@ -26,11 +29,13 @@ pub fn bytes_to_u32(bytes: Bytes) -> u32 { } pub fn u64_to_bytes(env: &Env, number: u64) -> Bytes { - let mut bytes = Bytes::new(&env); + let mut bytes = bytes!(&env, 0x00); let mut i = 7; + let mut leading_zero = true; while i >= 0 { let val = (number >> (i * 8) & 0xff) as u8; - if val > 0 { + if val > 0 || !leading_zero { + leading_zero = false; bytes.push_back(val); } @@ -48,11 +53,13 @@ pub fn bytes_to_u64(bytes: Bytes) -> u64 { } pub fn u128_to_bytes(env: &Env, number: u128) -> Bytes { - let mut bytes = Bytes::new(&env); + let mut bytes = bytes!(&env, 0x00); let mut i = 15; + let mut leading_zero = true; while i >= 0 { let val = (number >> (i * 8) & 0xff) as u8; - if val > 0 { + if val > 0 || !leading_zero { + leading_zero = false; bytes.push_back(val); } @@ -101,4 +108,4 @@ pub fn bytes_to_string(env: &Env, bytes: Bytes) -> String { bytes_xdr.set(3, 14); String::from_xdr(&env, &bytes_xdr).unwrap() -} +} \ No newline at end of file From cd26ae92a740d655cd8c30046aa53634347519fe Mon Sep 17 00:00:00 2001 From: bishalbikram Date: Fri, 20 Sep 2024 00:37:15 +0545 Subject: [PATCH 62/63] chore: configure upgrade authority for upgrading contracts --- contracts/asset_manager/src/config.rs | 1 + contracts/asset_manager/src/contract.rs | 37 ++++++++--- .../src/tests/asset_manager_test.rs | 36 +++++++++- contracts/asset_manager/src/tests/setup.rs | 10 ++- contracts/balanced_doller/src/config.rs | 3 +- contracts/balanced_doller/src/contract.rs | 24 +++++-- .../src/tests/balanced_dollar_test.rs | 65 ++++++++++++------- contracts/balanced_doller/src/tests/setup.rs | 14 ++-- contracts/xcall_manager/src/config.rs | 1 + contracts/xcall_manager/src/contract.rs | 30 ++++++--- contracts/xcall_manager/src/tests/setup.rs | 52 ++++++++------- .../src/tests/xcall_manager_test.rs | 54 +++++++++++---- 12 files changed, 232 insertions(+), 95 deletions(-) diff --git a/contracts/asset_manager/src/config.rs b/contracts/asset_manager/src/config.rs index 524b978..5ae6f70 100644 --- a/contracts/asset_manager/src/config.rs +++ b/contracts/asset_manager/src/config.rs @@ -9,6 +9,7 @@ pub struct ConfigData { pub native_address: Address, pub icon_asset_manager: String, pub xcall_network_address: String, + pub upgrade_authority: Address, } pub fn set_config(e: &Env, config: ConfigData) { diff --git a/contracts/asset_manager/src/contract.rs b/contracts/asset_manager/src/contract.rs index 7be1a75..d9ad8a5 100644 --- a/contracts/asset_manager/src/contract.rs +++ b/contracts/asset_manager/src/contract.rs @@ -1,5 +1,5 @@ use soroban_sdk::{ - contract, contractimpl, panic_with_error, token, Address, Bytes, BytesN, Env, String, Vec + contract, contractimpl, panic_with_error, token, Address, Bytes, BytesN, Env, String, Vec, }; mod xcall { soroban_sdk::contractimport!(file = "../../wasm/xcall.wasm"); @@ -7,12 +7,12 @@ mod xcall { use crate::errors::ContractError; use crate::storage_types::TokenData; use crate::{ - config::{get_config, set_config, ConfigData}, + config::{self, get_config, set_config, ConfigData}, states::{ extent_ttl, has_registry, read_administrator, read_token_data, read_tokens, write_administrator, write_registry, write_token_data, write_tokens, }, - storage_types::{DataKey, POINTS}, + storage_types::POINTS, xcall_manager_interface::XcallManagerClient, }; use soroban_rlp::balanced::address_utils::is_valid_string_address; @@ -47,7 +47,7 @@ impl AssetManager { pub fn set_admin(env: Env, new_admin: Address) { let admin = read_administrator(&env); admin.require_auth(); - + write_administrator(&env, &new_admin); } @@ -81,7 +81,16 @@ impl AssetManager { return Err(ContractError::PercentageShouldBeLessThanOrEqualToPOINTS); } - write_token_data(&env, token_address, TokenData{period, percentage, last_update: env.ledger().timestamp(), current_limit: 0}); + write_token_data( + &env, + token_address, + TokenData { + period, + percentage, + last_update: env.ledger().timestamp(), + current_limit: 0, + }, + ); Ok(()) } @@ -91,7 +100,7 @@ impl AssetManager { data.period, data.percentage, data.last_update, - data.current_limit + data.current_limit, ) } @@ -107,7 +116,6 @@ impl AssetManager { return Ok(Self::calculate_limit(&env, balance, token)?); } - fn get_token_balance(env: &Env, token: Address) -> u128 { let token_client = token::Client::new(env, &token); return token_client.balance(&env.current_contract_address()) as u128; @@ -251,7 +259,7 @@ impl AssetManager { xcall.require_auth(); let method = Deposit::get_method(&e, data.clone()); - + let icon_asset_manager = config.icon_asset_manager; let current_contract = e.current_contract_address(); if method == String::from_str(&e, &WITHDRAW_TO_NAME) { @@ -324,9 +332,18 @@ impl AssetManager { has_registry(&e) } + pub fn set_upgrade_authority(e: Env, upgrade_authority: Address) { + let mut config = config::get_config(&e); + + config.upgrade_authority.require_auth(); + + config.upgrade_authority = upgrade_authority; + config::set_config(&e, config); + } + pub fn upgrade(e: Env, new_wasm_hash: BytesN<32>) { - let admin: Address = e.storage().instance().get(&DataKey::Admin).unwrap(); - admin.require_auth(); + let config = get_config(&e); + config.upgrade_authority.require_auth(); e.deployer().update_current_contract_wasm(new_wasm_hash); } diff --git a/contracts/asset_manager/src/tests/asset_manager_test.rs b/contracts/asset_manager/src/tests/asset_manager_test.rs index e4d6fd8..a30949a 100644 --- a/contracts/asset_manager/src/tests/asset_manager_test.rs +++ b/contracts/asset_manager/src/tests/asset_manager_test.rs @@ -1,9 +1,10 @@ #![cfg(test)] extern crate std; -use crate::{contract::AssetManagerClient, storage_types::DataKey}; +use crate::{config, contract::AssetManagerClient, storage_types::DataKey}; use soroban_sdk::{ - testutils::{storage::Persistent, Address as _, AuthorizedFunction, AuthorizedInvocation}, token, Address, Bytes, IntoVal, String, Symbol, Vec + testutils::{storage::Persistent, Address as _, AuthorizedFunction, AuthorizedInvocation}, + token, Address, Bytes, IntoVal, String, Symbol, Vec, }; use soroban_rlp::balanced::messages::{deposit_revert::DepositRevert, withdraw_to::WithdrawTo}; @@ -523,7 +524,7 @@ fn test_extend_ttl() { client.configure_rate_limit(&ctx.token, &300, &300); let token = ctx.token; - + client.extend_ttl(); ctx.env.as_contract(&client.address, || { @@ -531,5 +532,34 @@ fn test_extend_ttl() { let before_ttl = ctx.env.storage().persistent().get_ttl(&key); std::println!("before ttl is: {:?}", before_ttl); }); +} + +#[test] +fn test_set_upgrade_authority() { + let ctx = TestContext::default(); + let client = AssetManagerClient::new(&ctx.env, &ctx.registry); + ctx.init_context(&client); + + let new_upgrade_authority = Address::generate(&ctx.env); + client.set_upgrade_authority(&new_upgrade_authority); + + assert_eq!( + ctx.env.auths(), + std::vec![( + ctx.upgrade_authority.clone(), + AuthorizedInvocation { + function: AuthorizedFunction::Contract(( + ctx.registry.clone(), + Symbol::new(&ctx.env, "set_upgrade_authority"), + (&new_upgrade_authority,).into_val(&ctx.env) + )), + sub_invocations: std::vec![] + } + )] + ); + ctx.env.as_contract(&client.address, || { + let config = config::get_config(&ctx.env); + assert_eq!(config.upgrade_authority, new_upgrade_authority) + }); } diff --git a/contracts/asset_manager/src/tests/setup.rs b/contracts/asset_manager/src/tests/setup.rs index f29dfff..7e57249 100644 --- a/contracts/asset_manager/src/tests/setup.rs +++ b/contracts/asset_manager/src/tests/setup.rs @@ -30,6 +30,7 @@ pub struct TestContext { pub admin: Address, pub depositor: Address, pub withdrawer: Address, + pub upgrade_authority: Address, pub xcall: Address, pub xcall_manager: Address, pub icon_asset_manager: String, @@ -56,6 +57,7 @@ impl TestContext { admin: Address::generate(&env), depositor: Address::generate(&env), withdrawer: Address::generate(&env), + upgrade_authority: Address::generate(&env), xcall: xcall.clone(), xcall_manager: xcall_manager, icon_asset_manager: String::from_str(&env, "icon01/hxjnfh4u"), @@ -63,7 +65,9 @@ impl TestContext { token: token.address(), centralized_connection: centralized_connection, nid: String::from_str(&env, "stellar"), - native_token: env.register_stellar_asset_contract_v2(token_admin.clone()).address(), + native_token: env + .register_stellar_asset_contract_v2(token_admin.clone()) + .address(), xcall_client: xcall::Client::new(&env, &xcall), env, } @@ -78,10 +82,10 @@ impl TestContext { xcall_manager: self.xcall_manager.clone(), native_address: self.native_token.clone(), icon_asset_manager: self.icon_asset_manager.clone(), - xcall_network_address: self.xcall_client.get_network_address() + xcall_network_address: self.xcall_client.get_network_address(), + upgrade_authority: self.upgrade_authority.clone(), }; client.initialize(&self.registry, &self.admin, &config); - } pub fn init_xcall_manager_context(&self) { diff --git a/contracts/balanced_doller/src/config.rs b/contracts/balanced_doller/src/config.rs index 13b88b8..edb5190 100644 --- a/contracts/balanced_doller/src/config.rs +++ b/contracts/balanced_doller/src/config.rs @@ -8,7 +8,8 @@ pub struct ConfigData { pub xcall_manager: Address, pub nid: String, pub icon_bn_usd: String, - pub xcall_network_address: String + pub xcall_network_address: String, + pub upgrade_authority: Address, } pub fn set_config(e: &Env, config: ConfigData) { diff --git a/contracts/balanced_doller/src/contract.rs b/contracts/balanced_doller/src/contract.rs index 8f855d5..8802007 100644 --- a/contracts/balanced_doller/src/contract.rs +++ b/contracts/balanced_doller/src/contract.rs @@ -3,12 +3,14 @@ use crate::allowance::{read_allowance, spend_allowance, write_allowance}; use crate::balance::{read_balance, receive_balance, spend_balance}; use crate::balanced_dollar; -use crate::config::ConfigData; +use crate::config::{self, ConfigData}; use crate::errors::ContractError; use crate::metadata::{read_decimal, read_name, read_symbol, write_metadata}; use crate::states::{has_administrator, read_administrator, write_administrator}; -use crate::storage_types::{DataKey, INSTANCE_BUMP_AMOUNT, INSTANCE_LIFETIME_THRESHOLD}; -use soroban_sdk::{contract, contractimpl, panic_with_error, Address, Bytes, BytesN, Env, String, Vec}; +use crate::storage_types::{INSTANCE_BUMP_AMOUNT, INSTANCE_LIFETIME_THRESHOLD}; +use soroban_sdk::{ + contract, contractimpl, panic_with_error, Address, Bytes, BytesN, Env, String, Vec, +}; use soroban_token_sdk::metadata::TokenMetadata; use soroban_token_sdk::TokenUtils; pub fn check_nonnegative_amount(amount: i128) { @@ -65,7 +67,7 @@ impl BalancedDollar { from: Address, amount: u128, to: String, - data: Option + data: Option, ) -> Result<(), ContractError> { from.require_auth(); let transfer_data = data.unwrap_or(Bytes::from_array(&e, &[0u8; 32])); @@ -85,9 +87,18 @@ impl BalancedDollar { has_administrator(&e) } + pub fn set_upgrade_authority(e: Env, upgrade_authority: Address) { + let mut config = config::get_config(&e); + + config.upgrade_authority.require_auth(); + + config.upgrade_authority = upgrade_authority; + config::set_config(&e, config); + } + pub fn upgrade(e: Env, new_wasm_hash: BytesN<32>) { - let admin: Address = e.storage().instance().get(&DataKey::Admin).unwrap(); - admin.require_auth(); + let config = config::get_config(&e); + config.upgrade_authority.require_auth(); e.deployer().update_current_contract_wasm(new_wasm_hash); } @@ -149,4 +160,3 @@ impl BalancedDollar { read_symbol(&e) } } - diff --git a/contracts/balanced_doller/src/tests/balanced_dollar_test.rs b/contracts/balanced_doller/src/tests/balanced_dollar_test.rs index 50f4ff7..0bc4a54 100644 --- a/contracts/balanced_doller/src/tests/balanced_dollar_test.rs +++ b/contracts/balanced_doller/src/tests/balanced_dollar_test.rs @@ -1,14 +1,16 @@ #![cfg(test)] extern crate std; -use crate::contract::BalancedDollarClient; +use crate::{config, contract::BalancedDollarClient}; use super::setup::*; use soroban_rlp::balanced::messages::{ cross_transfer::CrossTransfer, cross_transfer_revert::CrossTransferRevert, }; use soroban_sdk::{ - symbol_short, testutils::{Address as _, AuthorizedFunction, AuthorizedInvocation}, xdr::ToXdr, Address, Bytes, BytesN, FromVal, IntoVal, String, Vec + symbol_short, + testutils::{Address as _, AuthorizedFunction, AuthorizedInvocation}, + Address, Bytes, IntoVal, String, Symbol, Vec, }; #[test] @@ -67,7 +69,7 @@ fn test_cross_transfer_with_to_and_data() { &ctx.env, "CA36FQITV33RO5SJFPTNLRQBD6ZNAEJG7F7J5KWCV4OP7SQHDMIZCT33", )); - + std::println!("to address is: {:?}", to); let data = CrossTransfer::new( ctx.depositor.to_string(), @@ -76,12 +78,9 @@ fn test_cross_transfer_with_to_and_data() { Bytes::from_array(&ctx.env, &items), ) .encode(&ctx.env, String::from_str(&ctx.env, "xCrossTransfer")); - let sources = Vec::from_array(&ctx.env, [ctx.centralized_connection.to_string()]); - client.handle_call_message( &ctx.icon_bn_usd, &data, &sources); - - + client.handle_call_message(&ctx.icon_bn_usd, &data, &sources); ctx.mint_native_token(&from_address, 500u128); assert_eq!(ctx.get_native_token_balance(&from_address), 500u128); @@ -106,8 +105,6 @@ fn test_cross_transfer_with_to_and_data() { assert_eq!(ctx.get_native_token_balance(&from_address), 400u128) // why 300? } - - #[test] fn test_handle_call_message_for_cross_transfer() { let ctx = TestContext::default(); @@ -144,7 +141,7 @@ fn test_handle_call_message_for_cross_transfer() { assert_eq!(client.balance(withdrawer_address), 0); let sources = Vec::from_array(&ctx.env, [ctx.centralized_connection.to_string()]); - client.handle_call_message( &ctx.icon_bn_usd, &data, &sources); + client.handle_call_message(&ctx.icon_bn_usd, &data, &sources); assert_eq!(client.balance(withdrawer_address), bnusd_amount as i128) } @@ -220,7 +217,7 @@ fn test_handle_call_message_for_cross_transfer_panic_for_protocol_mismatch() { assert_eq!(client.balance(withdrawer_address), 0); let sources = Vec::from_array(&ctx.env, [ctx.xcall.to_string()]); - client.handle_call_message( &ctx.icon_bn_usd, &data, &sources); + client.handle_call_message(&ctx.icon_bn_usd, &data, &sources); assert_eq!(client.balance(withdrawer_address), bnusd_amount as i128) } @@ -262,7 +259,7 @@ fn test_handle_call_message_for_cross_transfer_panic_for_icon_bnusd() { assert_eq!(client.balance(withdrawer_address), 0); let sources = Vec::from_array(&ctx.env, [ctx.centralized_connection.to_string()]); - client.handle_call_message( &ctx.icon_governance, &data, &sources); + client.handle_call_message(&ctx.icon_governance, &data, &sources); assert_eq!(client.balance(withdrawer_address), bnusd_amount as i128) } @@ -305,7 +302,7 @@ fn test_handle_call_message_for_cross_transfer_panic_for_wront_message_type() { assert_eq!(client.balance(withdrawer_address), 0); let sources = Vec::from_array(&ctx.env, [ctx.centralized_connection.to_string()]); - client.handle_call_message( &ctx.icon_bn_usd, &data, &sources); + client.handle_call_message(&ctx.icon_bn_usd, &data, &sources); assert_eq!(client.balance(withdrawer_address), bnusd_amount as i128) } @@ -328,11 +325,7 @@ fn test_handle_call_message_for_cross_transfer_revert() { assert_eq!(client.balance(&ctx.withdrawer), 0); let sources = Vec::from_array(&ctx.env, [ctx.centralized_connection.to_string()]); - client.handle_call_message( - &ctx.xcall_client.get_network_address(), - &data, - &sources, - ); + client.handle_call_message(&ctx.xcall_client.get_network_address(), &data, &sources); assert_eq!(client.balance(&ctx.withdrawer), bnusd_amount as i128) } @@ -364,11 +357,7 @@ fn test_handle_call_message_for_cross_transfer_revert_panic_for_xcall() { "CBEPDNVYXQGWB5YUBXKJWYJA7OXTZW5LFLNO5JRRGE6Z6C5OSUZPCCEL" ), ); - client.handle_call_message( - &wrong_network_address, - &data, - &sources, - ); + client.handle_call_message(&wrong_network_address, &data, &sources); assert_eq!(client.balance(&ctx.withdrawer), bnusd_amount as i128) } @@ -383,3 +372,33 @@ fn test_extend_ttl() { client.extend_ttl() } + +#[test] +fn test_set_upgrade_authority() { + let ctx = TestContext::default(); + let client = BalancedDollarClient::new(&ctx.env, &ctx.registry); + ctx.init_context(&client); + + let new_upgrade_authority = Address::generate(&ctx.env); + client.set_upgrade_authority(&new_upgrade_authority); + + assert_eq!( + ctx.env.auths(), + std::vec![( + ctx.upgrade_authority.clone(), + AuthorizedInvocation { + function: AuthorizedFunction::Contract(( + ctx.registry.clone(), + Symbol::new(&ctx.env, "set_upgrade_authority"), + (&new_upgrade_authority,).into_val(&ctx.env) + )), + sub_invocations: std::vec![] + } + )] + ); + + ctx.env.as_contract(&client.address, || { + let config = config::get_config(&ctx.env); + assert_eq!(config.upgrade_authority, new_upgrade_authority) + }); +} diff --git a/contracts/balanced_doller/src/tests/setup.rs b/contracts/balanced_doller/src/tests/setup.rs index f6a0616..529cb0d 100644 --- a/contracts/balanced_doller/src/tests/setup.rs +++ b/contracts/balanced_doller/src/tests/setup.rs @@ -29,6 +29,7 @@ pub struct TestContext { pub admin: Address, pub depositor: Address, pub withdrawer: Address, + pub upgrade_authority: Address, pub xcall: Address, pub xcall_manager: Address, pub icon_bn_usd: String, @@ -44,7 +45,9 @@ impl TestContext { pub fn default() -> Self { let env = Env::default(); let token_admin = Address::generate(&env); - let token = env.register_stellar_asset_contract_v2(token_admin.clone()).address(); + let token = env + .register_stellar_asset_contract_v2(token_admin.clone()) + .address(); let balanced_dollar = env.register_contract(None, BalancedDollar); let centralized_connection = env.register_contract_wasm(None, connection::WASM); let xcall_manager = env.register_contract_wasm(None, xcall_manager::WASM); @@ -59,6 +62,7 @@ impl TestContext { admin: Address::generate(&env), depositor: Address::generate(&env), withdrawer: Address::generate(&env), + upgrade_authority: Address::generate(&env), xcall: xcall.clone(), xcall_manager, icon_bn_usd: String::from_str(&env, "icon01/hxjnfh4u"), @@ -66,7 +70,9 @@ impl TestContext { token, centralized_connection, nid: String::from_str(&env, "stellar"), - native_token: env.register_stellar_asset_contract_v2(token_admin.clone()).address(), + native_token: env + .register_stellar_asset_contract_v2(token_admin.clone()) + .address(), xcall_client: xcall::Client::new(&env, &xcall), env, } @@ -81,10 +87,10 @@ impl TestContext { xcall_manager: self.xcall_manager.clone(), nid: self.nid.clone(), icon_bn_usd: self.icon_bn_usd.clone(), - xcall_network_address: self.xcall_client.get_network_address() + xcall_network_address: self.xcall_client.get_network_address(), + upgrade_authority: self.upgrade_authority.clone(), }; client.initialize(&self.admin, &config); - } pub fn init_xcall_manager_context(&self) { diff --git a/contracts/xcall_manager/src/config.rs b/contracts/xcall_manager/src/config.rs index 57e34bd..e4eb4ad 100644 --- a/contracts/xcall_manager/src/config.rs +++ b/contracts/xcall_manager/src/config.rs @@ -6,6 +6,7 @@ use soroban_sdk::{contracttype, unwrap::UnwrapOptimized, Address, Env, String}; pub struct ConfigData { pub xcall: Address, pub icon_governance: String, + pub upgrade_authority: Address, } pub fn set_config(e: &Env, config: ConfigData) { diff --git a/contracts/xcall_manager/src/contract.rs b/contracts/xcall_manager/src/contract.rs index 121674e..335ae0e 100644 --- a/contracts/xcall_manager/src/contract.rs +++ b/contracts/xcall_manager/src/contract.rs @@ -1,14 +1,19 @@ -use soroban_sdk::{contract, contractimpl, panic_with_error, Address, Bytes, BytesN, Env, String, Vec}; +use soroban_sdk::{ + contract, contractimpl, panic_with_error, Address, Bytes, BytesN, Env, String, Vec, +}; mod xcall { soroban_sdk::contractimport!(file = "../../wasm/xcall.wasm"); } + use crate::{ - config::{get_config, set_config, ConfigData}, + config::{self, get_config, set_config, ConfigData}, states::{ extend_ttl, has_proposed_removed, has_registry, read_administrator, read_destinations, read_proposed_removed, read_sources, write_administrator, write_destinations, write_proposed_removed, write_registry, write_sources, - }, storage_types::DataKey, white_list_actions::WhiteListActions + }, + storage_types::DataKey, + white_list_actions::WhiteListActions, }; use soroban_rlp::balanced::messages::configure_protocols::ConfigureProtocols; @@ -37,7 +42,6 @@ impl XcallManager { set_config(&env, config); write_sources(&env, &sources); write_destinations(&env, &destinations); - } pub fn get_config(env: Env) -> ConfigData { @@ -73,7 +77,7 @@ impl XcallManager { pub fn remove_action(e: Env, action: Bytes) -> Result { let actions = WhiteListActions::new(DataKey::WhiteListedActions); - if !actions.contains(&e, action.clone()){ + if !actions.contains(&e, action.clone()) { return Err(ContractError::NotWhiteListed); } actions.remove(&e, action); @@ -133,7 +137,7 @@ impl XcallManager { } let actions = WhiteListActions::new(DataKey::WhiteListedActions); - if !actions.contains(&e, data.clone()){ + if !actions.contains(&e, data.clone()) { return Err(ContractError::NotWhiteListed); } actions.remove(&e, data.clone()); @@ -191,9 +195,18 @@ impl XcallManager { return Ok(new_array); } + pub fn set_upgrade_authority(e: Env, upgrade_authority: Address) { + let mut config = config::get_config(&e); + + config.upgrade_authority.require_auth(); + + config.upgrade_authority = upgrade_authority; + config::set_config(&e, config); + } + pub fn upgrade(e: Env, new_wasm_hash: BytesN<32>) { - let admin: Address = e.storage().instance().get(&DataKey::Admin).unwrap(); - admin.require_auth(); + let config = get_config(&e); + config.upgrade_authority.require_auth(); e.deployer().update_current_contract_wasm(new_wasm_hash); } @@ -201,5 +214,4 @@ impl XcallManager { pub fn extend_ttl(e: Env) { extend_ttl(&e); } - } diff --git a/contracts/xcall_manager/src/tests/setup.rs b/contracts/xcall_manager/src/tests/setup.rs index 8b7ad4b..ece3055 100644 --- a/contracts/xcall_manager/src/tests/setup.rs +++ b/contracts/xcall_manager/src/tests/setup.rs @@ -1,21 +1,15 @@ #![cfg(test)] extern crate std; - -use crate::contract::{ - XcallManager, XcallManagerClient -}; +use crate::contract::{XcallManager, XcallManagerClient}; use crate::config::ConfigData; use soroban_sdk::Vec; -use soroban_sdk::{ - testutils::Address as _, - Address, Env, String -}; +use soroban_sdk::{testutils::Address as _, Address, Env, String}; mod xcall { - soroban_sdk::contractimport!(file = "../../wasm/xcall.wasm" ); + soroban_sdk::contractimport!(file = "../../wasm/xcall.wasm"); } mod connection { @@ -23,17 +17,18 @@ mod connection { } pub struct TestContext { - pub env: Env, - pub registry:Address, - pub admin: Address, + pub env: Env, + pub registry: Address, + pub admin: Address, pub depositor: Address, - pub xcall: Address, + pub upgrade_authority: Address, + pub xcall: Address, pub icon_governance: String, pub xcall_network_address: String, pub token: Address, pub centralized_connection: Address, pub nid: String, - pub native_token: Address + pub native_token: Address, } impl TestContext { @@ -52,27 +47,41 @@ impl TestContext { registry: xcall_manager, admin: Address::generate(&env), depositor: Address::generate(&env), - xcall, + upgrade_authority: Address::generate(&env), + xcall, icon_governance: String::from_str(&env, "icon01/kjdnoi"), xcall_network_address: String::from_str(&env, "stellar/address"), token: token.address(), centralized_connection, nid: String::from_str(&env, "stellar"), - native_token: env.register_stellar_asset_contract_v2(token_admin.clone()).address(), - env + native_token: env + .register_stellar_asset_contract_v2(token_admin.clone()) + .address(), + env, } } pub fn init_context(&self, client: &XcallManagerClient<'static>) { self.env.mock_all_auths(); - let config = ConfigData {xcall: self.xcall.clone(), icon_governance: self.icon_governance.clone()}; + let config = ConfigData { + xcall: self.xcall.clone(), + icon_governance: self.icon_governance.clone(), + upgrade_authority: self.upgrade_authority.clone(), + }; let sources = Vec::from_array(&self.env, [self.centralized_connection.to_string()]); - let destinations = Vec::from_array(&self.env, [String::from_str(&self.env, "icon/address")]); - client.initialize(&self.registry, &self.admin, &config, &sources, &destinations); + let destinations = + Vec::from_array(&self.env, [String::from_str(&self.env, "icon/address")]); + client.initialize( + &self.registry, + &self.admin, + &config, + &sources, + &destinations, + ); self.init_xcall_state(); } - pub fn init_xcall_state(&self){ + pub fn init_xcall_state(&self) { let xcall_client = xcall::Client::new(&self.env, &self.xcall); xcall_client.initialize(&xcall::InitializeMsg { @@ -100,5 +109,4 @@ impl TestContext { let response_fee = 100; connection_client.set_fee(&self.nid, &message_fee, &response_fee); } - } diff --git a/contracts/xcall_manager/src/tests/xcall_manager_test.rs b/contracts/xcall_manager/src/tests/xcall_manager_test.rs index 87a595f..c89e290 100644 --- a/contracts/xcall_manager/src/tests/xcall_manager_test.rs +++ b/contracts/xcall_manager/src/tests/xcall_manager_test.rs @@ -1,14 +1,14 @@ #![cfg(test)] extern crate std; -use crate::contract::XcallManagerClient; +use crate::{config, contract::XcallManagerClient}; use super::setup::*; use soroban_rlp::balanced::messages::configure_protocols::ConfigureProtocols; use soroban_sdk::{ symbol_short, testutils::{Address as _, AuthorizedFunction, AuthorizedInvocation}, - vec, Address, IntoVal, String, Vec, + vec, Address, IntoVal, String, Symbol, Vec, }; #[test] @@ -89,8 +89,7 @@ fn test_whitelist_action() { client.white_list_actions(&data); let result = client.remove_action(&data); - assert!(result==true) - + assert!(result == true) } #[test] @@ -127,7 +126,7 @@ fn test_handle_call_message_for_configure_protocols_panic_for_action_not_whiteli assert_eq!(decoded.sources, sources); assert_eq!(decoded.destinations, destinations); let (s, _) = client.get_protocols(); - client.handle_call_message( &ctx.icon_governance, &data, &s); + client.handle_call_message(&ctx.icon_governance, &data, &s); let (s, d) = client.get_protocols(); assert_eq!(s, sources); @@ -158,7 +157,7 @@ fn test_handle_call_message_for_configure_protocols() { assert_eq!(decoded.sources, sources); assert_eq!(decoded.destinations, destinations); let (s, _) = client.get_protocols(); - client.handle_call_message( &ctx.icon_governance, &data, &s); + client.handle_call_message(&ctx.icon_governance, &data, &s); let (s, d) = client.get_protocols(); assert_eq!(s, sources); @@ -176,7 +175,8 @@ fn test_handle_call_message_for_configure_protocols() { String::from_str(&ctx.env, "stellar/address1"), String::from_str(&ctx.env, "stellar/address1"), ]; - let verifiy_false_second = client.verify_protocols(&Vec::from_array(&ctx.env, wrong_sources_second)); + let verifiy_false_second = + client.verify_protocols(&Vec::from_array(&ctx.env, wrong_sources_second)); assert_eq!(verifiy_false_second, false); let correct_sources = [ @@ -195,9 +195,7 @@ fn test_handle_call_message_for_configure_protocols() { //verify protocol recovery client.propose_removal(&String::from_str(&ctx.env, "stellar/address1")); - let with_protocol_remove: [String; 1] = [ - String::from_str(&ctx.env, "stellar/address"), - ]; + let with_protocol_remove: [String; 1] = [String::from_str(&ctx.env, "stellar/address")]; client.verify_protocol_recovery(&Vec::from_array(&ctx.env, with_protocol_remove)); } @@ -226,7 +224,7 @@ fn test_verify_protocol_recovery_without_removing_protocol() { assert_eq!(decoded.sources, sources); assert_eq!(decoded.destinations, destinations); let (s, _) = client.get_protocols(); - client.handle_call_message( &ctx.icon_governance, &data, &s); + client.handle_call_message(&ctx.icon_governance, &data, &s); //verify protocol recovery let without_protocol_remove: [String; 2] = [ @@ -271,7 +269,7 @@ fn test_get_modified_proposals() { .encode(&ctx.env, String::from_str(&ctx.env, "ConfigureProtocols")); client.white_list_actions(&data); let (s, _) = client.get_protocols(); - client.handle_call_message( &ctx.icon_governance, &data, &s); + client.handle_call_message(&ctx.icon_governance, &data, &s); client.propose_removal(&String::from_str(&ctx.env, "stellar/address")); @@ -364,7 +362,7 @@ fn test_handle_call_message_for_configure_protocols_panic_for_protocol_mismatch( assert_eq!(decoded.sources, sources); assert_eq!(decoded.destinations, destinations); let s = Vec::from_array(&ctx.env, [ctx.xcall.to_string()]); - client.handle_call_message( &ctx.icon_governance, &data, &s); + client.handle_call_message(&ctx.icon_governance, &data, &s); let (s, d) = client.get_protocols(); assert_eq!(s, sources); @@ -415,3 +413,33 @@ fn test_extend_ttl() { client.extend_ttl(); } + +#[test] +fn test_set_upgrade_authority() { + let ctx = TestContext::default(); + let client = XcallManagerClient::new(&ctx.env, &ctx.registry); + ctx.init_context(&client); + + let new_upgrade_authority = Address::generate(&ctx.env); + client.set_upgrade_authority(&new_upgrade_authority); + + assert_eq!( + ctx.env.auths(), + std::vec![( + ctx.upgrade_authority.clone(), + AuthorizedInvocation { + function: AuthorizedFunction::Contract(( + ctx.registry.clone(), + Symbol::new(&ctx.env, "set_upgrade_authority"), + (&new_upgrade_authority,).into_val(&ctx.env) + )), + sub_invocations: std::vec![] + } + )] + ); + + ctx.env.as_contract(&client.address, || { + let config = config::get_config(&ctx.env); + assert_eq!(config.upgrade_authority, new_upgrade_authority) + }); +} From bc20b05d7f94f926dea2c338cc0661e0befa37eb Mon Sep 17 00:00:00 2001 From: bishalbikram Date: Fri, 20 Sep 2024 11:36:27 +0545 Subject: [PATCH 63/63] fix: test setup --- contracts/asset_manager/src/tests/setup.rs | 1 + contracts/balanced_doller/src/tests/setup.rs | 1 + 2 files changed, 2 insertions(+) diff --git a/contracts/asset_manager/src/tests/setup.rs b/contracts/asset_manager/src/tests/setup.rs index 7e57249..937231b 100644 --- a/contracts/asset_manager/src/tests/setup.rs +++ b/contracts/asset_manager/src/tests/setup.rs @@ -93,6 +93,7 @@ impl TestContext { let config = XcallManagerConfigData { xcall: self.xcall.clone(), icon_governance: self.icon_governance.clone(), + upgrade_authority: self.upgrade_authority.clone(), }; let sources = Vec::from_array(&self.env, [self.centralized_connection.to_string()]); let destinations = diff --git a/contracts/balanced_doller/src/tests/setup.rs b/contracts/balanced_doller/src/tests/setup.rs index 529cb0d..2528889 100644 --- a/contracts/balanced_doller/src/tests/setup.rs +++ b/contracts/balanced_doller/src/tests/setup.rs @@ -98,6 +98,7 @@ impl TestContext { let config = XcallManagerConfigData { xcall: self.xcall.clone(), icon_governance: self.icon_governance.clone(), + upgrade_authority: self.upgrade_authority.clone(), }; let sources = Vec::from_array(&self.env, [self.centralized_connection.to_string()]); let destinations =