Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions contracts/invoice-escrow/src/events.rs
Original file line number Diff line number Diff line change
Expand Up @@ -47,3 +47,11 @@ pub fn escrow_refunded(env: &Env, inv_id: Symbol, funder: &Address, amount: i128
(inv_id, funder, amount),
);
}

/// Publish platform fee update event with old and new basis points.
pub fn platform_fee_updated(env: &Env, old_fee_bps: u32, new_fee_bps: u32) {
env.events().publish(
(Symbol::new(env, "platform_fee_updated"),),
(old_fee_bps, new_fee_bps),
);
}
14 changes: 6 additions & 8 deletions contracts/invoice-escrow/src/integration_test.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
#![cfg(test)]

use super::*;
use invoice_token::{InvoiceToken, InvoiceTokenClient};
use soroban_sdk::token::{Client as TokenClient, StellarAssetClient as AssetClient};
Expand All @@ -20,11 +18,11 @@ fn test_integration_escrow_lifecycle_happy_path() {
let payer = Address::generate(&env);

// 2. Register Escrow Contract
let escrow_id = env.register_contract(None, InvoiceEscrow);
let escrow_id = env.register(InvoiceEscrow, ());
let escrow_client = InvoiceEscrowClient::new(&env, &escrow_id);

// 3. Register Token Contract
let inv_token_id = env.register_contract(None, InvoiceToken);
let inv_token_id = env.register(InvoiceToken, ());
let inv_token_client = InvoiceTokenClient::new(&env, &inv_token_id);

// 4. Register Payment Token (Stellar Asset)
Expand Down Expand Up @@ -111,10 +109,10 @@ fn test_integration_refund_lifecycle() {
let seller = Address::generate(&env);
let buyer = Address::generate(&env);

let escrow_id = env.register_contract(None, InvoiceEscrow);
let escrow_id = env.register(InvoiceEscrow, ());
let escrow_client = InvoiceEscrowClient::new(&env, &escrow_id);

let inv_token_id = env.register_contract(None, InvoiceToken);
let inv_token_id = env.register(InvoiceToken, ());
let inv_token_client = InvoiceTokenClient::new(&env, &inv_token_id);

let payment_token_admin = Address::generate(&env);
Expand Down Expand Up @@ -181,10 +179,10 @@ fn test_integration_token_locked_during_active_escrow() {
let seller = Address::generate(&env);
let buyer = Address::generate(&env);

let escrow_id = env.register_contract(None, InvoiceEscrow);
let escrow_id = env.register(InvoiceEscrow, ());
let escrow_client = InvoiceEscrowClient::new(&env, &escrow_id);

let inv_token_id = env.register_contract(None, InvoiceToken);
let inv_token_id = env.register(InvoiceToken, ());
let inv_token_client = InvoiceTokenClient::new(&env, &inv_token_id);

let payment_token_admin = Address::generate(&env);
Expand Down
2 changes: 2 additions & 0 deletions contracts/invoice-escrow/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -224,8 +224,10 @@ impl InvoiceEscrow {
if new_fee_bps > MAX_BPS {
return Err(Error::InvalidFeeBps);
}
let old_fee_bps = config.fee_bps;
config.fee_bps = new_fee_bps;
storage::set_config(&env, &config);
events::platform_fee_updated(&env, old_fee_bps, new_fee_bps);
Ok(())
}

Expand Down
18 changes: 12 additions & 6 deletions contracts/invoice-escrow/src/test.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
#![cfg(test)]
#![allow(deprecated)]

use super::*;
Expand Down Expand Up @@ -397,7 +396,7 @@ fn test_no_settlement_event_on_invalid_state() {
let (_addr, topics, _data) = event;
// Check if this is a payment_settled event
let topic_vec: soroban_sdk::Vec<soroban_sdk::Val> = topics.clone();
if topic_vec.len() > 0 {
if !topic_vec.is_empty() {
if let Ok(symbol) = topic_vec.get(0).unwrap().try_into_val(&env) {
let sym: Symbol = symbol;
// Assert that no payment_settled event exists
Expand Down Expand Up @@ -451,7 +450,7 @@ fn test_no_refund_event_on_invalid_state() {
let (_addr, topics, _data) = event;
// Check if this is an escrow_refunded event
let topic_vec: soroban_sdk::Vec<soroban_sdk::Val> = topics.clone();
if topic_vec.len() > 0 {
if !topic_vec.is_empty() {
if let Ok(symbol) = topic_vec.get(0).unwrap().try_into_val(&env) {
let sym: Symbol = symbol;
// Assert that no escrow_refunded event exists
Expand Down Expand Up @@ -1166,9 +1165,16 @@ fn test_update_platform_fee() {
// Update fee
escrow_client.update_platform_fee_bps(&500);

// Verify updated fee
let config = escrow_client.get_config();
assert_eq!(config.fee_bps, 500);
// The update should emit a platform_fee_updated event with old/new values.
let events = env.events().all();
let event = events.last().unwrap();
let (_contract_addr, topics, data) = event;
assert_eq!(
topics,
(Symbol::new(&env, "platform_fee_updated"),).into_val(&env)
);
let event_data: (u32, u32) = data.try_into_val(&env).unwrap();
assert_eq!(event_data, (300, 500));
}

// ========== View Function Tests ==========
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,8 +25,7 @@
"sub_invocations": []
}
]
],
[]
]
],
"ledger": {
"protocol_version": 22,
Expand Down Expand Up @@ -156,5 +155,33 @@
]
]
},
"events": []
"events": [
{
"event": {
"ext": "v0",
"contract_id": "0000000000000000000000000000000000000000000000000000000000000001",
"type_": "contract",
"body": {
"v0": {
"topics": [
{
"symbol": "platform_fee_updated"
}
],
"data": {
"vec": [
{
"u32": 300
},
{
"u32": 500
}
]
}
}
}
},
"failed_call": false
}
]
}
16 changes: 16 additions & 0 deletions contracts/invoice-token/src/events.rs
Original file line number Diff line number Diff line change
Expand Up @@ -32,3 +32,19 @@ pub fn burn_event(env: &Env, from: &Address, amount: i128) {
env.events()
.publish((Symbol::new(env, "burn"), from), amount);
}

/// Emit transfer_locked update event with previous and new values.
pub fn transfer_locked_updated_event(env: &Env, old_value: bool, new_value: bool) {
env.events().publish(
(Symbol::new(env, "transfer_locked_updated"),),
(old_value, new_value),
);
}

/// Emit minter update event with previous and new minter addresses.
pub fn minter_updated_event(env: &Env, old_minter: &Address, new_minter: &Address) {
env.events().publish(
(Symbol::new(env, "minter_updated"),),
(old_minter, new_minter),
);
}
4 changes: 4 additions & 0 deletions contracts/invoice-token/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -251,17 +251,21 @@ impl InvoiceToken {
if caller != meta.admin && caller != meta.minter {
return Err(Error::Unauthorized);
}
let old_locked = meta.transfer_locked;
meta.transfer_locked = locked;
storage::set_metadata(&env, &meta);
events::transfer_locked_updated_event(&env, old_locked, locked);
Ok(())
}

/// Set minter address (admin only).
pub fn set_minter(env: Env, new_minter: Address) -> Result<(), Error> {
let mut meta = storage::get_metadata(&env).ok_or(Error::NotInit)?;
let old_minter = meta.minter.clone();
meta.admin.require_auth();
meta.minter = new_minter;
storage::set_metadata(&env, &meta);
events::minter_updated_event(&env, &old_minter, &meta.minter);
Ok(())
}

Expand Down
44 changes: 43 additions & 1 deletion contracts/invoice-token/src/test.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ use soroban_sdk::{Address, Env, IntoVal, String as SorobanString, Symbol, TryInt

fn setup_token(env: &Env) -> (InvoiceTokenClient<'_>, Address, Address) {
let contract_id = env.register(InvoiceToken, ());
let client = InvoiceTokenClient::new(&env, &contract_id);
let client = InvoiceTokenClient::new(env, &contract_id);
let admin = Address::generate(env);
let minter = Address::generate(env);
let name = SorobanString::from_str(env, "Invoice INV-001");
Expand Down Expand Up @@ -190,6 +190,27 @@ fn test_set_transfer_locked_toggle() {
assert_eq!(result, Err(Ok(crate::errors::Error::TransferLocked)));
}

#[test]
fn test_set_transfer_locked_event_emission() {
let env = Env::default();
env.mock_all_auths();
let (client, admin, minter) = setup_token(&env);

// Admin unlocks transfers and emits the old/new lock state.
client.mint(&admin, &1000, &minter);
client.set_transfer_locked(&admin, &false);

let events = env.events().all();
let event = events.last().unwrap();
let (_contract_addr, topics, data) = event;
assert_eq!(
topics,
(Symbol::new(&env, "transfer_locked_updated"),).into_val(&env)
);
let event_data: (bool, bool) = data.try_into_val(&env).unwrap();
assert_eq!(event_data, (true, false));
}

#[test]
fn test_set_transfer_locked_by_minter() {
let env = Env::default();
Expand All @@ -209,6 +230,27 @@ fn test_set_transfer_locked_by_minter() {
assert!(client.transfer_locked());
}

#[test]
fn test_set_minter_event_emission() {
let env = Env::default();
env.mock_all_auths();
let (client, _admin, old_minter) = setup_token(&env);

let new_minter = Address::generate(&env);
client.set_minter(&new_minter);

let events = env.events().all();
let event = events.last().unwrap();
let (_contract_addr, topics, data) = event;
assert_eq!(
topics,
(Symbol::new(&env, "minter_updated"),).into_val(&env)
);
let event_data: (Address, Address) = data.try_into_val(&env).unwrap();
assert_eq!(event_data.0, old_minter);
assert_eq!(event_data.1, new_minter);
}

#[test]
fn test_set_transfer_locked_unauthorized_fails() {
let env = Env::default();
Expand Down
Loading
Loading