Tracked as SR-007 in ISSUES.md.
Every event emitted by the SwiftRemit Soroban contract, generated by reading every emit_*
function in src/events.rs. This is the source of truth for off-chain
indexers, including this repo's own backend/src/remittance/events.ts.
Every "standard" event (emitted through the emit_event! macro or an equivalent manual
env.events().publish call that follows the same shape) is prefixed with an envelope of
(schema_version, ledger_sequence, ledger_timestamp) before the event's own payload
fields. SCHEMA_VERSION is defined in src/config.rs and is currently
1.
Versioning policy: SCHEMA_VERSION is incremented whenever the structure of any
event changes — fields added, removed, reordered, or retyped. It is a single contract-wide
version, not per-event, so indexers should treat any bump as "re-check every event shape
you consume," not just the one that changed. SCHEMA_VERSION is the first field in every
enveloped event's data tuple, so consumers can branch on it before decoding the rest of the
payload.
Not every event carries the envelope. A number of older/simpler events (see the
"No envelope" column below) publish only their raw payload with no
(schema_version, ledger_sequence, ledger_timestamp) prefix — mostly older escrow,
recipient-verification, and governance events. Treat any event topic not documented here as
unversioned and stable only by convention, not by contract.
src/events.rs currently defines the following function names twice, with the second
definition shadowing/conflicting with the first — a Rust error[E0428] (duplicate
definition) that will surface the next time this file is compiled:
emit_dispute_resolved— once with the full(schema, seq, ts, remittance_id, admin, in_favour_of_sender, resulting_status)envelope (topics("dispute", "resolved")), and once as a legacy no-envelope form (topic("dispute_resolved", id), payloadin_favour_of_sender).emit_remittance_failed— defined identically twice (topic("remittance_failed", id), payloadagent).emit_agent_suspended— defined identically twice (topics("agent", "suspnded")).
This table documents the first definition of each (the one actually reachable from
lib.rs, since Rust resolves to whichever the compiler accepts — in practice this needs a
one-line dedup fix in src/events.rs). Filed as a follow-up; out of scope for this
documentation pass (see SR-007's task list, which is docs-only).
| Function | Topics | Data (after envelope, if present) |
|---|---|---|
emit_paused |
("admin", "paused") |
admin |
emit_unpaused |
("admin", "unpaused") |
admin |
emit_admin_added |
("admin", "added") |
caller, new_admin |
emit_admin_removed |
("admin", "removed") |
caller, removed_admin |
emit_admin_nominated |
("admin", "nominated") |
nominator, nominee |
emit_admin_rotated |
("admin", "rotated") |
old_admin, new_admin |
emit_admin_transfer_proposed |
("admin", "proposed") |
current_admin, proposed_admin |
emit_admin_transfer_accepted |
("admin", "accepted") |
old_admin, new_admin |
| Function | Topics | Data (after envelope, if present) |
|---|---|---|
emit_remittance_created |
("remit", "created") |
remittance_id, sender, agent, amount, fee, integrator_fee, platform_fee, protocol_fee, net_amount |
emit_remittance_completed |
("remit", "complete") |
remittance_id, sender, agent |
emit_remittance_cancelled |
("remit", "cancel") |
remittance_id, sender, agent, token, amount |
emit_remittance_cancelled_with_reason |
("remit", "cancel_r") |
remittance_id, sender, agent, token, amount, reason |
emit_remittance_expired |
("remit", "expired") |
remittance_id, sender, token, refund_amount, expires_at |
emit_remittance_failed |
("remittance_failed", id) — no envelope |
agent |
emit_partial_payout |
("partial_payout", remittance_id) — no envelope |
agent, amount, disbursed_total, remaining_amount |
emit_dispute_raised |
("dispute", "raised") |
remittance_id, sender, evidence_hash |
emit_dispute_resolved |
("dispute", "resolved") |
remittance_id, admin, in_favour_of_sender, resulting_status (resulting_status is "Cancelled" if in_favour_of_sender, else "Completed") |
emit_settlement_completed |
("settlement_done", remittance_id) — no envelope |
sender, agent, token, payout_amount |
| Function | Topics | Data (after envelope, if present) |
|---|---|---|
emit_agent_registered |
("agent", "register") |
agent, caller, kyc_hash |
emit_agent_removed |
("agent", "removed") |
agent, caller |
emit_agent_suspended |
("agent", "suspnded") |
agent, reputation, min_threshold |
emit_agent_cap_set |
("agent_cap_set",) — no envelope |
agent, cap, caller |
emit_user_blacklisted |
("blacklist", "added") |
user, caller |
emit_user_removed_from_blacklist |
("blacklist", "removed") |
user, caller |
emit_token_whitelisted |
("token", "whitelist") |
token, caller |
emit_token_removed_from_whitelist |
("token", "rm_white") |
token, caller |
emit_token_fee_updated |
("token", "fee_upd") |
caller, token, fee_bps |
| Function | Topics | Data (after envelope, if present) |
|---|---|---|
emit_daily_limit_updated |
("limit", "updated") |
currency, country, old_limit, new_limit, admin |
emit_fee_updated |
("fee", "updated") |
fee_bps |
emit_fees_withdrawn |
("fee", "withdraw") |
caller, to, token, amount |
emit_fees_flushed |
("fee", "flushed") |
treasury, token, amount |
emit_protocol_fee_updated |
("fee", "proto_upd") |
caller, fee_bps |
emit_integrator_fees_withdrawn |
("intg_fee_wdrw",) — no envelope |
integrator, to, token, amount |
emit_treasury_updated |
("treasury_upd",) — no envelope |
caller, old_treasury, new_treasury |
| Function | Topics | Data (after envelope, if present) |
|---|---|---|
emit_circuit_breaker_paused |
("cb", "paused") |
caller, reason (envelope timestamp is the caller-supplied timestamp param, not env.ledger().timestamp()) |
emit_circuit_breaker_unpaused |
("cb", "unpaused") |
caller (same timestamp note as above) |
All three publish with no envelope.
| Function | Topics | Data |
|---|---|---|
emit_recipient_hash_registered |
("rcpt_hash_reg", remittance_id) |
recipient_hash, hash_schema_version |
emit_recipient_verified |
("rcpt_verified", remittance_id) |
agent |
emit_recipient_verification_failed |
("rcpt_vfy_fail", remittance_id) |
agent |
All four publish with no envelope.
| Function | Topics | Data |
|---|---|---|
emit_escrow_created |
("escrow_created", transfer_id) |
sender, recipient, amount |
emit_escrow_released |
("escrow_released", transfer_id) |
recipient, amount |
emit_escrow_refunded |
("escrow_refunded", transfer_id) |
sender, amount |
These publish (schema_version, ...) but — unlike the emit_event!-macro events above —
do not include ledger_sequence / ledger_timestamp in the envelope.
| Function | Topics | Data (after schema_version) |
|---|---|---|
emit_proposal_created |
("gov", "proposed") |
proposal_id, proposer, action_type, expiry |
emit_proposal_voted |
("gov", "voted") |
proposal_id, voter, approval_count |
emit_proposal_approved |
("gov", "approved") |
proposal_id, approval_timestamp |
emit_proposal_executed |
("gov", "executed") |
proposal_id, executor |
emit_proposal_expired |
("gov", "expired") |
proposal_id |
emit_governance_admin_added |
("gov", "adm_added") |
admin, proposal_id |
emit_governance_admin_removed |
("gov", "adm_rmvd") |
admin, proposal_id |
emit_fee_update_proposed |
("gov", "fee_prop") |
proposal_id, fee_bps |
emit_agent_management_proposed |
("gov", "agt_prop") |
proposal_id, agent, action |
emit_proposal_cleaned_up |
("gov", "cleaned_up") |
proposal_id |
| Function | Topics | Data (after envelope, if present) |
|---|---|---|
emit_migration_aborted |
("mig", "aborted") |
(schema_version, ledger_sequence, caller) — no timestamp |
All four use the full (schema, ledger_sequence, ledger_timestamp, ...) envelope.
| Function | Topics | Data (after envelope) |
|---|---|---|
emit_operation_proposed |
("msig", "proposed") |
op_id, proposer, op_type_tag |
emit_operation_approved |
("msig", "approved") |
op_id, approver, approval_count |
emit_operation_executed |
("msig", "executed") |
op_id, op_type_tag |
emit_operation_expired |
("msig", "expired") |
op_id, op_type_tag |
backend/src/remittance/events.ts is not a
raw on-chain topic listener — it's an internal EventEmitter that fans a remittance's
derived status (pending / processing / completed / failed / cancelled) out to
the webhook subscription system. It only distinguishes 5 coarse states, not the ~57 raw
event topics catalogued above. The rough mapping is:
| Backend status | Related on-chain topics |
|---|---|
pending |
("remit", "created") |
processing |
(no dedicated event — inferred from confirm_payout starting; see emit_partial_payout for partial-fill progress) |
completed |
("remit", "complete"), ("settlement_done", id) |
failed |
("remittance_failed", id) |
cancelled |
("remit", "cancel"), ("remit", "cancel_r"), ("remit", "expired") |
Everything else in this catalogue (admin, fee, governance, multi-sig, escrow, dispute,
circuit-breaker events) currently has no corresponding handler in
events.ts — it is either consumed elsewhere in the backend or not indexed at all. Wiring
those up is tracked as a follow-up; it's outside SR-007's docs-only scope.