Skip to content

Commit e2ebd57

Browse files
Merge pull request #98 from graycioustukura-sketch/feat/reveal-key-event
feat: emit key_revld event on successful reveal_key
2 parents b8d1e0b + 428dde9 commit e2ebd57

1 file changed

Lines changed: 110 additions & 2 deletions

File tree

  • contracts/atomic_swap/src

contracts/atomic_swap/src/lib.rs

Lines changed: 110 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,17 @@ pub struct SwapCancelledEvent {
4545
pub canceller: Address,
4646
}
4747

48+
// ── Events ────────────────────────────────────────────────────────────────────
49+
50+
/// Payload published when a key is successfully revealed and the swap completes.
51+
/// Topic: `key_revld` (symbol_short, max 9 chars) — used by off-chain indexers.
52+
#[contracttype]
53+
#[derive(Clone, Debug, PartialEq)]
54+
pub struct KeyRevealedEvent {
55+
pub swap_id: u64,
56+
pub decryption_key: BytesN<32>,
57+
}
58+
4859
// ── Contract ──────────────────────────────────────────────────────────────────
4960

5061
#[contract]
@@ -114,8 +125,10 @@ impl AtomicSwap {
114125
env.storage().persistent().set(&DataKey::Swap(swap_id), &swap);
115126
}
116127

117-
/// Seller reveals the decryption key; escrowed payment releases to seller.
118-
pub fn reveal_key(env: Env, swap_id: u64, _decryption_key: BytesN<32>) {
128+
/// Seller reveals the decryption key; payment releases.
129+
/// Emits a `key_revld` event on success so external systems can detect
130+
/// when the key becomes available.
131+
pub fn reveal_key(env: Env, swap_id: u64, decryption_key: BytesN<32>) {
119132
let mut swap: SwapRecord = env
120133
.storage()
121134
.persistent()
@@ -131,6 +144,12 @@ impl AtomicSwap {
131144

132145
swap.status = SwapStatus::Completed;
133146
env.storage().persistent().set(&DataKey::Swap(swap_id), &swap);
147+
148+
// Emit event — only reached after successful state transition.
149+
env.events().publish(
150+
(symbol_short!("key_revld"),),
151+
KeyRevealedEvent { swap_id, decryption_key },
152+
);
134153
}
135154

136155
/// Cancel a swap (invalid key or timeout). Emits a `swap_cancelled` event
@@ -463,3 +482,92 @@ mod tests {
463482
assert_eq!(env.events().all().len(), 0);
464483
}
465484
}
485+
486+
// ── Tests ─────────────────────────────────────────────────────────────────────
487+
488+
#[cfg(test)]
489+
mod tests {
490+
use super::*;
491+
use soroban_sdk::{
492+
testutils::{Address as _, BytesN as _, Events},
493+
vec, Env, IntoVal,
494+
};
495+
496+
fn setup() -> (Env, Address) {
497+
let env = Env::default();
498+
env.mock_all_auths();
499+
let contract_id = env.register_contract(None, AtomicSwap);
500+
(env, contract_id)
501+
}
502+
503+
/// Bring a swap to Accepted state and return its ID + the key used.
504+
fn accepted_swap(env: &Env, client: &AtomicSwapClient) -> (u64, BytesN<32>) {
505+
let buyer = Address::generate(env);
506+
let swap_id = client.initiate_swap(&1u64, &1000_i128, &buyer);
507+
client.accept_swap(&swap_id);
508+
let key = BytesN::random(env);
509+
(swap_id, key)
510+
}
511+
512+
#[test]
513+
fn test_reveal_key_emits_event_with_correct_values() {
514+
let (env, contract_id) = setup();
515+
let client = AtomicSwapClient::new(&env, &contract_id);
516+
let (swap_id, key) = accepted_swap(&env, &client);
517+
518+
client.reveal_key(&swap_id, &key);
519+
520+
// State must be Completed
521+
assert_eq!(client.get_swap(&swap_id).status, SwapStatus::Completed);
522+
523+
// Exactly one event emitted
524+
let events = env.events().all();
525+
assert_eq!(events.len(), 1);
526+
527+
// Topic is correct
528+
let (_, topics, data) = events.get(0).unwrap();
529+
assert_eq!(topics, vec![&env, symbol_short!("key_revld").into_val(&env)]);
530+
531+
// Payload fields match exactly
532+
let payload: KeyRevealedEvent = data.into_val(&env);
533+
assert_eq!(payload.swap_id, swap_id);
534+
assert_eq!(payload.decryption_key, key);
535+
}
536+
537+
#[test]
538+
#[should_panic(expected = "swap not accepted")]
539+
fn test_reveal_key_on_pending_swap_fails_no_event() {
540+
let (env, contract_id) = setup();
541+
let client = AtomicSwapClient::new(&env, &contract_id);
542+
let buyer = Address::generate(&env);
543+
let swap_id = client.initiate_swap(&1u64, &1000_i128, &buyer);
544+
let key = BytesN::random(&env);
545+
546+
// Swap is still Pending — must panic before event fires
547+
client.reveal_key(&swap_id, &key);
548+
}
549+
550+
#[test]
551+
#[should_panic(expected = "swap not accepted")]
552+
fn test_reveal_key_on_completed_swap_fails_no_event() {
553+
let (env, contract_id) = setup();
554+
let client = AtomicSwapClient::new(&env, &contract_id);
555+
let (swap_id, key) = accepted_swap(&env, &client);
556+
557+
client.reveal_key(&swap_id, &key);
558+
// Second call on an already-Completed swap — must panic
559+
client.reveal_key(&swap_id, &key);
560+
}
561+
562+
#[test]
563+
fn test_no_event_emitted_on_normal_completion_without_reveal() {
564+
let (env, contract_id) = setup();
565+
let client = AtomicSwapClient::new(&env, &contract_id);
566+
let buyer = Address::generate(&env);
567+
let swap_id = client.initiate_swap(&1u64, &1000_i128, &buyer);
568+
client.accept_swap(&swap_id);
569+
570+
// No reveal_key called — events list must be empty
571+
assert_eq!(env.events().all().len(), 0);
572+
}
573+
}

0 commit comments

Comments
 (0)