From 0674721f9fd1c8c1f9556da6d565dfadced2ed50 Mon Sep 17 00:00:00 2001 From: Ayodeji Olanrewaju <111335900+GdAyo19@users.noreply.github.com> Date: Tue, 28 Jul 2026 09:29:57 +0000 Subject: [PATCH 1/2] fix: add reinitialization guard to initialize() in FeeCollector and Settlement contracts - Add AlreadyInitialized = 8 to FeeCollectorError and SettlementError enums - Guard initialize() against being called twice in FeeCollector contract - Convert placeholder escrow contract into Settlement contract with initialize() guard - Add double-initialize tests for both contracts --- contract/soroban/contracts/escrow/src/lib.rs | 39 ++++-- contract/soroban/contracts/escrow/src/test.rs | 49 +++++-- .../contracts/fee-collector/src/lib.rs | 12 +- .../contracts/fee-collector/src/test.rs | 10 ++ package-lock.json | 120 ++++++++++++++++++ 5 files changed, 201 insertions(+), 29 deletions(-) diff --git a/contract/soroban/contracts/escrow/src/lib.rs b/contract/soroban/contracts/escrow/src/lib.rs index f812004..07964ba 100644 --- a/contract/soroban/contracts/escrow/src/lib.rs +++ b/contract/soroban/contracts/escrow/src/lib.rs @@ -1,22 +1,33 @@ #![no_std] -use soroban_sdk::{contract, contractimpl, vec, Env, String, Vec}; +use soroban_sdk::{contract, contracterror, contractimpl, contracttype, Address, Env}; +use soroban_sdk::panic_with_error; + +#[contracttype] +pub enum DataKey { + Admin, +} + +#[contracterror] +#[derive(Copy, Clone, Debug, PartialEq)] +pub enum SettlementError { + AlreadyInitialized = 8, +} #[contract] -pub struct Contract; +pub struct SettlementContract; -// This is a sample contract. Replace this placeholder with your own contract logic. -// A corresponding test example is available in `test.rs`. -// -// For comprehensive examples, visit . -// The repository includes use cases for the Stellar ecosystem, such as data storage on -// the blockchain, token swaps, liquidity pools, and more. -// -// Refer to the official documentation: -// . #[contractimpl] -impl Contract { - pub fn hello(env: Env, to: String) -> Vec { - vec![&env, String::from_str(&env, "Hello"), to] +impl SettlementContract { + pub fn initialize(env: Env, admin: Address) { + if env.storage().instance().has(&DataKey::Admin) { + panic_with_error!(&env, SettlementError::AlreadyInitialized); + } + admin.require_auth(); + env.storage().instance().set(&DataKey::Admin, &admin); + } + + pub fn get_admin(env: Env) -> Option
{ + env.storage().instance().get(&DataKey::Admin) } } diff --git a/contract/soroban/contracts/escrow/src/test.rs b/contract/soroban/contracts/escrow/src/test.rs index 0bdcba0..a28916c 100644 --- a/contract/soroban/contracts/escrow/src/test.rs +++ b/contract/soroban/contracts/escrow/src/test.rs @@ -1,21 +1,42 @@ #![cfg(test)] use super::*; -use soroban_sdk::{vec, Env, String}; +use soroban_sdk::testutils::Address as _; +use soroban_sdk::{Env}; #[test] -fn test() { +fn initialize_sets_admin() { let env = Env::default(); - let contract_id = env.register(Contract, ()); - let client = ContractClient::new(&env, &contract_id); - - let words = client.hello(&String::from_str(&env, "Dev")); - assert_eq!( - words, - vec![ - &env, - String::from_str(&env, "Hello"), - String::from_str(&env, "Dev"), - ] - ); + env.mock_all_auths(); + + let contract_id = env.register(SettlementContract, ()); + let client = SettlementContractClient::new(&env, &contract_id); + + let admin = Address::generate(&env); + client.initialize(&admin); + + assert_eq!(client.get_admin(), Some(admin)); +} + +#[test] +#[should_panic] +fn double_initialize_panics() { + let env = Env::default(); + env.mock_all_auths(); + + let contract_id = env.register(SettlementContract, ()); + let client = SettlementContractClient::new(&env, &contract_id); + + let admin = Address::generate(&env); + client.initialize(&admin); + client.initialize(&admin); +} + +#[test] +fn get_admin_returns_none_before_initialize() { + let env = Env::default(); + let contract_id = env.register(SettlementContract, ()); + let client = SettlementContractClient::new(&env, &contract_id); + + assert_eq!(client.get_admin(), None); } diff --git a/contract/soroban/contracts/fee-collector/src/lib.rs b/contract/soroban/contracts/fee-collector/src/lib.rs index 9d9302e..b244658 100644 --- a/contract/soroban/contracts/fee-collector/src/lib.rs +++ b/contract/soroban/contracts/fee-collector/src/lib.rs @@ -1,7 +1,8 @@ #![no_std] use soroban_sdk::{ - contract, contractevent, contractimpl, contracttype, token, Address, Env, + contract, contracterror, contractevent, contractimpl, contracttype, token, Address, Env, }; +use soroban_sdk::panic_with_error; #[contracttype] pub enum DataKey { @@ -10,6 +11,12 @@ pub enum DataKey { Treasury, } +#[contracterror] +#[derive(Copy, Clone, Debug, PartialEq)] +pub enum FeeCollectorError { + AlreadyInitialized = 8, +} + #[contractevent(data_format = "vec")] pub struct Initialized { #[topic] @@ -40,6 +47,9 @@ pub struct FeeCollectorContract; #[contractimpl] impl FeeCollectorContract { pub fn initialize(env: Env, admin: Address, fee_bps: u32, treasury: Address) { + if env.storage().instance().has(&DataKey::Admin) { + panic_with_error!(&env, FeeCollectorError::AlreadyInitialized); + } admin.require_auth(); env.storage().instance().set(&DataKey::Admin, &admin); env.storage().instance().set(&DataKey::FeeBps, &fee_bps); diff --git a/contract/soroban/contracts/fee-collector/src/test.rs b/contract/soroban/contracts/fee-collector/src/test.rs index 86ae0aa..56ca809 100644 --- a/contract/soroban/contracts/fee-collector/src/test.rs +++ b/contract/soroban/contracts/fee-collector/src/test.rs @@ -79,6 +79,16 @@ fn set_fee_bps_above_limit_panics() { client.set_fee_bps(&201); } +#[test] +#[should_panic] +fn double_initialize_panics() { + let (env, contract_id, _token_address, admin, treasury) = setup(); + let client = FeeCollectorContractClient::new(&env, &contract_id); + + client.initialize(&admin, &75, &treasury); + client.initialize(&admin, &75, &treasury); +} + #[test] #[should_panic] fn deduct_before_initialize_panics() { diff --git a/package-lock.json b/package-lock.json index d8d9b7a..0466803 100644 --- a/package-lock.json +++ b/package-lock.json @@ -39185,6 +39185,126 @@ "funding": { "url": "https://github.com/sponsors/colinhacks" } + }, + "node_modules/@next/swc-darwin-arm64": { + "version": "16.2.1", + "resolved": "https://registry.npmjs.org/@next/swc-darwin-arm64/-/swc-darwin-arm64-16.2.1.tgz", + "integrity": "sha512-BwZ8w8YTaSEr2HIuXLMLxIdElNMPvY9fLqb20LX9A9OMGtJilhHLbCL3ggyd0TwjmMcTxi0XXt+ur1vWUoxj2Q==", + "cpu": [ + "arm64" + ], + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@next/swc-darwin-x64": { + "version": "16.2.1", + "resolved": "https://registry.npmjs.org/@next/swc-darwin-x64/-/swc-darwin-x64-16.2.1.tgz", + "integrity": "sha512-/vrcE6iQSJq3uL3VGVHiXeaKbn8Es10DGTGRJnRZlkNQQk3kaNtAJg8Y6xuAlrx/6INKVjkfi5rY0iEXorZ6uA==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@next/swc-linux-arm64-gnu": { + "version": "16.2.1", + "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-gnu/-/swc-linux-arm64-gnu-16.2.1.tgz", + "integrity": "sha512-uLn+0BK+C31LTVbQ/QU+UaVrV0rRSJQ8RfniQAHPghDdgE+SlroYqcmFnO5iNjNfVWCyKZHYrs3Nl0mUzWxbBw==", + "cpu": [ + "arm64" + ], + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@next/swc-linux-arm64-musl": { + "version": "16.2.1", + "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-musl/-/swc-linux-arm64-musl-16.2.1.tgz", + "integrity": "sha512-ssKq6iMRnHdnycGp9hCuGnXJZ0YPr4/wNwrfE5DbmvEcgl9+yv97/Kq3TPVDfYome1SW5geciLB9aiEqKXQjlQ==", + "cpu": [ + "arm64" + ], + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@next/swc-linux-x64-gnu": { + "version": "16.2.1", + "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-gnu/-/swc-linux-x64-gnu-16.2.1.tgz", + "integrity": "sha512-HQm7SrHRELJ30T1TSmT706IWovFFSRGxfgUkyWJZF/RKBMdbdRWJuFrcpDdE5vy9UXjFOx6L3mRdqH04Mmx0hg==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@next/swc-linux-x64-musl": { + "version": "16.2.1", + "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-musl/-/swc-linux-x64-musl-16.2.1.tgz", + "integrity": "sha512-aV2iUaC/5HGEpbBkE+4B8aHIudoOy5DYekAKOMSHoIYQ66y/wIVeaRx8MS2ZMdxe/HIXlMho4ubdZs/J8441Tg==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@next/swc-win32-arm64-msvc": { + "version": "16.2.1", + "resolved": "https://registry.npmjs.org/@next/swc-win32-arm64-msvc/-/swc-win32-arm64-msvc-16.2.1.tgz", + "integrity": "sha512-IXdNgiDHaSk0ZUJ+xp0OQTdTgnpx1RCfRTalhn3cjOP+IddTMINwA7DXZrwTmGDO8SUr5q2hdP/du4DcrB1GxA==", + "cpu": [ + "arm64" + ], + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@next/swc-win32-x64-msvc": { + "version": "16.2.1", + "resolved": "https://registry.npmjs.org/@next/swc-win32-x64-msvc/-/swc-win32-x64-msvc-16.2.1.tgz", + "integrity": "sha512-qvU+3a39Hay+ieIztkGSbF7+mccbbg1Tk25hc4JDylf8IHjYmY/Zm64Qq1602yPyQqvie+vf5T/uPwNxDNIoeg==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 10" + } } } } From f87dd3ef7df1910164e867ca962a6a3531295474 Mon Sep 17 00:00:00 2001 From: Collins Ikechukwu Date: Fri, 31 Jul 2026 08:38:13 +0100 Subject: [PATCH 2/2] fix: assert exact AlreadyInitialized error in tests, drop unrelated lockfile churn - Replace bare #[should_panic] double-init tests with try_initialize assertions on the exact contract error - Use error code 1 instead of arbitrary 8 - Revert unrelated package-lock.json platform-binary additions - Tidy soroban_sdk imports --- contract/soroban/contracts/escrow/src/lib.rs | 7 +- contract/soroban/contracts/escrow/src/test.rs | 14 +- ...lize_fails_with_already_initialized.1.json | 142 +++++++ ...dmin_returns_none_before_initialize.1.json | 77 ++++ .../test/initialize_sets_admin.1.json | 142 +++++++ .../contracts/fee-collector/src/lib.rs | 6 +- .../contracts/fee-collector/src/test.rs | 12 +- ...lize_fails_with_already_initialized.1.json | 364 ++++++++++++++++++ package-lock.json | 120 ------ 9 files changed, 751 insertions(+), 133 deletions(-) create mode 100644 contract/soroban/contracts/escrow/test_snapshots/test/double_initialize_fails_with_already_initialized.1.json create mode 100644 contract/soroban/contracts/escrow/test_snapshots/test/get_admin_returns_none_before_initialize.1.json create mode 100644 contract/soroban/contracts/escrow/test_snapshots/test/initialize_sets_admin.1.json create mode 100644 contract/soroban/contracts/fee-collector/test_snapshots/test/double_initialize_fails_with_already_initialized.1.json diff --git a/contract/soroban/contracts/escrow/src/lib.rs b/contract/soroban/contracts/escrow/src/lib.rs index 07964ba..09241e5 100644 --- a/contract/soroban/contracts/escrow/src/lib.rs +++ b/contract/soroban/contracts/escrow/src/lib.rs @@ -1,6 +1,7 @@ #![no_std] -use soroban_sdk::{contract, contracterror, contractimpl, contracttype, Address, Env}; -use soroban_sdk::panic_with_error; +use soroban_sdk::{ + contract, contracterror, contractimpl, contracttype, panic_with_error, Address, Env, +}; #[contracttype] pub enum DataKey { @@ -10,7 +11,7 @@ pub enum DataKey { #[contracterror] #[derive(Copy, Clone, Debug, PartialEq)] pub enum SettlementError { - AlreadyInitialized = 8, + AlreadyInitialized = 1, } #[contract] diff --git a/contract/soroban/contracts/escrow/src/test.rs b/contract/soroban/contracts/escrow/src/test.rs index a28916c..fa5939d 100644 --- a/contract/soroban/contracts/escrow/src/test.rs +++ b/contract/soroban/contracts/escrow/src/test.rs @@ -2,7 +2,7 @@ use super::*; use soroban_sdk::testutils::Address as _; -use soroban_sdk::{Env}; +use soroban_sdk::Env; #[test] fn initialize_sets_admin() { @@ -19,8 +19,7 @@ fn initialize_sets_admin() { } #[test] -#[should_panic] -fn double_initialize_panics() { +fn double_initialize_fails_with_already_initialized() { let env = Env::default(); env.mock_all_auths(); @@ -29,7 +28,14 @@ fn double_initialize_panics() { let admin = Address::generate(&env); client.initialize(&admin); - client.initialize(&admin); + + let result = client.try_initialize(&admin); + assert_eq!( + result, + Err(Ok(soroban_sdk::Error::from_contract_error( + SettlementError::AlreadyInitialized as u32 + ))) + ); } #[test] diff --git a/contract/soroban/contracts/escrow/test_snapshots/test/double_initialize_fails_with_already_initialized.1.json b/contract/soroban/contracts/escrow/test_snapshots/test/double_initialize_fails_with_already_initialized.1.json new file mode 100644 index 0000000..061af37 --- /dev/null +++ b/contract/soroban/contracts/escrow/test_snapshots/test/double_initialize_fails_with_already_initialized.1.json @@ -0,0 +1,142 @@ +{ + "generators": { + "address": 2, + "nonce": 0, + "mux_id": 0 + }, + "auth": [ + [], + [ + [ + "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFCT4", + { + "function": { + "contract_fn": { + "contract_address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD2KM", + "function_name": "initialize", + "args": [ + { + "address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFCT4" + } + ] + } + }, + "sub_invocations": [] + } + ] + ], + [] + ], + "ledger": { + "protocol_version": 23, + "sequence_number": 0, + "timestamp": 0, + "network_id": "0000000000000000000000000000000000000000000000000000000000000000", + "base_reserve": 0, + "min_persistent_entry_ttl": 4096, + "min_temp_entry_ttl": 16, + "max_entry_ttl": 6312000, + "ledger_entries": [ + [ + { + "contract_data": { + "contract": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD2KM", + "key": "ledger_key_contract_instance", + "durability": "persistent" + } + }, + [ + { + "last_modified_ledger_seq": 0, + "data": { + "contract_data": { + "ext": "v0", + "contract": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD2KM", + "key": "ledger_key_contract_instance", + "durability": "persistent", + "val": { + "contract_instance": { + "executable": { + "wasm": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855" + }, + "storage": [ + { + "key": { + "vec": [ + { + "symbol": "Admin" + } + ] + }, + "val": { + "address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFCT4" + } + } + ] + } + } + } + }, + "ext": "v0" + }, + 4095 + ] + ], + [ + { + "contract_data": { + "contract": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFCT4", + "key": { + "ledger_key_nonce": { + "nonce": "801925984706572462" + } + }, + "durability": "temporary" + } + }, + [ + { + "last_modified_ledger_seq": 0, + "data": { + "contract_data": { + "ext": "v0", + "contract": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFCT4", + "key": { + "ledger_key_nonce": { + "nonce": "801925984706572462" + } + }, + "durability": "temporary", + "val": "void" + } + }, + "ext": "v0" + }, + 6311999 + ] + ], + [ + { + "contract_code": { + "hash": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855" + } + }, + [ + { + "last_modified_ledger_seq": 0, + "data": { + "contract_code": { + "ext": "v0", + "hash": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", + "code": "" + } + }, + "ext": "v0" + }, + 4095 + ] + ] + ] + }, + "events": [] +} \ No newline at end of file diff --git a/contract/soroban/contracts/escrow/test_snapshots/test/get_admin_returns_none_before_initialize.1.json b/contract/soroban/contracts/escrow/test_snapshots/test/get_admin_returns_none_before_initialize.1.json new file mode 100644 index 0000000..6a19fbf --- /dev/null +++ b/contract/soroban/contracts/escrow/test_snapshots/test/get_admin_returns_none_before_initialize.1.json @@ -0,0 +1,77 @@ +{ + "generators": { + "address": 1, + "nonce": 0, + "mux_id": 0 + }, + "auth": [ + [], + [] + ], + "ledger": { + "protocol_version": 23, + "sequence_number": 0, + "timestamp": 0, + "network_id": "0000000000000000000000000000000000000000000000000000000000000000", + "base_reserve": 0, + "min_persistent_entry_ttl": 4096, + "min_temp_entry_ttl": 16, + "max_entry_ttl": 6312000, + "ledger_entries": [ + [ + { + "contract_data": { + "contract": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD2KM", + "key": "ledger_key_contract_instance", + "durability": "persistent" + } + }, + [ + { + "last_modified_ledger_seq": 0, + "data": { + "contract_data": { + "ext": "v0", + "contract": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD2KM", + "key": "ledger_key_contract_instance", + "durability": "persistent", + "val": { + "contract_instance": { + "executable": { + "wasm": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855" + }, + "storage": null + } + } + } + }, + "ext": "v0" + }, + 4095 + ] + ], + [ + { + "contract_code": { + "hash": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855" + } + }, + [ + { + "last_modified_ledger_seq": 0, + "data": { + "contract_code": { + "ext": "v0", + "hash": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", + "code": "" + } + }, + "ext": "v0" + }, + 4095 + ] + ] + ] + }, + "events": [] +} \ No newline at end of file diff --git a/contract/soroban/contracts/escrow/test_snapshots/test/initialize_sets_admin.1.json b/contract/soroban/contracts/escrow/test_snapshots/test/initialize_sets_admin.1.json new file mode 100644 index 0000000..061af37 --- /dev/null +++ b/contract/soroban/contracts/escrow/test_snapshots/test/initialize_sets_admin.1.json @@ -0,0 +1,142 @@ +{ + "generators": { + "address": 2, + "nonce": 0, + "mux_id": 0 + }, + "auth": [ + [], + [ + [ + "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFCT4", + { + "function": { + "contract_fn": { + "contract_address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD2KM", + "function_name": "initialize", + "args": [ + { + "address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFCT4" + } + ] + } + }, + "sub_invocations": [] + } + ] + ], + [] + ], + "ledger": { + "protocol_version": 23, + "sequence_number": 0, + "timestamp": 0, + "network_id": "0000000000000000000000000000000000000000000000000000000000000000", + "base_reserve": 0, + "min_persistent_entry_ttl": 4096, + "min_temp_entry_ttl": 16, + "max_entry_ttl": 6312000, + "ledger_entries": [ + [ + { + "contract_data": { + "contract": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD2KM", + "key": "ledger_key_contract_instance", + "durability": "persistent" + } + }, + [ + { + "last_modified_ledger_seq": 0, + "data": { + "contract_data": { + "ext": "v0", + "contract": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD2KM", + "key": "ledger_key_contract_instance", + "durability": "persistent", + "val": { + "contract_instance": { + "executable": { + "wasm": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855" + }, + "storage": [ + { + "key": { + "vec": [ + { + "symbol": "Admin" + } + ] + }, + "val": { + "address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFCT4" + } + } + ] + } + } + } + }, + "ext": "v0" + }, + 4095 + ] + ], + [ + { + "contract_data": { + "contract": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFCT4", + "key": { + "ledger_key_nonce": { + "nonce": "801925984706572462" + } + }, + "durability": "temporary" + } + }, + [ + { + "last_modified_ledger_seq": 0, + "data": { + "contract_data": { + "ext": "v0", + "contract": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFCT4", + "key": { + "ledger_key_nonce": { + "nonce": "801925984706572462" + } + }, + "durability": "temporary", + "val": "void" + } + }, + "ext": "v0" + }, + 6311999 + ] + ], + [ + { + "contract_code": { + "hash": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855" + } + }, + [ + { + "last_modified_ledger_seq": 0, + "data": { + "contract_code": { + "ext": "v0", + "hash": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", + "code": "" + } + }, + "ext": "v0" + }, + 4095 + ] + ] + ] + }, + "events": [] +} \ No newline at end of file diff --git a/contract/soroban/contracts/fee-collector/src/lib.rs b/contract/soroban/contracts/fee-collector/src/lib.rs index b244658..12376ee 100644 --- a/contract/soroban/contracts/fee-collector/src/lib.rs +++ b/contract/soroban/contracts/fee-collector/src/lib.rs @@ -1,8 +1,8 @@ #![no_std] use soroban_sdk::{ - contract, contracterror, contractevent, contractimpl, contracttype, token, Address, Env, + contract, contracterror, contractevent, contractimpl, contracttype, panic_with_error, token, + Address, Env, }; -use soroban_sdk::panic_with_error; #[contracttype] pub enum DataKey { @@ -14,7 +14,7 @@ pub enum DataKey { #[contracterror] #[derive(Copy, Clone, Debug, PartialEq)] pub enum FeeCollectorError { - AlreadyInitialized = 8, + AlreadyInitialized = 1, } #[contractevent(data_format = "vec")] diff --git a/contract/soroban/contracts/fee-collector/src/test.rs b/contract/soroban/contracts/fee-collector/src/test.rs index 56ca809..a2ddede 100644 --- a/contract/soroban/contracts/fee-collector/src/test.rs +++ b/contract/soroban/contracts/fee-collector/src/test.rs @@ -80,13 +80,19 @@ fn set_fee_bps_above_limit_panics() { } #[test] -#[should_panic] -fn double_initialize_panics() { +fn double_initialize_fails_with_already_initialized() { let (env, contract_id, _token_address, admin, treasury) = setup(); let client = FeeCollectorContractClient::new(&env, &contract_id); client.initialize(&admin, &75, &treasury); - client.initialize(&admin, &75, &treasury); + + let result = client.try_initialize(&admin, &75, &treasury); + assert_eq!( + result, + Err(Ok(soroban_sdk::Error::from_contract_error( + FeeCollectorError::AlreadyInitialized as u32 + ))) + ); } #[test] diff --git a/contract/soroban/contracts/fee-collector/test_snapshots/test/double_initialize_fails_with_already_initialized.1.json b/contract/soroban/contracts/fee-collector/test_snapshots/test/double_initialize_fails_with_already_initialized.1.json new file mode 100644 index 0000000..198ef54 --- /dev/null +++ b/contract/soroban/contracts/fee-collector/test_snapshots/test/double_initialize_fails_with_already_initialized.1.json @@ -0,0 +1,364 @@ +{ + "generators": { + "address": 5, + "nonce": 0, + "mux_id": 0 + }, + "auth": [ + [], + [ + [ + "GAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGO6V", + { + "function": { + "contract_fn": { + "contract_address": "CBUSYNQKASUYFWYC3M2GUEDMX4AIVWPALDBYJPNK6554BREHTGZ2IUNF", + "function_name": "set_admin", + "args": [ + { + "address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFCT4" + } + ] + } + }, + "sub_invocations": [] + } + ] + ], + [ + [ + "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAITA4", + { + "function": { + "contract_fn": { + "contract_address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD2KM", + "function_name": "initialize", + "args": [ + { + "address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAITA4" + }, + { + "u32": 75 + }, + { + "address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAK3IM" + } + ] + } + }, + "sub_invocations": [] + } + ] + ], + [] + ], + "ledger": { + "protocol_version": 23, + "sequence_number": 0, + "timestamp": 0, + "network_id": "0000000000000000000000000000000000000000000000000000000000000000", + "base_reserve": 0, + "min_persistent_entry_ttl": 4096, + "min_temp_entry_ttl": 16, + "max_entry_ttl": 6312000, + "ledger_entries": [ + [ + { + "account": { + "account_id": "GAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGO6V" + } + }, + [ + { + "last_modified_ledger_seq": 0, + "data": { + "account": { + "account_id": "GAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGO6V", + "balance": "0", + "seq_num": "0", + "num_sub_entries": 0, + "inflation_dest": null, + "flags": 0, + "home_domain": "", + "thresholds": "01010101", + "signers": [], + "ext": "v0" + } + }, + "ext": "v0" + }, + null + ] + ], + [ + { + "contract_data": { + "contract": "GAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGO6V", + "key": { + "ledger_key_nonce": { + "nonce": "801925984706572462" + } + }, + "durability": "temporary" + } + }, + [ + { + "last_modified_ledger_seq": 0, + "data": { + "contract_data": { + "ext": "v0", + "contract": "GAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGO6V", + "key": { + "ledger_key_nonce": { + "nonce": "801925984706572462" + } + }, + "durability": "temporary", + "val": "void" + } + }, + "ext": "v0" + }, + 6311999 + ] + ], + [ + { + "contract_data": { + "contract": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD2KM", + "key": "ledger_key_contract_instance", + "durability": "persistent" + } + }, + [ + { + "last_modified_ledger_seq": 0, + "data": { + "contract_data": { + "ext": "v0", + "contract": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD2KM", + "key": "ledger_key_contract_instance", + "durability": "persistent", + "val": { + "contract_instance": { + "executable": { + "wasm": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855" + }, + "storage": [ + { + "key": { + "vec": [ + { + "symbol": "Admin" + } + ] + }, + "val": { + "address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAITA4" + } + }, + { + "key": { + "vec": [ + { + "symbol": "FeeBps" + } + ] + }, + "val": { + "u32": 75 + } + }, + { + "key": { + "vec": [ + { + "symbol": "Treasury" + } + ] + }, + "val": { + "address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAK3IM" + } + } + ] + } + } + } + }, + "ext": "v0" + }, + 4095 + ] + ], + [ + { + "contract_data": { + "contract": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAITA4", + "key": { + "ledger_key_nonce": { + "nonce": "5541220902715666415" + } + }, + "durability": "temporary" + } + }, + [ + { + "last_modified_ledger_seq": 0, + "data": { + "contract_data": { + "ext": "v0", + "contract": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAITA4", + "key": { + "ledger_key_nonce": { + "nonce": "5541220902715666415" + } + }, + "durability": "temporary", + "val": "void" + } + }, + "ext": "v0" + }, + 6311999 + ] + ], + [ + { + "contract_data": { + "contract": "CBUSYNQKASUYFWYC3M2GUEDMX4AIVWPALDBYJPNK6554BREHTGZ2IUNF", + "key": "ledger_key_contract_instance", + "durability": "persistent" + } + }, + [ + { + "last_modified_ledger_seq": 0, + "data": { + "contract_data": { + "ext": "v0", + "contract": "CBUSYNQKASUYFWYC3M2GUEDMX4AIVWPALDBYJPNK6554BREHTGZ2IUNF", + "key": "ledger_key_contract_instance", + "durability": "persistent", + "val": { + "contract_instance": { + "executable": "stellar_asset", + "storage": [ + { + "key": { + "symbol": "METADATA" + }, + "val": { + "map": [ + { + "key": { + "symbol": "decimal" + }, + "val": { + "u32": 7 + } + }, + { + "key": { + "symbol": "name" + }, + "val": { + "string": "aaa:GAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGO6V" + } + }, + { + "key": { + "symbol": "symbol" + }, + "val": { + "string": "aaa" + } + } + ] + } + }, + { + "key": { + "vec": [ + { + "symbol": "Admin" + } + ] + }, + "val": { + "address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFCT4" + } + }, + { + "key": { + "vec": [ + { + "symbol": "AssetInfo" + } + ] + }, + "val": { + "vec": [ + { + "symbol": "AlphaNum4" + }, + { + "map": [ + { + "key": { + "symbol": "asset_code" + }, + "val": { + "string": "aaa\\0" + } + }, + { + "key": { + "symbol": "issuer" + }, + "val": { + "bytes": "0000000000000000000000000000000000000000000000000000000000000003" + } + } + ] + } + ] + } + } + ] + } + } + } + }, + "ext": "v0" + }, + 120960 + ] + ], + [ + { + "contract_code": { + "hash": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855" + } + }, + [ + { + "last_modified_ledger_seq": 0, + "data": { + "contract_code": { + "ext": "v0", + "hash": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", + "code": "" + } + }, + "ext": "v0" + }, + 4095 + ] + ] + ] + }, + "events": [] +} \ No newline at end of file diff --git a/package-lock.json b/package-lock.json index 0466803..d8d9b7a 100644 --- a/package-lock.json +++ b/package-lock.json @@ -39185,126 +39185,6 @@ "funding": { "url": "https://github.com/sponsors/colinhacks" } - }, - "node_modules/@next/swc-darwin-arm64": { - "version": "16.2.1", - "resolved": "https://registry.npmjs.org/@next/swc-darwin-arm64/-/swc-darwin-arm64-16.2.1.tgz", - "integrity": "sha512-BwZ8w8YTaSEr2HIuXLMLxIdElNMPvY9fLqb20LX9A9OMGtJilhHLbCL3ggyd0TwjmMcTxi0XXt+ur1vWUoxj2Q==", - "cpu": [ - "arm64" - ], - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": ">= 10" - } - }, - "node_modules/@next/swc-darwin-x64": { - "version": "16.2.1", - "resolved": "https://registry.npmjs.org/@next/swc-darwin-x64/-/swc-darwin-x64-16.2.1.tgz", - "integrity": "sha512-/vrcE6iQSJq3uL3VGVHiXeaKbn8Es10DGTGRJnRZlkNQQk3kaNtAJg8Y6xuAlrx/6INKVjkfi5rY0iEXorZ6uA==", - "cpu": [ - "x64" - ], - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": ">= 10" - } - }, - "node_modules/@next/swc-linux-arm64-gnu": { - "version": "16.2.1", - "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-gnu/-/swc-linux-arm64-gnu-16.2.1.tgz", - "integrity": "sha512-uLn+0BK+C31LTVbQ/QU+UaVrV0rRSJQ8RfniQAHPghDdgE+SlroYqcmFnO5iNjNfVWCyKZHYrs3Nl0mUzWxbBw==", - "cpu": [ - "arm64" - ], - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">= 10" - } - }, - "node_modules/@next/swc-linux-arm64-musl": { - "version": "16.2.1", - "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-musl/-/swc-linux-arm64-musl-16.2.1.tgz", - "integrity": "sha512-ssKq6iMRnHdnycGp9hCuGnXJZ0YPr4/wNwrfE5DbmvEcgl9+yv97/Kq3TPVDfYome1SW5geciLB9aiEqKXQjlQ==", - "cpu": [ - "arm64" - ], - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">= 10" - } - }, - "node_modules/@next/swc-linux-x64-gnu": { - "version": "16.2.1", - "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-gnu/-/swc-linux-x64-gnu-16.2.1.tgz", - "integrity": "sha512-HQm7SrHRELJ30T1TSmT706IWovFFSRGxfgUkyWJZF/RKBMdbdRWJuFrcpDdE5vy9UXjFOx6L3mRdqH04Mmx0hg==", - "cpu": [ - "x64" - ], - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">= 10" - } - }, - "node_modules/@next/swc-linux-x64-musl": { - "version": "16.2.1", - "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-musl/-/swc-linux-x64-musl-16.2.1.tgz", - "integrity": "sha512-aV2iUaC/5HGEpbBkE+4B8aHIudoOy5DYekAKOMSHoIYQ66y/wIVeaRx8MS2ZMdxe/HIXlMho4ubdZs/J8441Tg==", - "cpu": [ - "x64" - ], - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">= 10" - } - }, - "node_modules/@next/swc-win32-arm64-msvc": { - "version": "16.2.1", - "resolved": "https://registry.npmjs.org/@next/swc-win32-arm64-msvc/-/swc-win32-arm64-msvc-16.2.1.tgz", - "integrity": "sha512-IXdNgiDHaSk0ZUJ+xp0OQTdTgnpx1RCfRTalhn3cjOP+IddTMINwA7DXZrwTmGDO8SUr5q2hdP/du4DcrB1GxA==", - "cpu": [ - "arm64" - ], - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">= 10" - } - }, - "node_modules/@next/swc-win32-x64-msvc": { - "version": "16.2.1", - "resolved": "https://registry.npmjs.org/@next/swc-win32-x64-msvc/-/swc-win32-x64-msvc-16.2.1.tgz", - "integrity": "sha512-qvU+3a39Hay+ieIztkGSbF7+mccbbg1Tk25hc4JDylf8IHjYmY/Zm64Qq1602yPyQqvie+vf5T/uPwNxDNIoeg==", - "cpu": [ - "x64" - ], - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">= 10" - } } } }