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
19 changes: 15 additions & 4 deletions contracts/split/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,13 @@ fn admin_key() -> Symbol {
fn admins_key() -> Symbol {
symbol_short!("admins")
}

/// Issue #477: One-shot initialiser guard — instance storage.
/// Set to `true` at the end of `initialize()`; checked at the top to prevent
/// re-initialisation (front-run protection).
fn initialised_key() -> Symbol {
symbol_short!("init_flg")
}
fn paused_key() -> Symbol {
symbol_short!("paused")
}
Expand Down Expand Up @@ -2385,10 +2392,11 @@ impl SplitContract {
rate_limit: u32,
rate_window: u64,
) {
assert!(
!env.storage().instance().has(&admin_key()),
"already initialized"
);
// Issue #477: one-shot initialiser guard using a dedicated key so the
// guard cannot be bypassed by front-running the admin write.
if env.storage().instance().get::<_, bool>(&initialised_key()).unwrap_or(false) {
panic!("AlreadyInitialised");
}
assert!(creation_fee >= 0, "creation_fee must be non-negative");
assert!(
platform_fee_bps <= 10_000,
Expand Down Expand Up @@ -2431,6 +2439,9 @@ impl SplitContract {
env.storage()
.instance()
.set(&storage_quota_key(), &DEFAULT_INVOICE_STORAGE_QUOTA);
// Issue #477: set the initialisation flag atomically at the end so the
// contract is marked fully initialised only after all state is written.
env.storage().instance().set(&initialised_key(), &true);
}

/// Add a new admin with a given role. Requires SuperAdmin auth.
Expand Down
2 changes: 2 additions & 0 deletions contracts/split/src/storage_snapshot.rs
Original file line number Diff line number Diff line change
Expand Up @@ -125,6 +125,8 @@ fn storage_key_snapshot() {
"upgrade_proposal_key",
hex_xdr(&env, upgrade_proposal_key()),
));
// Issue #477: one-shot initialiser guard — instance storage
keys.push(("initialised_key", hex_xdr(&env, initialised_key())));

// -----------------------------------------------------------------------
// Persistent-tier keys (per-entity)
Expand Down
1 change: 1 addition & 0 deletions tests/snapshots/storage_keys.json
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@
"governance_contract_key": "0000000f00000007676f765f63747200",
"group_key": "0000001000000001000000020000000f0000000367727000000000050000000000000001",
"group_treasury_key": "0000001000000001000000020000000f000000066772705f74720000000000050000000000000001",
"initialised_key": "0000000f00000008696e69745f666c67",
"invoice_compact_key": "0000001000000001000000020000000f00000007696e765f63707400000000050000000000000001",
"invoice_count_key": "0000001000000001000000020000000f00000009696e765f636f756e740000000000001200000000000000000000000000000000000000000000000000000000000000000000000000000000",
"invoice_ext2_key": "0000001000000001000000020000000f00000007696e765f65783200000000050000000000000001",
Expand Down
Loading