Skip to content
Open
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
36 changes: 36 additions & 0 deletions apps/onchain/CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,42 @@ Welcome to the on-chain contracts workspace! This document outlines the developm
- Constants: `SCREAMING_SNAKE_CASE` (e.g., `MAX_PRIVACY_LEVEL`)
- Variables: `snake_case` (e.g., `account_address`)

### Event Versioning

Every contract event **must** include a `version: u32` field as its first data field
so that backend and data-processing consumers can detect schema changes.

1. Define a module-level constant in the events module:
```rust
/// Canonical event version. Bump this when the schema of any event in this
/// module changes so consumers can detect the difference.
pub const EVENT_VERSION: u32 = 1;
```

2. Add `version` as the first field in every event struct:
```rust
#[contractevent]
pub struct SomeEvent {
/// Schema version for consumer-side migration detection.
pub version: u32,
#[topic]
pub user: Address,
pub amount: i128,
}
```

3. Pass `EVENT_VERSION` when publishing:
```rust
events::SomeEvent {
version: events::EVENT_VERSION,
user,
amount,
}.publish(&env);
```

4. When changing an event schema (adding, removing, or reordering fields),
**increment** `EVENT_VERSION` so consumers can distinguish the format.

### Import Order
```rust
// 1. External crates
Expand Down
67 changes: 66 additions & 1 deletion apps/onchain/contracts/feature_flags/src/events.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,30 @@
use soroban_sdk::{contractevent, Address, Symbol};
use soroban_sdk::{contractevent, Address, Env, Symbol};

pub const EVENT_VERSION_INITIALIZED: u32 = 1u32;
pub const EVENT_VERSION_FLAG_SET: u32 = 1u32;
pub const EVENT_VERSION_ADMIN_TRANSFERRED: u32 = 1u32;

pub mod schema_ids {
use super::*;

pub fn initialized_v1(env: &Env) -> Symbol {
Symbol::new(env, "sys.initialized.v1")
}

pub fn flag_set_v1(env: &Env) -> Symbol {
Symbol::new(env, "admin.flag_set.v1")
}

pub fn admin_transferred_v1(env: &Env) -> Symbol {
Symbol::new(env, "admin.transferred.v1")
}
}

#[contractevent]
pub struct InitializedEvent {
pub admin: Address,
pub version: u32,
pub schema_id: Symbol,
}

#[contractevent]
Expand All @@ -11,10 +33,53 @@ pub struct FlagSetEvent {
pub key: Symbol,
pub enabled: bool,
pub toggled_by: Address,
pub version: u32,
pub schema_id: Symbol,
}

#[contractevent]
pub struct AdminTransferredEvent {
pub old_admin: Address,
pub new_admin: Address,
pub version: u32,
pub schema_id: Symbol,
}

pub fn publish_initialized(env: &Env, admin: Address) {
InitializedEvent {
admin,
version: EVENT_VERSION_INITIALIZED,
schema_id: schema_ids::initialized_v1(env),
}
.publish(env);
}

pub fn publish_flag_set(
env: &Env,
key: Symbol,
enabled: bool,
toggled_by: Address,
) {
FlagSetEvent {
key,
enabled,
toggled_by,
version: EVENT_VERSION_FLAG_SET,
schema_id: schema_ids::flag_set_v1(env),
}
.publish(env);
}

pub fn publish_admin_transferred(
env: &Env,
old_admin: Address,
new_admin: Address,
) {
AdminTransferredEvent {
old_admin,
new_admin,
version: EVENT_VERSION_ADMIN_TRANSFERRED,
schema_id: schema_ids::admin_transferred_v1(env),
}
.publish(env);
}
15 changes: 3 additions & 12 deletions apps/onchain/contracts/feature_flags/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ impl FeatureFlagsContract {
env.storage().instance().set(&DataKey::Admin, &admin);
env.storage().instance().set(&DataKey::Paused, &false);

events::InitializedEvent { admin }.publish(&env);
events::publish_initialized(&env, admin);
Ok(())
}

Expand Down Expand Up @@ -83,12 +83,7 @@ impl FeatureFlagsContract {
env.storage().instance().set(&DataKey::FlagList, &list);
}

events::FlagSetEvent {
key,
enabled,
toggled_by: caller,
}
.publish(&env);
events::publish_flag_set(&env, key, enabled, caller);

Ok(())
}
Expand Down Expand Up @@ -141,11 +136,7 @@ impl FeatureFlagsContract {

env.storage().instance().set(&DataKey::Admin, &new_admin);

events::AdminTransferredEvent {
old_admin: current_admin,
new_admin,
}
.publish(&env);
events::publish_admin_transferred(&env, current_admin, new_admin);

Ok(())
}
Expand Down
58 changes: 57 additions & 1 deletion apps/onchain/contracts/lumen_token/src/events.rs
Original file line number Diff line number Diff line change
@@ -1,11 +1,33 @@
use soroban_sdk::{contractevent, Address, BytesN};
use soroban_sdk::{contractevent, Address, BytesN, Env, Symbol};

pub const EVENT_VERSION_UPGRADED: u32 = 1u32;
pub const EVENT_VERSION_ADMIN_CHANGED: u32 = 1u32;
pub const EVENT_VERSION_BURN: u32 = 1u32;

pub mod schema_ids {
use super::*;

pub fn upgraded_v1(env: &Env) -> Symbol {
Symbol::new(env, "admin.upgraded.v1")
}

pub fn admin_changed_v1(env: &Env) -> Symbol {
Symbol::new(env, "admin.changed.v1")
}

pub fn burn_v1(env: &Env) -> Symbol {
Symbol::new(env, "token.burned.v1")
}
}

/// Emitted when the contract WASM is upgraded to a new hash.
#[contractevent]
pub struct UpgradedEvent {
#[topic]
pub admin: Address,
pub new_wasm_hash: BytesN<32>,
pub version: u32,
pub schema_id: Symbol,
}

/// Emitted when the admin role is transferred to a new address.
Expand All @@ -14,11 +36,45 @@ pub struct AdminChangedEvent {
#[topic]
pub old_admin: Address,
pub new_admin: Address,
pub version: u32,
pub schema_id: Symbol,
}

#[contractevent]
pub struct BurnEvent {
#[topic]
pub from: Address,
pub amount: i128,
pub version: u32,
pub schema_id: Symbol,
}

pub fn publish_upgraded(env: &Env, admin: Address, new_wasm_hash: BytesN<32>) {
UpgradedEvent {
admin,
new_wasm_hash,
version: EVENT_VERSION_UPGRADED,
schema_id: schema_ids::upgraded_v1(env),
}
.publish(env);
}

pub fn publish_admin_changed(env: &Env, old_admin: Address, new_admin: Address) {
AdminChangedEvent {
old_admin,
new_admin,
version: EVENT_VERSION_ADMIN_CHANGED,
schema_id: schema_ids::admin_changed_v1(env),
}
.publish(env);
}

pub fn publish_burn(env: &Env, from: Address, amount: i128) {
BurnEvent {
from,
amount,
version: EVENT_VERSION_BURN,
schema_id: schema_ids::burn_v1(env),
}
.publish(env);
}
19 changes: 6 additions & 13 deletions apps/onchain/contracts/lumen_token/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ mod metadata;
mod storage;
mod test;

use events::{AdminChangedEvent, BurnEvent, UpgradedEvent};
use events;
use soroban_sdk::{contract, contractimpl, Address, BytesN, Env, String};

#[contract]
Expand All @@ -35,11 +35,7 @@ impl LumenToken {
let old_admin = admin::read_administrator(&e);
old_admin.require_auth();
admin::write_administrator(&e, &new_admin);
AdminChangedEvent {
old_admin,
new_admin,
}
.publish(&e);
events::publish_admin_changed(&e, old_admin, new_admin);
}

pub fn freeze(e: Env, id: Address) {
Expand Down Expand Up @@ -87,15 +83,16 @@ impl LumenToken {
from.require_auth();
balance::check_not_frozen(&e, &from);
balance::spend_balance(&e, from.clone(), amount);
BurnEvent { from, amount }.publish(&e);
events::publish_burn(&e, from, amount);
}

pub fn burn_from(e: Env, spender: Address, from: Address, amount: i128) {
spender.require_auth();
balance::check_not_frozen(&e, &spender);

allowance::spend_allowance(&e, from.clone(), spender, amount);
balance::spend_balance(&e, from.clone(), amount);
BurnEvent { from, amount }.publish(&e);
events::publish_burn(&e, from, amount);
}

pub fn decimals(e: Env) -> u32 {
Expand All @@ -121,10 +118,6 @@ impl LumenToken {
caller.require_auth();
e.deployer()
.update_current_contract_wasm(new_wasm_hash.clone());
UpgradedEvent {
admin: caller,
new_wasm_hash,
}
.publish(&e);
events::publish_upgraded(&e, caller, new_wasm_hash);
}
}
Loading
Loading