@layerzerolabs/protocol-stellar-v2 0.2.19 → 0.2.21
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.turbo/turbo-build.log +795 -791
- package/.turbo/turbo-lint.log +325 -155
- package/.turbo/turbo-test.log +1398 -1277
- package/Cargo.lock +122 -111
- package/Cargo.toml +32 -16
- package/contracts/common-macros/Cargo.toml +7 -7
- package/contracts/common-macros/src/auth.rs +18 -37
- package/contracts/common-macros/src/contract_ttl.rs +18 -7
- package/contracts/common-macros/src/lib.rs +31 -14
- package/contracts/common-macros/src/lz_contract.rs +38 -7
- package/contracts/common-macros/src/storage.rs +251 -292
- package/contracts/common-macros/src/tests/contract_ttl.rs +1 -1
- package/contracts/common-macros/src/tests/snapshots/common_macros__tests__auth__snapshot_generated_multisig_code.snap +6 -12
- package/contracts/common-macros/src/tests/snapshots/common_macros__tests__auth__snapshot_generated_ownable_code.snap +12 -17
- package/contracts/common-macros/src/tests/snapshots/common_macros__tests__contract_ttl__snapshot_generated_contractimpl_code.snap +2 -1
- package/contracts/common-macros/src/tests/snapshots/common_macros__tests__ttl_configurable__snapshot_generated_ttl_configurable_code.snap +2 -7
- package/contracts/common-macros/src/tests/snapshots/common_macros__tests__upgradeable__snapshot_generated_upgradeable_code.snap +20 -14
- package/contracts/common-macros/src/tests/upgradeable.rs +26 -4
- package/contracts/common-macros/src/ttl_configurable.rs +2 -10
- package/contracts/common-macros/src/ttl_extendable.rs +2 -10
- package/contracts/common-macros/src/upgradeable.rs +61 -26
- package/contracts/common-macros/src/utils.rs +0 -9
- package/contracts/endpoint-v2/src/lib.rs +3 -2
- package/contracts/endpoint-v2/src/tests/endpoint_v2/clear.rs +2 -2
- package/contracts/endpoint-v2/src/tests/endpoint_v2/lz_receive_alert.rs +3 -3
- package/contracts/endpoint-v2/src/tests/endpoint_v2/send.rs +4 -4
- package/contracts/endpoint-v2/src/tests/endpoint_v2/set_delegate.rs +17 -5
- package/contracts/endpoint-v2/src/tests/endpoint_v2/set_zro.rs +4 -4
- package/contracts/endpoint-v2/src/tests/endpoint_v2/verify.rs +2 -2
- package/contracts/endpoint-v2/src/tests/message_lib_manager/register_library.rs +2 -2
- package/contracts/endpoint-v2/src/tests/message_lib_manager/set_default_receive_lib_timeout.rs +6 -6
- package/contracts/endpoint-v2/src/tests/message_lib_manager/set_default_receive_library.rs +67 -37
- package/contracts/endpoint-v2/src/tests/message_lib_manager/set_default_send_library.rs +5 -5
- package/contracts/endpoint-v2/src/tests/message_lib_manager/set_receive_library.rs +44 -54
- package/contracts/endpoint-v2/src/tests/message_lib_manager/set_receive_library_timeout.rs +7 -7
- package/contracts/endpoint-v2/src/tests/message_lib_manager/set_send_library.rs +8 -8
- package/contracts/endpoint-v2/src/tests/messaging_channel/burn.rs +3 -3
- package/contracts/endpoint-v2/src/tests/messaging_channel/nilify.rs +4 -4
- package/contracts/endpoint-v2/src/tests/messaging_channel/skip.rs +3 -3
- package/contracts/endpoint-v2/src/tests/messaging_composer/clear_compose.rs +2 -2
- package/contracts/endpoint-v2/src/tests/messaging_composer/lz_compose_alert.rs +3 -3
- package/contracts/endpoint-v2/src/tests/messaging_composer/send_compose.rs +2 -2
- package/contracts/layerzero-views/Cargo.toml +0 -1
- package/contracts/layerzero-views/src/layerzero_view.rs +1 -13
- package/contracts/macro-integration-tests/Cargo.toml +5 -15
- package/contracts/macro-integration-tests/tests/runtime/oapp/mod.rs +48 -0
- package/contracts/macro-integration-tests/tests/runtime/oapp/oapp_core.rs +170 -0
- package/contracts/macro-integration-tests/tests/runtime/oapp/options_type3.rs +154 -0
- package/contracts/macro-integration-tests/tests/runtime/oapp/receiver.rs +338 -0
- package/contracts/macro-integration-tests/tests/runtime/oapp/sender.rs +435 -0
- package/contracts/macro-integration-tests/tests/runtime.rs +1 -0
- package/contracts/macro-integration-tests/tests/ui/oapp/fail/custom_wrong_value.rs +8 -0
- package/contracts/macro-integration-tests/tests/ui/oapp/fail/custom_wrong_value.stderr +5 -0
- package/contracts/macro-integration-tests/tests/ui/oapp/fail/missing_lz_receive_internal.rs +8 -0
- package/contracts/macro-integration-tests/tests/ui/oapp/fail/missing_lz_receive_internal.stderr +71 -0
- package/contracts/macro-integration-tests/tests/ui/oapp/fail/non_struct_input.rs +10 -0
- package/contracts/macro-integration-tests/tests/ui/oapp/fail/non_struct_input.stderr +5 -0
- package/contracts/macro-integration-tests/tests/ui/oapp/fail/unknown_custom_option.rs +8 -0
- package/contracts/macro-integration-tests/tests/ui/oapp/fail/unknown_custom_option.stderr +5 -0
- package/contracts/macro-integration-tests/tests/ui/oapp/fail/wrong_key.rs +8 -0
- package/contracts/macro-integration-tests/tests/ui/oapp/fail/wrong_key.stderr +5 -0
- package/contracts/macro-integration-tests/tests/ui/oapp/pass/custom_all.rs +38 -0
- package/contracts/macro-integration-tests/tests/ui/oapp/pass/custom_single_trait.rs +96 -0
- package/contracts/macro-integration-tests/tests/ui/oapp/pass/minimal_contract.rs +64 -0
- package/contracts/macro-integration-tests/tests/ui/oapp/pass/struct_with_fields.rs +46 -0
- package/contracts/macro-integration-tests/tests/ui/ownable/fail/only_auth_missing_env.stderr +8 -0
- package/contracts/macro-integration-tests/tests/ui/ownable/pass/namespacing_and_imports.rs +1 -1
- package/contracts/macro-integration-tests/tests/ui/ownable/pass/only_auth_env_param_variants.rs +1 -1
- package/contracts/macro-integration-tests/tests/ui_oapp.rs +11 -0
- package/contracts/message-libs/message-lib-common/Cargo.toml +0 -1
- package/contracts/message-libs/message-lib-common/src/errors.rs +1 -1
- package/contracts/message-libs/treasury/Cargo.toml +0 -2
- package/contracts/message-libs/treasury/src/tests/treasury_tests.rs +2 -2
- package/contracts/message-libs/uln-302/src/events.rs +4 -0
- package/contracts/message-libs/uln-302/src/send_uln.rs +22 -6
- package/contracts/message-libs/uln-302/src/tests/receive_uln302/effective_receive_uln_config.rs +2 -2
- package/contracts/message-libs/uln-302/src/tests/receive_uln302/set_default_receive_uln_configs.rs +2 -2
- package/contracts/message-libs/uln-302/src/tests/receive_uln302/verify.rs +2 -2
- package/contracts/message-libs/uln-302/src/tests/send_uln302/effective_executor_config.rs +2 -2
- package/contracts/message-libs/uln-302/src/tests/send_uln302/effective_send_uln_config.rs +2 -2
- package/contracts/message-libs/uln-302/src/tests/send_uln302/send.rs +21 -67
- package/contracts/message-libs/uln-302/src/tests/send_uln302/set_default_executor_configs.rs +2 -2
- package/contracts/message-libs/uln-302/src/tests/send_uln302/set_default_send_uln_configs.rs +2 -2
- package/contracts/oapps/counter/Cargo.toml +5 -6
- package/contracts/oapps/counter/integration_tests/setup_uln.rs +1 -1
- package/contracts/oapps/counter/integration_tests/utils.rs +19 -12
- package/contracts/oapps/oapp/src/errors.rs +1 -1
- package/contracts/oapps/oapp/src/interfaces/mod.rs +3 -0
- package/contracts/oapps/oapp/src/interfaces/oapp_msg_inspector.rs +47 -0
- package/contracts/oapps/oapp/src/lib.rs +1 -0
- package/contracts/oapps/oapp/src/macro_tests/test_macros.rs +4 -4
- package/contracts/oapps/oapp/src/oapp_core.rs +5 -5
- package/contracts/oapps/oapp/src/oapp_options_type3.rs +12 -4
- package/contracts/oapps/oapp/src/oapp_receiver.rs +14 -9
- package/contracts/oapps/oapp/src/tests/mod.rs +4 -4
- package/contracts/oapps/oapp/src/tests/oapp_core.rs +223 -0
- package/contracts/oapps/oapp/src/tests/oapp_options_type3.rs +240 -0
- package/contracts/oapps/oapp/src/tests/oapp_receiver.rs +381 -0
- package/contracts/oapps/oapp/src/tests/oapp_sender.rs +569 -0
- package/contracts/oapps/oapp-macros/Cargo.toml +8 -4
- package/contracts/oapps/oapp-macros/src/generators.rs +9 -34
- package/contracts/oapps/oapp-macros/src/lib.rs +3 -0
- package/contracts/oapps/oapp-macros/src/tests/mod.rs +2 -0
- package/contracts/oapps/oapp-macros/src/tests/oapp.rs +88 -0
- package/contracts/oapps/oapp-macros/src/tests/parse_custom_impls.rs +86 -0
- package/contracts/oapps/oapp-macros/src/tests/snapshots/oapp_macros__tests__oapp__snapshot_generate_oapp.snap +103 -0
- package/contracts/oapps/oft/integration-tests/utils.rs +28 -8
- package/contracts/oapps/oft/src/extensions/oft_fee.rs +153 -75
- package/contracts/oapps/oft/src/extensions/pausable.rs +61 -12
- package/contracts/oapps/oft/src/extensions/rate_limiter.rs +198 -134
- package/contracts/oapps/oft/src/oft.rs +45 -50
- package/contracts/oapps/oft/src/oft_types/lock_unlock.rs +1 -1
- package/contracts/oapps/oft/src/oft_types/mint_burn.rs +4 -26
- package/contracts/oapps/oft-core/Cargo.toml +1 -4
- package/contracts/oapps/oft-core/integration-tests/setup.rs +3 -3
- package/contracts/oapps/oft-core/integration-tests/utils.rs +21 -3
- package/contracts/oapps/oft-core/src/errors.rs +3 -2
- package/contracts/oapps/oft-core/src/events.rs +6 -0
- package/contracts/oapps/oft-core/src/lib.rs +1 -1
- package/contracts/oapps/oft-core/src/oft_core.rs +341 -246
- package/contracts/oapps/oft-core/src/storage.rs +7 -3
- package/contracts/oapps/oft-core/src/tests/mod.rs +1 -0
- package/contracts/oapps/oft-core/src/tests/test_decimals.rs +37 -2
- package/contracts/oapps/oft-core/src/tests/test_lz_receive.rs +2 -2
- package/contracts/oapps/oft-core/src/tests/test_msg_inspector.rs +323 -0
- package/contracts/oapps/oft-core/src/tests/test_send.rs +2 -2
- package/contracts/oapps/oft-core/src/tests/test_utils.rs +61 -16
- package/contracts/upgrader/src/lib.rs +30 -57
- package/contracts/upgrader/src/tests/test_data/test_upgradeable_contract1.wasm +0 -0
- package/contracts/upgrader/src/tests/test_data/test_upgradeable_contract2.wasm +0 -0
- package/contracts/upgrader/src/tests/test_upgrader.rs +44 -35
- package/contracts/utils/Cargo.toml +0 -1
- package/contracts/utils/src/buffer_reader.rs +1 -0
- package/contracts/utils/src/errors.rs +4 -2
- package/contracts/utils/src/multisig.rs +17 -8
- package/contracts/utils/src/ownable.rs +6 -6
- package/contracts/utils/src/testing_utils.rs +124 -54
- package/contracts/utils/src/tests/multisig.rs +12 -12
- package/contracts/utils/src/tests/ownable.rs +6 -6
- package/contracts/utils/src/tests/testing_utils.rs +50 -167
- package/contracts/utils/src/tests/ttl_configurable.rs +5 -5
- package/contracts/utils/src/tests/upgradeable.rs +372 -175
- package/contracts/utils/src/ttl_configurable.rs +13 -7
- package/contracts/utils/src/upgradeable.rs +48 -23
- package/contracts/workers/dvn/Cargo.toml +6 -6
- package/contracts/workers/dvn/src/auth.rs +12 -42
- package/contracts/workers/dvn/src/dvn.rs +15 -40
- package/contracts/workers/dvn/src/errors.rs +0 -1
- package/contracts/workers/dvn/src/interfaces/dvn.rs +35 -0
- package/contracts/workers/dvn/src/lib.rs +4 -3
- package/contracts/workers/dvn/src/tests/auth.rs +1 -1
- package/contracts/workers/dvn/src/tests/dvn.rs +19 -15
- package/contracts/workers/dvn/src/tests/multisig/set_threshold.rs +2 -4
- package/contracts/workers/dvn/src/tests/multisig/verify_signatures.rs +1 -3
- package/contracts/workers/dvn/src/tests/setup.rs +5 -9
- package/contracts/workers/dvn-fee-lib/Cargo.toml +2 -2
- package/contracts/workers/dvn-fee-lib/src/dvn_fee_lib.rs +38 -22
- package/contracts/workers/dvn-fee-lib/src/lib.rs +12 -2
- package/contracts/workers/dvn-fee-lib/src/tests/dvn_fee_lib.rs +17 -16
- package/contracts/workers/executor/Cargo.toml +4 -0
- package/contracts/workers/executor/src/executor.rs +15 -36
- package/contracts/workers/executor/src/lib.rs +2 -2
- package/contracts/workers/executor/src/tests/auth.rs +394 -0
- package/contracts/workers/executor/src/tests/executor.rs +410 -0
- package/contracts/workers/executor/src/tests/mod.rs +3 -0
- package/contracts/workers/executor/src/tests/setup.rs +250 -0
- package/contracts/workers/executor-fee-lib/Cargo.toml +7 -1
- package/contracts/workers/executor-fee-lib/src/executor_fee_lib.rs +62 -15
- package/contracts/workers/executor-fee-lib/src/executor_option.rs +28 -1
- package/contracts/workers/executor-fee-lib/src/lib.rs +11 -2
- package/contracts/workers/executor-fee-lib/src/tests/executor_fee_lib.rs +701 -0
- package/contracts/workers/executor-fee-lib/src/tests/executor_option.rs +370 -0
- package/contracts/workers/executor-fee-lib/src/tests/mod.rs +4 -0
- package/contracts/workers/executor-fee-lib/src/tests/setup.rs +60 -0
- package/contracts/workers/executor-helper/Cargo.toml +0 -1
- package/contracts/workers/executor-helper/src/lib.rs +3 -0
- package/contracts/workers/executor-helper/src/tests/executor_helper.rs +184 -0
- package/contracts/workers/executor-helper/src/tests/mod.rs +2 -0
- package/contracts/workers/executor-helper/src/tests/setup.rs +366 -0
- package/contracts/workers/fee-lib-interfaces/Cargo.toml +14 -0
- package/contracts/workers/{worker/src/interfaces/mod.rs → fee-lib-interfaces/src/lib.rs} +4 -3
- package/contracts/workers/price-feed/Cargo.toml +7 -1
- package/contracts/workers/price-feed/src/events.rs +1 -1
- package/contracts/workers/price-feed/src/lib.rs +12 -4
- package/contracts/workers/price-feed/src/price_feed.rs +5 -21
- package/contracts/workers/price-feed/src/storage.rs +1 -1
- package/contracts/workers/price-feed/src/tests/mod.rs +2 -0
- package/contracts/workers/price-feed/src/tests/price_feed.rs +869 -0
- package/contracts/workers/price-feed/src/tests/setup.rs +70 -0
- package/contracts/workers/price-feed/src/types.rs +1 -1
- package/contracts/workers/worker/src/errors.rs +1 -4
- package/contracts/workers/worker/src/lib.rs +0 -2
- package/contracts/workers/worker/src/storage.rs +32 -29
- package/contracts/workers/worker/src/tests/setup.rs +2 -8
- package/contracts/workers/worker/src/tests/worker.rs +96 -74
- package/contracts/workers/worker/src/worker.rs +75 -75
- package/docs/error-spec.md +55 -0
- package/docs/layerzero-v2-on-stellar.md +447 -0
- package/docs/oapp-guide.md +212 -0
- package/docs/oft-guide.md +314 -0
- package/package.json +3 -3
- package/sdk/.turbo/turbo-test.log +268 -263
- package/sdk/dist/generated/bml.d.ts +12 -4
- package/sdk/dist/generated/bml.js +9 -7
- package/sdk/dist/generated/counter.d.ts +306 -298
- package/sdk/dist/generated/counter.js +48 -46
- package/sdk/dist/generated/dvn.d.ts +450 -411
- package/sdk/dist/generated/dvn.js +66 -64
- package/sdk/dist/generated/dvn_fee_lib.d.ts +294 -338
- package/sdk/dist/generated/dvn_fee_lib.js +33 -64
- package/sdk/dist/generated/endpoint.d.ts +108 -100
- package/sdk/dist/generated/endpoint.js +21 -19
- package/sdk/dist/generated/executor.d.ts +414 -370
- package/sdk/dist/generated/executor.js +58 -55
- package/sdk/dist/generated/executor_fee_lib.d.ts +333 -377
- package/sdk/dist/generated/executor_fee_lib.js +34 -65
- package/sdk/dist/generated/executor_helper.d.ts +26 -190
- package/sdk/dist/generated/executor_helper.js +23 -28
- package/sdk/dist/generated/layerzero_view.d.ts +1271 -0
- package/sdk/dist/generated/layerzero_view.js +294 -0
- package/sdk/dist/generated/oft.d.ts +408 -385
- package/sdk/dist/generated/oft.js +89 -92
- package/sdk/dist/generated/price_feed.d.ts +385 -429
- package/sdk/dist/generated/price_feed.js +50 -81
- package/sdk/dist/generated/sml.d.ts +108 -100
- package/sdk/dist/generated/sml.js +21 -19
- package/sdk/dist/generated/treasury.d.ts +108 -100
- package/sdk/dist/generated/treasury.js +21 -19
- package/sdk/dist/generated/uln302.d.ts +108 -100
- package/sdk/dist/generated/uln302.js +23 -21
- package/sdk/dist/generated/upgrader.d.ts +189 -18
- package/sdk/dist/generated/upgrader.js +84 -4
- package/sdk/dist/index.d.ts +1 -0
- package/sdk/dist/index.js +2 -0
- package/sdk/package.json +1 -1
- package/sdk/src/index.ts +3 -0
- package/sdk/test/oft-sml.test.ts +4 -4
- package/sdk/test/suites/localnet.ts +84 -20
- package/sdk/test/upgrader.test.ts +2 -3
- package/tools/ts-bindings-gen/src/main.rs +2 -1
- package/contracts/ERROR_SPEC.md +0 -44
- package/contracts/endpoint-v2/ARCHITECTURE.md +0 -233
- package/contracts/oapps/oapp/src/tests/test_oapp_core.rs +0 -175
- package/contracts/oapps/oapp/src/tests/test_oapp_options_type3.rs +0 -212
- package/contracts/oapps/oapp/src/tests/test_oapp_receiver.rs +0 -153
- package/contracts/oapps/oapp/src/tests/test_oapp_sender.rs +0 -294
- /package/contracts/workers/{worker/src/interfaces → fee-lib-interfaces/src}/dvn_fee_lib.rs +0 -0
- /package/contracts/workers/{worker/src/interfaces → fee-lib-interfaces/src}/executor_fee_lib.rs +0 -0
- /package/contracts/workers/{worker/src/interfaces → fee-lib-interfaces/src}/price_feed.rs +0 -0
|
@@ -2,45 +2,25 @@
|
|
|
2
2
|
|
|
3
3
|
//! # Upgrader Contract
|
|
4
4
|
//!
|
|
5
|
-
//! A stateless utility contract for performing upgrade and migrate operations
|
|
6
|
-
//!
|
|
7
|
-
//! This contract provides a convenient way to upgrade other contracts, especially useful for
|
|
8
|
-
//! performing upgrade+migrate atomically in a single transaction.
|
|
5
|
+
//! A stateless utility contract for performing atomic upgrade and migrate operations
|
|
6
|
+
//! on contracts implementing the [`Upgradeable`](utils::upgradeable::Upgradeable) trait.
|
|
9
7
|
//!
|
|
10
8
|
//! ## Security Model
|
|
11
9
|
//!
|
|
12
|
-
//! The Upgrader is
|
|
13
|
-
//!
|
|
14
|
-
//!
|
|
10
|
+
//! The Upgrader is permissionless - anyone can call it, but security is enforced by the
|
|
11
|
+
//! target contract's authorization checks. The target contract's `#[only_auth]` guard
|
|
12
|
+
//! ensures only its authorizer can successfully upgrade it.
|
|
15
13
|
//!
|
|
16
14
|
//! ## Usage
|
|
17
15
|
//!
|
|
18
|
-
//! Deploy this contract once, then anyone can use it to upgrade contracts they own.
|
|
19
|
-
//!
|
|
20
16
|
//! ```ignore
|
|
21
|
-
//! // Deploy upgrader (no initialization needed)
|
|
22
|
-
//! let upgrader_id = env.register(Upgrader, ());
|
|
23
17
|
//! let upgrader = UpgraderClient::new(&env, &upgrader_id);
|
|
24
|
-
//!
|
|
25
|
-
//!
|
|
26
|
-
//! upgrader.upgrade(&target_contract, &new_wasm_hash);
|
|
27
|
-
//!
|
|
28
|
-
//! // Or upgrade and migrate in one transaction
|
|
29
|
-
//! let migration_data = vec![&env, val1, val2];
|
|
30
|
-
//! upgrader.upgrade_and_migrate(&target_contract, &new_wasm_hash, migration_data);
|
|
18
|
+
//! let migration_data = my_data.to_xdr(&env);
|
|
19
|
+
//! upgrader.upgrade_and_migrate(&target_contract, &new_wasm_hash, &migration_data);
|
|
31
20
|
//! ```
|
|
32
21
|
|
|
33
|
-
use soroban_sdk::{contract,
|
|
34
|
-
|
|
35
|
-
/// Symbol for the migrate function call
|
|
36
|
-
pub const MIGRATE: Symbol = symbol_short!("migrate");
|
|
37
|
-
|
|
38
|
-
/// Trait representing an upgradeable contract's interface
|
|
39
|
-
#[contractclient(name = "UpgradeableContractClient")]
|
|
40
|
-
pub trait UpgradeableContract {
|
|
41
|
-
/// Upgrades the contract to new WASM bytecode
|
|
42
|
-
fn upgrade(env: &Env, new_wasm_hash: BytesN<32>);
|
|
43
|
-
}
|
|
22
|
+
use soroban_sdk::{contract, contractimpl, xdr::ToXdr, Address, Bytes, BytesN, Env};
|
|
23
|
+
use utils::upgradeable::UpgradeableClient;
|
|
44
24
|
|
|
45
25
|
/// Upgrader contract for managing upgrades of other contracts.
|
|
46
26
|
///
|
|
@@ -51,46 +31,39 @@ pub struct Upgrader;
|
|
|
51
31
|
|
|
52
32
|
#[contractimpl]
|
|
53
33
|
impl Upgrader {
|
|
54
|
-
///
|
|
34
|
+
/// Upgrades a target contract without custom migration data.
|
|
35
|
+
///
|
|
36
|
+
/// This is a convenience wrapper that calls `upgrade_and_migrate` with empty migration data.
|
|
37
|
+
///
|
|
38
|
+
/// # Arguments
|
|
39
|
+
/// * `contract_address` - The address of the contract to upgrade
|
|
40
|
+
/// * `wasm_hash` - The hash of the new WASM bytecode
|
|
41
|
+
pub fn upgrade(env: &Env, contract_address: &Address, wasm_hash: &BytesN<32>) {
|
|
42
|
+
Self::upgrade_and_migrate(env, contract_address, wasm_hash, &().to_xdr(env));
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
/// Upgrades a target contract and runs its migration in a single transaction.
|
|
55
46
|
///
|
|
56
47
|
/// The caller must be authorized as the authorizer of the target contract.
|
|
57
48
|
/// This is enforced by the target contract's `#[only_auth]` check.
|
|
58
49
|
///
|
|
59
|
-
/// This is useful for atomic upgrades where you want to ensure the migration
|
|
60
|
-
/// happens immediately after the upgrade, or the entire operation fails.
|
|
61
|
-
///
|
|
62
50
|
/// # Arguments
|
|
63
51
|
/// * `contract_address` - The address of the contract to upgrade
|
|
64
52
|
/// * `wasm_hash` - The hash of the new WASM bytecode
|
|
65
|
-
/// * `migration_data` -
|
|
66
|
-
///
|
|
53
|
+
/// * `migration_data` - XDR-encoded bytes to pass to the migrate function.
|
|
54
|
+
/// Use `value.to_xdr(&env)` to encode the target contract's MigrationData type.
|
|
67
55
|
///
|
|
68
56
|
/// # Example
|
|
69
57
|
/// ```ignore
|
|
70
|
-
///
|
|
71
|
-
///
|
|
72
|
-
/// &env,
|
|
73
|
-
/// 42u32.into_val(&env),
|
|
74
|
-
/// true.into_val(&env),
|
|
75
|
-
/// ];
|
|
76
|
-
/// upgrader.upgrade_and_migrate(&contract_addr, &wasm_hash, migration_data);
|
|
58
|
+
/// let migration_data = my_data.to_xdr(&env);
|
|
59
|
+
/// upgrader.upgrade_and_migrate(&contract_addr, &wasm_hash, &migration_data);
|
|
77
60
|
/// ```
|
|
78
|
-
pub fn upgrade_and_migrate(
|
|
79
|
-
env
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
migration_data: Vec<soroban_sdk::Val>,
|
|
83
|
-
) {
|
|
84
|
-
let contract_client = UpgradeableContractClient::new(env, contract_address);
|
|
85
|
-
|
|
86
|
-
// First upgrade the contract
|
|
87
|
-
contract_client.upgrade(&wasm_hash);
|
|
88
|
-
|
|
89
|
-
// Then call migrate with the provided data
|
|
90
|
-
// We use invoke_contract because the migration data type is unknown to this contract
|
|
91
|
-
env.invoke_contract::<()>(contract_address, &MIGRATE, migration_data);
|
|
61
|
+
pub fn upgrade_and_migrate(env: &Env, contract_address: &Address, wasm_hash: &BytesN<32>, migration_data: &Bytes) {
|
|
62
|
+
let client = UpgradeableClient::new(env, contract_address);
|
|
63
|
+
client.upgrade(wasm_hash);
|
|
64
|
+
client.migrate(migration_data);
|
|
92
65
|
}
|
|
93
66
|
}
|
|
94
67
|
|
|
95
68
|
#[cfg(test)]
|
|
96
|
-
mod tests;
|
|
69
|
+
mod tests;
|
|
Binary file
|
|
Binary file
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
extern crate std;
|
|
2
2
|
|
|
3
|
-
use soroban_sdk::{contractclient, testutils::Address as _, Address, BytesN, Env
|
|
3
|
+
use soroban_sdk::{contractclient, testutils::Address as _, xdr::ToXdr, Address, BytesN, Env};
|
|
4
4
|
|
|
5
5
|
use crate::{Upgrader, UpgraderClient};
|
|
6
6
|
|
|
@@ -17,16 +17,20 @@ trait TestUpgradeableContract2 {
|
|
|
17
17
|
}
|
|
18
18
|
|
|
19
19
|
mod contract_v1 {
|
|
20
|
-
|
|
21
|
-
// #[upgradeable]
|
|
22
|
-
// #[ownable]
|
|
23
|
-
// pub struct TestUpgradeableContract;
|
|
20
|
+
//#![no_std]
|
|
24
21
|
|
|
25
|
-
//
|
|
26
|
-
//
|
|
22
|
+
// use soroban_sdk::{contractimpl, Env, Symbol, Address, contractclient};
|
|
23
|
+
// use utils::{ upgradeable::UpgradeableInternal};
|
|
24
|
+
// use common_macros::lz_contract;
|
|
27
25
|
|
|
28
|
-
//
|
|
29
|
-
//
|
|
26
|
+
// #[lz_contract(upgradeable)]
|
|
27
|
+
// pub struct DummyContract;
|
|
28
|
+
|
|
29
|
+
// impl UpgradeableInternal for DummyContract {
|
|
30
|
+
// type MigrationData = u32;
|
|
31
|
+
|
|
32
|
+
// fn __migrate(env: &Env, migration_data: &Self::MigrationData) {
|
|
33
|
+
// env.storage().instance().set(&Symbol::new(env, "counter2"), migration_data);
|
|
30
34
|
// }
|
|
31
35
|
// }
|
|
32
36
|
|
|
@@ -35,34 +39,37 @@ mod contract_v1 {
|
|
|
35
39
|
// fn counter(env: &Env) -> u32;
|
|
36
40
|
// }
|
|
37
41
|
|
|
38
|
-
// #[
|
|
39
|
-
// impl TestUpgradeable for
|
|
42
|
+
// #[contractimpl]
|
|
43
|
+
// impl TestUpgradeable for DummyContract {
|
|
40
44
|
// fn counter(env: &Env) -> u32 {
|
|
41
45
|
// env.storage().instance().get(&Symbol::new(env, "counter")).unwrap_or(0)
|
|
42
46
|
// }
|
|
43
47
|
// }
|
|
44
48
|
|
|
45
|
-
// #[
|
|
46
|
-
// impl
|
|
49
|
+
// #[contractimpl]
|
|
50
|
+
// impl DummyContract {
|
|
47
51
|
// pub fn __constructor(env: &Env, owner: &Address) {
|
|
48
52
|
// Self::init_owner(env, owner);
|
|
49
53
|
// env.storage().instance().set(&Symbol::new(env, "counter"), &1_u32);
|
|
50
54
|
// }
|
|
51
55
|
// }
|
|
52
|
-
use super::MigrationData;
|
|
53
56
|
soroban_sdk::contractimport!(file = "./src/tests/test_data/test_upgradeable_contract1.wasm");
|
|
54
57
|
}
|
|
55
58
|
mod contract_v2 {
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
//
|
|
59
|
-
//
|
|
59
|
+
//#![no_std]
|
|
60
|
+
|
|
61
|
+
// use soroban_sdk::{contractimpl, Env, Symbol, Address, contractclient};
|
|
62
|
+
// use utils::{ upgradeable::UpgradeableInternal};
|
|
63
|
+
// use common_macros::lz_contract;
|
|
64
|
+
|
|
65
|
+
// #[lz_contract(upgradeable)]
|
|
66
|
+
// pub struct DummyContract;
|
|
60
67
|
|
|
61
|
-
// impl UpgradeableInternal for
|
|
62
|
-
// type MigrationData =
|
|
68
|
+
// impl UpgradeableInternal for DummyContract {
|
|
69
|
+
// type MigrationData = u32;
|
|
63
70
|
|
|
64
|
-
// fn
|
|
65
|
-
// env.storage().instance().set(&Symbol::new(env, "counter2"),
|
|
71
|
+
// fn __migrate(env: &Env, migration_data: &Self::MigrationData) {
|
|
72
|
+
// env.storage().instance().set(&Symbol::new(env, "counter2"), migration_data);
|
|
66
73
|
// }
|
|
67
74
|
// }
|
|
68
75
|
|
|
@@ -72,8 +79,8 @@ mod contract_v2 {
|
|
|
72
79
|
// fn counter2(env: &Env) -> u32;
|
|
73
80
|
// }
|
|
74
81
|
|
|
75
|
-
// #[
|
|
76
|
-
// impl TestUpgradeable for
|
|
82
|
+
// #[contractimpl]
|
|
83
|
+
// impl TestUpgradeable for DummyContract {
|
|
77
84
|
// fn counter(env: &Env) -> u32 {
|
|
78
85
|
// env.storage().instance().get(&Symbol::new(env, "counter")).unwrap_or(0)
|
|
79
86
|
// }
|
|
@@ -82,7 +89,14 @@ mod contract_v2 {
|
|
|
82
89
|
// env.storage().instance().get(&Symbol::new(env, "counter2")).unwrap_or(0)
|
|
83
90
|
// }
|
|
84
91
|
// }
|
|
85
|
-
|
|
92
|
+
|
|
93
|
+
// #[contractimpl]
|
|
94
|
+
// impl DummyContract {
|
|
95
|
+
// pub fn __constructor(env: &Env, owner: &Address) {
|
|
96
|
+
// Self::init_owner(env, owner);
|
|
97
|
+
// env.storage().instance().set(&Symbol::new(env, "counter"), &1_u32);
|
|
98
|
+
// }
|
|
99
|
+
// }
|
|
86
100
|
soroban_sdk::contractimport!(file = "./src/tests/test_data/test_upgradeable_contract2.wasm");
|
|
87
101
|
}
|
|
88
102
|
|
|
@@ -90,9 +104,6 @@ fn install_new_wasm(e: &Env) -> BytesN<32> {
|
|
|
90
104
|
e.deployer().upload_contract_wasm(contract_v2::WASM)
|
|
91
105
|
}
|
|
92
106
|
|
|
93
|
-
#[allow(dead_code)]
|
|
94
|
-
type MigrationData = ();
|
|
95
|
-
|
|
96
107
|
#[test]
|
|
97
108
|
fn test_upgrade_with_upgrader() {
|
|
98
109
|
let e = Env::default();
|
|
@@ -107,14 +118,12 @@ fn test_upgrade_with_upgrader() {
|
|
|
107
118
|
let upgrader_client = UpgraderClient::new(&e, &upgrader);
|
|
108
119
|
|
|
109
120
|
let new_wasm_hash = install_new_wasm(&e);
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
&soroban_sdk::vec![&e, ().try_into_val(&e).unwrap()],
|
|
115
|
-
);
|
|
121
|
+
let counter_value = 2_u32;
|
|
122
|
+
// Encode migration data as XDR bytes
|
|
123
|
+
let migration_data = counter_value.to_xdr(&e);
|
|
124
|
+
upgrader_client.upgrade_and_migrate(&contract_id, &new_wasm_hash, &migration_data);
|
|
116
125
|
|
|
117
126
|
let client_v2 = TestUpgradeableContractClient2::new(&e, &contract_id);
|
|
118
127
|
|
|
119
|
-
assert_eq!(client_v2.counter2(),
|
|
128
|
+
assert_eq!(client_v2.counter2(), counter_value);
|
|
120
129
|
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
use common_macros::contract_error;
|
|
2
2
|
|
|
3
3
|
// Utils library error codes: 1000-1099
|
|
4
|
-
// See
|
|
4
|
+
// See docs/error-spec.md for allocation rules
|
|
5
5
|
|
|
6
6
|
/// BufferReaderError: 1000-1009
|
|
7
7
|
#[contract_error]
|
|
@@ -44,7 +44,9 @@ pub enum BytesExtError {
|
|
|
44
44
|
/// UpgradeableError: 1050-1059
|
|
45
45
|
#[contract_error]
|
|
46
46
|
pub enum UpgradeableError {
|
|
47
|
-
|
|
47
|
+
InvalidMigrationData = 1050,
|
|
48
|
+
MigrationNotAllowed,
|
|
49
|
+
UpgradesFrozen,
|
|
48
50
|
}
|
|
49
51
|
|
|
50
52
|
/// MultisigError: 1060-1069
|
|
@@ -58,7 +58,7 @@ pub trait Multisig: Auth {
|
|
|
58
58
|
// ===========================================================================
|
|
59
59
|
|
|
60
60
|
/// Adds or removes a signer from the multisig. Requires owner authorization.
|
|
61
|
-
fn set_signer(env: &Env, signer: &BytesN<20>, active: bool) {
|
|
61
|
+
fn set_signer(env: &soroban_sdk::Env, signer: &soroban_sdk::BytesN<20>, active: bool) {
|
|
62
62
|
auth::require_auth::<Self>(env);
|
|
63
63
|
match active {
|
|
64
64
|
true => add_signer(env, signer),
|
|
@@ -67,7 +67,7 @@ pub trait Multisig: Auth {
|
|
|
67
67
|
}
|
|
68
68
|
|
|
69
69
|
/// Sets the signature threshold (quorum). Requires owner authorization.
|
|
70
|
-
fn set_threshold(env: &Env, threshold: u32) {
|
|
70
|
+
fn set_threshold(env: &soroban_sdk::Env, threshold: u32) {
|
|
71
71
|
auth::require_auth::<Self>(env);
|
|
72
72
|
set_threshold(env, threshold);
|
|
73
73
|
}
|
|
@@ -77,22 +77,22 @@ pub trait Multisig: Auth {
|
|
|
77
77
|
// ===========================================================================
|
|
78
78
|
|
|
79
79
|
/// Returns all registered signers.
|
|
80
|
-
fn get_signers(env: &Env) -> Vec<BytesN<20>> {
|
|
80
|
+
fn get_signers(env: &soroban_sdk::Env) -> soroban_sdk::Vec<soroban_sdk::BytesN<20>> {
|
|
81
81
|
MultisigStorage::signers(env)
|
|
82
82
|
}
|
|
83
83
|
|
|
84
84
|
/// Returns the total number of registered signers.
|
|
85
|
-
fn total_signers(env: &Env) -> u32 {
|
|
85
|
+
fn total_signers(env: &soroban_sdk::Env) -> u32 {
|
|
86
86
|
MultisigStorage::signers(env).len()
|
|
87
87
|
}
|
|
88
88
|
|
|
89
89
|
/// Checks if an address is a registered signer.
|
|
90
|
-
fn is_signer(env: &Env, signer: &BytesN<20>) -> bool {
|
|
90
|
+
fn is_signer(env: &soroban_sdk::Env, signer: &soroban_sdk::BytesN<20>) -> bool {
|
|
91
91
|
MultisigStorage::signers(env).iter().any(|s| &s == signer)
|
|
92
92
|
}
|
|
93
93
|
|
|
94
94
|
/// Returns the current signature threshold (quorum).
|
|
95
|
-
fn threshold(env: &Env) -> u32 {
|
|
95
|
+
fn threshold(env: &soroban_sdk::Env) -> u32 {
|
|
96
96
|
MultisigStorage::threshold(env)
|
|
97
97
|
}
|
|
98
98
|
|
|
@@ -101,12 +101,21 @@ pub trait Multisig: Auth {
|
|
|
101
101
|
// ===========================================================================
|
|
102
102
|
|
|
103
103
|
/// Verifies signatures against the configured threshold.
|
|
104
|
-
fn verify_signatures(
|
|
104
|
+
fn verify_signatures(
|
|
105
|
+
env: &soroban_sdk::Env,
|
|
106
|
+
digest: &soroban_sdk::BytesN<32>,
|
|
107
|
+
signatures: &soroban_sdk::Vec<soroban_sdk::BytesN<65>>,
|
|
108
|
+
) {
|
|
105
109
|
Self::verify_n_signatures(env, digest, signatures, MultisigStorage::threshold(env));
|
|
106
110
|
}
|
|
107
111
|
|
|
108
112
|
/// Verifies signatures against a custom threshold.
|
|
109
|
-
fn verify_n_signatures(
|
|
113
|
+
fn verify_n_signatures(
|
|
114
|
+
env: &soroban_sdk::Env,
|
|
115
|
+
digest: &soroban_sdk::BytesN<32>,
|
|
116
|
+
signatures: &soroban_sdk::Vec<soroban_sdk::BytesN<65>>,
|
|
117
|
+
threshold: u32,
|
|
118
|
+
) {
|
|
110
119
|
assert_with_error!(env, threshold > 0, MultisigError::ZeroThreshold);
|
|
111
120
|
assert_with_error!(env, signatures.len() >= threshold, MultisigError::SignatureError);
|
|
112
121
|
|
|
@@ -64,12 +64,12 @@ pub trait Ownable: Sized + Auth {
|
|
|
64
64
|
// ===========================================================================
|
|
65
65
|
|
|
66
66
|
/// Returns the current owner address, or None if no owner is set.
|
|
67
|
-
fn owner(env: &Env) -> Option<Address> {
|
|
67
|
+
fn owner(env: &soroban_sdk::Env) -> Option<soroban_sdk::Address> {
|
|
68
68
|
OwnableStorage::owner(env)
|
|
69
69
|
}
|
|
70
70
|
|
|
71
71
|
/// Returns the pending owner address for 2-step transfer, or None if no transfer is pending.
|
|
72
|
-
fn pending_owner(env: &Env) -> Option<Address> {
|
|
72
|
+
fn pending_owner(env: &soroban_sdk::Env) -> Option<soroban_sdk::Address> {
|
|
73
73
|
OwnableStorage::pending_owner(env)
|
|
74
74
|
}
|
|
75
75
|
|
|
@@ -85,7 +85,7 @@ pub trait Ownable: Sized + Auth {
|
|
|
85
85
|
/// # Panics
|
|
86
86
|
/// - `OwnerNotSet` if no owner is currently set
|
|
87
87
|
/// - `TransferInProgress` if a 2-step transfer is in progress
|
|
88
|
-
fn transfer_ownership(env: &Env, new_owner: &Address) {
|
|
88
|
+
fn transfer_ownership(env: &soroban_sdk::Env, new_owner: &soroban_sdk::Address) {
|
|
89
89
|
let old_owner = enforce_owner_auth::<Self>(env);
|
|
90
90
|
assert_no_pending_transfer::<Self>(env);
|
|
91
91
|
|
|
@@ -112,7 +112,7 @@ pub trait Ownable: Sized + Auth {
|
|
|
112
112
|
/// - `NoPendingTransfer` when cancelling and no pending transfer exists
|
|
113
113
|
/// - `InvalidTtl` if ttl exceeds max TTL
|
|
114
114
|
/// - `InvalidPendingOwner` when cancelling with wrong new_owner address
|
|
115
|
-
fn propose_ownership_transfer(env: &Env, new_owner: &Address, ttl: u32) {
|
|
115
|
+
fn propose_ownership_transfer(env: &soroban_sdk::Env, new_owner: &soroban_sdk::Address, ttl: u32) {
|
|
116
116
|
let old_owner = enforce_owner_auth::<Self>(env);
|
|
117
117
|
|
|
118
118
|
// Cancel case: ttl == 0
|
|
@@ -142,7 +142,7 @@ pub trait Ownable: Sized + Auth {
|
|
|
142
142
|
///
|
|
143
143
|
/// # Panics
|
|
144
144
|
/// - `NoPendingTransfer` if there is no pending transfer (or it expired)
|
|
145
|
-
fn accept_ownership(env: &Env) {
|
|
145
|
+
fn accept_ownership(env: &soroban_sdk::Env) {
|
|
146
146
|
let new_owner = Self::pending_owner(env).unwrap_or_panic(env, OwnableError::NoPendingTransfer);
|
|
147
147
|
|
|
148
148
|
// Require authorization from the pending owner
|
|
@@ -169,7 +169,7 @@ pub trait Ownable: Sized + Auth {
|
|
|
169
169
|
/// # Panics
|
|
170
170
|
/// - `OwnerNotSet` if no owner is currently set
|
|
171
171
|
/// - `TransferInProgress` if a 2-step transfer is in progress (cancel it first)
|
|
172
|
-
fn renounce_ownership(env: &Env) {
|
|
172
|
+
fn renounce_ownership(env: &soroban_sdk::Env) {
|
|
173
173
|
let old_owner = enforce_owner_auth::<Self>(env);
|
|
174
174
|
assert_no_pending_transfer::<Self>(env);
|
|
175
175
|
|
|
@@ -1,26 +1,76 @@
|
|
|
1
|
-
use soroban_sdk::{testutils::Events, xdr
|
|
1
|
+
use soroban_sdk::{testutils::Events, xdr, Address, Env, Event, TryFromVal, Val, Vec};
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
3
|
+
/// Decodes a raw emitted contract event (XDR) into `(topics, data)`.
|
|
4
|
+
///
|
|
5
|
+
/// Soroban testutils exposes events as [`ContractEvents`](soroban_sdk::testutils::ContractEvents),
|
|
6
|
+
/// which internally stores XDR [`ContractEvent`](soroban_sdk::xdr::ContractEvent) values.
|
|
7
|
+
/// This helper converts the XDR topics/data into `soroban_sdk::Val` so tests can inspect
|
|
8
|
+
/// topics and data using normal Soroban conversions (`TryFromVal` / `IntoVal`).
|
|
9
|
+
///
|
|
10
|
+
/// Returns `None` if any topic or the data payload can't be converted into `Val` for the
|
|
11
|
+
/// provided `Env`.
|
|
12
|
+
///
|
|
13
|
+
/// # Example
|
|
14
|
+
/// ```ignore
|
|
15
|
+
/// let events = env.events().all().filter_by_contract(&contract);
|
|
16
|
+
/// for ev in events.events().iter() {
|
|
17
|
+
/// let (topics, data) = utils::testing_utils::decode_event_topics_data(&env, ev).unwrap();
|
|
18
|
+
/// // ... inspect topics/data ...
|
|
19
|
+
/// }
|
|
20
|
+
/// ```
|
|
21
|
+
pub fn decode_event_topics_data(env: &Env, event: &xdr::ContractEvent) -> Option<(Vec<Val>, Val)> {
|
|
22
|
+
// In the current Soroban SDK version this is always `V0`.
|
|
23
|
+
// Using a single-variant match avoids "irrefutable let-else" warnings.
|
|
24
|
+
let v0 = match &event.body {
|
|
25
|
+
xdr::ContractEventBody::V0(v0) => v0,
|
|
26
|
+
};
|
|
27
|
+
|
|
28
|
+
let mut topics = Vec::<Val>::new(env);
|
|
29
|
+
for t in v0.topics.iter() {
|
|
30
|
+
topics.push_back(Val::try_from_val(env, t).ok()?);
|
|
14
31
|
}
|
|
15
|
-
|
|
32
|
+
let data = Val::try_from_val(env, &v0.data).ok()?;
|
|
33
|
+
Some((topics, data))
|
|
16
34
|
}
|
|
17
35
|
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
36
|
+
/// Asserts that the environment emitted exactly one event: `expected`.
|
|
37
|
+
///
|
|
38
|
+
/// This is a **strict equality** assertion over `env.events().all()`:
|
|
39
|
+
/// the full event list must be exactly `[expected]` (no extra events).
|
|
40
|
+
///
|
|
41
|
+
/// Uses the event struct's `.topics()` and `.data()` methods (generated by `#[contractevent]`)
|
|
42
|
+
/// to compare against emitted events. No more hardcoding topic names or field keys!
|
|
43
|
+
///
|
|
44
|
+
/// # Example
|
|
45
|
+
/// ```ignore
|
|
46
|
+
/// use crate::events::OwnershipTransferred;
|
|
47
|
+
///
|
|
48
|
+
/// let expected = OwnershipTransferred {
|
|
49
|
+
/// previous_owner: owner.clone(),
|
|
50
|
+
/// new_owner: new_owner.clone(),
|
|
51
|
+
/// };
|
|
52
|
+
/// assert_eq_event(&env, &contract, expected);
|
|
53
|
+
/// ```
|
|
54
|
+
pub fn assert_eq_event<E: Event>(env: &Env, contract: &Address, expected: E) {
|
|
55
|
+
// Compare against the emitted `xdr::ContractEvent` directly. This avoids the
|
|
56
|
+
// `xdr -> Val` roundtrip and ensures we match exactly what was emitted.
|
|
57
|
+
//
|
|
58
|
+
// IMPORTANT: This asserts *equality* (not "contains").
|
|
59
|
+
extern crate std;
|
|
60
|
+
|
|
61
|
+
assert_eq!(
|
|
62
|
+
env.events().all(),
|
|
63
|
+
std::vec![expected.to_xdr(env, contract)],
|
|
64
|
+
"Expected exactly one event. Expected topics: {:?}, data: {:?}",
|
|
65
|
+
expected.topics(env),
|
|
66
|
+
expected.data(env),
|
|
67
|
+
);
|
|
21
68
|
}
|
|
22
69
|
|
|
23
|
-
/// Asserts that
|
|
70
|
+
/// Asserts that the contract emitted an event equal to `expected`.
|
|
71
|
+
///
|
|
72
|
+
/// This is a **contains** assertion: after filtering events by `contract`,
|
|
73
|
+
/// `expected` must appear at least once (order doesn't matter; extra events allowed).
|
|
24
74
|
///
|
|
25
75
|
/// Uses the event struct's `.topics()` and `.data()` methods (generated by `#[contractevent]`)
|
|
26
76
|
/// to compare against emitted events. No more hardcoding topic names or field keys!
|
|
@@ -33,68 +83,86 @@ fn data_eq(env: &Env, a: &Val, b: &Val) -> bool {
|
|
|
33
83
|
/// previous_owner: owner.clone(),
|
|
34
84
|
/// new_owner: new_owner.clone(),
|
|
35
85
|
/// };
|
|
36
|
-
///
|
|
86
|
+
/// assert_eq_event(&env, &contract, expected);
|
|
37
87
|
/// ```
|
|
38
|
-
pub fn
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
let
|
|
88
|
+
pub fn assert_contains_event<E: Event>(env: &Env, contract: &Address, expected: E) {
|
|
89
|
+
// Compare against the emitted `xdr::ContractEvent` directly. This avoids the
|
|
90
|
+
// `xdr -> Val` roundtrip and ensures we match exactly what was emitted.
|
|
91
|
+
let expected_xdr = expected.to_xdr(env, contract);
|
|
42
92
|
|
|
93
|
+
let events = env.events().all().filter_by_contract(contract);
|
|
43
94
|
let mut found = false;
|
|
44
|
-
for
|
|
45
|
-
if
|
|
95
|
+
for event in events.events().iter() {
|
|
96
|
+
if *event == expected_xdr {
|
|
46
97
|
found = true;
|
|
47
98
|
break;
|
|
48
99
|
}
|
|
49
100
|
}
|
|
50
101
|
|
|
51
|
-
assert!(
|
|
102
|
+
assert!(
|
|
103
|
+
found,
|
|
104
|
+
"Expected event not found. Expected topics: {:?}, data: {:?}",
|
|
105
|
+
expected.topics(env),
|
|
106
|
+
expected.data(env)
|
|
107
|
+
);
|
|
52
108
|
}
|
|
53
109
|
|
|
54
|
-
///
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
110
|
+
/// Asserts that the environment emitted events that match `expected_events` exactly.
|
|
111
|
+
///
|
|
112
|
+
/// This is a **strict equality** assertion over `env.events().all()`:
|
|
113
|
+
/// the full event list must match `expected_events` **in order** and **count**
|
|
114
|
+
/// (no missing/extra events).
|
|
115
|
+
///
|
|
116
|
+
/// # Example
|
|
117
|
+
/// ```ignore
|
|
118
|
+
/// assert_eq_events(env, &contract, &[
|
|
119
|
+
/// &Event1 { ... },
|
|
120
|
+
/// &Event2 { ... },
|
|
121
|
+
/// ]);
|
|
122
|
+
/// ```
|
|
59
123
|
|
|
60
|
-
pub
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
124
|
+
pub fn assert_eq_events(env: &Env, contract: &Address, expected_events: &[&dyn Event]) {
|
|
125
|
+
// Note: this module is only compiled for tests / testutils usage, where `std` is available.
|
|
126
|
+
extern crate std;
|
|
127
|
+
let expected_xdrs: std::vec::Vec<xdr::ContractEvent> =
|
|
128
|
+
expected_events.iter().map(|e| e.to_xdr(env, contract)).collect();
|
|
65
129
|
|
|
66
|
-
|
|
67
|
-
|
|
130
|
+
assert_eq!(env.events().all(), expected_xdrs, "Expected events to match exactly");
|
|
131
|
+
}
|
|
68
132
|
|
|
69
|
-
/// Asserts that all
|
|
70
|
-
///
|
|
133
|
+
/// Asserts that all `expected_events` were emitted by the contract (in any order).
|
|
134
|
+
///
|
|
135
|
+
/// This is a **contains** assertion with multiset semantics: after filtering events by
|
|
136
|
+
/// `contract`, every expected event must be present, and duplicates in `expected_events`
|
|
137
|
+
/// require duplicate emissions. Extra emitted events are allowed.
|
|
71
138
|
///
|
|
72
139
|
/// # Example
|
|
73
140
|
/// ```ignore
|
|
74
|
-
///
|
|
75
|
-
///
|
|
76
|
-
///
|
|
77
|
-
/// Event1 { ... }.expected(env),
|
|
78
|
-
/// Event2 { ... }.expected(env),
|
|
141
|
+
/// assert_eq_events(env, &contract, &[
|
|
142
|
+
/// &Event1 { ... },
|
|
143
|
+
/// &Event2 { ... },
|
|
79
144
|
/// ]);
|
|
80
145
|
/// ```
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
// Track which emitted events have already been matched so that duplicate expectations
|
|
84
|
-
// require duplicate emissions (multiset semantics).
|
|
85
|
-
//
|
|
146
|
+
|
|
147
|
+
pub fn assert_contains_events(env: &Env, contract: &Address, expected_events: &[&dyn Event]) {
|
|
86
148
|
// Note: this module is only compiled for tests / testutils usage, where `std` is available.
|
|
87
149
|
extern crate std;
|
|
88
|
-
let
|
|
150
|
+
let events = env.events().all().filter_by_contract(contract);
|
|
151
|
+
let raw_events = events.events();
|
|
152
|
+
// Track which emitted events have already been matched so that duplicate expectations
|
|
153
|
+
// require duplicate emissions (multiset semantics).
|
|
154
|
+
// We use a `std::vec::Vec<bool>` as a "used" mask to implement multiset matching.
|
|
155
|
+
let mut used: std::vec::Vec<bool> = std::vec![false; raw_events.len()];
|
|
89
156
|
|
|
90
157
|
for (i, expected) in expected_events.iter().enumerate() {
|
|
158
|
+
let expected_xdr = expected.to_xdr(env, contract);
|
|
159
|
+
|
|
91
160
|
let mut found = false;
|
|
92
|
-
for (idx,
|
|
161
|
+
for (idx, event) in raw_events.iter().enumerate() {
|
|
93
162
|
if used[idx] {
|
|
94
163
|
continue;
|
|
95
164
|
}
|
|
96
|
-
if
|
|
97
|
-
{
|
|
165
|
+
if *event == expected_xdr {
|
|
98
166
|
used[idx] = true;
|
|
99
167
|
found = true;
|
|
100
168
|
break;
|
|
@@ -104,7 +172,9 @@ pub fn assert_events(env: &Env, contract: &Address, expected_events: &[ExpectedE
|
|
|
104
172
|
assert!(
|
|
105
173
|
found,
|
|
106
174
|
"Expected event #{} not found. Expected topics: {:?}, data: {:?}",
|
|
107
|
-
i,
|
|
175
|
+
i,
|
|
176
|
+
expected.topics(env),
|
|
177
|
+
expected.data(env)
|
|
108
178
|
);
|
|
109
179
|
}
|
|
110
180
|
}
|