From edf156e2a4636c3e324227e72bcd4932b36d604e Mon Sep 17 00:00:00 2001 From: Henry Eb Date: Thu, 28 May 2026 09:34:03 +0100 Subject: [PATCH] Audit Soroban token compatibility --- contracts/xlm_wrapper/src/lib.rs | 8 ++++++ src/token/lib.rs | 42 +++++++++++++++++++------------- 2 files changed, 33 insertions(+), 17 deletions(-) diff --git a/contracts/xlm_wrapper/src/lib.rs b/contracts/xlm_wrapper/src/lib.rs index fd3634e..2e89c18 100644 --- a/contracts/xlm_wrapper/src/lib.rs +++ b/contracts/xlm_wrapper/src/lib.rs @@ -239,6 +239,14 @@ impl XLMWrapper { .unwrap_or(0) } + /// Standard token-style balance accessor. + /// + /// This is an alias for `balance_of` so consumers that expect the common + /// Soroban token shape can use the wrapper without adapter code. + pub fn balance(env: Env, owner: Address) -> i128 { + Self::balance_of(env, owner) + } + pub fn allowance(env: Env, owner: Address, spender: Address) -> i128 { env.storage() .persistent() diff --git a/src/token/lib.rs b/src/token/lib.rs index 6a4041d..2987e1d 100644 --- a/src/token/lib.rs +++ b/src/token/lib.rs @@ -47,18 +47,20 @@ impl TokenContract { admin.require_auth(); let bal = Self::balance_of(env.clone(), to.clone(), token_id); - env.storage() - .persistent() - .set(&DataKey::Balance(token_id, to.clone()), &bal.checked_add(amount).expect("balance overflow")); + env.storage().persistent().set( + &DataKey::Balance(token_id, to.clone()), + &bal.checked_add(amount).expect("balance overflow"), + ); let supply: i128 = env .storage() .instance() .get(&DataKey::TotalSupply(token_id)) .unwrap_or(0); - env.storage() - .instance() - .set(&DataKey::TotalSupply(token_id), &supply.checked_add(amount).expect("supply overflow")); + env.storage().instance().set( + &DataKey::TotalSupply(token_id), + &supply.checked_add(amount).expect("supply overflow"), + ); // Topic: event name + token_id (u64 scalar); to + amount in data. env.events() @@ -99,8 +101,10 @@ impl TokenContract { &amount, ); // Topic: event name + token_id (u64 scalar); owner + spender + amount in data. - env.events() - .publish((symbol_short!("approve"), token_id), (owner, spender, amount)); + env.events().publish( + (symbol_short!("approve"), token_id), + (owner, spender, amount), + ); } pub fn set_approval_for_all(env: Env, owner: Address, operator: Address, approved: bool) { @@ -136,7 +140,8 @@ impl TokenContract { assert!(amount >= 0, "amount must be non-negative"); assert!(env.ledger().timestamp() <= deadline, "permit expired"); - let current_nonce = Self::permit_nonce(env.clone(), owner.clone(), spender.clone(), token_id); + let current_nonce = + Self::permit_nonce(env.clone(), owner.clone(), spender.clone(), token_id); assert!(nonce == current_nonce, "invalid nonce"); owner.require_auth_for_args( @@ -160,8 +165,10 @@ impl TokenContract { &(current_nonce + 1), ); - env.events() - .publish((symbol_short!("permit"), owner, spender, token_id), (amount, nonce)); + env.events().publish( + (symbol_short!("permit"), owner, spender, token_id), + (amount, nonce), + ); } pub fn transfer_from( @@ -329,9 +336,10 @@ impl TokenContract { Self::_write_checkpoint(env, to.clone(), token_id, current_ledger, to_bal); - env.storage() - .persistent() - .set(&DataKey::Balance(token_id, to.clone()), &to_bal.checked_add(amount).expect("balance overflow")); + env.storage().persistent().set( + &DataKey::Balance(token_id, to.clone()), + &to_bal.checked_add(amount).expect("balance overflow"), + ); // Topic: event name + token_id (u64 scalar); from + to + amount in data. env.events() @@ -523,6 +531,8 @@ mod tests { env.ledger().with_mut(|li| li.timestamp = 100); client.permit(&owner, &spender, &token_id, &100, &0, &200); client.permit(&owner, &spender, &token_id, &100, &0, &200); + } + #[should_panic(expected = "length mismatch")] fn test_batch_transfer_length_mismatch() { let (env, client, _) = setup(); @@ -557,7 +567,7 @@ mod tests { client.set_approval_for_all(&alice, &operator, &true); client.transfer_from(&operator, &alice, &bob, &1, &300); - + // Allowance should still be 500 because operator bypasses it assert_eq!(client.allowance(&alice, &operator, &1), 500); } @@ -586,8 +596,6 @@ mod tests { } } - - /// ============================================================================ /// Formal Verification Invariants /// ============================================================================