From 38c6b2806f7325f9307dd757fcec4984a39552a1 Mon Sep 17 00:00:00 2001 From: AI Assistant Date: Tue, 24 Mar 2026 17:35:32 +0100 Subject: [PATCH 1/2] feat: implement internal balance tracking and accounting --- contracts/src/lib.rs | 1 + contracts/src/treasury.rs | 63 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 64 insertions(+) create mode 100644 contracts/src/treasury.rs diff --git a/contracts/src/lib.rs b/contracts/src/lib.rs index cc5c254..c4307fc 100644 --- a/contracts/src/lib.rs +++ b/contracts/src/lib.rs @@ -3,3 +3,4 @@ pub mod escrow; pub mod subscription; pub mod payment_intent; +pub mod treasury; diff --git a/contracts/src/treasury.rs b/contracts/src/treasury.rs new file mode 100644 index 0000000..90fe139 --- /dev/null +++ b/contracts/src/treasury.rs @@ -0,0 +1,63 @@ +#![no_std] +use soroban_sdk::{contract, contractimpl, contracttype, Address, Env}; + +#[contracttype] +#[derive(Clone, Debug, Eq, PartialEq)] +pub enum DataKey { + Balance(Address), +} + +#[contracttype] +#[derive(Clone, Debug, Eq, PartialEq)] +pub struct TreasuryBalance { + pub available_balance: i128, + pub reserved_balance: i128, +} + +#[contract] +pub struct TreasuryContract; + +#[contractimpl] +impl TreasuryContract { + pub fn mint(env: Env, admin: Address, to: Address, amount: i128) { + admin.require_auth(); + if amount <= 0 { + panic!("amount must be positive"); + } + + let key = DataKey::Balance(to.clone()); + let mut balance = env.storage().persistent().get::<_, TreasuryBalance>(&key).unwrap_or(TreasuryBalance { + available_balance: 0, + reserved_balance: 0, + }); + + balance.available_balance = balance.available_balance.checked_add(amount).expect("overflow"); + + env.storage().persistent().set(&key, &balance); + } + + pub fn burn(env: Env, admin: Address, from: Address, amount: i128) { + admin.require_auth(); + if amount <= 0 { + panic!("amount must be positive"); + } + + let key = DataKey::Balance(from.clone()); + let mut balance = env.storage().persistent().get::<_, TreasuryBalance>(&key).unwrap_or(TreasuryBalance { + available_balance: 0, + reserved_balance: 0, + }); + + balance.available_balance = balance.available_balance.checked_sub(amount).expect("underflow"); + + env.storage().persistent().set(&key, &balance); + } + + pub fn get_balance(env: Env, id: Address) -> TreasuryBalance { + let key = DataKey::Balance(id); + env.storage().persistent().get::<_, TreasuryBalance>(&key).unwrap_or(TreasuryBalance { + available_balance: 0, + reserved_balance: 0, + }) + } +} From 68f5f4bd21058b9ab46b504a8b748d3fafaeec76 Mon Sep 17 00:00:00 2001 From: AI Assistant Date: Tue, 24 Mar 2026 19:01:17 +0100 Subject: [PATCH 2/2] fix: implement internal balance tracking for treasury --- contracts/src/treasury.rs | 83 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 83 insertions(+) diff --git a/contracts/src/treasury.rs b/contracts/src/treasury.rs index 90fe139..e707af9 100644 --- a/contracts/src/treasury.rs +++ b/contracts/src/treasury.rs @@ -60,4 +60,87 @@ impl TreasuryContract { reserved_balance: 0, }) } + + pub fn transfer(env: Env, admin: Address, from: Address, to: Address, amount: i128) { + admin.require_auth(); + if amount <= 0 { panic!("amount must be positive"); } + if from == to { return; } + + let key_from = DataKey::Balance(from.clone()); + let mut balance_from = env.storage().persistent().get::<_, TreasuryBalance>(&key_from).unwrap_or(TreasuryBalance { + available_balance: 0, + reserved_balance: 0, + }); + + balance_from.available_balance = balance_from.available_balance.checked_sub(amount).expect("insufficient available balance"); + env.storage().persistent().set(&key_from, &balance_from); + + let key_to = DataKey::Balance(to.clone()); + let mut balance_to = env.storage().persistent().get::<_, TreasuryBalance>(&key_to).unwrap_or(TreasuryBalance { + available_balance: 0, + reserved_balance: 0, + }); + + balance_to.available_balance = balance_to.available_balance.checked_add(amount).expect("overflow"); + env.storage().persistent().set(&key_to, &balance_to); + } + + pub fn reserve(env: Env, admin: Address, from: Address, amount: i128) { + admin.require_auth(); + if amount <= 0 { panic!("amount must be positive"); } + + let key = DataKey::Balance(from.clone()); + let mut balance = env.storage().persistent().get::<_, TreasuryBalance>(&key).unwrap_or(TreasuryBalance { + available_balance: 0, + reserved_balance: 0, + }); + + balance.available_balance = balance.available_balance.checked_sub(amount).expect("insufficient available balance"); + balance.reserved_balance = balance.reserved_balance.checked_add(amount).expect("overflow"); + + env.storage().persistent().set(&key, &balance); + } + + pub fn release(env: Env, admin: Address, from: Address, amount: i128) { + admin.require_auth(); + if amount <= 0 { panic!("amount must be positive"); } + + let key = DataKey::Balance(from.clone()); + let mut balance = env.storage().persistent().get::<_, TreasuryBalance>(&key).unwrap_or(TreasuryBalance { + available_balance: 0, + reserved_balance: 0, + }); + + balance.reserved_balance = balance.reserved_balance.checked_sub(amount).expect("insufficient reserved balance"); + balance.available_balance = balance.available_balance.checked_add(amount).expect("overflow"); + + env.storage().persistent().set(&key, &balance); + } + + pub fn transfer_reserved(env: Env, admin: Address, from: Address, to: Address, amount: i128) { + admin.require_auth(); + if amount <= 0 { panic!("amount must be positive"); } + + let key_from = DataKey::Balance(from.clone()); + let mut balance_from = env.storage().persistent().get::<_, TreasuryBalance>(&key_from).unwrap_or(TreasuryBalance { + available_balance: 0, + reserved_balance: 0, + }); + + balance_from.reserved_balance = balance_from.reserved_balance.checked_sub(amount).expect("insufficient reserved balance"); + env.storage().persistent().set(&key_from, &balance_from); + + if from != to { + let key_to = DataKey::Balance(to.clone()); + let mut balance_to = env.storage().persistent().get::<_, TreasuryBalance>(&key_to).unwrap_or(TreasuryBalance { + available_balance: 0, + reserved_balance: 0, + }); + + balance_to.available_balance = balance_to.available_balance.checked_add(amount).expect("overflow"); + env.storage().persistent().set(&key_to, &balance_to); + } else { + balance_from.available_balance = balance_from.available_balance.checked_add(amount).expect("overflow"); + env.storage().persistent().set(&key_from, &balance_from); + } }