diff --git a/.gitignore b/.gitignore index aa989f7a..2b371f3e 100644 --- a/.gitignore +++ b/.gitignore @@ -6,6 +6,8 @@ # Soroban compiled output *.wasm *.d +# Allow test fixture WASM binaries in testdata directories +!contracts/*/testdata/*.wasm # Node / SDK node_modules/ diff --git a/contracts/admin/src/lib.rs b/contracts/admin/src/lib.rs index e3f32c55..b1c0ab0d 100644 --- a/contracts/admin/src/lib.rs +++ b/contracts/admin/src/lib.rs @@ -1591,6 +1591,90 @@ pub fn require_valid_wasm_hash( Ok(()) } +/// Executes an approved WASM upgrade immediately when all signers have approved. +/// +/// This is an emergency bypass for critical security patches: when 100% of the +/// configured admin pool members have approved a proposal, this function allows +/// immediate execution without waiting for the mandatory timelock delay. +/// +/// The security model remains strong: 100% approval is much stricter than the +/// configured threshold (typically 2-of-3 or similar), and all other checks +/// (authorization, pool membership, existence, prior execution) are preserved. +/// +/// # Authorization & Guarantees +/// +/// - The executor must be an admin-pool member and must have authorized the +/// invocation; execution is not restricted to the singular contract admin. +/// - The proposal identified by `proposal_id` must exist, must not have been +/// executed before, and must have approvals from **every** admin-pool member +/// (100% quorum, checked via `approvals.len() == pool.len()`). +/// - **No timelock is enforced** — execution proceeds immediately upon 100% approval. +/// - The `executed` flag is persisted **before** the external WASM update is +/// performed (checks-effects-interactions), so a reentrant call can never +/// execute the same proposal twice. +/// - If 100% approval is not met, the function reverts with [`AdminError::QuorumNotMet`]. +/// +/// # Errors +/// +/// Returns [`AdminError::UnauthorizedRole`] if the executor is not an admin-pool member, +/// [`AdminError::ProposalNotFound`] if no proposal exists under `proposal_id`, +/// [`AdminError::ProposalAlreadyExecuted`] if the proposal was already executed, or +/// [`AdminError::QuorumNotMet`] if not all admin-pool members have approved (100% quorum not met). +/// +/// # Events +/// +/// Emits an `upgraded` event with `(executor, proposal_id, wasm_hash)` on success. +/// +/// @notice Executes proposal `proposal_id` immediately as a WASM upgrade to `wasm_hash`, but only if all signers have approved (100% quorum). +/// @dev Requires pool membership, authorization, and unanimous approval. Bypasses the timelock guard. The executed flag is set before the WASM update to guard against reentrancy. +/// @param env The Soroban environment. +/// @param executor The address performing the upgrade; must be an admin-pool member. +/// @param proposal_id The ID of the proposal; must have unanimous approval. +/// @param wasm_hash The hash of the new WASM to install on the current contract. +/// @return `Ok(())` on success, or one of the [`AdminError`] variants listed above. +pub fn emergency_execute_upgrade( + env: &Env, + executor: Address, + proposal_id: u64, + wasm_hash: soroban_sdk::BytesN<32>, +) -> Result<(), AdminError> { + executor.require_auth(); + + let pool = get_admin_pool(env); + if !pool.contains(&executor) { + return Err(AdminError::UnauthorizedRole); + } + + let mut proposal: Proposal = env + .storage() + .instance() + .get(&AdminKey::Proposal(proposal_id)) + .ok_or(AdminError::ProposalNotFound)?; + + if proposal.executed { + return Err(AdminError::ProposalAlreadyExecuted); + } + + // Emergency quorum check: all signers must have approved (100% agreement). + // proposal.approvals.len() must equal the total pool size. + if proposal.approvals.len() != pool.len() { + return Err(AdminError::QuorumNotMet); + } + + // Effect first (checks-effects-interactions): persist the executed flag so + // a reentrant invocation cannot execute the same proposal twice. + proposal.executed = true; + env.storage() + .instance() + .set(&AdminKey::Proposal(proposal_id), &proposal); + extend_instance_ttl(env); + + events::emit_upgraded(env, &executor, proposal_id, &wasm_hash); + + env.deployer().update_current_contract_wasm(wasm_hash); + Ok(()) +} + #[cfg(test)] mod tests { use super::*; @@ -1686,6 +1770,15 @@ mod tests { super::execute_upgrade(&env, executor, proposal_id, wasm_hash) } + pub fn emergency_execute_upgrade( + env: Env, + executor: Address, + proposal_id: u64, + wasm_hash: soroban_sdk::BytesN<32>, + ) -> Result<(), AdminError> { + super::emergency_execute_upgrade(&env, executor, proposal_id, wasm_hash) + } + pub fn get_proposal_unlock_time(env: Env, proposal_id: u64) -> Option { super::get_proposal_unlock_time(&env, proposal_id) } @@ -3800,6 +3893,7 @@ mod tests { #[test] fn test_is_proposal_ready_returns_false_for_nonexistent_proposal() { let env = Env::default(); + env.mock_all_auths(); let contract_id = env.register(AdminContract, ()); let client = AdminContractClient::new(&env, &contract_id); diff --git a/contracts/admin/test_snapshots/test_emergency_execute_upgrade_fails_if_already_executed.1.json b/contracts/admin/test_snapshots/test_emergency_execute_upgrade_fails_if_already_executed.1.json new file mode 100644 index 00000000..096e00a6 --- /dev/null +++ b/contracts/admin/test_snapshots/test_emergency_execute_upgrade_fails_if_already_executed.1.json @@ -0,0 +1,506 @@ +{ + "generators": { + "address": 3, + "nonce": 0 + }, + "auth": [ + [], + [], + [ + [ + "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFCT4", + { + "function": { + "contract_fn": { + "contract_address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD2KM", + "function_name": "set_admin_pool", + "args": [ + { + "vec": [ + { + "address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFCT4" + }, + { + "address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHK3M" + } + ] + }, + { + "u32": 2 + } + ] + } + }, + "sub_invocations": [] + } + ] + ], + [ + [ + "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFCT4", + { + "function": { + "contract_fn": { + "contract_address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD2KM", + "function_name": "create_proposal", + "args": [ + { + "address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFCT4" + }, + { + "string": "Already Executed" + } + ] + } + }, + "sub_invocations": [] + } + ] + ], + [ + [ + "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHK3M", + { + "function": { + "contract_fn": { + "contract_address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD2KM", + "function_name": "approve_proposal", + "args": [ + { + "address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHK3M" + }, + { + "u64": 0 + } + ] + } + }, + "sub_invocations": [] + } + ] + ], + [ + [ + "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFCT4", + { + "function": { + "contract_fn": { + "contract_address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD2KM", + "function_name": "", + "args": [] + } + }, + "sub_invocations": [] + } + ] + ], + [] + ], + "ledger": { + "protocol_version": 22, + "sequence_number": 0, + "timestamp": 0, + "network_id": "0000000000000000000000000000000000000000000000000000000000000000", + "base_reserve": 0, + "min_persistent_entry_ttl": 4096, + "min_temp_entry_ttl": 16, + "max_entry_ttl": 6312000, + "ledger_entries": [ + [ + { + "contract_data": { + "contract": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD2KM", + "key": { + "vec": [ + { + "symbol": "RoleMask" + }, + { + "address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFCT4" + } + ] + }, + "durability": "persistent" + } + }, + [ + { + "last_modified_ledger_seq": 0, + "data": { + "contract_data": { + "ext": "v0", + "contract": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD2KM", + "key": { + "vec": [ + { + "symbol": "RoleMask" + }, + { + "address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFCT4" + } + ] + }, + "durability": "persistent", + "val": { + "u32": 1 + } + } + }, + "ext": "v0" + }, + 4095 + ] + ], + [ + { + "contract_data": { + "contract": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD2KM", + "key": "ledger_key_contract_instance", + "durability": "persistent" + } + }, + [ + { + "last_modified_ledger_seq": 0, + "data": { + "contract_data": { + "ext": "v0", + "contract": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD2KM", + "key": "ledger_key_contract_instance", + "durability": "persistent", + "val": { + "contract_instance": { + "executable": { + "wasm": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855" + }, + "storage": [ + { + "key": { + "vec": [ + { + "symbol": "Admin" + } + ] + }, + "val": { + "address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFCT4" + } + }, + { + "key": { + "vec": [ + { + "symbol": "AdminPool" + } + ] + }, + "val": { + "vec": [ + { + "address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFCT4" + }, + { + "address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHK3M" + } + ] + } + }, + { + "key": { + "vec": [ + { + "symbol": "Proposal" + }, + { + "u64": 0 + } + ] + }, + "val": { + "map": [ + { + "key": { + "symbol": "approvals" + }, + "val": { + "vec": [ + { + "address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFCT4" + }, + { + "address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHK3M" + } + ] + } + }, + { + "key": { + "symbol": "creator" + }, + "val": { + "address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFCT4" + } + }, + { + "key": { + "symbol": "description" + }, + "val": { + "string": "Already Executed" + } + }, + { + "key": { + "symbol": "executed" + }, + "val": { + "bool": true + } + } + ] + } + }, + { + "key": { + "vec": [ + { + "symbol": "ProposalIdCounter" + } + ] + }, + "val": { + "u64": 1 + } + }, + { + "key": { + "vec": [ + { + "symbol": "ProposalTimelock" + }, + { + "u64": 0 + } + ] + }, + "val": { + "u64": 86400 + } + }, + { + "key": { + "vec": [ + { + "symbol": "Threshold" + } + ] + }, + "val": { + "u32": 2 + } + } + ] + } + } + } + }, + "ext": "v0" + }, + 4095 + ] + ], + [ + { + "contract_data": { + "contract": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFCT4", + "key": { + "ledger_key_nonce": { + "nonce": 801925984706572462 + } + }, + "durability": "temporary" + } + }, + [ + { + "last_modified_ledger_seq": 0, + "data": { + "contract_data": { + "ext": "v0", + "contract": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFCT4", + "key": { + "ledger_key_nonce": { + "nonce": 801925984706572462 + } + }, + "durability": "temporary", + "val": "void" + } + }, + "ext": "v0" + }, + 6311999 + ] + ], + [ + { + "contract_data": { + "contract": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFCT4", + "key": { + "ledger_key_nonce": { + "nonce": 4837995959683129791 + } + }, + "durability": "temporary" + } + }, + [ + { + "last_modified_ledger_seq": 0, + "data": { + "contract_data": { + "ext": "v0", + "contract": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFCT4", + "key": { + "ledger_key_nonce": { + "nonce": 4837995959683129791 + } + }, + "durability": "temporary", + "val": "void" + } + }, + "ext": "v0" + }, + 6311999 + ] + ], + [ + { + "contract_data": { + "contract": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFCT4", + "key": { + "ledger_key_nonce": { + "nonce": 5541220902715666415 + } + }, + "durability": "temporary" + } + }, + [ + { + "last_modified_ledger_seq": 0, + "data": { + "contract_data": { + "ext": "v0", + "contract": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFCT4", + "key": { + "ledger_key_nonce": { + "nonce": 5541220902715666415 + } + }, + "durability": "temporary", + "val": "void" + } + }, + "ext": "v0" + }, + 6311999 + ] + ], + [ + { + "contract_data": { + "contract": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHK3M", + "key": { + "ledger_key_nonce": { + "nonce": 1033654523790656264 + } + }, + "durability": "temporary" + } + }, + [ + { + "last_modified_ledger_seq": 0, + "data": { + "contract_data": { + "ext": "v0", + "contract": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHK3M", + "key": { + "ledger_key_nonce": { + "nonce": 1033654523790656264 + } + }, + "durability": "temporary", + "val": "void" + } + }, + "ext": "v0" + }, + 6311999 + ] + ], + [ + { + "contract_code": { + "hash": "47d3644146df9f61f2b57e5365bca149a4fc9e80aff26a9dd853d550db94545e" + } + }, + [ + { + "last_modified_ledger_seq": 0, + "data": { + "contract_code": { + "ext": { + "v1": { + "ext": "v0", + "cost_inputs": { + "ext": "v0", + "n_instructions": 3, + "n_functions": 2, + "n_globals": 1, + "n_table_entries": 0, + "n_types": 2, + "n_data_segments": 0, + "n_elem_segments": 0, + "n_imports": 0, + "n_exports": 3, + "n_data_segment_bytes": 0 + } + } + }, + "hash": "47d3644146df9f61f2b57e5365bca149a4fc9e80aff26a9dd853d550db94545e", + "code": "0061736d010000000108026000017e600000030302000105030100100609017f01418080c0000b071603066d656d6f727902000568656c6c6f0000015f00010a0e0209004285808080a0050b02000b002f0e636f6e747261637473706563763000000000000000000000000568656c6c6f000000000000000000000100000005001e11636f6e7472616374656e766d6574617630000000000000001600000000006f0e636f6e74726163746d65746176300000000000000005727376657200000000000006312e39382e3000000000000000000008727373646b7665720000003032322e302e31312333346637663533616533316530666430326161623433366139383732653739666136373163613032" + } + }, + "ext": "v0" + }, + 4095 + ] + ], + [ + { + "contract_code": { + "hash": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855" + } + }, + [ + { + "last_modified_ledger_seq": 0, + "data": { + "contract_code": { + "ext": "v0", + "hash": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", + "code": "" + } + }, + "ext": "v0" + }, + 4095 + ] + ] + ] + }, + "events": [] +} \ No newline at end of file diff --git a/contracts/admin/test_snapshots/test_emergency_execute_upgrade_fails_with_nonexistent_proposal.1.json b/contracts/admin/test_snapshots/test_emergency_execute_upgrade_fails_with_nonexistent_proposal.1.json new file mode 100644 index 00000000..c2fb0780 --- /dev/null +++ b/contracts/admin/test_snapshots/test_emergency_execute_upgrade_fails_with_nonexistent_proposal.1.json @@ -0,0 +1,222 @@ +{ + "generators": { + "address": 2, + "nonce": 0 + }, + "auth": [ + [], + [], + [ + [ + "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFCT4", + { + "function": { + "contract_fn": { + "contract_address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD2KM", + "function_name": "set_admin_pool", + "args": [ + { + "vec": [ + { + "address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFCT4" + } + ] + }, + { + "u32": 1 + } + ] + } + }, + "sub_invocations": [] + } + ] + ], + [] + ], + "ledger": { + "protocol_version": 22, + "sequence_number": 0, + "timestamp": 0, + "network_id": "0000000000000000000000000000000000000000000000000000000000000000", + "base_reserve": 0, + "min_persistent_entry_ttl": 4096, + "min_temp_entry_ttl": 16, + "max_entry_ttl": 6312000, + "ledger_entries": [ + [ + { + "contract_data": { + "contract": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD2KM", + "key": { + "vec": [ + { + "symbol": "RoleMask" + }, + { + "address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFCT4" + } + ] + }, + "durability": "persistent" + } + }, + [ + { + "last_modified_ledger_seq": 0, + "data": { + "contract_data": { + "ext": "v0", + "contract": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD2KM", + "key": { + "vec": [ + { + "symbol": "RoleMask" + }, + { + "address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFCT4" + } + ] + }, + "durability": "persistent", + "val": { + "u32": 1 + } + } + }, + "ext": "v0" + }, + 4095 + ] + ], + [ + { + "contract_data": { + "contract": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD2KM", + "key": "ledger_key_contract_instance", + "durability": "persistent" + } + }, + [ + { + "last_modified_ledger_seq": 0, + "data": { + "contract_data": { + "ext": "v0", + "contract": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD2KM", + "key": "ledger_key_contract_instance", + "durability": "persistent", + "val": { + "contract_instance": { + "executable": { + "wasm": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855" + }, + "storage": [ + { + "key": { + "vec": [ + { + "symbol": "Admin" + } + ] + }, + "val": { + "address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFCT4" + } + }, + { + "key": { + "vec": [ + { + "symbol": "AdminPool" + } + ] + }, + "val": { + "vec": [ + { + "address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFCT4" + } + ] + } + }, + { + "key": { + "vec": [ + { + "symbol": "Threshold" + } + ] + }, + "val": { + "u32": 1 + } + } + ] + } + } + } + }, + "ext": "v0" + }, + 4095 + ] + ], + [ + { + "contract_data": { + "contract": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFCT4", + "key": { + "ledger_key_nonce": { + "nonce": 801925984706572462 + } + }, + "durability": "temporary" + } + }, + [ + { + "last_modified_ledger_seq": 0, + "data": { + "contract_data": { + "ext": "v0", + "contract": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFCT4", + "key": { + "ledger_key_nonce": { + "nonce": 801925984706572462 + } + }, + "durability": "temporary", + "val": "void" + } + }, + "ext": "v0" + }, + 6311999 + ] + ], + [ + { + "contract_code": { + "hash": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855" + } + }, + [ + { + "last_modified_ledger_seq": 0, + "data": { + "contract_code": { + "ext": "v0", + "hash": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", + "code": "" + } + }, + "ext": "v0" + }, + 4095 + ] + ] + ] + }, + "events": [] +} \ No newline at end of file diff --git a/contracts/admin/test_snapshots/test_emergency_execute_upgrade_fails_with_partial_approval.1.json b/contracts/admin/test_snapshots/test_emergency_execute_upgrade_fails_with_partial_approval.1.json new file mode 100644 index 00000000..17c73fcd --- /dev/null +++ b/contracts/admin/test_snapshots/test_emergency_execute_upgrade_fails_with_partial_approval.1.json @@ -0,0 +1,426 @@ +{ + "generators": { + "address": 4, + "nonce": 0 + }, + "auth": [ + [], + [], + [ + [ + "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFCT4", + { + "function": { + "contract_fn": { + "contract_address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD2KM", + "function_name": "set_admin_pool", + "args": [ + { + "vec": [ + { + "address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFCT4" + }, + { + "address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHK3M" + }, + { + "address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAITA4" + } + ] + }, + { + "u32": 2 + } + ] + } + }, + "sub_invocations": [] + } + ] + ], + [ + [ + "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFCT4", + { + "function": { + "contract_fn": { + "contract_address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD2KM", + "function_name": "create_proposal", + "args": [ + { + "address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFCT4" + }, + { + "string": "Partial Approval" + } + ] + } + }, + "sub_invocations": [] + } + ] + ], + [ + [ + "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHK3M", + { + "function": { + "contract_fn": { + "contract_address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD2KM", + "function_name": "approve_proposal", + "args": [ + { + "address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHK3M" + }, + { + "u64": 0 + } + ] + } + }, + "sub_invocations": [] + } + ] + ], + [] + ], + "ledger": { + "protocol_version": 22, + "sequence_number": 0, + "timestamp": 0, + "network_id": "0000000000000000000000000000000000000000000000000000000000000000", + "base_reserve": 0, + "min_persistent_entry_ttl": 4096, + "min_temp_entry_ttl": 16, + "max_entry_ttl": 6312000, + "ledger_entries": [ + [ + { + "contract_data": { + "contract": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD2KM", + "key": { + "vec": [ + { + "symbol": "RoleMask" + }, + { + "address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFCT4" + } + ] + }, + "durability": "persistent" + } + }, + [ + { + "last_modified_ledger_seq": 0, + "data": { + "contract_data": { + "ext": "v0", + "contract": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD2KM", + "key": { + "vec": [ + { + "symbol": "RoleMask" + }, + { + "address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFCT4" + } + ] + }, + "durability": "persistent", + "val": { + "u32": 1 + } + } + }, + "ext": "v0" + }, + 4095 + ] + ], + [ + { + "contract_data": { + "contract": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD2KM", + "key": "ledger_key_contract_instance", + "durability": "persistent" + } + }, + [ + { + "last_modified_ledger_seq": 0, + "data": { + "contract_data": { + "ext": "v0", + "contract": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD2KM", + "key": "ledger_key_contract_instance", + "durability": "persistent", + "val": { + "contract_instance": { + "executable": { + "wasm": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855" + }, + "storage": [ + { + "key": { + "vec": [ + { + "symbol": "Admin" + } + ] + }, + "val": { + "address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFCT4" + } + }, + { + "key": { + "vec": [ + { + "symbol": "AdminPool" + } + ] + }, + "val": { + "vec": [ + { + "address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFCT4" + }, + { + "address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHK3M" + }, + { + "address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAITA4" + } + ] + } + }, + { + "key": { + "vec": [ + { + "symbol": "Proposal" + }, + { + "u64": 0 + } + ] + }, + "val": { + "map": [ + { + "key": { + "symbol": "approvals" + }, + "val": { + "vec": [ + { + "address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFCT4" + }, + { + "address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHK3M" + } + ] + } + }, + { + "key": { + "symbol": "creator" + }, + "val": { + "address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFCT4" + } + }, + { + "key": { + "symbol": "description" + }, + "val": { + "string": "Partial Approval" + } + }, + { + "key": { + "symbol": "executed" + }, + "val": { + "bool": false + } + } + ] + } + }, + { + "key": { + "vec": [ + { + "symbol": "ProposalIdCounter" + } + ] + }, + "val": { + "u64": 1 + } + }, + { + "key": { + "vec": [ + { + "symbol": "ProposalTimelock" + }, + { + "u64": 0 + } + ] + }, + "val": { + "u64": 86400 + } + }, + { + "key": { + "vec": [ + { + "symbol": "Threshold" + } + ] + }, + "val": { + "u32": 2 + } + } + ] + } + } + } + }, + "ext": "v0" + }, + 4095 + ] + ], + [ + { + "contract_data": { + "contract": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFCT4", + "key": { + "ledger_key_nonce": { + "nonce": 801925984706572462 + } + }, + "durability": "temporary" + } + }, + [ + { + "last_modified_ledger_seq": 0, + "data": { + "contract_data": { + "ext": "v0", + "contract": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFCT4", + "key": { + "ledger_key_nonce": { + "nonce": 801925984706572462 + } + }, + "durability": "temporary", + "val": "void" + } + }, + "ext": "v0" + }, + 6311999 + ] + ], + [ + { + "contract_data": { + "contract": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFCT4", + "key": { + "ledger_key_nonce": { + "nonce": 5541220902715666415 + } + }, + "durability": "temporary" + } + }, + [ + { + "last_modified_ledger_seq": 0, + "data": { + "contract_data": { + "ext": "v0", + "contract": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFCT4", + "key": { + "ledger_key_nonce": { + "nonce": 5541220902715666415 + } + }, + "durability": "temporary", + "val": "void" + } + }, + "ext": "v0" + }, + 6311999 + ] + ], + [ + { + "contract_data": { + "contract": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHK3M", + "key": { + "ledger_key_nonce": { + "nonce": 1033654523790656264 + } + }, + "durability": "temporary" + } + }, + [ + { + "last_modified_ledger_seq": 0, + "data": { + "contract_data": { + "ext": "v0", + "contract": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHK3M", + "key": { + "ledger_key_nonce": { + "nonce": 1033654523790656264 + } + }, + "durability": "temporary", + "val": "void" + } + }, + "ext": "v0" + }, + 6311999 + ] + ], + [ + { + "contract_code": { + "hash": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855" + } + }, + [ + { + "last_modified_ledger_seq": 0, + "data": { + "contract_code": { + "ext": "v0", + "hash": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", + "code": "" + } + }, + "ext": "v0" + }, + 4095 + ] + ] + ] + }, + "events": [] +} \ No newline at end of file diff --git a/contracts/admin/test_snapshots/test_emergency_execute_upgrade_fails_with_unauthorized_caller.1.json b/contracts/admin/test_snapshots/test_emergency_execute_upgrade_fails_with_unauthorized_caller.1.json new file mode 100644 index 00000000..ad721cca --- /dev/null +++ b/contracts/admin/test_snapshots/test_emergency_execute_upgrade_fails_with_unauthorized_caller.1.json @@ -0,0 +1,420 @@ +{ + "generators": { + "address": 4, + "nonce": 0 + }, + "auth": [ + [], + [], + [ + [ + "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFCT4", + { + "function": { + "contract_fn": { + "contract_address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD2KM", + "function_name": "set_admin_pool", + "args": [ + { + "vec": [ + { + "address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFCT4" + }, + { + "address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHK3M" + } + ] + }, + { + "u32": 2 + } + ] + } + }, + "sub_invocations": [] + } + ] + ], + [ + [ + "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFCT4", + { + "function": { + "contract_fn": { + "contract_address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD2KM", + "function_name": "create_proposal", + "args": [ + { + "address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFCT4" + }, + { + "string": "Emergency" + } + ] + } + }, + "sub_invocations": [] + } + ] + ], + [ + [ + "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHK3M", + { + "function": { + "contract_fn": { + "contract_address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD2KM", + "function_name": "approve_proposal", + "args": [ + { + "address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHK3M" + }, + { + "u64": 0 + } + ] + } + }, + "sub_invocations": [] + } + ] + ], + [] + ], + "ledger": { + "protocol_version": 22, + "sequence_number": 0, + "timestamp": 0, + "network_id": "0000000000000000000000000000000000000000000000000000000000000000", + "base_reserve": 0, + "min_persistent_entry_ttl": 4096, + "min_temp_entry_ttl": 16, + "max_entry_ttl": 6312000, + "ledger_entries": [ + [ + { + "contract_data": { + "contract": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD2KM", + "key": { + "vec": [ + { + "symbol": "RoleMask" + }, + { + "address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFCT4" + } + ] + }, + "durability": "persistent" + } + }, + [ + { + "last_modified_ledger_seq": 0, + "data": { + "contract_data": { + "ext": "v0", + "contract": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD2KM", + "key": { + "vec": [ + { + "symbol": "RoleMask" + }, + { + "address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFCT4" + } + ] + }, + "durability": "persistent", + "val": { + "u32": 1 + } + } + }, + "ext": "v0" + }, + 4095 + ] + ], + [ + { + "contract_data": { + "contract": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD2KM", + "key": "ledger_key_contract_instance", + "durability": "persistent" + } + }, + [ + { + "last_modified_ledger_seq": 0, + "data": { + "contract_data": { + "ext": "v0", + "contract": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD2KM", + "key": "ledger_key_contract_instance", + "durability": "persistent", + "val": { + "contract_instance": { + "executable": { + "wasm": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855" + }, + "storage": [ + { + "key": { + "vec": [ + { + "symbol": "Admin" + } + ] + }, + "val": { + "address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFCT4" + } + }, + { + "key": { + "vec": [ + { + "symbol": "AdminPool" + } + ] + }, + "val": { + "vec": [ + { + "address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFCT4" + }, + { + "address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHK3M" + } + ] + } + }, + { + "key": { + "vec": [ + { + "symbol": "Proposal" + }, + { + "u64": 0 + } + ] + }, + "val": { + "map": [ + { + "key": { + "symbol": "approvals" + }, + "val": { + "vec": [ + { + "address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFCT4" + }, + { + "address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHK3M" + } + ] + } + }, + { + "key": { + "symbol": "creator" + }, + "val": { + "address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFCT4" + } + }, + { + "key": { + "symbol": "description" + }, + "val": { + "string": "Emergency" + } + }, + { + "key": { + "symbol": "executed" + }, + "val": { + "bool": false + } + } + ] + } + }, + { + "key": { + "vec": [ + { + "symbol": "ProposalIdCounter" + } + ] + }, + "val": { + "u64": 1 + } + }, + { + "key": { + "vec": [ + { + "symbol": "ProposalTimelock" + }, + { + "u64": 0 + } + ] + }, + "val": { + "u64": 86400 + } + }, + { + "key": { + "vec": [ + { + "symbol": "Threshold" + } + ] + }, + "val": { + "u32": 2 + } + } + ] + } + } + } + }, + "ext": "v0" + }, + 4095 + ] + ], + [ + { + "contract_data": { + "contract": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFCT4", + "key": { + "ledger_key_nonce": { + "nonce": 801925984706572462 + } + }, + "durability": "temporary" + } + }, + [ + { + "last_modified_ledger_seq": 0, + "data": { + "contract_data": { + "ext": "v0", + "contract": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFCT4", + "key": { + "ledger_key_nonce": { + "nonce": 801925984706572462 + } + }, + "durability": "temporary", + "val": "void" + } + }, + "ext": "v0" + }, + 6311999 + ] + ], + [ + { + "contract_data": { + "contract": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFCT4", + "key": { + "ledger_key_nonce": { + "nonce": 5541220902715666415 + } + }, + "durability": "temporary" + } + }, + [ + { + "last_modified_ledger_seq": 0, + "data": { + "contract_data": { + "ext": "v0", + "contract": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFCT4", + "key": { + "ledger_key_nonce": { + "nonce": 5541220902715666415 + } + }, + "durability": "temporary", + "val": "void" + } + }, + "ext": "v0" + }, + 6311999 + ] + ], + [ + { + "contract_data": { + "contract": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHK3M", + "key": { + "ledger_key_nonce": { + "nonce": 1033654523790656264 + } + }, + "durability": "temporary" + } + }, + [ + { + "last_modified_ledger_seq": 0, + "data": { + "contract_data": { + "ext": "v0", + "contract": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHK3M", + "key": { + "ledger_key_nonce": { + "nonce": 1033654523790656264 + } + }, + "durability": "temporary", + "val": "void" + } + }, + "ext": "v0" + }, + 6311999 + ] + ], + [ + { + "contract_code": { + "hash": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855" + } + }, + [ + { + "last_modified_ledger_seq": 0, + "data": { + "contract_code": { + "ext": "v0", + "hash": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", + "code": "" + } + }, + "ext": "v0" + }, + 4095 + ] + ] + ] + }, + "events": [] +} \ No newline at end of file diff --git a/contracts/admin/test_snapshots/test_emergency_execute_upgrade_succeeds_with_100_percent_approval.1.json b/contracts/admin/test_snapshots/test_emergency_execute_upgrade_succeeds_with_100_percent_approval.1.json new file mode 100644 index 00000000..2b950006 --- /dev/null +++ b/contracts/admin/test_snapshots/test_emergency_execute_upgrade_succeeds_with_100_percent_approval.1.json @@ -0,0 +1,650 @@ +{ + "generators": { + "address": 4, + "nonce": 0 + }, + "auth": [ + [], + [], + [ + [ + "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFCT4", + { + "function": { + "contract_fn": { + "contract_address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD2KM", + "function_name": "set_admin_pool", + "args": [ + { + "vec": [ + { + "address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFCT4" + }, + { + "address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHK3M" + }, + { + "address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAITA4" + } + ] + }, + { + "u32": 2 + } + ] + } + }, + "sub_invocations": [] + } + ] + ], + [ + [ + "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFCT4", + { + "function": { + "contract_fn": { + "contract_address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD2KM", + "function_name": "create_proposal", + "args": [ + { + "address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFCT4" + }, + { + "string": "Emergency Patch" + } + ] + } + }, + "sub_invocations": [] + } + ] + ], + [ + [ + "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHK3M", + { + "function": { + "contract_fn": { + "contract_address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD2KM", + "function_name": "approve_proposal", + "args": [ + { + "address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHK3M" + }, + { + "u64": 0 + } + ] + } + }, + "sub_invocations": [] + } + ] + ], + [ + [ + "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAITA4", + { + "function": { + "contract_fn": { + "contract_address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD2KM", + "function_name": "approve_proposal", + "args": [ + { + "address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAITA4" + }, + { + "u64": 0 + } + ] + } + }, + "sub_invocations": [] + } + ] + ], + [ + [ + "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFCT4", + { + "function": { + "contract_fn": { + "contract_address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD2KM", + "function_name": "emergency_execute_upgrade", + "args": [ + { + "address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFCT4" + }, + { + "u64": 0 + }, + { + "bytes": "47d3644146df9f61f2b57e5365bca149a4fc9e80aff26a9dd853d550db94545e" + } + ] + } + }, + "sub_invocations": [] + } + ] + ] + ], + "ledger": { + "protocol_version": 22, + "sequence_number": 0, + "timestamp": 0, + "network_id": "0000000000000000000000000000000000000000000000000000000000000000", + "base_reserve": 0, + "min_persistent_entry_ttl": 4096, + "min_temp_entry_ttl": 16, + "max_entry_ttl": 6312000, + "ledger_entries": [ + [ + { + "contract_data": { + "contract": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD2KM", + "key": { + "vec": [ + { + "symbol": "RoleMask" + }, + { + "address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFCT4" + } + ] + }, + "durability": "persistent" + } + }, + [ + { + "last_modified_ledger_seq": 0, + "data": { + "contract_data": { + "ext": "v0", + "contract": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD2KM", + "key": { + "vec": [ + { + "symbol": "RoleMask" + }, + { + "address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFCT4" + } + ] + }, + "durability": "persistent", + "val": { + "u32": 1 + } + } + }, + "ext": "v0" + }, + 4095 + ] + ], + [ + { + "contract_data": { + "contract": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD2KM", + "key": "ledger_key_contract_instance", + "durability": "persistent" + } + }, + [ + { + "last_modified_ledger_seq": 0, + "data": { + "contract_data": { + "ext": "v0", + "contract": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD2KM", + "key": "ledger_key_contract_instance", + "durability": "persistent", + "val": { + "contract_instance": { + "executable": { + "wasm": "47d3644146df9f61f2b57e5365bca149a4fc9e80aff26a9dd853d550db94545e" + }, + "storage": [ + { + "key": { + "vec": [ + { + "symbol": "Admin" + } + ] + }, + "val": { + "address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFCT4" + } + }, + { + "key": { + "vec": [ + { + "symbol": "AdminPool" + } + ] + }, + "val": { + "vec": [ + { + "address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFCT4" + }, + { + "address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHK3M" + }, + { + "address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAITA4" + } + ] + } + }, + { + "key": { + "vec": [ + { + "symbol": "Proposal" + }, + { + "u64": 0 + } + ] + }, + "val": { + "map": [ + { + "key": { + "symbol": "approvals" + }, + "val": { + "vec": [ + { + "address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFCT4" + }, + { + "address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHK3M" + }, + { + "address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAITA4" + } + ] + } + }, + { + "key": { + "symbol": "creator" + }, + "val": { + "address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFCT4" + } + }, + { + "key": { + "symbol": "description" + }, + "val": { + "string": "Emergency Patch" + } + }, + { + "key": { + "symbol": "executed" + }, + "val": { + "bool": true + } + } + ] + } + }, + { + "key": { + "vec": [ + { + "symbol": "ProposalIdCounter" + } + ] + }, + "val": { + "u64": 1 + } + }, + { + "key": { + "vec": [ + { + "symbol": "ProposalTimelock" + }, + { + "u64": 0 + } + ] + }, + "val": { + "u64": 86400 + } + }, + { + "key": { + "vec": [ + { + "symbol": "Threshold" + } + ] + }, + "val": { + "u32": 2 + } + } + ] + } + } + } + }, + "ext": "v0" + }, + 4095 + ] + ], + [ + { + "contract_data": { + "contract": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFCT4", + "key": { + "ledger_key_nonce": { + "nonce": 801925984706572462 + } + }, + "durability": "temporary" + } + }, + [ + { + "last_modified_ledger_seq": 0, + "data": { + "contract_data": { + "ext": "v0", + "contract": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFCT4", + "key": { + "ledger_key_nonce": { + "nonce": 801925984706572462 + } + }, + "durability": "temporary", + "val": "void" + } + }, + "ext": "v0" + }, + 6311999 + ] + ], + [ + { + "contract_data": { + "contract": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFCT4", + "key": { + "ledger_key_nonce": { + "nonce": 2032731177588607455 + } + }, + "durability": "temporary" + } + }, + [ + { + "last_modified_ledger_seq": 0, + "data": { + "contract_data": { + "ext": "v0", + "contract": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFCT4", + "key": { + "ledger_key_nonce": { + "nonce": 2032731177588607455 + } + }, + "durability": "temporary", + "val": "void" + } + }, + "ext": "v0" + }, + 6311999 + ] + ], + [ + { + "contract_data": { + "contract": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFCT4", + "key": { + "ledger_key_nonce": { + "nonce": 5541220902715666415 + } + }, + "durability": "temporary" + } + }, + [ + { + "last_modified_ledger_seq": 0, + "data": { + "contract_data": { + "ext": "v0", + "contract": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFCT4", + "key": { + "ledger_key_nonce": { + "nonce": 5541220902715666415 + } + }, + "durability": "temporary", + "val": "void" + } + }, + "ext": "v0" + }, + 6311999 + ] + ], + [ + { + "contract_data": { + "contract": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHK3M", + "key": { + "ledger_key_nonce": { + "nonce": 1033654523790656264 + } + }, + "durability": "temporary" + } + }, + [ + { + "last_modified_ledger_seq": 0, + "data": { + "contract_data": { + "ext": "v0", + "contract": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHK3M", + "key": { + "ledger_key_nonce": { + "nonce": 1033654523790656264 + } + }, + "durability": "temporary", + "val": "void" + } + }, + "ext": "v0" + }, + 6311999 + ] + ], + [ + { + "contract_data": { + "contract": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAITA4", + "key": { + "ledger_key_nonce": { + "nonce": 4837995959683129791 + } + }, + "durability": "temporary" + } + }, + [ + { + "last_modified_ledger_seq": 0, + "data": { + "contract_data": { + "ext": "v0", + "contract": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAITA4", + "key": { + "ledger_key_nonce": { + "nonce": 4837995959683129791 + } + }, + "durability": "temporary", + "val": "void" + } + }, + "ext": "v0" + }, + 6311999 + ] + ], + [ + { + "contract_code": { + "hash": "47d3644146df9f61f2b57e5365bca149a4fc9e80aff26a9dd853d550db94545e" + } + }, + [ + { + "last_modified_ledger_seq": 0, + "data": { + "contract_code": { + "ext": { + "v1": { + "ext": "v0", + "cost_inputs": { + "ext": "v0", + "n_instructions": 3, + "n_functions": 2, + "n_globals": 1, + "n_table_entries": 0, + "n_types": 2, + "n_data_segments": 0, + "n_elem_segments": 0, + "n_imports": 0, + "n_exports": 3, + "n_data_segment_bytes": 0 + } + } + }, + "hash": "47d3644146df9f61f2b57e5365bca149a4fc9e80aff26a9dd853d550db94545e", + "code": "0061736d010000000108026000017e600000030302000105030100100609017f01418080c0000b071603066d656d6f727902000568656c6c6f0000015f00010a0e0209004285808080a0050b02000b002f0e636f6e747261637473706563763000000000000000000000000568656c6c6f000000000000000000000100000005001e11636f6e7472616374656e766d6574617630000000000000001600000000006f0e636f6e74726163746d65746176300000000000000005727376657200000000000006312e39382e3000000000000000000008727373646b7665720000003032322e302e31312333346637663533616533316530666430326161623433366139383732653739666136373163613032" + } + }, + "ext": "v0" + }, + 4095 + ] + ], + [ + { + "contract_code": { + "hash": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855" + } + }, + [ + { + "last_modified_ledger_seq": 0, + "data": { + "contract_code": { + "ext": "v0", + "hash": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", + "code": "" + } + }, + "ext": "v0" + }, + 4095 + ] + ] + ] + }, + "events": [ + { + "event": { + "ext": "v0", + "contract_id": "0000000000000000000000000000000000000000000000000000000000000001", + "type_": "contract", + "body": { + "v0": { + "topics": [ + { + "symbol": "upgraded" + } + ], + "data": { + "vec": [ + { + "address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFCT4" + }, + { + "u64": 0 + }, + { + "bytes": "47d3644146df9f61f2b57e5365bca149a4fc9e80aff26a9dd853d550db94545e" + } + ] + } + } + } + }, + "failed_call": false + }, + { + "event": { + "ext": "v0", + "contract_id": "0000000000000000000000000000000000000000000000000000000000000001", + "type_": "system", + "body": { + "v0": { + "topics": [ + { + "symbol": "executable_update" + }, + { + "vec": [ + { + "symbol": "Wasm" + }, + { + "bytes": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855" + } + ] + }, + { + "vec": [ + { + "symbol": "Wasm" + }, + { + "bytes": "47d3644146df9f61f2b57e5365bca149a4fc9e80aff26a9dd853d550db94545e" + } + ] + } + ], + "data": { + "vec": [] + } + } + } + }, + "failed_call": false + } + ] +} \ No newline at end of file diff --git a/contracts/admin/test_snapshots/test_normal_execute_upgrade_with_timelock_still_works.1.json b/contracts/admin/test_snapshots/test_normal_execute_upgrade_with_timelock_still_works.1.json new file mode 100644 index 00000000..dab3293d --- /dev/null +++ b/contracts/admin/test_snapshots/test_normal_execute_upgrade_with_timelock_still_works.1.json @@ -0,0 +1,588 @@ +{ + "generators": { + "address": 3, + "nonce": 0 + }, + "auth": [ + [], + [], + [ + [ + "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFCT4", + { + "function": { + "contract_fn": { + "contract_address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD2KM", + "function_name": "set_admin_pool", + "args": [ + { + "vec": [ + { + "address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFCT4" + }, + { + "address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHK3M" + } + ] + }, + { + "u32": 2 + } + ] + } + }, + "sub_invocations": [] + } + ] + ], + [ + [ + "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFCT4", + { + "function": { + "contract_fn": { + "contract_address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD2KM", + "function_name": "create_proposal", + "args": [ + { + "address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFCT4" + }, + { + "string": "Normal Path" + } + ] + } + }, + "sub_invocations": [] + } + ] + ], + [], + [ + [ + "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHK3M", + { + "function": { + "contract_fn": { + "contract_address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD2KM", + "function_name": "approve_proposal", + "args": [ + { + "address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHK3M" + }, + { + "u64": 0 + } + ] + } + }, + "sub_invocations": [] + } + ] + ], + [], + [ + [ + "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFCT4", + { + "function": { + "contract_fn": { + "contract_address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD2KM", + "function_name": "execute_upgrade", + "args": [ + { + "address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFCT4" + }, + { + "u64": 0 + }, + { + "bytes": "47d3644146df9f61f2b57e5365bca149a4fc9e80aff26a9dd853d550db94545e" + } + ] + } + }, + "sub_invocations": [] + } + ] + ] + ], + "ledger": { + "protocol_version": 22, + "sequence_number": 0, + "timestamp": 86401, + "network_id": "0000000000000000000000000000000000000000000000000000000000000000", + "base_reserve": 0, + "min_persistent_entry_ttl": 4096, + "min_temp_entry_ttl": 16, + "max_entry_ttl": 6312000, + "ledger_entries": [ + [ + { + "contract_data": { + "contract": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD2KM", + "key": { + "vec": [ + { + "symbol": "RoleMask" + }, + { + "address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFCT4" + } + ] + }, + "durability": "persistent" + } + }, + [ + { + "last_modified_ledger_seq": 0, + "data": { + "contract_data": { + "ext": "v0", + "contract": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD2KM", + "key": { + "vec": [ + { + "symbol": "RoleMask" + }, + { + "address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFCT4" + } + ] + }, + "durability": "persistent", + "val": { + "u32": 1 + } + } + }, + "ext": "v0" + }, + 4095 + ] + ], + [ + { + "contract_data": { + "contract": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD2KM", + "key": "ledger_key_contract_instance", + "durability": "persistent" + } + }, + [ + { + "last_modified_ledger_seq": 0, + "data": { + "contract_data": { + "ext": "v0", + "contract": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD2KM", + "key": "ledger_key_contract_instance", + "durability": "persistent", + "val": { + "contract_instance": { + "executable": { + "wasm": "47d3644146df9f61f2b57e5365bca149a4fc9e80aff26a9dd853d550db94545e" + }, + "storage": [ + { + "key": { + "vec": [ + { + "symbol": "Admin" + } + ] + }, + "val": { + "address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFCT4" + } + }, + { + "key": { + "vec": [ + { + "symbol": "AdminPool" + } + ] + }, + "val": { + "vec": [ + { + "address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFCT4" + }, + { + "address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHK3M" + } + ] + } + }, + { + "key": { + "vec": [ + { + "symbol": "Proposal" + }, + { + "u64": 0 + } + ] + }, + "val": { + "map": [ + { + "key": { + "symbol": "approvals" + }, + "val": { + "vec": [ + { + "address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFCT4" + }, + { + "address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHK3M" + } + ] + } + }, + { + "key": { + "symbol": "creator" + }, + "val": { + "address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFCT4" + } + }, + { + "key": { + "symbol": "description" + }, + "val": { + "string": "Normal Path" + } + }, + { + "key": { + "symbol": "executed" + }, + "val": { + "bool": true + } + } + ] + } + }, + { + "key": { + "vec": [ + { + "symbol": "ProposalIdCounter" + } + ] + }, + "val": { + "u64": 1 + } + }, + { + "key": { + "vec": [ + { + "symbol": "ProposalTimelock" + }, + { + "u64": 0 + } + ] + }, + "val": { + "u64": 86400 + } + }, + { + "key": { + "vec": [ + { + "symbol": "Threshold" + } + ] + }, + "val": { + "u32": 2 + } + } + ] + } + } + } + }, + "ext": "v0" + }, + 4095 + ] + ], + [ + { + "contract_data": { + "contract": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFCT4", + "key": { + "ledger_key_nonce": { + "nonce": 801925984706572462 + } + }, + "durability": "temporary" + } + }, + [ + { + "last_modified_ledger_seq": 0, + "data": { + "contract_data": { + "ext": "v0", + "contract": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFCT4", + "key": { + "ledger_key_nonce": { + "nonce": 801925984706572462 + } + }, + "durability": "temporary", + "val": "void" + } + }, + "ext": "v0" + }, + 6311999 + ] + ], + [ + { + "contract_data": { + "contract": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFCT4", + "key": { + "ledger_key_nonce": { + "nonce": 4270020994084947596 + } + }, + "durability": "temporary" + } + }, + [ + { + "last_modified_ledger_seq": 0, + "data": { + "contract_data": { + "ext": "v0", + "contract": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFCT4", + "key": { + "ledger_key_nonce": { + "nonce": 4270020994084947596 + } + }, + "durability": "temporary", + "val": "void" + } + }, + "ext": "v0" + }, + 6311999 + ] + ], + [ + { + "contract_data": { + "contract": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFCT4", + "key": { + "ledger_key_nonce": { + "nonce": 5541220902715666415 + } + }, + "durability": "temporary" + } + }, + [ + { + "last_modified_ledger_seq": 0, + "data": { + "contract_data": { + "ext": "v0", + "contract": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFCT4", + "key": { + "ledger_key_nonce": { + "nonce": 5541220902715666415 + } + }, + "durability": "temporary", + "val": "void" + } + }, + "ext": "v0" + }, + 6311999 + ] + ], + [ + { + "contract_data": { + "contract": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHK3M", + "key": { + "ledger_key_nonce": { + "nonce": 4837995959683129791 + } + }, + "durability": "temporary" + } + }, + [ + { + "last_modified_ledger_seq": 0, + "data": { + "contract_data": { + "ext": "v0", + "contract": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHK3M", + "key": { + "ledger_key_nonce": { + "nonce": 4837995959683129791 + } + }, + "durability": "temporary", + "val": "void" + } + }, + "ext": "v0" + }, + 6311999 + ] + ], + [ + { + "contract_code": { + "hash": "47d3644146df9f61f2b57e5365bca149a4fc9e80aff26a9dd853d550db94545e" + } + }, + [ + { + "last_modified_ledger_seq": 0, + "data": { + "contract_code": { + "ext": { + "v1": { + "ext": "v0", + "cost_inputs": { + "ext": "v0", + "n_instructions": 3, + "n_functions": 2, + "n_globals": 1, + "n_table_entries": 0, + "n_types": 2, + "n_data_segments": 0, + "n_elem_segments": 0, + "n_imports": 0, + "n_exports": 3, + "n_data_segment_bytes": 0 + } + } + }, + "hash": "47d3644146df9f61f2b57e5365bca149a4fc9e80aff26a9dd853d550db94545e", + "code": "0061736d010000000108026000017e600000030302000105030100100609017f01418080c0000b071603066d656d6f727902000568656c6c6f0000015f00010a0e0209004285808080a0050b02000b002f0e636f6e747261637473706563763000000000000000000000000568656c6c6f000000000000000000000100000005001e11636f6e7472616374656e766d6574617630000000000000001600000000006f0e636f6e74726163746d65746176300000000000000005727376657200000000000006312e39382e3000000000000000000008727373646b7665720000003032322e302e31312333346637663533616533316530666430326161623433366139383732653739666136373163613032" + } + }, + "ext": "v0" + }, + 4095 + ] + ], + [ + { + "contract_code": { + "hash": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855" + } + }, + [ + { + "last_modified_ledger_seq": 0, + "data": { + "contract_code": { + "ext": "v0", + "hash": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", + "code": "" + } + }, + "ext": "v0" + }, + 4095 + ] + ] + ] + }, + "events": [ + { + "event": { + "ext": "v0", + "contract_id": "0000000000000000000000000000000000000000000000000000000000000001", + "type_": "contract", + "body": { + "v0": { + "topics": [ + { + "symbol": "upgraded" + } + ], + "data": { + "vec": [ + { + "address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFCT4" + }, + { + "u64": 0 + }, + { + "bytes": "47d3644146df9f61f2b57e5365bca149a4fc9e80aff26a9dd853d550db94545e" + } + ] + } + } + } + }, + "failed_call": false + }, + { + "event": { + "ext": "v0", + "contract_id": "0000000000000000000000000000000000000000000000000000000000000001", + "type_": "system", + "body": { + "v0": { + "topics": [ + { + "symbol": "executable_update" + }, + { + "vec": [ + { + "symbol": "Wasm" + }, + { + "bytes": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855" + } + ] + }, + { + "vec": [ + { + "symbol": "Wasm" + }, + { + "bytes": "47d3644146df9f61f2b57e5365bca149a4fc9e80aff26a9dd853d550db94545e" + } + ] + } + ], + "data": { + "vec": [] + } + } + } + }, + "failed_call": false + } + ] +} \ No newline at end of file diff --git a/contracts/admin/test_snapshots/tests/proptest/fuzz_admin_implicitly_has_all_roles.10.json b/contracts/admin/test_snapshots/tests/proptest/fuzz_admin_implicitly_has_all_roles.10.json index e30ff926..e3d76722 100644 --- a/contracts/admin/test_snapshots/tests/proptest/fuzz_admin_implicitly_has_all_roles.10.json +++ b/contracts/admin/test_snapshots/tests/proptest/fuzz_admin_implicitly_has_all_roles.10.json @@ -4,7 +4,6 @@ "nonce": 0 }, "auth": [ - [], [], [], [ @@ -260,7 +259,7 @@ { "vec": [ { - "symbol": "SuperAdmin" + "symbol": "Admin" } ] }, diff --git a/contracts/admin/test_snapshots/tests/proptest/fuzz_admin_implicitly_has_all_roles.49.json b/contracts/admin/test_snapshots/tests/proptest/fuzz_admin_implicitly_has_all_roles.49.json index 4842a58d..e3d76722 100644 --- a/contracts/admin/test_snapshots/tests/proptest/fuzz_admin_implicitly_has_all_roles.49.json +++ b/contracts/admin/test_snapshots/tests/proptest/fuzz_admin_implicitly_has_all_roles.49.json @@ -4,7 +4,6 @@ "nonce": 0 }, "auth": [ - [], [], [], [ @@ -260,7 +259,7 @@ { "vec": [ { - "symbol": "Pauser" + "symbol": "Admin" } ] }, diff --git a/contracts/admin/test_snapshots/tests/proptest/fuzz_admin_implicitly_has_all_roles.61.json b/contracts/admin/test_snapshots/tests/proptest/fuzz_admin_implicitly_has_all_roles.61.json index 4842a58d..e3d76722 100644 --- a/contracts/admin/test_snapshots/tests/proptest/fuzz_admin_implicitly_has_all_roles.61.json +++ b/contracts/admin/test_snapshots/tests/proptest/fuzz_admin_implicitly_has_all_roles.61.json @@ -4,7 +4,6 @@ "nonce": 0 }, "auth": [ - [], [], [], [ @@ -260,7 +259,7 @@ { "vec": [ { - "symbol": "Pauser" + "symbol": "Admin" } ] }, diff --git a/contracts/admin/test_snapshots/tests/proptest/fuzz_admin_implicitly_has_all_roles.65.json b/contracts/admin/test_snapshots/tests/proptest/fuzz_admin_implicitly_has_all_roles.65.json index e30ff926..b6cf261d 100644 --- a/contracts/admin/test_snapshots/tests/proptest/fuzz_admin_implicitly_has_all_roles.65.json +++ b/contracts/admin/test_snapshots/tests/proptest/fuzz_admin_implicitly_has_all_roles.65.json @@ -260,7 +260,7 @@ { "vec": [ { - "symbol": "SuperAdmin" + "symbol": "Minter" } ] }, diff --git a/contracts/admin/test_snapshots/tests/proptest/fuzz_admin_implicitly_has_all_roles.68.json b/contracts/admin/test_snapshots/tests/proptest/fuzz_admin_implicitly_has_all_roles.68.json index 4842a58d..e30ff926 100644 --- a/contracts/admin/test_snapshots/tests/proptest/fuzz_admin_implicitly_has_all_roles.68.json +++ b/contracts/admin/test_snapshots/tests/proptest/fuzz_admin_implicitly_has_all_roles.68.json @@ -260,7 +260,7 @@ { "vec": [ { - "symbol": "Pauser" + "symbol": "SuperAdmin" } ] }, diff --git a/contracts/admin/test_snapshots/tests/proptest/fuzz_admin_implicitly_has_all_roles.83.json b/contracts/admin/test_snapshots/tests/proptest/fuzz_admin_implicitly_has_all_roles.83.json index 4842a58d..e3d76722 100644 --- a/contracts/admin/test_snapshots/tests/proptest/fuzz_admin_implicitly_has_all_roles.83.json +++ b/contracts/admin/test_snapshots/tests/proptest/fuzz_admin_implicitly_has_all_roles.83.json @@ -4,7 +4,6 @@ "nonce": 0 }, "auth": [ - [], [], [], [ @@ -260,7 +259,7 @@ { "vec": [ { - "symbol": "Pauser" + "symbol": "Admin" } ] }, diff --git a/contracts/admin/test_snapshots/tests/proptest/fuzz_grant_role_emits_event.14.json b/contracts/admin/test_snapshots/tests/proptest/fuzz_grant_role_emits_event.14.json index b344a423..071736d7 100644 --- a/contracts/admin/test_snapshots/tests/proptest/fuzz_grant_role_emits_event.14.json +++ b/contracts/admin/test_snapshots/tests/proptest/fuzz_grant_role_emits_event.14.json @@ -21,7 +21,7 @@ { "vec": [ { - "symbol": "SuperAdmin" + "symbol": "Pauser" } ] }, @@ -127,7 +127,7 @@ }, "durability": "persistent", "val": { - "u32": 4 + "u32": 8 } } }, @@ -292,7 +292,7 @@ { "vec": [ { - "symbol": "SuperAdmin" + "symbol": "Pauser" } ] }, diff --git a/contracts/admin/test_snapshots/tests/proptest/fuzz_grant_role_emits_event.33.json b/contracts/admin/test_snapshots/tests/proptest/fuzz_grant_role_emits_event.33.json index b344a423..627a6cd3 100644 --- a/contracts/admin/test_snapshots/tests/proptest/fuzz_grant_role_emits_event.33.json +++ b/contracts/admin/test_snapshots/tests/proptest/fuzz_grant_role_emits_event.33.json @@ -21,7 +21,7 @@ { "vec": [ { - "symbol": "SuperAdmin" + "symbol": "Admin" } ] }, @@ -127,7 +127,7 @@ }, "durability": "persistent", "val": { - "u32": 4 + "u32": 1 } } }, @@ -292,7 +292,7 @@ { "vec": [ { - "symbol": "SuperAdmin" + "symbol": "Admin" } ] }, diff --git a/contracts/admin/test_snapshots/tests/proptest/fuzz_grant_role_emits_event.56.json b/contracts/admin/test_snapshots/tests/proptest/fuzz_grant_role_emits_event.56.json index b344a423..65d23388 100644 --- a/contracts/admin/test_snapshots/tests/proptest/fuzz_grant_role_emits_event.56.json +++ b/contracts/admin/test_snapshots/tests/proptest/fuzz_grant_role_emits_event.56.json @@ -21,7 +21,7 @@ { "vec": [ { - "symbol": "SuperAdmin" + "symbol": "Minter" } ] }, @@ -127,7 +127,7 @@ }, "durability": "persistent", "val": { - "u32": 4 + "u32": 2 } } }, @@ -292,7 +292,7 @@ { "vec": [ { - "symbol": "SuperAdmin" + "symbol": "Minter" } ] }, diff --git a/contracts/admin/test_snapshots/tests/proptest/fuzz_grant_role_emits_event.59.json b/contracts/admin/test_snapshots/tests/proptest/fuzz_grant_role_emits_event.59.json index 65d23388..b344a423 100644 --- a/contracts/admin/test_snapshots/tests/proptest/fuzz_grant_role_emits_event.59.json +++ b/contracts/admin/test_snapshots/tests/proptest/fuzz_grant_role_emits_event.59.json @@ -21,7 +21,7 @@ { "vec": [ { - "symbol": "Minter" + "symbol": "SuperAdmin" } ] }, @@ -127,7 +127,7 @@ }, "durability": "persistent", "val": { - "u32": 2 + "u32": 4 } } }, @@ -292,7 +292,7 @@ { "vec": [ { - "symbol": "Minter" + "symbol": "SuperAdmin" } ] }, diff --git a/contracts/admin/test_snapshots/tests/proptest/fuzz_grant_role_emits_event.90.json b/contracts/admin/test_snapshots/tests/proptest/fuzz_grant_role_emits_event.90.json index 65d23388..b344a423 100644 --- a/contracts/admin/test_snapshots/tests/proptest/fuzz_grant_role_emits_event.90.json +++ b/contracts/admin/test_snapshots/tests/proptest/fuzz_grant_role_emits_event.90.json @@ -21,7 +21,7 @@ { "vec": [ { - "symbol": "Minter" + "symbol": "SuperAdmin" } ] }, @@ -127,7 +127,7 @@ }, "durability": "persistent", "val": { - "u32": 2 + "u32": 4 } } }, @@ -292,7 +292,7 @@ { "vec": [ { - "symbol": "Minter" + "symbol": "SuperAdmin" } ] }, diff --git a/contracts/admin/test_snapshots/tests/proptest/fuzz_grant_role_every_variant.3.json b/contracts/admin/test_snapshots/tests/proptest/fuzz_grant_role_every_variant.3.json index 75d05075..8512e871 100644 --- a/contracts/admin/test_snapshots/tests/proptest/fuzz_grant_role_every_variant.3.json +++ b/contracts/admin/test_snapshots/tests/proptest/fuzz_grant_role_every_variant.3.json @@ -21,7 +21,7 @@ { "vec": [ { - "symbol": "Pauser" + "symbol": "SuperAdmin" } ] }, @@ -128,7 +128,7 @@ }, "durability": "persistent", "val": { - "u32": 8 + "u32": 4 } } }, @@ -259,7 +259,7 @@ { "vec": [ { - "symbol": "Pauser" + "symbol": "SuperAdmin" } ] }, diff --git a/contracts/admin/test_snapshots/tests/proptest/fuzz_grant_role_every_variant.61.json b/contracts/admin/test_snapshots/tests/proptest/fuzz_grant_role_every_variant.61.json index 8512e871..75d05075 100644 --- a/contracts/admin/test_snapshots/tests/proptest/fuzz_grant_role_every_variant.61.json +++ b/contracts/admin/test_snapshots/tests/proptest/fuzz_grant_role_every_variant.61.json @@ -21,7 +21,7 @@ { "vec": [ { - "symbol": "SuperAdmin" + "symbol": "Pauser" } ] }, @@ -128,7 +128,7 @@ }, "durability": "persistent", "val": { - "u32": 4 + "u32": 8 } } }, @@ -259,7 +259,7 @@ { "vec": [ { - "symbol": "SuperAdmin" + "symbol": "Pauser" } ] }, diff --git a/contracts/admin/test_snapshots/tests/proptest/fuzz_grant_role_every_variant.98.json b/contracts/admin/test_snapshots/tests/proptest/fuzz_grant_role_every_variant.98.json index 75d05075..eaba25f5 100644 --- a/contracts/admin/test_snapshots/tests/proptest/fuzz_grant_role_every_variant.98.json +++ b/contracts/admin/test_snapshots/tests/proptest/fuzz_grant_role_every_variant.98.json @@ -21,7 +21,7 @@ { "vec": [ { - "symbol": "Pauser" + "symbol": "Minter" } ] }, @@ -128,7 +128,7 @@ }, "durability": "persistent", "val": { - "u32": 8 + "u32": 2 } } }, @@ -259,7 +259,7 @@ { "vec": [ { - "symbol": "Pauser" + "symbol": "Minter" } ] }, diff --git a/contracts/admin/test_snapshots/tests/proptest/fuzz_grant_role_idempotent.12.json b/contracts/admin/test_snapshots/tests/proptest/fuzz_grant_role_idempotent.12.json index fd41f0cb..85dd907b 100644 --- a/contracts/admin/test_snapshots/tests/proptest/fuzz_grant_role_idempotent.12.json +++ b/contracts/admin/test_snapshots/tests/proptest/fuzz_grant_role_idempotent.12.json @@ -441,6 +441,64 @@ } ] ], + [ + [ + "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFCT4", + { + "function": { + "contract_fn": { + "contract_address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD2KM", + "function_name": "grant_role", + "args": [ + { + "address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFCT4" + }, + { + "vec": [ + { + "symbol": "Minter" + } + ] + }, + { + "address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHK3M" + } + ] + } + }, + "sub_invocations": [] + } + ] + ], + [ + [ + "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFCT4", + { + "function": { + "contract_fn": { + "contract_address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD2KM", + "function_name": "grant_role", + "args": [ + { + "address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFCT4" + }, + { + "vec": [ + { + "symbol": "Minter" + } + ] + }, + { + "address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHK3M" + } + ] + } + }, + "sub_invocations": [] + } + ] + ], [] ], "ledger": { diff --git a/contracts/admin/test_snapshots/tests/proptest/fuzz_grant_role_idempotent.58.json b/contracts/admin/test_snapshots/tests/proptest/fuzz_grant_role_idempotent.58.json index b0b87b13..88f71ef3 100644 --- a/contracts/admin/test_snapshots/tests/proptest/fuzz_grant_role_idempotent.58.json +++ b/contracts/admin/test_snapshots/tests/proptest/fuzz_grant_role_idempotent.58.json @@ -180,6 +180,209 @@ } ] ], + [ + [ + "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFCT4", + { + "function": { + "contract_fn": { + "contract_address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD2KM", + "function_name": "grant_role", + "args": [ + { + "address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFCT4" + }, + { + "vec": [ + { + "symbol": "Pauser" + } + ] + }, + { + "address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHK3M" + } + ] + } + }, + "sub_invocations": [] + } + ] + ], + [ + [ + "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFCT4", + { + "function": { + "contract_fn": { + "contract_address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD2KM", + "function_name": "grant_role", + "args": [ + { + "address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFCT4" + }, + { + "vec": [ + { + "symbol": "Pauser" + } + ] + }, + { + "address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHK3M" + } + ] + } + }, + "sub_invocations": [] + } + ] + ], + [ + [ + "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFCT4", + { + "function": { + "contract_fn": { + "contract_address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD2KM", + "function_name": "grant_role", + "args": [ + { + "address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFCT4" + }, + { + "vec": [ + { + "symbol": "Pauser" + } + ] + }, + { + "address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHK3M" + } + ] + } + }, + "sub_invocations": [] + } + ] + ], + [ + [ + "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFCT4", + { + "function": { + "contract_fn": { + "contract_address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD2KM", + "function_name": "grant_role", + "args": [ + { + "address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFCT4" + }, + { + "vec": [ + { + "symbol": "Pauser" + } + ] + }, + { + "address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHK3M" + } + ] + } + }, + "sub_invocations": [] + } + ] + ], + [ + [ + "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFCT4", + { + "function": { + "contract_fn": { + "contract_address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD2KM", + "function_name": "grant_role", + "args": [ + { + "address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFCT4" + }, + { + "vec": [ + { + "symbol": "Pauser" + } + ] + }, + { + "address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHK3M" + } + ] + } + }, + "sub_invocations": [] + } + ] + ], + [ + [ + "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFCT4", + { + "function": { + "contract_fn": { + "contract_address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD2KM", + "function_name": "grant_role", + "args": [ + { + "address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFCT4" + }, + { + "vec": [ + { + "symbol": "Pauser" + } + ] + }, + { + "address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHK3M" + } + ] + } + }, + "sub_invocations": [] + } + ] + ], + [ + [ + "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFCT4", + { + "function": { + "contract_fn": { + "contract_address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD2KM", + "function_name": "grant_role", + "args": [ + { + "address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFCT4" + }, + { + "vec": [ + { + "symbol": "Pauser" + } + ] + }, + { + "address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHK3M" + } + ] + } + }, + "sub_invocations": [] + } + ] + ], [] ], "ledger": { @@ -327,6 +530,39 @@ 4095 ] ], + [ + { + "contract_data": { + "contract": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFCT4", + "key": { + "ledger_key_nonce": { + "nonce": 115220454072064130 + } + }, + "durability": "temporary" + } + }, + [ + { + "last_modified_ledger_seq": 0, + "data": { + "contract_data": { + "ext": "v0", + "contract": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFCT4", + "key": { + "ledger_key_nonce": { + "nonce": 115220454072064130 + } + }, + "durability": "temporary", + "val": "void" + } + }, + "ext": "v0" + }, + 6311999 + ] + ], [ { "contract_data": { @@ -393,6 +629,72 @@ 6311999 ] ], + [ + { + "contract_data": { + "contract": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFCT4", + "key": { + "ledger_key_nonce": { + "nonce": 1194852393571756375 + } + }, + "durability": "temporary" + } + }, + [ + { + "last_modified_ledger_seq": 0, + "data": { + "contract_data": { + "ext": "v0", + "contract": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFCT4", + "key": { + "ledger_key_nonce": { + "nonce": 1194852393571756375 + } + }, + "durability": "temporary", + "val": "void" + } + }, + "ext": "v0" + }, + 6311999 + ] + ], + [ + { + "contract_data": { + "contract": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFCT4", + "key": { + "ledger_key_nonce": { + "nonce": 1301173170172112462 + } + }, + "durability": "temporary" + } + }, + [ + { + "last_modified_ledger_seq": 0, + "data": { + "contract_data": { + "ext": "v0", + "contract": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFCT4", + "key": { + "ledger_key_nonce": { + "nonce": 1301173170172112462 + } + }, + "durability": "temporary", + "val": "void" + } + }, + "ext": "v0" + }, + 6311999 + ] + ], [ { "contract_data": { @@ -426,6 +728,39 @@ 6311999 ] ], + [ + { + "contract_data": { + "contract": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFCT4", + "key": { + "ledger_key_nonce": { + "nonce": 3126073502131104533 + } + }, + "durability": "temporary" + } + }, + [ + { + "last_modified_ledger_seq": 0, + "data": { + "contract_data": { + "ext": "v0", + "contract": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFCT4", + "key": { + "ledger_key_nonce": { + "nonce": 3126073502131104533 + } + }, + "durability": "temporary", + "val": "void" + } + }, + "ext": "v0" + }, + 6311999 + ] + ], [ { "contract_data": { @@ -525,6 +860,105 @@ 6311999 ] ], + [ + { + "contract_data": { + "contract": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFCT4", + "key": { + "ledger_key_nonce": { + "nonce": 5806905060045992000 + } + }, + "durability": "temporary" + } + }, + [ + { + "last_modified_ledger_seq": 0, + "data": { + "contract_data": { + "ext": "v0", + "contract": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFCT4", + "key": { + "ledger_key_nonce": { + "nonce": 5806905060045992000 + } + }, + "durability": "temporary", + "val": "void" + } + }, + "ext": "v0" + }, + 6311999 + ] + ], + [ + { + "contract_data": { + "contract": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFCT4", + "key": { + "ledger_key_nonce": { + "nonce": 6277191135259896685 + } + }, + "durability": "temporary" + } + }, + [ + { + "last_modified_ledger_seq": 0, + "data": { + "contract_data": { + "ext": "v0", + "contract": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFCT4", + "key": { + "ledger_key_nonce": { + "nonce": 6277191135259896685 + } + }, + "durability": "temporary", + "val": "void" + } + }, + "ext": "v0" + }, + 6311999 + ] + ], + [ + { + "contract_data": { + "contract": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFCT4", + "key": { + "ledger_key_nonce": { + "nonce": 8370022561469687789 + } + }, + "durability": "temporary" + } + }, + [ + { + "last_modified_ledger_seq": 0, + "data": { + "contract_data": { + "ext": "v0", + "contract": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFCT4", + "key": { + "ledger_key_nonce": { + "nonce": 8370022561469687789 + } + }, + "durability": "temporary", + "val": "void" + } + }, + "ext": "v0" + }, + 6311999 + ] + ], [ { "contract_code": { diff --git a/contracts/admin/test_snapshots/tests/proptest/fuzz_grant_role_many_holders.90.json b/contracts/admin/test_snapshots/tests/proptest/fuzz_grant_role_many_holders.90.json index 33dfa5ff..9910f4dd 100644 --- a/contracts/admin/test_snapshots/tests/proptest/fuzz_grant_role_many_holders.90.json +++ b/contracts/admin/test_snapshots/tests/proptest/fuzz_grant_role_many_holders.90.json @@ -30,7 +30,7 @@ { "vec": [ { - "symbol": "Minter" + "symbol": "SuperAdmin" } ] }, @@ -59,7 +59,7 @@ { "vec": [ { - "symbol": "Minter" + "symbol": "SuperAdmin" } ] }, @@ -88,7 +88,7 @@ { "vec": [ { - "symbol": "Minter" + "symbol": "SuperAdmin" } ] }, @@ -117,7 +117,7 @@ { "vec": [ { - "symbol": "Minter" + "symbol": "SuperAdmin" } ] }, @@ -377,7 +377,7 @@ }, "durability": "persistent", "val": { - "u32": 2 + "u32": 4 } } }, @@ -422,7 +422,7 @@ }, "durability": "persistent", "val": { - "u32": 2 + "u32": 4 } } }, @@ -467,7 +467,7 @@ }, "durability": "persistent", "val": { - "u32": 2 + "u32": 4 } } }, @@ -512,7 +512,7 @@ }, "durability": "persistent", "val": { - "u32": 2 + "u32": 4 } } }, @@ -1132,7 +1132,7 @@ { "vec": [ { - "symbol": "Minter" + "symbol": "SuperAdmin" } ] }, diff --git a/contracts/admin/test_snapshots/tests/proptest/fuzz_grant_role_multiple_roles.66.json b/contracts/admin/test_snapshots/tests/proptest/fuzz_grant_role_multiple_roles.66.json index 27d2276a..5e97f86a 100644 --- a/contracts/admin/test_snapshots/tests/proptest/fuzz_grant_role_multiple_roles.66.json +++ b/contracts/admin/test_snapshots/tests/proptest/fuzz_grant_role_multiple_roles.66.json @@ -6,64 +6,6 @@ "auth": [ [], [], - [ - [ - "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFCT4", - { - "function": { - "contract_fn": { - "contract_address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD2KM", - "function_name": "grant_role", - "args": [ - { - "address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFCT4" - }, - { - "vec": [ - { - "symbol": "Minter" - } - ] - }, - { - "address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHK3M" - } - ] - } - }, - "sub_invocations": [] - } - ] - ], - [ - [ - "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFCT4", - { - "function": { - "contract_fn": { - "contract_address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD2KM", - "function_name": "grant_role", - "args": [ - { - "address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFCT4" - }, - { - "vec": [ - { - "symbol": "Pauser" - } - ] - }, - { - "address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHK3M" - } - ] - } - }, - "sub_invocations": [] - } - ] - ], [], [], [] @@ -123,51 +65,6 @@ 4095 ] ], - [ - { - "contract_data": { - "contract": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD2KM", - "key": { - "vec": [ - { - "symbol": "RoleMask" - }, - { - "address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHK3M" - } - ] - }, - "durability": "persistent" - } - }, - [ - { - "last_modified_ledger_seq": 0, - "data": { - "contract_data": { - "ext": "v0", - "contract": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD2KM", - "key": { - "vec": [ - { - "symbol": "RoleMask" - }, - { - "address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHK3M" - } - ] - }, - "durability": "persistent", - "val": { - "u32": 10 - } - } - }, - "ext": "v0" - }, - 4095 - ] - ], [ { "contract_data": { @@ -213,72 +110,6 @@ 4095 ] ], - [ - { - "contract_data": { - "contract": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFCT4", - "key": { - "ledger_key_nonce": { - "nonce": 801925984706572462 - } - }, - "durability": "temporary" - } - }, - [ - { - "last_modified_ledger_seq": 0, - "data": { - "contract_data": { - "ext": "v0", - "contract": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFCT4", - "key": { - "ledger_key_nonce": { - "nonce": 801925984706572462 - } - }, - "durability": "temporary", - "val": "void" - } - }, - "ext": "v0" - }, - 6311999 - ] - ], - [ - { - "contract_data": { - "contract": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFCT4", - "key": { - "ledger_key_nonce": { - "nonce": 5541220902715666415 - } - }, - "durability": "temporary" - } - }, - [ - { - "last_modified_ledger_seq": 0, - "data": { - "contract_data": { - "ext": "v0", - "contract": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFCT4", - "key": { - "ledger_key_nonce": { - "nonce": 5541220902715666415 - } - }, - "durability": "temporary", - "val": "void" - } - }, - "ext": "v0" - }, - 6311999 - ] - ], [ { "contract_code": { @@ -328,7 +159,7 @@ ] }, { - "bool": true + "bool": false } ] } diff --git a/contracts/admin/test_snapshots/tests/proptest/fuzz_grant_role_self_grant.50.json b/contracts/admin/test_snapshots/tests/proptest/fuzz_grant_role_self_grant.50.json index ac3991c5..75b151cb 100644 --- a/contracts/admin/test_snapshots/tests/proptest/fuzz_grant_role_self_grant.50.json +++ b/contracts/admin/test_snapshots/tests/proptest/fuzz_grant_role_self_grant.50.json @@ -50,7 +50,7 @@ { "vec": [ { - "symbol": "Admin" + "symbol": "Minter" } ] }, @@ -157,7 +157,7 @@ }, "durability": "persistent", "val": { - "u32": 5 + "u32": 6 } } }, @@ -321,7 +321,7 @@ { "vec": [ { - "symbol": "Admin" + "symbol": "Minter" } ] }, diff --git a/contracts/admin/test_snapshots/tests/proptest/fuzz_grant_role_self_grant.62.json b/contracts/admin/test_snapshots/tests/proptest/fuzz_grant_role_self_grant.62.json index ac3991c5..50d0a072 100644 --- a/contracts/admin/test_snapshots/tests/proptest/fuzz_grant_role_self_grant.62.json +++ b/contracts/admin/test_snapshots/tests/proptest/fuzz_grant_role_self_grant.62.json @@ -50,7 +50,7 @@ { "vec": [ { - "symbol": "Admin" + "symbol": "SuperAdmin" } ] }, @@ -157,7 +157,7 @@ }, "durability": "persistent", "val": { - "u32": 5 + "u32": 4 } } }, @@ -321,7 +321,7 @@ { "vec": [ { - "symbol": "Admin" + "symbol": "SuperAdmin" } ] }, diff --git a/contracts/admin/test_snapshots/tests/proptest/fuzz_grant_role_self_grant.95.json b/contracts/admin/test_snapshots/tests/proptest/fuzz_grant_role_self_grant.95.json index 50d0a072..3e48b172 100644 --- a/contracts/admin/test_snapshots/tests/proptest/fuzz_grant_role_self_grant.95.json +++ b/contracts/admin/test_snapshots/tests/proptest/fuzz_grant_role_self_grant.95.json @@ -50,7 +50,7 @@ { "vec": [ { - "symbol": "SuperAdmin" + "symbol": "Pauser" } ] }, @@ -157,7 +157,7 @@ }, "durability": "persistent", "val": { - "u32": 4 + "u32": 12 } } }, @@ -321,7 +321,7 @@ { "vec": [ { - "symbol": "SuperAdmin" + "symbol": "Pauser" } ] }, diff --git a/contracts/admin/test_snapshots/tests/proptest/fuzz_grant_role_via_super_admin.17.json b/contracts/admin/test_snapshots/tests/proptest/fuzz_grant_role_via_super_admin.17.json index aab8f056..3df05ebe 100644 --- a/contracts/admin/test_snapshots/tests/proptest/fuzz_grant_role_via_super_admin.17.json +++ b/contracts/admin/test_snapshots/tests/proptest/fuzz_grant_role_via_super_admin.17.json @@ -51,7 +51,7 @@ { "vec": [ { - "symbol": "Admin" + "symbol": "SuperAdmin" } ] }, @@ -203,7 +203,7 @@ }, "durability": "persistent", "val": { - "u32": 1 + "u32": 4 } } }, @@ -367,7 +367,7 @@ { "vec": [ { - "symbol": "Admin" + "symbol": "SuperAdmin" } ] }, diff --git a/contracts/admin/test_snapshots/tests/proptest/fuzz_grant_role_via_super_admin.35.json b/contracts/admin/test_snapshots/tests/proptest/fuzz_grant_role_via_super_admin.35.json index aab8f056..c63c60ac 100644 --- a/contracts/admin/test_snapshots/tests/proptest/fuzz_grant_role_via_super_admin.35.json +++ b/contracts/admin/test_snapshots/tests/proptest/fuzz_grant_role_via_super_admin.35.json @@ -51,7 +51,7 @@ { "vec": [ { - "symbol": "Admin" + "symbol": "Pauser" } ] }, @@ -203,7 +203,7 @@ }, "durability": "persistent", "val": { - "u32": 1 + "u32": 8 } } }, @@ -367,7 +367,7 @@ { "vec": [ { - "symbol": "Admin" + "symbol": "Pauser" } ] }, diff --git a/contracts/admin/test_snapshots/tests/proptest/fuzz_grant_role_via_super_admin.60.json b/contracts/admin/test_snapshots/tests/proptest/fuzz_grant_role_via_super_admin.60.json index c63c60ac..3df05ebe 100644 --- a/contracts/admin/test_snapshots/tests/proptest/fuzz_grant_role_via_super_admin.60.json +++ b/contracts/admin/test_snapshots/tests/proptest/fuzz_grant_role_via_super_admin.60.json @@ -51,7 +51,7 @@ { "vec": [ { - "symbol": "Pauser" + "symbol": "SuperAdmin" } ] }, @@ -203,7 +203,7 @@ }, "durability": "persistent", "val": { - "u32": 8 + "u32": 4 } } }, @@ -367,7 +367,7 @@ { "vec": [ { - "symbol": "Pauser" + "symbol": "SuperAdmin" } ] }, diff --git a/contracts/admin/test_snapshots/tests/proptest/fuzz_grant_role_via_super_admin.87.json b/contracts/admin/test_snapshots/tests/proptest/fuzz_grant_role_via_super_admin.87.json index 693074d6..c63c60ac 100644 --- a/contracts/admin/test_snapshots/tests/proptest/fuzz_grant_role_via_super_admin.87.json +++ b/contracts/admin/test_snapshots/tests/proptest/fuzz_grant_role_via_super_admin.87.json @@ -51,7 +51,7 @@ { "vec": [ { - "symbol": "Minter" + "symbol": "Pauser" } ] }, @@ -203,7 +203,7 @@ }, "durability": "persistent", "val": { - "u32": 2 + "u32": 8 } } }, @@ -367,7 +367,7 @@ { "vec": [ { - "symbol": "Minter" + "symbol": "Pauser" } ] }, diff --git a/contracts/admin/test_snapshots/tests/proptest/fuzz_grant_role_via_super_admin.90.json b/contracts/admin/test_snapshots/tests/proptest/fuzz_grant_role_via_super_admin.90.json index 693074d6..c63c60ac 100644 --- a/contracts/admin/test_snapshots/tests/proptest/fuzz_grant_role_via_super_admin.90.json +++ b/contracts/admin/test_snapshots/tests/proptest/fuzz_grant_role_via_super_admin.90.json @@ -51,7 +51,7 @@ { "vec": [ { - "symbol": "Minter" + "symbol": "Pauser" } ] }, @@ -203,7 +203,7 @@ }, "durability": "persistent", "val": { - "u32": 2 + "u32": 8 } } }, @@ -367,7 +367,7 @@ { "vec": [ { - "symbol": "Minter" + "symbol": "Pauser" } ] }, diff --git a/contracts/admin/test_snapshots/tests/proptest/fuzz_grant_role_via_super_admin.95.json b/contracts/admin/test_snapshots/tests/proptest/fuzz_grant_role_via_super_admin.95.json index c63c60ac..693074d6 100644 --- a/contracts/admin/test_snapshots/tests/proptest/fuzz_grant_role_via_super_admin.95.json +++ b/contracts/admin/test_snapshots/tests/proptest/fuzz_grant_role_via_super_admin.95.json @@ -51,7 +51,7 @@ { "vec": [ { - "symbol": "Pauser" + "symbol": "Minter" } ] }, @@ -203,7 +203,7 @@ }, "durability": "persistent", "val": { - "u32": 8 + "u32": 2 } } }, @@ -367,7 +367,7 @@ { "vec": [ { - "symbol": "Pauser" + "symbol": "Minter" } ] }, diff --git a/contracts/admin/testdata/contract.wasm b/contracts/admin/testdata/contract.wasm new file mode 100644 index 00000000..275050c9 Binary files /dev/null and b/contracts/admin/testdata/contract.wasm differ diff --git a/contracts/admin/tests/upgrade_e2e.rs b/contracts/admin/tests/upgrade_e2e.rs index 1f982778..cfcf78c8 100644 --- a/contracts/admin/tests/upgrade_e2e.rs +++ b/contracts/admin/tests/upgrade_e2e.rs @@ -4,6 +4,11 @@ use bc_forge_admin::{AdminError, Role, TIMELOCK_DELAY_SECS}; use soroban_sdk::testutils::{Address as _, Ledger as _}; use soroban_sdk::{contract, contractimpl, vec, Address, BytesN, Env, String}; +fn upload_upgrade_wasm(env: &Env) -> BytesN<32> { + let wasm = include_bytes!("../testdata/contract.wasm"); + env.deployer().upload_contract_wasm(wasm.as_slice()) +} + #[contract] pub struct AdminContract; @@ -75,6 +80,15 @@ impl AdminContract { bc_forge_admin::execute_upgrade(&env, executor, proposal_id, wasm_hash) } + pub fn emergency_execute_upgrade( + env: Env, + executor: Address, + proposal_id: u64, + wasm_hash: BytesN<32>, + ) -> Result<(), AdminError> { + bc_forge_admin::emergency_execute_upgrade(&env, executor, proposal_id, wasm_hash) + } + pub fn migrate_admin(env: Env) { bc_forge_admin::migrate_admin(&env); } @@ -206,3 +220,197 @@ fn test_unauthorized_user_cannot_grant_roles_post_upgrade() { assert!(res.is_err()); assert!(!client.has_role(&Role::Minter, &user_b)); } + +/// Test emergency execution with 100% approval: should succeed immediately without timelock. +#[test] +fn test_emergency_execute_upgrade_succeeds_with_100_percent_approval() { + let env = Env::default(); + env.mock_all_auths(); + + let contract_id = env.register(AdminContract, ()); + let client = AdminContractClient::new(&env, &contract_id); + + let admin1 = Address::generate(&env); + let admin2 = Address::generate(&env); + let admin3 = Address::generate(&env); + + client.set_admin(&admin1); + let pool = vec![&env, admin1.clone(), admin2.clone(), admin3.clone()]; + client.set_admin_pool(&pool, &2); // Threshold is 2, but we'll get 3 approvals for emergency + + // Create proposal + let proposal_id = client.create_proposal(&admin1, &String::from_str(&env, "Emergency Patch")); + + // Get all admins to approve (100% approval) + client.approve_proposal(&admin2, &proposal_id); + client.approve_proposal(&admin3, &proposal_id); + + let upgrade_wasm = upload_upgrade_wasm(&env); + + // The emergency guard should pass and the actual contract upgrade should succeed. + let res = client.try_emergency_execute_upgrade(&admin1, &proposal_id, &upgrade_wasm); + assert!(res.is_ok()); +} + +/// Test emergency execution with < 100% approval: should fail. +#[test] +fn test_emergency_execute_upgrade_fails_with_partial_approval() { + let env = Env::default(); + env.mock_all_auths(); + + let contract_id = env.register(AdminContract, ()); + let client = AdminContractClient::new(&env, &contract_id); + + let admin1 = Address::generate(&env); + let admin2 = Address::generate(&env); + let admin3 = Address::generate(&env); + + client.set_admin(&admin1); + let pool = vec![&env, admin1.clone(), admin2.clone(), admin3.clone()]; + client.set_admin_pool(&pool, &2); + + // Create proposal with only 2 approvals out of 3 (not 100%) + let proposal_id = client.create_proposal(&admin1, &String::from_str(&env, "Partial Approval")); + client.approve_proposal(&admin2, &proposal_id); + + let dummy_wasm_hash = BytesN::from_array(&env, &[3u8; 32]); + + // Emergency execute should fail (QuorumNotMet = 8) + let res = client.try_emergency_execute_upgrade(&admin1, &proposal_id, &dummy_wasm_hash); + assert!(res.is_err()); + // Error code 8 is QuorumNotMet + assert_eq!(res, Err(Ok(AdminError::QuorumNotMet))); +} + +/// Test that normal timelock-based execution still works correctly after emergency feature. +#[test] +fn test_normal_execute_upgrade_with_timelock_still_works() { + let env = Env::default(); + env.mock_all_auths(); + + let contract_id = env.register(AdminContract, ()); + let client = AdminContractClient::new(&env, &contract_id); + + let admin1 = Address::generate(&env); + let admin2 = Address::generate(&env); + + client.set_admin(&admin1); + let pool = vec![&env, admin1.clone(), admin2.clone()]; + client.set_admin_pool(&pool, &2); // Threshold 2 (100% with 2 admins - will need emergency path) + + // Create proposal with only 1 approval (not 100%, won't be ready for emergency) + let proposal_id = client.create_proposal(&admin1, &String::from_str(&env, "Normal Path")); + + let dummy_wasm_hash = BytesN::from_array(&env, &[4u8; 32]); + + // Normal execute should fail (QuorumNotMet because only 1 approval) + let res = client.try_execute_upgrade(&admin1, &proposal_id, &dummy_wasm_hash); + assert_eq!(res, Err(Ok(AdminError::QuorumNotMet))); // QuorumNotMet + + // Now get the second approval to reach threshold + client.approve_proposal(&admin2, &proposal_id); + + // Still need to wait for timelock before normal execution + let res = client.try_execute_upgrade(&admin1, &proposal_id, &dummy_wasm_hash); + assert_eq!(res, Err(Ok(AdminError::TimelockActive))); // TimelockActive + + // Advance ledger timestamp past timelock + let mut ledger_info = env.ledger().get(); + ledger_info.timestamp += TIMELOCK_DELAY_SECS + 1; + env.ledger().set(ledger_info); + + let upgrade_wasm = upload_upgrade_wasm(&env); + + // The timelock guard passes and the actual upgrade succeeds with a real wasm hash. + let res = client.try_execute_upgrade(&admin1, &proposal_id, &upgrade_wasm); + assert!(res.is_ok()); +} + +/// Test emergency execution fails with unauthorized caller. +#[test] +fn test_emergency_execute_upgrade_fails_with_unauthorized_caller() { + let env = Env::default(); + env.mock_all_auths(); + + let contract_id = env.register(AdminContract, ()); + let client = AdminContractClient::new(&env, &contract_id); + + let admin1 = Address::generate(&env); + let admin2 = Address::generate(&env); + let unauthorized = Address::generate(&env); + + client.set_admin(&admin1); + let pool = vec![&env, admin1.clone(), admin2.clone()]; + client.set_admin_pool(&pool, &2); + + // Create proposal with full approval + let proposal_id = client.create_proposal(&admin1, &String::from_str(&env, "Emergency")); + client.approve_proposal(&admin2, &proposal_id); + + let dummy_wasm_hash = BytesN::from_array(&env, &[5u8; 32]); + + // Unauthorized caller attempting emergency execute must fail + let res = client.try_emergency_execute_upgrade(&unauthorized, &proposal_id, &dummy_wasm_hash); + assert!(res.is_err()); + // Error code 3 is UnauthorizedRole + assert_eq!(res, Err(Ok(AdminError::UnauthorizedRole))); +} + +/// Test emergency execution fails if proposal doesn't exist. +#[test] +fn test_emergency_execute_upgrade_fails_with_nonexistent_proposal() { + let env = Env::default(); + env.mock_all_auths(); + + let contract_id = env.register(AdminContract, ()); + let client = AdminContractClient::new(&env, &contract_id); + + let admin = Address::generate(&env); + client.set_admin(&admin); + let pool = vec![&env, admin.clone()]; + client.set_admin_pool(&pool, &1); + + let dummy_wasm_hash = BytesN::from_array(&env, &[6u8; 32]); + let nonexistent_proposal_id = 999u64; + + // Attempt emergency execute on nonexistent proposal + let res = + client.try_emergency_execute_upgrade(&admin, &nonexistent_proposal_id, &dummy_wasm_hash); + assert!(res.is_err()); + // Error code 7 is ProposalNotFound + assert_eq!(res, Err(Ok(AdminError::ProposalNotFound))); +} + +/// Test emergency execution fails if proposal was already executed. +#[test] +fn test_emergency_execute_upgrade_fails_if_already_executed() { + let env = Env::default(); + env.mock_all_auths(); + + let contract_id = env.register(AdminContract, ()); + let client = AdminContractClient::new(&env, &contract_id); + + let admin1 = Address::generate(&env); + let admin2 = Address::generate(&env); + + client.set_admin(&admin1); + let pool = vec![&env, admin1.clone(), admin2.clone()]; + client.set_admin_pool(&pool, &2); + + // Create proposal with full approval + let proposal_id = client.create_proposal(&admin1, &String::from_str(&env, "Already Executed")); + client.approve_proposal(&admin2, &proposal_id); + + let upgrade_wasm = upload_upgrade_wasm(&env); + + // Set the proposal to executed without changing the contract code, so a second + // emergency execution must fail on the executed-state guard alone. + env.as_contract(&contract_id, || { + bc_forge_admin::mark_executed(&env, proposal_id); + }); + + // Second attempt should fail (ProposalAlreadyExecuted = 9) + let res = client.try_emergency_execute_upgrade(&admin1, &proposal_id, &upgrade_wasm); + assert!(res.is_err()); + assert_eq!(res, Err(Ok(AdminError::ProposalAlreadyExecuted))); +} diff --git a/contracts/wrapper/src/lib.rs b/contracts/wrapper/src/lib.rs index 176e2e1e..0c4b8e35 100644 --- a/contracts/wrapper/src/lib.rs +++ b/contracts/wrapper/src/lib.rs @@ -211,6 +211,23 @@ impl WrapperContract { /// /// @notice Returns the total number of shares in circulation; defaults to 0 /// when the supply has never been written (e.g. before initialization). + fn read_unlock_time(env: &Env, user: &Address) -> Option { + env.storage() + .persistent() + .get(&DataKey::UnlockTime(user.clone())) + } + + fn write_unlock_time(env: &Env, user: &Address, unlock_timestamp: u64) { + env.storage() + .persistent() + .set(&DataKey::UnlockTime(user.clone()), &unlock_timestamp); + } + + fn remove_unlock_time(env: &Env, user: &Address) { + env.storage() + .persistent() + .remove(&DataKey::UnlockTime(user.clone())); + } fn read_supply(env: &Env) -> i128 { env.storage().instance().get(&DataKey::Supply).unwrap_or(0) }