diff --git a/Cargo.toml b/Cargo.toml
index 8c7aeaf..2461b88 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -14,4 +14,4 @@ soroban-sdk = { version = "22.0.7", features = ["testutils"] }
testutils = ["soroban-sdk/testutils"]
[lib]
-crate-type = ["cdylib", "rlib"]
+crate-type = ["cdylib", "rlib"]
\ No newline at end of file
diff --git a/src/escrow.rs b/src/escrow.rs
index 09757ce..3ec0837 100644
--- a/src/escrow.rs
+++ b/src/escrow.rs
@@ -1,3 +1,5 @@
+#![no_std]
+
use core::fmt::Write;
use heapless::String as HString;
use soroban_sdk::{
@@ -113,6 +115,16 @@ impl EscrowContract {
status: EscrowStatus::Active,
};
+ crate::event::EventEmitter::emit_escrow_created(
+ &env,
+ id.clone(),
+ sender.clone(),
+ recipient.clone(),
+ token.clone(),
+ amount,
+ timeout_duration,
+ );
+
// Save the escrow
env.storage().instance().set(&id, &escrow);
@@ -150,6 +162,16 @@ impl EscrowContract {
&escrow.amount,
);
+ // Emit escrow release event
+ crate::event::EventEmitter::emit_escrow_released(
+ &env,
+ escrow_id.clone(),
+ escrow.sender.clone(),
+ escrow.recipient.clone(),
+ escrow.token.clone(),
+ escrow.amount,
+ );
+
// Update the escrow status
let updated_escrow = EscrowConfig {
status: EscrowStatus::Released,
@@ -284,7 +306,6 @@ impl EscrowContract {
.get(&ESCROW_COUNT_KEY)
.unwrap_or(0u32);
let mut escrows = Vec::new(&env);
-
for i in 0..count {
let mut s: HString<12> = HString::new();
s.push_str("escrow_").unwrap();
@@ -304,7 +325,6 @@ impl EscrowContract {
});
}
}
-
escrows
}
-}
+}
\ No newline at end of file
diff --git a/src/event.rs b/src/event.rs
new file mode 100644
index 0000000..6691fcf
--- /dev/null
+++ b/src/event.rs
@@ -0,0 +1,334 @@
+#![no_std]
+
+use soroban_sdk::{contracttype, symbol_short, Address, Bytes, BytesN, Env, Symbol, Vec};
+
+// Event topics for efficient filtering and indexing
+pub const ESCROW_TOPIC: Symbol = symbol_short!("ESCROW");
+pub const SWAP_TOPIC: Symbol = symbol_short!("SWAP");
+pub const MULTISIG_TOPIC: Symbol = symbol_short!("MULTISIG");
+pub const TOKEN_TOPIC: Symbol = symbol_short!("TOKEN");
+pub const SYSTEM_TOPIC: Symbol = symbol_short!("SYSTEM");
+
+// Escrow event data structure
+#[contracttype]
+#[derive(Clone, Debug)]
+pub struct EscrowCreatedData {
+ pub escrow_id: Symbol,
+ pub sender: Address,
+ pub recipient: Address,
+ pub token: Address,
+ pub amount: i128,
+ pub created_at: u64,
+ pub timeout_at: u64,
+}
+
+#[contracttype]
+#[derive(Clone, Debug)]
+pub struct EscrowReleasedData {
+ pub escrow_id: Symbol,
+ pub released_by: Address,
+ pub recipient: Address,
+ pub token: Address,
+ pub amount: i128,
+ pub released_at: u64,
+}
+
+#[contracttype]
+#[derive(Clone, Debug)]
+pub struct EscrowRefundedData {
+ pub escrow_id: Symbol,
+ pub refunded_by: Address,
+ pub sender: Address,
+ pub token: Address,
+ pub amount: i128,
+ pub refunded_at: u64,
+}
+
+// Swap event data structures
+#[contracttype]
+#[derive(Clone, Debug)]
+pub struct SwapOfferCreatedData {
+ pub offer_id: u64,
+ pub creator: Address,
+ pub offer_token: Address,
+ pub offer_amount: i128,
+ pub request_token: Address,
+ pub request_amount: i128,
+ pub exchange_rate: i128,
+ pub expires_at: u64,
+ pub created_at: u64,
+}
+
+#[contracttype]
+#[derive(Clone, Debug)]
+pub struct SwapOfferAcceptedData {
+ pub offer_id: u64,
+ pub creator: Address,
+ pub acceptor: Address,
+ pub offer_token: Address,
+ pub offer_amount: i128,
+ pub request_token: Address,
+ pub request_amount: i128,
+ pub fee_amount: i128,
+ pub fee_token: Address,
+ pub accepted_at: u64,
+}
+
+// Token event data structures
+#[contracttype]
+#[derive(Clone, Debug)]
+pub struct TokenTransferredData {
+ pub token: Address,
+ pub from: Address,
+ pub to: Address,
+ pub amount: i128,
+ pub from_balance: i128,
+ pub to_balance: i128,
+ pub transferred_at: u64,
+}
+
+#[contracttype]
+#[derive(Clone, Debug)]
+pub struct TokenMintedData {
+ pub token: Address,
+ pub to: Address,
+ pub amount: i128,
+ pub minter: Address,
+ pub minted_at: u64,
+}
+
+// Multisig event data structures
+#[contracttype]
+#[derive(Clone, Debug)]
+pub struct MultisigTransactionProposedData {
+ pub nonce: u32,
+ pub proposer: Address,
+ pub operation_hash: BytesN<32>,
+ pub threshold: u32,
+ pub current_signatures: u32,
+ pub proposed_at: u64,
+}
+
+#[contracttype]
+#[derive(Clone, Debug)]
+pub struct MultisigTransactionExecutedData {
+ pub nonce: u32,
+ pub signers: Vec
,
+ pub operation_hash: BytesN<32>,
+ pub executed_at: u64,
+}
+
+#[contracttype]
+#[derive(Clone, Debug)]
+pub struct MultisigConfigUpdatedData {
+ pub old_signers: Vec,
+ pub new_signers: Vec,
+ pub old_threshold: u32,
+ pub new_threshold: u32,
+ pub updated_at: u64,
+}
+
+// Wallet event data structures
+#[contracttype]
+#[derive(Clone, Debug)]
+pub struct WalletToppedUpData {
+ pub wallet: Address,
+ pub token: Address,
+ pub amount: i128,
+ pub source: Address,
+ pub new_balance: i128,
+ pub topped_up_at: u64,
+}
+
+// System event data structures
+#[contracttype]
+#[derive(Clone, Debug)]
+pub struct ContractErrorData {
+ pub contract_address: Address,
+ pub error_type: Symbol,
+ pub error_message: Bytes,
+ pub context_data: Bytes,
+ pub occurred_at: u64,
+}
+
+// Comprehensive event system using tuple variants
+#[contracttype]
+#[derive(Clone, Debug)]
+pub enum DeFiEvent {
+ EscrowCreated(EscrowCreatedData),
+ EscrowReleased(EscrowReleasedData),
+ EscrowRefunded(EscrowRefundedData),
+ SwapOfferCreated(SwapOfferCreatedData),
+ SwapOfferAccepted(SwapOfferAcceptedData),
+ TokenTransferred(TokenTransferredData),
+ TokenMinted(TokenMintedData),
+ MultisigTransactionProposed(MultisigTransactionProposedData),
+ MultisigTransactionExecuted(MultisigTransactionExecutedData),
+ MultisigConfigUpdated(MultisigConfigUpdatedData),
+ WalletToppedUp(WalletToppedUpData),
+ ContractError(ContractErrorData),
+}
+
+// Event emission utilities
+pub struct EventEmitter;
+
+impl EventEmitter {
+ pub fn emit_event(env: &Env, topic: Symbol, event: DeFiEvent) {
+ env.events().publish((topic,), event);
+ }
+
+ pub fn emit_escrow_created(
+ env: &Env,
+ escrow_id: Symbol,
+ sender: Address,
+ recipient: Address,
+ token: Address,
+ amount: i128,
+ timeout_duration: u64,
+ ) {
+ let created_at = env.ledger().timestamp();
+ let event_data = EscrowCreatedData {
+ escrow_id,
+ sender,
+ recipient,
+ token,
+ amount,
+ created_at,
+ timeout_at: created_at + timeout_duration,
+ };
+ let event = DeFiEvent::EscrowCreated(event_data);
+ Self::emit_event(env, ESCROW_TOPIC, event);
+ }
+
+ pub fn emit_escrow_released(
+ env: &Env,
+ escrow_id: Symbol,
+ released_by: Address,
+ recipient: Address,
+ token: Address,
+ amount: i128,
+ ) {
+ let event_data = EscrowReleasedData {
+ escrow_id,
+ released_by,
+ recipient,
+ token,
+ amount,
+ released_at: env.ledger().timestamp(),
+ };
+ let event = DeFiEvent::EscrowReleased(event_data);
+ Self::emit_event(env, ESCROW_TOPIC, event);
+ }
+
+ pub fn emit_swap_offer_created(
+ env: &Env,
+ offer_id: u64,
+ creator: Address,
+ offer_token: Address,
+ offer_amount: i128,
+ request_token: Address,
+ request_amount: i128,
+ expires_at: u64,
+ ) {
+ let exchange_rate = if request_amount > 0 {
+ (offer_amount * 1_000_000_000_000_000_000) / request_amount
+ } else {
+ 0
+ };
+
+ let event_data = SwapOfferCreatedData {
+ offer_id,
+ creator,
+ offer_token,
+ offer_amount,
+ request_token,
+ request_amount,
+ exchange_rate,
+ expires_at,
+ created_at: env.ledger().timestamp(),
+ };
+ let event = DeFiEvent::SwapOfferCreated(event_data);
+ Self::emit_event(env, SWAP_TOPIC, event);
+ }
+
+ pub fn emit_token_transfer(
+ env: &Env,
+ token: Address,
+ from: Address,
+ to: Address,
+ amount: i128,
+ from_balance: i128,
+ to_balance: i128,
+ ) {
+ let event_data = TokenTransferredData {
+ token,
+ from,
+ to,
+ amount,
+ from_balance,
+ to_balance,
+ transferred_at: env.ledger().timestamp(),
+ };
+ let event = DeFiEvent::TokenTransferred(event_data);
+ Self::emit_event(env, TOKEN_TOPIC, event);
+ }
+
+ pub fn emit_wallet_topped_up(
+ env: &Env,
+ wallet: Address,
+ token: Address,
+ amount: i128,
+ source: Address,
+ new_balance: i128,
+ ) {
+ let event_data = WalletToppedUpData {
+ wallet,
+ token,
+ amount,
+ source,
+ new_balance,
+ topped_up_at: env.ledger().timestamp(),
+ };
+ let event = DeFiEvent::WalletToppedUp(event_data);
+ Self::emit_event(env, SYSTEM_TOPIC, event);
+ }
+
+ pub fn emit_contract_error(
+ env: &Env,
+ contract_address: Address,
+ error_type: Symbol,
+ error_message: &str,
+ context_data: &[u8],
+ ) {
+ let event_data = ContractErrorData {
+ contract_address,
+ error_type,
+ error_message: Bytes::from_slice(env, error_message.as_bytes()),
+ context_data: Bytes::from_slice(env, context_data),
+ occurred_at: env.ledger().timestamp(),
+ };
+ let event = DeFiEvent::ContractError(event_data);
+ Self::emit_event(env, SYSTEM_TOPIC, event);
+ }
+}
+
+// Event query utilities for backends and explorers
+pub struct EventQuery;
+
+impl EventQuery {
+ pub fn escrow_events_filter() -> Symbol {
+ ESCROW_TOPIC
+ }
+ pub fn swap_events_filter() -> Symbol {
+ SWAP_TOPIC
+ }
+ pub fn multisig_events_filter() -> Symbol {
+ MULTISIG_TOPIC
+ }
+ pub fn token_events_filter() -> Symbol {
+ TOKEN_TOPIC
+ }
+ pub fn system_events_filter() -> Symbol {
+ SYSTEM_TOPIC
+ }
+}
\ No newline at end of file
diff --git a/src/lib.rs b/src/lib.rs
index 6c704fb..cdaf593 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -2,6 +2,7 @@
pub mod conversion;
pub mod escrow;
+pub mod event;
pub mod events;
pub mod multisig;
pub mod token;
@@ -10,7 +11,7 @@ pub mod utils;
pub use conversion::ConversionContract;
pub use conversion::Currency;
pub use escrow::EscrowContract;
-pub use events::*;
+pub use event::*;
pub use multisig::MultiSigContract;
pub use token::TokenContract;
-pub use utils::*;
+pub use utils::*;
\ No newline at end of file
diff --git a/src/multisig.rs b/src/multisig.rs
index 9f6ed17..56bd3fd 100644
--- a/src/multisig.rs
+++ b/src/multisig.rs
@@ -1,98 +1,129 @@
-use soroban_sdk::{contract, contractimpl, contracttype, Address, BytesN, Env, Vec};
-
-// The MultiSig configuration
-#[contracttype]
-#[derive(Clone, Debug)]
-pub struct MultiSigConfig {
- signers: Vec,
- threshold: u32,
- nonce: u32,
-}
-
-// Transaction structure
-#[contracttype]
-#[derive(Clone)]
-pub struct Transaction {
- operation: BytesN<32>, // Using BytesN instead of Vec
- timestamp: u64,
- nonce: u32,
-}
-
-#[contract]
-pub struct MultiSigContract;
-
-// Configuration key for storage
-const CONFIG_KEY: &str = "CONFIG";
-
-#[contractimpl]
-impl MultiSigContract {
- pub fn initialize(env: Env, signers: Vec, threshold: u32) -> MultiSigConfig {
- if threshold == 0 || threshold > signers.len() {
- panic!("Invalid threshold");
- }
-
- let config = MultiSigConfig {
- signers,
- threshold,
- nonce: 0,
- };
-
- env.storage().instance().set(&CONFIG_KEY, &config);
- config
- }
-
- pub fn propose_transaction(
- env: Env,
- operation: BytesN<32>,
- signatures: Vec>, // Using BytesN for signatures
- ) -> bool {
- let config: MultiSigConfig = env.storage().instance().get(&CONFIG_KEY).unwrap();
- let timestamp = env.ledger().timestamp();
-
- // Create the transaction
- let _transaction = Transaction {
- operation,
- timestamp,
- nonce: config.nonce,
- };
-
- // In a real implementation, we would verify signatures here
- // This is simplified as soroban_auth is not directly compatible with newer SDK
-
- // For testing purposes, we'll just count each signature as valid
- // In a real implementation, we would need to implement proper signature verification
- let valid_signatures = signatures.len();
-
- // Check if threshold is met
- if valid_signatures >= config.threshold {
- // Update nonce for replay protection
- let new_config = MultiSigConfig {
- signers: config.signers.clone(),
- threshold: config.threshold,
- nonce: config.nonce + 1,
- };
- env.storage().instance().set(&CONFIG_KEY, &new_config);
-
- // Execute the operation
- // Note: In a real implementation, you would decode and execute the operation here
- true
- } else {
- false
- }
- }
-
- pub fn get_config(env: Env) -> MultiSigConfig {
- env.storage().instance().get(&CONFIG_KEY).unwrap()
- }
-}
-// fn main() {
-// let env = Env::default();
-
-// // Create an empty soroban_sdk::Vec
-// let signers = Vec::::new(&env);
-
-// // Call initialize with proper type
-// let multisig = MultiSigContract::initialize(env, signers, 1);
-
-// println!("MultiSig initialized: {:?}", multisig);
-// }
+#![no_std]
+
+use soroban_sdk::{
+ contract, contractimpl, contracttype, symbol_short, Address, BytesN, Env, Symbol, Vec,
+};
+
+#[contracttype]
+#[derive(Clone, Debug)]
+pub struct MultiSigConfig {
+ signers: Vec,
+ threshold: u32,
+ nonce: u32,
+}
+
+#[contracttype]
+#[derive(Clone)]
+pub struct Transaction {
+ operation: BytesN<32>,
+ timestamp: u64,
+ nonce: u32,
+}
+
+#[contract]
+pub struct MultiSigContract;
+
+const CONFIG_KEY: Symbol = symbol_short!("CONFIG");
+
+#[contractimpl]
+impl MultiSigContract {
+ pub fn initialize(env: Env, signers: Vec, threshold: u32) -> MultiSigConfig {
+ if threshold == 0 || threshold > signers.len() as u32 {
+ panic!("Invalid threshold");
+ }
+
+ let config = MultiSigConfig {
+ signers,
+ threshold,
+ nonce: 0,
+ };
+
+ env.storage().instance().set(&CONFIG_KEY, &config);
+ config
+ }
+
+ pub fn propose_transaction(
+ env: Env,
+ operation: BytesN<32>,
+ signatures: Vec>,
+ proposer: Address,
+ ) -> bool {
+ let mut config: MultiSigConfig = env.storage().instance().get(&CONFIG_KEY).unwrap();
+ let timestamp = env.ledger().timestamp();
+
+ let _transaction = Transaction {
+ operation: operation.clone(),
+ timestamp,
+ nonce: config.nonce,
+ };
+
+ let valid_signatures = signatures.len() as u32;
+
+ let event = crate::event::DeFiEvent::MultisigTransactionProposed(
+ crate::event::MultisigTransactionProposedData {
+ nonce: config.nonce,
+ proposer: proposer.clone(),
+ operation_hash: operation.clone(),
+ threshold: config.threshold,
+ current_signatures: valid_signatures,
+ proposed_at: env.ledger().timestamp(),
+ },
+ );
+ crate::event::EventEmitter::emit_event(&env, crate::event::MULTISIG_TOPIC, event);
+
+ if valid_signatures >= config.threshold {
+ let exec_event = crate::event::DeFiEvent::MultisigTransactionExecuted(
+ crate::event::MultisigTransactionExecutedData {
+ nonce: config.nonce,
+ signers: config.signers.clone(),
+ operation_hash: operation,
+ executed_at: env.ledger().timestamp(),
+ },
+ );
+ crate::event::EventEmitter::emit_event(&env, crate::event::MULTISIG_TOPIC, exec_event);
+
+ config.nonce += 1;
+ env.storage().instance().set(&CONFIG_KEY, &config);
+
+ true
+ } else {
+ false
+ }
+ }
+
+ pub fn get_config(env: Env) -> MultiSigConfig {
+ env.storage().instance().get(&CONFIG_KEY).unwrap()
+ }
+
+ pub fn update_config(
+ env: Env,
+ new_signers: Vec,
+ new_threshold: u32,
+ proposer: Address,
+ ) -> MultiSigConfig {
+ if new_threshold == 0 || new_threshold > new_signers.len() as u32 {
+ panic!("Invalid threshold");
+ }
+
+ let old_config: MultiSigConfig = env.storage().instance().get(&CONFIG_KEY).unwrap();
+
+ let new_config = MultiSigConfig {
+ signers: new_signers.clone(),
+ threshold: new_threshold,
+ nonce: old_config.nonce,
+ };
+
+ let event = crate::event::DeFiEvent::MultisigConfigUpdated(
+ crate::event::MultisigConfigUpdatedData {
+ old_signers: old_config.signers,
+ new_signers,
+ old_threshold: old_config.threshold,
+ new_threshold,
+ updated_at: env.ledger().timestamp(),
+ },
+ );
+ crate::event::EventEmitter::emit_event(&env, crate::event::MULTISIG_TOPIC, event);
+ env.storage().instance().set(&CONFIG_KEY, &new_config);
+ new_config
+ }
+}
\ No newline at end of file
diff --git a/src/swap.rs b/src/swap.rs
index 485d3be..77eb7d9 100644
--- a/src/swap.rs
+++ b/src/swap.rs
@@ -126,17 +126,20 @@ impl SwapTrait for SwapContract {
env.storage().set(&DataKey::OfferCounter, &offer_id);
// Emit offer created event
- events::emit(&env, SwapEvent::OfferCreated {
+ // ✨ NEW: Emit swap offer creation event
+ crate::event::EventEmitter::emit_swap_offer_created(
+ &env,
offer_id,
- creator: creator.clone(),
- offer_token: offer.offer_token.clone(),
+ creator.clone(),
+ offer_token.clone(),
offer_amount,
- request_token: offer.request_token.clone(),
+ request_token.clone(),
request_amount,
expires_at,
- });
-
+ );
+
offer_id
+
}
fn accept_offer(env: Env, offer_id: u64) -> bool {
@@ -204,14 +207,38 @@ impl SwapTrait for SwapContract {
// Remove the offer
env.storage().remove(&DataKey::Offer(offer_id));
- // Emit offer accepted event
- events::emit(&env, SwapEvent::OfferAccepted {
+ let event = crate::event::DeFiEvent::SwapOfferAccepted {
+ topic: crate::event::SWAP_TOPIC,
offer_id,
- acceptor,
- });
-
+ creator: offer.creator.clone(),
+ acceptor: acceptor.clone(),
+ offer_token: offer.offer_token.clone(),
+ offer_amount: amount_after_fee,
+ request_token: offer.request_token.clone(),
+ request_amount: offer.request_amount,
+ fee_amount,
+ fee_token: offer.offer_token.clone(),
+ accepted_at: env.ledger().timestamp(),
+ tx_hash: None,
+ };
+ crate::event::EventEmitter::emit_event(&env, event);
+ }
+
+ if fee_amount > 0 {
+ let fee_event = crate::event::DeFiEvent::SwapFeeCollected {
+ topic: crate::event::SWAP_TOPIC,
+ offer_id,
+ fee_collector: config.fee_collector.clone(),
+ token: offer.offer_token.clone(),
+ amount: fee_amount,
+ fee_bps: config.fee_bps,
+ collected_at: env.ledger().timestamp(),
+ tx_hash: None,
+ };
+ crate::event::EventEmitter::emit_event(&env, fee_event);
+ }
+
true
- }
fn cancel_offer(env: Env, offer_id: u64) -> bool {
diff --git a/src/token.rs b/src/token.rs
index a155872..5f45282 100644
--- a/src/token.rs
+++ b/src/token.rs
@@ -1,24 +1,130 @@
-use soroban_sdk::{contract, contractimpl, Address, Env};
+#![no_std]
+
+use soroban_sdk::{contract, contractimpl, contracttype, symbol_short, Address, Env, Symbol};
+
+#[contracttype]
+#[derive(Clone)]
+pub struct TokenConfig {
+ admin: Address,
+ name: Symbol,
+ symbol: Symbol,
+ decimals: u32,
+}
+
+#[contracttype]
+#[derive(Clone, Debug)]
+pub struct Balance {
+ amount: i128,
+}
+
+const CONFIG_KEY: Symbol = symbol_short!("CONFIG");
#[contract]
pub struct TokenContract;
#[contractimpl]
impl TokenContract {
- pub fn initialize(_env: Env, admin: Address) -> Address {
- admin
+ pub fn initialize(
+ env: Env,
+ admin: Address,
+ name: Symbol,
+ symbol: Symbol,
+ decimals: u32,
+ ) -> TokenConfig {
+ let config = TokenConfig {
+ admin,
+ name,
+ symbol,
+ decimals,
+ };
+ env.storage().instance().set(&CONFIG_KEY, &config);
+ config
}
+ pub fn mint(env: Env, minter: Address, to: Address, amount: i128) {
+ // Validate inputs
+ if amount <= 0 {
+ panic!("Amount must be positive");
+ }
- pub fn mint(_env: Env, _to: Address, _amount: i128) {
- // Just a stub for testing
- }
+ // Require minter (admin) authorization
+ minter.require_auth();
+
+ // Check if minter is admin
+ let config: TokenConfig = env.storage().instance().get(&CONFIG_KEY).unwrap();
+ if minter != config.admin {
+ panic!("Only admin can mint");
+ }
+
+ // Update balance
+ let mut to_balance: Balance = env
+ .storage()
+ .instance()
+ .get(&to)
+ .unwrap_or(Balance { amount: 0 });
+ to_balance.amount += amount;
+ env.storage().instance().set(&to, &to_balance);
- pub fn transfer(_env: Env, _from: Address, _to: Address, _amount: i128) {
- // Just a stub for testing
+ // Emit token mint event
+ let event = crate::event::DeFiEvent::TokenMinted(crate::event::TokenMintedData {
+ token: env.current_contract_address(),
+ to: to.clone(),
+ amount,
+ minter: minter.clone(),
+ minted_at: env.ledger().timestamp(),
+ });
+ crate::event::EventEmitter::emit_event(&env, crate::event::TOKEN_TOPIC, event);
}
+ pub fn transfer(env: Env, from: Address, to: Address, amount: i128) {
+ // Validate inputs
+ if amount <= 0 {
+ panic!("Amount must be positive");
+ }
- pub fn balance(_env: Env, _of: Address) -> i128 {
- // For testing, return a simple value based on the address
- 100
+ // Require from authorization
+ from.require_auth();
+
+ // Update balances
+ let mut from_balance: Balance = env
+ .storage()
+ .instance()
+ .get(&from)
+ .unwrap_or(Balance { amount: 0 });
+ let mut to_balance: Balance = env
+ .storage()
+ .instance()
+ .get(&to)
+ .unwrap_or(Balance { amount: 0 });
+
+ if from_balance.amount < amount {
+ panic!("Insufficient balance");
+ }
+
+ from_balance.amount -= amount;
+ to_balance.amount += amount;
+
+ env.storage().instance().set(&from, &from_balance);
+ env.storage().instance().set(&to, &to_balance);
+
+ // Emit token transfer event
+ crate::event::EventEmitter::emit_token_transfer(
+ &env,
+ env.current_contract_address(),
+ from.clone(),
+ to.clone(),
+ amount,
+ from_balance.amount,
+ to_balance.amount,
+ );
}
-}
+ pub fn balance(env: Env, of: Address) -> i128 {
+ let balance: Balance = env
+ .storage()
+ .instance()
+ .get(&of)
+ .unwrap_or(Balance { amount: 0 });
+ balance.amount
+ }
+ pub fn get_config(env: Env) -> TokenConfig {
+ env.storage().instance().get(&CONFIG_KEY).unwrap()
+ }
+}
\ No newline at end of file
diff --git a/src/utils.rs b/src/utils.rs
index cedfaa5..19fda1e 100644
--- a/src/utils.rs
+++ b/src/utils.rs
@@ -1,4 +1,6 @@
-use soroban_sdk::{contracttype, log, token, Address, Env};
+#![no_std]
+
+use soroban_sdk::{contracttype, log, token, Address, Env, Vec};
use crate::conversion::Currency;
@@ -33,7 +35,7 @@ pub fn validate_future_timestamp(env: &Env, timestamp: u64) -> Result<(), Conver
}
/// Validates an address
-pub fn validate_address(_env: &Env, address: &Address) -> Result<(), ConversionError> {
+pub fn validate_address(env: &Env, address: &Address) -> Result<(), ConversionError> {
if address.to_string().is_empty() {
return Err(ConversionError::InvalidAddress);
}
@@ -42,7 +44,7 @@ pub fn validate_address(_env: &Env, address: &Address) -> Result<(), ConversionE
/// Transfers tokens from one account to another
pub fn transfer_tokens(
- _env: &Env,
+ env: &Env,
token_address: &Address,
from: &Address,
to: &Address,
@@ -52,22 +54,32 @@ pub fn transfer_tokens(
return Err(ConversionError::InvalidAmount);
}
- let token_client = token::Client::new(_env, token_address);
+ // Get balances before transfer
+ let from_balance_before = get_token_balance(env, token_address, from);
+ let to_balance_before = get_token_balance(env, token_address, to);
+
+ let token_client = token::Client::new(env, token_address);
token_client.transfer(from, to, amount);
- log!(
- _env,
- "Transferred {} tokens from {} to {}",
- amount,
- from,
- to
+ // Emit detailed transfer event with balance changes
+ crate::event::EventEmitter::emit_token_transfer(
+ env,
+ token_address.clone(),
+ from.clone(),
+ to.clone(),
+ *amount,
+ from_balance_before - amount,
+ to_balance_before + amount,
);
+
+ log!(env, "transferred {} tokens from {} to {}", amount, from, to);
+
Ok(())
}
/// Gets the balance of an account for a specific token
-pub fn get_token_balance(_env: &Env, token_address: &Address, account: &Address) -> i128 {
- let token_client = token::Client::new(_env, token_address);
+pub fn get_token_balance(env: &Env, token_address: &Address, account: &Address) -> i128 {
+ let token_client = token::Client::new(env, token_address);
token_client.balance(account)
}
@@ -161,7 +173,7 @@ pub fn get_currency_symbol(currency: &Currency) -> &'static str {
/// Validates rate lock duration
pub fn validate_rate_lock_duration(
- _env: &Env,
+ env: &Env,
duration: u64,
max_duration: u64,
) -> Result<(), ConversionError> {
@@ -178,7 +190,7 @@ pub fn is_rate_expired(rate_updated_at: u64, validity_duration: u64, current_tim
/// Atomic balance update helper
pub fn update_balance_atomically(
- _env: &Env,
+ env: &Env,
user: &Address,
currency: &Currency,
current_balance: i128,
@@ -193,23 +205,20 @@ pub fn update_balance_atomically(
} else {
current_balance + amount_change
};
-
log!(
- _env,
+ env,
"Balance updated for {}: {} {} -> {}",
user,
get_currency_symbol(currency),
current_balance,
new_balance
);
-
Ok(new_balance)
}
-
-pub fn validate_token_contract(_env: &Env, _token_address: &Address) -> bool {
+pub fn validate_token_contract(env: &Env, _token_address: &Address) -> bool {
true
}
-pub fn validate_token_balance(_env: &Env, _token_address: &Address, _amount: i128) -> bool {
+pub fn validate_token_balance(env: &Env, _token_address: &Address, _amount: i128) -> bool {
true
-}
+}
\ No newline at end of file