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
56 changes: 51 additions & 5 deletions EVENT_SCHEMA.md
Original file line number Diff line number Diff line change
Expand Up @@ -762,10 +762,54 @@ so indexers can link the cancellation to the in-flight handover without a data d

---

### `upgraded`
### `upgrade_started`, `upgrade_completed`, `upgraded`

Emitted when the admin upgrades the contract WASM via `upgrade()`. The new WASM hash
is persisted to instance storage and is queryable via `get_version()`.
A successful `upgrade()` call publishes three events in this order:

1. `upgrade_started` — published *before* the host swaps the contract WASM.
2. `upgrade_completed` — published *after* the WASM swap and the
`ContractVersion` storage write.
3. `upgraded` — legacy single-event shape retained for backwards
compatibility with off-chain subscribers written against the
pre-lifecycle schema. New indexers should subscribe to the structured
pair above.

Receipt of `upgrade_started` without a matching `upgrade_completed` at the
same `(ledger, timestamp)` means the host trapped between the two emits;
the WASM swap and `ContractVersion` write were rolled back.

#### `upgrade_started` and `upgrade_completed`

| Index | Location | Type | Description |
|---------|----------|----------------|--------------------------------------------------------------|
| topic 0 | topics | Symbol | `"upgrade_started"` or `"upgrade_completed"` |
| topic 1 | topics | Address | `caller` -- the address that authorized `upgrade()` |
| data | data | `UpgradeEvent` | structured payload (see below) |

`UpgradeEvent` fields:

| Field | Type | Description |
|-----------------|-----------------------|-----------------------------------------------------------------------------|
| `caller` | `Address` | Same as topic 1; included in data for indexers that store the payload only. |
| `previous_wasm` | `Option<BytesN<32>>` | Hash recorded by the prior `upgrade()`. `None` on the first upgrade. |
| `new_wasm` | `BytesN<32>` | Hash being deployed by this call. |
| `ledger` | `u32` | `env.ledger().sequence()` captured before the WASM swap. |
| `timestamp` | `u64` | `env.ledger().timestamp()` captured before the WASM swap. |

```json
{
"topics": ["upgrade_completed", "GADMIN..."],
"data": {
"caller": "GADMIN...",
"previous_wasm": "a1b2c3d4...",
"new_wasm": "f0e1d2c3...",
"ledger": 1234567,
"timestamp": 1700000000
}
}
```

#### `upgraded` (legacy)

| Index | Location | Type | Description |
|---------|----------|------------|---------------------------------------------------|
Expand All @@ -780,8 +824,10 @@ is persisted to instance storage and is queryable via `get_version()`.
}
```

> `get_version()` returns this hash immediately after the transaction. Only one WASM
> version is stored; calling `upgrade()` again overwrites the previous value.
> `get_version()` returns the new hash immediately after the transaction. Only
> one WASM version is stored; calling `upgrade()` again overwrites the
> previous value (which is then visible to consumers as the next event's
> `previous_wasm`).
---

### `yield_deposited`
Expand Down
36 changes: 36 additions & 0 deletions contracts/vault/src/events.rs
Original file line number Diff line number Diff line change
Expand Up @@ -174,10 +174,32 @@ pub fn event_metadata_removed(env: &Env) -> Symbol {
/// Returns the Symbol for the `"upgraded"` event topic.
///
/// Emitted when the vault contract is upgraded to a new WASM hash.
///
/// Retained for backwards compatibility with off-chain consumers that subscribed
/// to the original single-event shape. Newly written indexers should prefer the
/// structured [`event_upgrade_started`] / [`event_upgrade_completed`] pair.
pub fn event_upgraded(env: &Env) -> Symbol {
Symbol::new(env, "upgraded")
}

/// Returns the Symbol for the `"upgrade_started"` event topic.
///
/// Emitted *before* the host swaps the contract WASM. Pairs with
/// [`event_upgrade_completed`] so indexers can distinguish a host-level trap
/// mid-upgrade from a fully applied upgrade.
pub fn event_upgrade_started(env: &Env) -> Symbol {
Symbol::new(env, "upgrade_started")
}

/// Returns the Symbol for the `"upgrade_completed"` event topic.
///
/// Emitted *after* the WASM swap and the `ContractVersion` storage write.
/// Receipt of this event without a preceding `upgrade_started` at the same
/// `(ledger, timestamp)` would indicate event-emission tampering.
pub fn event_upgrade_completed(env: &Env) -> Symbol {
Symbol::new(env, "upgrade_completed")
}

/// Returns the Symbol for the `"allowlist_add"` event topic.
///
/// Emitted when the owner adds an address to the vault deposit allowlist.
Expand Down Expand Up @@ -394,6 +416,20 @@ mod tests {
assert_eq!(sym, Symbol::new(&env, "upgraded"));
}

#[test]
fn test_event_upgrade_started_bytes() {
let env = soroban_sdk::Env::default();
let sym = event_upgrade_started(&env);
assert_eq!(sym, Symbol::new(&env, "upgrade_started"));
}

#[test]
fn test_event_upgrade_completed_bytes() {
let env = soroban_sdk::Env::default();
let sym = event_upgrade_completed(&env);
assert_eq!(sym, Symbol::new(&env, "upgrade_completed"));
}

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