@layerzerolabs/protocol-stellar-v2 0.2.15 → 0.2.19
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 +365 -297
- package/.turbo/turbo-lint.log +142 -110
- package/.turbo/turbo-test.log +1273 -1222
- package/Cargo.lock +20 -5
- package/Cargo.toml +4 -1
- package/contracts/ERROR_SPEC.md +44 -0
- package/contracts/common-macros/src/auth.rs +113 -0
- package/contracts/common-macros/src/contract_ttl.rs +84 -0
- package/contracts/common-macros/src/lib.rs +181 -30
- package/contracts/common-macros/src/lz_contract.rs +83 -0
- package/contracts/common-macros/src/tests/{ownable.rs → auth.rs} +48 -15
- package/contracts/common-macros/src/tests/contract_ttl.rs +662 -0
- package/contracts/common-macros/src/tests/mod.rs +2 -2
- package/contracts/common-macros/src/tests/snapshots/common_macros__tests__auth__snapshot_generated_multisig_code.snap +20 -0
- package/contracts/common-macros/src/tests/snapshots/common_macros__tests__auth__snapshot_generated_ownable_code.snap +24 -0
- package/contracts/common-macros/src/tests/snapshots/{common_macros__tests__ownable__snapshot_only_owner_preserves_function_signature.snap → common_macros__tests__auth__snapshot_only_auth_preserves_function_signature.snap} +4 -4
- package/contracts/common-macros/src/tests/snapshots/{common_macros__tests__contract_impl__snapshot_generated_contract_impl_code.snap → common_macros__tests__contract_ttl__snapshot_generated_contractimpl_code.snap} +3 -3
- package/contracts/common-macros/src/tests/snapshots/common_macros__tests__contract_ttl__snapshot_generated_contracttrait_code.snap +69 -0
- package/contracts/common-macros/src/tests/snapshots/common_macros__tests__ttl_configurable__snapshot_generated_ttl_configurable_code.snap +7 -21
- package/contracts/common-macros/src/tests/snapshots/common_macros__tests__upgradeable__snapshot_generated_upgradeable_code.snap +2 -2
- package/contracts/common-macros/src/ttl_configurable.rs +19 -34
- package/contracts/common-macros/src/ttl_extendable.rs +36 -0
- package/contracts/common-macros/src/upgradeable.rs +5 -5
- package/contracts/common-macros/src/utils.rs +9 -0
- package/contracts/endpoint-v2/src/constants.rs +4 -4
- package/contracts/endpoint-v2/src/endpoint_v2.rs +38 -40
- package/contracts/endpoint-v2/src/errors.rs +4 -3
- package/contracts/endpoint-v2/src/events.rs +1 -1
- package/contracts/endpoint-v2/src/message_lib_manager.rs +18 -5
- package/contracts/endpoint-v2/src/messaging_channel.rs +11 -1
- package/contracts/endpoint-v2/src/messaging_composer.rs +11 -1
- package/contracts/endpoint-v2/src/storage.rs +1 -1
- package/contracts/endpoint-v2/src/tests/endpoint_v2/pay_messaging_fees.rs +3 -3
- package/contracts/endpoint-v2/src/tests/endpoint_v2/quote.rs +1 -1
- package/contracts/endpoint-v2/src/tests/endpoint_v2/require_oapp_auth.rs +2 -2
- package/contracts/endpoint-v2/src/tests/endpoint_v2/send.rs +3 -3
- package/contracts/endpoint-v2/src/tests/endpoint_v2/set_zro.rs +4 -4
- package/contracts/endpoint-v2/src/tests/message_lib_manager/require_receive_lib_for_eid.rs +3 -3
- package/contracts/endpoint-v2/src/tests/message_lib_manager/require_registered.rs +1 -1
- package/contracts/endpoint-v2/src/tests/message_lib_manager/require_send_lib_for_eid.rs +3 -3
- package/contracts/endpoint-v2/src/tests/message_lib_manager/require_supported_eid.rs +1 -1
- package/contracts/endpoint-v2/src/tests/messaging_channel/clear_payload.rs +4 -4
- package/contracts/endpoint-v2/src/tests/messaging_channel/inbound.rs +1 -1
- package/contracts/layerzero-views/src/layerzero_view.rs +3 -6
- package/contracts/macro-integration-tests/tests/runtime/ownable/mod.rs +2 -2
- package/contracts/macro-integration-tests/tests/runtime/ownable/{only_owner_guard.rs → only_auth_guard.rs} +1 -1
- package/contracts/macro-integration-tests/tests/runtime/ttl_configurable/configuration.rs +1 -1
- package/contracts/macro-integration-tests/tests/runtime/ttl_configurable/freeze.rs +1 -1
- package/contracts/macro-integration-tests/tests/runtime/ttl_configurable/mod.rs +0 -1
- package/contracts/macro-integration-tests/tests/ui/ownable/fail/{only_owner_missing_env.rs → only_auth_missing_env.rs} +3 -3
- package/contracts/macro-integration-tests/tests/ui/ownable/fail/{only_owner_missing_env.stderr → only_auth_missing_env.stderr} +4 -4
- package/contracts/macro-integration-tests/tests/ui/ownable/pass/namespacing_and_imports.rs +2 -3
- package/contracts/macro-integration-tests/tests/ui/ownable/pass/{only_owner_env_param_variants.rs → only_auth_env_param_variants.rs} +9 -9
- package/contracts/macro-integration-tests/tests/ui/ttl_configurable/pass/minimal_contract.rs +6 -6
- package/contracts/message-libs/message-lib-common/src/errors.rs +7 -2
- package/contracts/message-libs/message-lib-common/src/tests/packet_codec_v1/decode_packet_header.rs +3 -3
- package/contracts/message-libs/message-lib-common/src/tests/worker_options/append_lz_receive_option.rs +1 -2
- package/contracts/message-libs/message-lib-common/src/tests/worker_options/append_native_drop_option.rs +1 -2
- package/contracts/message-libs/message-lib-common/src/tests/worker_options/convert_legacy_options.rs +9 -9
- package/contracts/message-libs/message-lib-common/src/tests/worker_options/extract_type_3_options.rs +1 -1
- package/contracts/message-libs/message-lib-common/src/tests/worker_options/left_pad_to_bytes32.rs +1 -1
- package/contracts/message-libs/message-lib-common/src/tests/worker_options/split_worker_options.rs +2 -2
- package/contracts/message-libs/simple-message-lib/src/simple_message_lib.rs +7 -9
- package/contracts/message-libs/treasury/src/errors.rs +2 -2
- package/contracts/message-libs/treasury/src/events.rs +1 -1
- package/contracts/message-libs/treasury/src/interfaces/zro_fee_lib.rs +2 -2
- package/contracts/message-libs/treasury/src/storage.rs +1 -1
- package/contracts/message-libs/treasury/src/tests/treasury_tests.rs +1 -1
- package/contracts/message-libs/treasury/src/treasury.rs +14 -16
- package/contracts/message-libs/uln-302/src/receive_uln.rs +13 -2
- package/contracts/message-libs/uln-302/src/send_uln.rs +24 -4
- package/contracts/message-libs/uln-302/src/uln302.rs +6 -24
- package/contracts/oapps/counter/Cargo.toml +14 -1
- package/contracts/oapps/counter/integration_tests/mod.rs +4 -1
- package/contracts/oapps/counter/integration_tests/{setup.rs → setup_sml.rs} +48 -80
- package/contracts/oapps/counter/integration_tests/setup_uln.rs +997 -0
- package/contracts/oapps/counter/integration_tests/signing.rs +62 -0
- package/contracts/oapps/counter/integration_tests/test_with_sml.rs +24 -55
- package/contracts/oapps/counter/integration_tests/test_with_uln.rs +314 -0
- package/contracts/oapps/counter/integration_tests/utils.rs +196 -53
- package/contracts/oapps/counter/src/counter.rs +67 -43
- package/contracts/oapps/counter/src/tests/mod.rs +0 -13
- package/contracts/oapps/counter/src/tests/test_counter.rs +5 -7
- package/contracts/oapps/oapp/src/errors.rs +5 -1
- package/contracts/oapps/oapp/src/macro_tests/test_macros.rs +93 -78
- package/contracts/oapps/oapp/src/oapp_core.rs +36 -21
- package/contracts/oapps/oapp/src/oapp_options_type3.rs +48 -12
- package/contracts/oapps/oapp/src/oapp_receiver.rs +106 -41
- package/contracts/oapps/oapp/src/oapp_sender.rs +26 -34
- package/contracts/oapps/oapp/src/tests/test_oapp_core.rs +9 -8
- package/contracts/oapps/oapp/src/tests/test_oapp_options_type3.rs +25 -17
- package/contracts/oapps/oapp/src/tests/test_oapp_receiver.rs +7 -7
- package/contracts/oapps/oapp/src/tests/test_oapp_sender.rs +14 -15
- package/contracts/oapps/oapp-macros/src/generators.rs +128 -0
- package/contracts/oapps/oapp-macros/src/lib.rs +113 -56
- package/contracts/oapps/oft/Cargo.toml +10 -7
- package/contracts/oapps/{oft-std → oft}/integration-tests/extensions/test_oft_fee.rs +3 -4
- package/contracts/oapps/{oft-std → oft}/integration-tests/extensions/test_pausable.rs +2 -3
- package/contracts/oapps/{oft-std → oft}/integration-tests/extensions/test_rate_limiter.rs +1 -1
- package/contracts/oapps/oft/integration-tests/mod.rs +1 -1
- package/contracts/oapps/oft/integration-tests/setup.rs +29 -110
- package/contracts/oapps/oft/integration-tests/utils.rs +254 -21
- package/contracts/oapps/oft/src/extensions/oft_fee.rs +13 -14
- package/contracts/oapps/oft/src/extensions/pausable.rs +4 -4
- package/contracts/oapps/oft/src/extensions/rate_limiter.rs +5 -5
- package/contracts/oapps/oft/src/lib.rs +11 -13
- package/contracts/oapps/oft/src/oft.rs +147 -225
- package/contracts/oapps/oft/src/oft_types/lock_unlock.rs +9 -13
- package/contracts/oapps/oft/src/oft_types/mint_burn.rs +31 -14
- package/contracts/oapps/oft/src/oft_types/mod.rs +13 -0
- package/contracts/oapps/{oft-std → oft-core}/Cargo.toml +6 -4
- package/contracts/oapps/{oft-std → oft-core}/integration-tests/mod.rs +1 -1
- package/contracts/oapps/{oft-std → oft-core}/integration-tests/setup.rs +129 -30
- package/contracts/oapps/{oft → oft-core}/integration-tests/test_with_sml.rs +3 -3
- package/contracts/oapps/oft-core/integration-tests/utils.rs +201 -0
- package/contracts/oapps/oft-core/src/errors.rs +13 -0
- package/contracts/oapps/oft-core/src/lib.rs +18 -0
- package/contracts/oapps/oft-core/src/oft_core.rs +439 -0
- package/contracts/oapps/{oft → oft-core}/src/storage.rs +2 -0
- package/contracts/oapps/{oft → oft-core}/src/tests/mod.rs +0 -2
- package/contracts/oapps/{oft → oft-core}/src/tests/test_decimals.rs +2 -2
- package/contracts/oapps/{oft → oft-core}/src/tests/test_lz_receive.rs +7 -7
- package/contracts/oapps/{oft → oft-core}/src/tests/test_oft_msg_codec.rs +4 -5
- package/contracts/oapps/{oft → oft-core}/src/tests/test_resolve_address.rs +3 -3
- package/contracts/oapps/{oft → oft-core}/src/tests/test_utils.rs +78 -37
- package/contracts/oapps/oft-core/src/types.rs +58 -0
- package/contracts/oapps/{oft → oft-core}/src/utils.rs +1 -1
- package/contracts/upgrader/src/lib.rs +4 -4
- package/contracts/utils/src/auth.rs +44 -0
- package/contracts/utils/src/errors.rs +31 -5
- package/contracts/utils/src/lib.rs +3 -0
- package/contracts/utils/src/multisig.rs +211 -0
- package/contracts/utils/src/ownable.rs +137 -13
- package/contracts/utils/src/tests/buffer_reader.rs +6 -6
- package/contracts/utils/src/tests/buffer_writer.rs +6 -6
- package/contracts/utils/src/tests/bytes_ext.rs +2 -4
- package/contracts/utils/src/tests/mod.rs +1 -0
- package/contracts/utils/src/tests/multisig.rs +731 -0
- package/contracts/utils/src/tests/option_ext.rs +2 -5
- package/contracts/utils/src/tests/ownable.rs +456 -7
- package/contracts/utils/src/tests/ttl_configurable.rs +27 -16
- package/contracts/utils/src/tests/upgradeable.rs +4 -2
- package/contracts/utils/src/ttl_configurable.rs +23 -8
- package/contracts/utils/src/ttl_extendable.rs +27 -0
- package/contracts/utils/src/upgradeable.rs +2 -0
- package/contracts/workers/dvn/Cargo.toml +1 -1
- package/contracts/workers/dvn/src/auth.rs +7 -7
- package/contracts/workers/dvn/src/dvn.rs +10 -38
- package/contracts/workers/dvn/src/errors.rs +0 -7
- package/contracts/workers/dvn/src/events.rs +1 -14
- package/contracts/workers/dvn/src/interfaces/dvn.rs +2 -2
- package/contracts/workers/dvn/src/interfaces/mod.rs +0 -2
- package/contracts/workers/dvn/src/storage.rs +3 -13
- package/contracts/workers/dvn/src/tests/auth.rs +4 -4
- package/contracts/workers/dvn/src/tests/dvn.rs +1 -2
- package/contracts/workers/dvn/src/tests/multisig/set_signer.rs +7 -8
- package/contracts/workers/dvn/src/tests/multisig/set_threshold.rs +11 -8
- package/contracts/workers/dvn/src/tests/multisig/verify_signatures.rs +11 -12
- package/contracts/workers/dvn/src/tests/setup.rs +5 -5
- package/contracts/workers/dvn-fee-lib/Cargo.toml +1 -1
- package/contracts/workers/dvn-fee-lib/src/dvn_fee_lib.rs +3 -6
- package/contracts/workers/executor/src/auth.rs +80 -16
- package/contracts/workers/executor/src/executor.rs +5 -31
- package/contracts/workers/executor/src/storage.rs +2 -9
- package/contracts/workers/executor-fee-lib/Cargo.toml +1 -1
- package/contracts/workers/executor-fee-lib/src/executor_fee_lib.rs +3 -6
- package/contracts/workers/executor-helper/Cargo.toml +1 -1
- package/contracts/workers/executor-helper/src/executor_helper.rs +53 -73
- package/contracts/workers/price-feed/Cargo.toml +1 -1
- package/contracts/workers/price-feed/src/price_feed.rs +7 -10
- package/contracts/workers/worker/src/errors.rs +4 -0
- package/contracts/workers/worker/src/tests/worker.rs +7 -6
- package/contracts/workers/worker/src/worker.rs +20 -16
- package/package.json +7 -5
- package/sdk/.turbo/turbo-build.log +1 -0
- package/sdk/.turbo/turbo-test.log +1019 -0
- package/sdk/dist/generated/bml.d.ts +95 -8
- package/sdk/dist/generated/bml.js +95 -36
- package/sdk/dist/generated/counter.d.ts +289 -44
- package/sdk/dist/generated/counter.js +119 -49
- package/sdk/dist/generated/dvn.d.ts +312 -229
- package/sdk/dist/generated/dvn.js +144 -83
- package/sdk/dist/generated/dvn_fee_lib.d.ts +258 -63
- package/sdk/dist/generated/dvn_fee_lib.js +95 -26
- package/sdk/dist/generated/endpoint.d.ts +219 -24
- package/sdk/dist/generated/endpoint.js +108 -41
- package/sdk/dist/generated/executor.d.ts +239 -87
- package/sdk/dist/generated/executor.js +135 -63
- package/sdk/dist/generated/executor_fee_lib.d.ts +278 -74
- package/sdk/dist/generated/executor_fee_lib.js +135 -59
- package/sdk/dist/generated/executor_helper.d.ts +163 -21
- package/sdk/dist/generated/executor_helper.js +124 -52
- package/sdk/dist/generated/oft.d.ts +1842 -0
- package/sdk/dist/generated/oft.js +345 -0
- package/sdk/dist/generated/price_feed.d.ts +258 -63
- package/sdk/dist/generated/price_feed.js +95 -26
- package/sdk/dist/generated/sml.d.ts +235 -34
- package/sdk/dist/generated/sml.js +126 -53
- package/sdk/dist/generated/treasury.d.ts +1016 -0
- package/sdk/dist/generated/treasury.js +248 -0
- package/sdk/dist/generated/uln302.d.ts +235 -34
- package/sdk/dist/generated/uln302.js +126 -53
- package/sdk/dist/generated/upgrader.d.ts +17 -2
- package/sdk/dist/generated/upgrader.js +19 -1
- package/sdk/dist/index.d.ts +2 -1
- package/sdk/dist/index.js +2 -1
- package/sdk/package.json +6 -3
- package/sdk/src/index.ts +2 -1
- package/sdk/test/counter-sml.test.ts +376 -0
- package/sdk/test/counter-uln.test.ts +493 -0
- package/sdk/test/{oft.test.ts → oft-sml.test.ts} +196 -321
- package/sdk/test/suites/constants.ts +22 -2
- package/sdk/test/suites/globalSetup.ts +450 -0
- package/sdk/test/suites/localnet.ts +23 -6
- package/sdk/test/upgrader.test.ts +7 -16
- package/sdk/test/utils.ts +558 -85
- package/sdk/turbo.json +8 -0
- package/sdk/vitest.config.ts +21 -0
- package/tools/ts-bindings-gen/Cargo.toml +2 -0
- package/tools/ts-bindings-gen/src/main.rs +52 -4
- package/contracts/common-macros/src/contract_impl.rs +0 -52
- package/contracts/common-macros/src/ownable.rs +0 -41
- package/contracts/common-macros/src/tests/contract_impl.rs +0 -386
- package/contracts/common-macros/src/tests/snapshots/common_macros__tests__ownable__snapshot_generated_ownable_code.snap +0 -12
- package/contracts/macro-integration-tests/tests/runtime/ttl_configurable/extend_instance_ttl.rs +0 -50
- package/contracts/oapps/oapp-macros/src/oapp_core.rs +0 -41
- package/contracts/oapps/oapp-macros/src/oapp_full.rs +0 -21
- package/contracts/oapps/oapp-macros/src/oapp_options_type3.rs +0 -31
- package/contracts/oapps/oapp-macros/src/oapp_receiver.rs +0 -48
- package/contracts/oapps/oapp-macros/src/oapp_sender.rs +0 -21
- package/contracts/oapps/oapp-macros/src/util.rs +0 -107
- package/contracts/oapps/oft/src/constants.rs +0 -5
- package/contracts/oapps/oft/src/default_oft_impl.rs +0 -152
- package/contracts/oapps/oft/src/errors.rs +0 -8
- package/contracts/oapps/oft/src/interfaces/mint_burn_token.rs +0 -23
- package/contracts/oapps/oft/src/interfaces/mod.rs +0 -3
- package/contracts/oapps/oft/src/tests/extensions/mod.rs +0 -11
- package/contracts/oapps/oft/src/tests/extensions/setup.rs +0 -903
- package/contracts/oapps/oft/src/tests/extensions/test_oft_fee.rs +0 -749
- package/contracts/oapps/oft/src/tests/extensions/test_pausable.rs +0 -432
- package/contracts/oapps/oft/src/tests/extensions/test_rate_limiter.rs +0 -1078
- package/contracts/oapps/oft/src/types.rs +0 -38
- package/contracts/oapps/oft-std/integration-tests/utils.rs +0 -427
- package/contracts/oapps/oft-std/src/lib.rs +0 -16
- package/contracts/oapps/oft-std/src/oft.rs +0 -156
- package/contracts/workers/dvn/src/interfaces/multisig.rs +0 -56
- package/contracts/workers/dvn/src/multisig.rs +0 -157
- package/sdk/dist/generated/oft_std.d.ts +0 -1544
- package/sdk/dist/generated/oft_std.js +0 -271
- package/sdk/test/index.test.ts +0 -375
- /package/contracts/oapps/{oft-std → oft}/integration-tests/extensions/mod.rs +0 -0
- /package/contracts/oapps/{oft → oft-core}/src/codec/mod.rs +0 -0
- /package/contracts/oapps/{oft → oft-core}/src/codec/oft_compose_msg_codec.rs +0 -0
- /package/contracts/oapps/{oft → oft-core}/src/codec/oft_msg_codec.rs +0 -0
- /package/contracts/oapps/{oft → oft-core}/src/events.rs +0 -0
- /package/contracts/oapps/{oft → oft-core}/src/tests/test_oft_compose_msg_codec.rs +0 -0
- /package/contracts/oapps/{oft → oft-core}/src/tests/test_oft_version.rs +0 -0
- /package/contracts/oapps/{oft → oft-core}/src/tests/test_quote_oft.rs +0 -0
- /package/contracts/oapps/{oft → oft-core}/src/tests/test_quote_send.rs +0 -0
- /package/contracts/oapps/{oft → oft-core}/src/tests/test_send.rs +0 -0
- /package/contracts/oapps/{oft → oft-core}/src/tests/test_token.rs +0 -0
- /package/sdk/test/suites/{testUpgradeable.ts → dummyContractClient.ts} +0 -0
|
@@ -2,17 +2,19 @@
|
|
|
2
2
|
//!
|
|
3
3
|
//! This module provides common test contracts and helpers used across multiple test files.
|
|
4
4
|
|
|
5
|
-
use crate::
|
|
6
|
-
|
|
7
|
-
|
|
5
|
+
use crate::{
|
|
6
|
+
codec::oft_msg_codec::OFTMessage,
|
|
7
|
+
oft_core::OFTClient,
|
|
8
|
+
types::{OFTReceipt, SendParam},
|
|
9
|
+
};
|
|
8
10
|
use endpoint_v2::{LayerZeroReceiverClient, MessagingFee, MessagingParams, MessagingReceipt, Origin};
|
|
9
11
|
use oapp::oapp_core::OAppCoreClient;
|
|
10
|
-
use soroban_sdk::{address_payload::AddressPayload, log, String};
|
|
11
12
|
use soroban_sdk::{
|
|
12
|
-
|
|
13
|
+
address_payload::AddressPayload,
|
|
14
|
+
bytes, contract, contractimpl, log, symbol_short,
|
|
13
15
|
testutils::{Address as _, MockAuth, MockAuthInvoke},
|
|
14
16
|
token::{StellarAssetClient, TokenClient},
|
|
15
|
-
Address, Bytes, BytesN, Env, IntoVal, Symbol,
|
|
17
|
+
Address, Bytes, BytesN, Env, IntoVal, String, Symbol,
|
|
16
18
|
};
|
|
17
19
|
use stellar_macros::default_impl;
|
|
18
20
|
use stellar_tokens::fungible::{Base, FungibleToken};
|
|
@@ -102,11 +104,21 @@ pub fn create_origin(src_eid: u32, sender: &BytesN<32>, nonce: u64) -> Origin {
|
|
|
102
104
|
// ==================== Test OFT Contracts ====================
|
|
103
105
|
|
|
104
106
|
mod test_mint_burn_oft {
|
|
105
|
-
|
|
107
|
+
use crate::{
|
|
108
|
+
self as oft_core,
|
|
109
|
+
oft_core::{initialize_oft, lz_receive, OFTCore, OFTInternal},
|
|
110
|
+
types::OFTReceipt,
|
|
111
|
+
};
|
|
112
|
+
use endpoint_v2::Origin;
|
|
113
|
+
use oapp::oapp_receiver::LzReceiveInternal;
|
|
114
|
+
use soroban_sdk::{contractclient, contractimpl, Address, Bytes, BytesN, Env};
|
|
106
115
|
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
116
|
+
#[contractclient(name = "MintBurnTokenClient")]
|
|
117
|
+
#[allow(dead_code)]
|
|
118
|
+
trait MintBurnToken {
|
|
119
|
+
fn mint(env: Env, to: Address, amount: i128);
|
|
120
|
+
fn burn(env: Env, from: Address, amount: i128);
|
|
121
|
+
}
|
|
110
122
|
|
|
111
123
|
#[oapp_macros::oapp]
|
|
112
124
|
pub struct TestMintBurnOFT;
|
|
@@ -121,37 +133,55 @@ mod test_mint_burn_oft {
|
|
|
121
133
|
delegate: &Option<Address>,
|
|
122
134
|
shared_decimals: u32,
|
|
123
135
|
) {
|
|
124
|
-
|
|
136
|
+
initialize_oft::<Self>(env, owner, token, endpoint, delegate, shared_decimals)
|
|
125
137
|
}
|
|
126
138
|
}
|
|
127
139
|
|
|
128
140
|
#[contractimpl(contracttrait)]
|
|
129
|
-
impl
|
|
141
|
+
impl OFTCore for TestMintBurnOFT {}
|
|
142
|
+
|
|
143
|
+
impl LzReceiveInternal for TestMintBurnOFT {
|
|
144
|
+
fn __lz_receive(
|
|
145
|
+
env: &Env,
|
|
146
|
+
origin: &Origin,
|
|
147
|
+
guid: &BytesN<32>,
|
|
148
|
+
message: &Bytes,
|
|
149
|
+
extra_data: &Bytes,
|
|
150
|
+
executor: &Address,
|
|
151
|
+
value: i128,
|
|
152
|
+
) {
|
|
153
|
+
lz_receive::<Self>(env, executor, origin, guid, message, extra_data, value)
|
|
154
|
+
}
|
|
155
|
+
}
|
|
130
156
|
|
|
131
157
|
impl OFTInternal for TestMintBurnOFT {
|
|
132
158
|
fn __debit(env: &Env, sender: &Address, amount_ld: i128, min_amount_ld: i128, dst_eid: u32) -> OFTReceipt {
|
|
133
|
-
|
|
159
|
+
// Inline mint_burn::debit implementation
|
|
160
|
+
let receipt = Self::__debit_view(env, amount_ld, min_amount_ld, dst_eid);
|
|
161
|
+
MintBurnTokenClient::new(env, &Self::token(env)).burn(sender, &receipt.amount_received_ld);
|
|
162
|
+
receipt
|
|
134
163
|
}
|
|
135
164
|
|
|
136
|
-
fn __credit(env: &Env, to: &Address, amount_ld: i128,
|
|
137
|
-
|
|
165
|
+
fn __credit(env: &Env, to: &Address, amount_ld: i128, _src_eid: u32) -> i128 {
|
|
166
|
+
// Inline mint_burn::credit implementation
|
|
167
|
+
MintBurnTokenClient::new(env, &Self::token(env)).mint(to, &amount_ld);
|
|
168
|
+
amount_ld
|
|
138
169
|
}
|
|
139
170
|
}
|
|
140
171
|
}
|
|
141
172
|
pub use test_mint_burn_oft::TestMintBurnOFT;
|
|
142
173
|
|
|
143
174
|
mod test_lock_unlock_oft {
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
175
|
+
use crate::{
|
|
176
|
+
self as oft_core,
|
|
177
|
+
oft_core::{initialize_oft, lz_receive, OFTCore, OFTInternal},
|
|
178
|
+
types::OFTReceipt,
|
|
179
|
+
};
|
|
148
180
|
use endpoint_v2::Origin;
|
|
149
|
-
use oapp::oapp_receiver::OAppReceiver;
|
|
150
|
-
use
|
|
151
|
-
use soroban_sdk::{contractimpl, Address, Bytes, BytesN, Env};
|
|
181
|
+
use oapp::oapp_receiver::{LzReceiveInternal, OAppReceiver};
|
|
182
|
+
use soroban_sdk::{contractimpl, token::TokenClient, Address, Bytes, BytesN, Env};
|
|
152
183
|
|
|
153
|
-
#[oapp_macros::oapp]
|
|
154
|
-
#[oapp_manual_impl(receiver)]
|
|
184
|
+
#[oapp_macros::oapp(custom = [receiver])]
|
|
155
185
|
pub struct TestLockUnlockOFT;
|
|
156
186
|
|
|
157
187
|
#[contractimpl]
|
|
@@ -164,36 +194,47 @@ mod test_lock_unlock_oft {
|
|
|
164
194
|
delegate: &Option<Address>,
|
|
165
195
|
shared_decimals: u32,
|
|
166
196
|
) {
|
|
167
|
-
|
|
197
|
+
initialize_oft::<Self>(env, owner, token, endpoint, delegate, shared_decimals)
|
|
168
198
|
}
|
|
169
199
|
}
|
|
170
200
|
|
|
171
201
|
#[contractimpl(contracttrait)]
|
|
172
|
-
impl
|
|
202
|
+
impl OFTCore for TestLockUnlockOFT {}
|
|
173
203
|
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
fn lz_receive(
|
|
204
|
+
impl LzReceiveInternal for TestLockUnlockOFT {
|
|
205
|
+
fn __lz_receive(
|
|
177
206
|
env: &Env,
|
|
178
|
-
executor: &Address,
|
|
179
207
|
origin: &Origin,
|
|
180
208
|
guid: &BytesN<32>,
|
|
181
209
|
message: &Bytes,
|
|
182
210
|
extra_data: &Bytes,
|
|
211
|
+
executor: &Address,
|
|
183
212
|
value: i128,
|
|
184
213
|
) {
|
|
185
|
-
|
|
186
|
-
Self::__lz_receive(env, executor, origin, guid, message, extra_data, value);
|
|
214
|
+
lz_receive::<Self>(env, executor, origin, guid, message, extra_data, value)
|
|
187
215
|
}
|
|
188
216
|
}
|
|
189
217
|
|
|
218
|
+
// Custom receiver to demonstrate overriding next_nonce or other methods
|
|
219
|
+
#[contractimpl(contracttrait)]
|
|
220
|
+
impl OAppReceiver for TestLockUnlockOFT {}
|
|
221
|
+
|
|
190
222
|
impl OFTInternal for TestLockUnlockOFT {
|
|
191
223
|
fn __debit(env: &Env, sender: &Address, amount_ld: i128, min_amount_ld: i128, dst_eid: u32) -> OFTReceipt {
|
|
192
|
-
|
|
224
|
+
// Inline lock_unlock::debit implementation
|
|
225
|
+
let receipt: OFTReceipt = Self::__debit_view(env, amount_ld, min_amount_ld, dst_eid);
|
|
226
|
+
TokenClient::new(env, &Self::token(env)).transfer(
|
|
227
|
+
sender,
|
|
228
|
+
env.current_contract_address(),
|
|
229
|
+
&receipt.amount_received_ld,
|
|
230
|
+
);
|
|
231
|
+
receipt
|
|
193
232
|
}
|
|
194
233
|
|
|
195
|
-
fn __credit(env: &Env, to: &Address, amount_ld: i128,
|
|
196
|
-
|
|
234
|
+
fn __credit(env: &Env, to: &Address, amount_ld: i128, _src_eid: u32) -> i128 {
|
|
235
|
+
// Inline lock_unlock::credit implementation
|
|
236
|
+
TokenClient::new(env, &Self::token(env)).transfer(&env.current_contract_address(), to, &amount_ld);
|
|
237
|
+
amount_ld
|
|
197
238
|
}
|
|
198
239
|
}
|
|
199
240
|
}
|
|
@@ -265,12 +306,12 @@ impl MockEndpointWithCompose {
|
|
|
265
306
|
env.storage().instance().set(&symbol_short!("zro"), &zro_token);
|
|
266
307
|
}
|
|
267
308
|
|
|
268
|
-
/// Returns the native token address (required by
|
|
309
|
+
/// Returns the native token address (required by OAppSenderInternal)
|
|
269
310
|
pub fn native_token(env: Env) -> Address {
|
|
270
311
|
env.storage().instance().get(&symbol_short!("ntk")).unwrap()
|
|
271
312
|
}
|
|
272
313
|
|
|
273
|
-
/// Returns the ZRO token address (required by
|
|
314
|
+
/// Returns the ZRO token address (required by OAppSenderInternal)
|
|
274
315
|
pub fn zro(env: Env) -> Option<Address> {
|
|
275
316
|
env.storage().instance().get(&symbol_short!("zro"))
|
|
276
317
|
}
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
use soroban_sdk::{contracttype, Bytes, BytesN};
|
|
2
|
+
|
|
3
|
+
/// Message type for simple OFT send
|
|
4
|
+
pub const SEND: u32 = 1;
|
|
5
|
+
|
|
6
|
+
/// Message type for OFT send with compose functionality
|
|
7
|
+
pub const SEND_AND_CALL: u32 = 2;
|
|
8
|
+
|
|
9
|
+
/// Parameters for sending OFT tokens cross-chain
|
|
10
|
+
#[contracttype]
|
|
11
|
+
#[derive(Clone, PartialEq, Eq, Debug)]
|
|
12
|
+
pub struct SendParam {
|
|
13
|
+
/// The destination endpoint ID
|
|
14
|
+
pub dst_eid: u32,
|
|
15
|
+
/// The recipient address on the destination chain (32 bytes)
|
|
16
|
+
pub to: BytesN<32>,
|
|
17
|
+
/// The amount to send in local decimals
|
|
18
|
+
pub amount_ld: i128,
|
|
19
|
+
/// The minimum amount to receive in local decimals (slippage protection)
|
|
20
|
+
pub min_amount_ld: i128,
|
|
21
|
+
/// Additional options for the LayerZero message (Optional)
|
|
22
|
+
pub extra_options: Bytes,
|
|
23
|
+
/// Compose message to execute on the destination (Optional)
|
|
24
|
+
pub compose_msg: Bytes,
|
|
25
|
+
/// OFT command for custom behavior (Optional)
|
|
26
|
+
pub oft_cmd: Bytes,
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
/// Transfer limits for OFT operations
|
|
30
|
+
#[contracttype]
|
|
31
|
+
#[derive(Clone, PartialEq, Eq, Debug)]
|
|
32
|
+
pub struct OFTLimit {
|
|
33
|
+
/// The minimum amount to send in local decimals
|
|
34
|
+
pub min_amount_ld: i128,
|
|
35
|
+
/// The maximum amount to send in local decimals
|
|
36
|
+
pub max_amount_ld: i128,
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
/// Receipt containing amounts sent and received in an OFT transfer
|
|
40
|
+
#[contracttype]
|
|
41
|
+
#[derive(Clone, PartialEq, Eq, Debug)]
|
|
42
|
+
pub struct OFTReceipt {
|
|
43
|
+
/// The amount sent in local decimals
|
|
44
|
+
pub amount_sent_ld: i128,
|
|
45
|
+
/// The amount received in local decimals on the remote
|
|
46
|
+
pub amount_received_ld: i128,
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
/// Details about fees charged in an OFT operation
|
|
50
|
+
#[contracttype]
|
|
51
|
+
#[derive(Clone, PartialEq, Eq, Debug)]
|
|
52
|
+
pub struct OFTFeeDetail {
|
|
53
|
+
/// The amount of the fee in local decimals. Positive values represent fees charged,
|
|
54
|
+
/// while negative values represent rewards given.
|
|
55
|
+
pub fee_amount_ld: i128,
|
|
56
|
+
/// The description of the fee
|
|
57
|
+
pub description: Bytes,
|
|
58
|
+
}
|
|
@@ -38,7 +38,7 @@ pub fn remove_dust(amount_ld: i128, conversion_rate: i128) -> i128 {
|
|
|
38
38
|
///
|
|
39
39
|
/// # Returns
|
|
40
40
|
/// A 32-byte payload (contract ID hash or Ed25519 public key)
|
|
41
|
-
pub fn
|
|
41
|
+
pub fn address_payload(address: &Address) -> BytesN<32> {
|
|
42
42
|
match address.to_payload().unwrap() {
|
|
43
43
|
AddressPayload::ContractIdHash(payload) => payload,
|
|
44
44
|
AddressPayload::AccountIdPublicKeyEd25519(payload) => payload,
|
|
@@ -10,8 +10,8 @@
|
|
|
10
10
|
//! ## Security Model
|
|
11
11
|
//!
|
|
12
12
|
//! The Upgrader is a permissionless utility - anyone can call it, but security is enforced
|
|
13
|
-
//! by the target contract's
|
|
14
|
-
//! contract's `#[
|
|
13
|
+
//! by the target contract's authorization checks. When you call `upgrader.upgrade()`, the target
|
|
14
|
+
//! contract's `#[only_auth]` guard ensures only the target's authorizer can successfully upgrade it.
|
|
15
15
|
//!
|
|
16
16
|
//! ## Usage
|
|
17
17
|
//!
|
|
@@ -53,8 +53,8 @@ pub struct Upgrader;
|
|
|
53
53
|
impl Upgrader {
|
|
54
54
|
/// Upgrade a target contract and run its migration in a single transaction
|
|
55
55
|
///
|
|
56
|
-
/// The caller must be authorized as the
|
|
57
|
-
/// This is enforced by the target contract's `#[
|
|
56
|
+
/// The caller must be authorized as the authorizer of the target contract.
|
|
57
|
+
/// This is enforced by the target contract's `#[only_auth]` check.
|
|
58
58
|
///
|
|
59
59
|
/// This is useful for atomic upgrades where you want to ensure the migration
|
|
60
60
|
/// happens immediately after the upgrade, or the entire operation fails.
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
//! Base authorization trait for owner-protected operations.
|
|
2
|
+
//!
|
|
3
|
+
//! The `Auth` trait provides a common interface for authorization that can be
|
|
4
|
+
//! implemented by different access control patterns (e.g., single owner, multisig).
|
|
5
|
+
|
|
6
|
+
use soroban_sdk::{contractclient, Address, Env};
|
|
7
|
+
|
|
8
|
+
// ===========================================================================
|
|
9
|
+
// Auth trait
|
|
10
|
+
// ===========================================================================
|
|
11
|
+
|
|
12
|
+
/// Base trait for authorization.
|
|
13
|
+
///
|
|
14
|
+
/// Provides the authorizer address for owner-protected operations. This trait
|
|
15
|
+
/// is implemented by both `Ownable` (external owner) and `Multisig` (self-owning).
|
|
16
|
+
#[contractclient(name = "AuthClient")]
|
|
17
|
+
pub trait Auth: Sized {
|
|
18
|
+
/// Returns the address that authorizes owner-protected operations.
|
|
19
|
+
///
|
|
20
|
+
/// For `Ownable` contracts, this returns the stored owner address.
|
|
21
|
+
/// For `Multisig` contracts, this returns the contract's own address
|
|
22
|
+
/// (self-owning pattern).
|
|
23
|
+
fn authorizer(env: &Env) -> Address;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
// ===========================================================================
|
|
27
|
+
// Auth helper functions
|
|
28
|
+
// ===========================================================================
|
|
29
|
+
|
|
30
|
+
/// Enforces authorization from the authorizer and returns the authorizer address.
|
|
31
|
+
///
|
|
32
|
+
/// Panics if the authorizer has not provided authorization for this invocation.
|
|
33
|
+
pub fn enforce_auth<T: Auth>(env: &Env) -> Address {
|
|
34
|
+
let authorizer = T::authorizer(env);
|
|
35
|
+
authorizer.require_auth();
|
|
36
|
+
authorizer
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
/// Requires authorization from the authorizer.
|
|
40
|
+
///
|
|
41
|
+
/// Panics if the authorizer has not provided authorization for this invocation.
|
|
42
|
+
pub fn require_auth<T: Auth>(env: &Env) {
|
|
43
|
+
let _ = enforce_auth::<T>(env);
|
|
44
|
+
}
|
|
@@ -1,35 +1,61 @@
|
|
|
1
1
|
use common_macros::contract_error;
|
|
2
2
|
|
|
3
|
+
// Utils library error codes: 1000-1099
|
|
4
|
+
// See ERROR_SPEC.md for allocation rules
|
|
5
|
+
|
|
6
|
+
/// BufferReaderError: 1000-1009
|
|
3
7
|
#[contract_error]
|
|
4
8
|
pub enum BufferReaderError {
|
|
5
9
|
InvalidLength = 1000,
|
|
6
10
|
InvalidAddressPayload,
|
|
7
11
|
}
|
|
8
12
|
|
|
13
|
+
/// BufferWriterError: 1010-1019
|
|
9
14
|
#[contract_error]
|
|
10
15
|
pub enum BufferWriterError {
|
|
11
|
-
InvalidAddressPayload =
|
|
16
|
+
InvalidAddressPayload = 1010,
|
|
12
17
|
}
|
|
13
18
|
|
|
19
|
+
/// TtlConfigurableError: 1020-1029
|
|
14
20
|
#[contract_error]
|
|
15
21
|
pub enum TtlConfigurableError {
|
|
16
|
-
InvalidTtlConfig =
|
|
22
|
+
InvalidTtlConfig = 1020,
|
|
17
23
|
TtlConfigFrozen,
|
|
18
24
|
TtlConfigAlreadyFrozen,
|
|
19
25
|
}
|
|
20
26
|
|
|
27
|
+
/// OwnableError: 1030-1039
|
|
21
28
|
#[contract_error]
|
|
22
29
|
pub enum OwnableError {
|
|
23
|
-
|
|
30
|
+
InvalidPendingOwner = 1030,
|
|
31
|
+
InvalidTtl,
|
|
32
|
+
NoPendingTransfer,
|
|
33
|
+
OwnerAlreadySet,
|
|
24
34
|
OwnerNotSet,
|
|
35
|
+
TransferInProgress,
|
|
25
36
|
}
|
|
26
37
|
|
|
38
|
+
/// BytesExtError: 1040-1049
|
|
27
39
|
#[contract_error]
|
|
28
40
|
pub enum BytesExtError {
|
|
29
|
-
LengthMismatch =
|
|
41
|
+
LengthMismatch = 1040,
|
|
30
42
|
}
|
|
31
43
|
|
|
44
|
+
/// UpgradeableError: 1050-1059
|
|
32
45
|
#[contract_error]
|
|
33
46
|
pub enum UpgradeableError {
|
|
34
|
-
MigrationNotAllowed =
|
|
47
|
+
MigrationNotAllowed = 1050,
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
/// MultisigError: 1060-1069
|
|
51
|
+
#[contract_error]
|
|
52
|
+
pub enum MultisigError {
|
|
53
|
+
AlreadyInitialized = 1060,
|
|
54
|
+
InvalidSigner,
|
|
55
|
+
SignatureError,
|
|
56
|
+
SignerAlreadyExists,
|
|
57
|
+
SignerNotFound,
|
|
58
|
+
TotalSignersLessThanThreshold,
|
|
59
|
+
UnsortedSigners,
|
|
60
|
+
ZeroThreshold,
|
|
35
61
|
}
|
|
@@ -1,12 +1,15 @@
|
|
|
1
1
|
#![no_std]
|
|
2
2
|
|
|
3
|
+
pub mod auth;
|
|
3
4
|
pub mod buffer_reader;
|
|
4
5
|
pub mod buffer_writer;
|
|
5
6
|
pub mod bytes_ext;
|
|
6
7
|
pub mod errors;
|
|
8
|
+
pub mod multisig;
|
|
7
9
|
pub mod option_ext;
|
|
8
10
|
pub mod ownable;
|
|
9
11
|
pub mod ttl_configurable;
|
|
12
|
+
pub mod ttl_extendable;
|
|
10
13
|
pub mod upgradeable;
|
|
11
14
|
|
|
12
15
|
#[cfg(test)]
|
|
@@ -0,0 +1,211 @@
|
|
|
1
|
+
use crate::{
|
|
2
|
+
self as utils, // Alias for #[storage] macro's generated `utils::ttl_configurable` path
|
|
3
|
+
auth::{self, Auth},
|
|
4
|
+
errors::MultisigError,
|
|
5
|
+
};
|
|
6
|
+
use common_macros::{contract_trait, storage};
|
|
7
|
+
use soroban_sdk::{assert_with_error, contractevent, Bytes, BytesN, Env, Vec};
|
|
8
|
+
|
|
9
|
+
// ===========================================================================
|
|
10
|
+
// Multisig events
|
|
11
|
+
// ===========================================================================
|
|
12
|
+
|
|
13
|
+
/// Event emitted when a signer is added or removed.
|
|
14
|
+
#[contractevent]
|
|
15
|
+
#[derive(Clone, Debug, Eq, PartialEq)]
|
|
16
|
+
pub struct SignerSet {
|
|
17
|
+
#[topic]
|
|
18
|
+
pub signer: BytesN<20>,
|
|
19
|
+
pub active: bool,
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
/// Event emitted when the signature threshold is changed.
|
|
23
|
+
#[contractevent]
|
|
24
|
+
#[derive(Clone, Debug, Eq, PartialEq)]
|
|
25
|
+
pub struct ThresholdSet {
|
|
26
|
+
pub threshold: u32,
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
// ===========================================================================
|
|
30
|
+
// Multisig storage
|
|
31
|
+
// ===========================================================================
|
|
32
|
+
|
|
33
|
+
/// Storage keys for Multisig.
|
|
34
|
+
#[storage]
|
|
35
|
+
pub enum MultisigStorage {
|
|
36
|
+
#[persistent(Vec<BytesN<20>>)]
|
|
37
|
+
#[default(Vec::new(env))]
|
|
38
|
+
Signers,
|
|
39
|
+
|
|
40
|
+
#[instance(u32)]
|
|
41
|
+
#[default(0)]
|
|
42
|
+
Threshold,
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
// ===========================================================================
|
|
46
|
+
// Multisig trait with default implementation
|
|
47
|
+
// ===========================================================================
|
|
48
|
+
|
|
49
|
+
/// Trait for contracts with secp256k1 multisig signature verification.
|
|
50
|
+
///
|
|
51
|
+
/// Extends `Auth` to provide self-owning authorization. Contracts implementing
|
|
52
|
+
/// `Multisig` should implement `Auth::authorizer()` to return `env.current_contract_address()`,
|
|
53
|
+
/// allowing the multisig quorum to serve as the authorizer for owner-protected operations.
|
|
54
|
+
#[contract_trait]
|
|
55
|
+
pub trait Multisig: Auth {
|
|
56
|
+
// ===========================================================================
|
|
57
|
+
// Mutation functions, only callable by the contract itself
|
|
58
|
+
// ===========================================================================
|
|
59
|
+
|
|
60
|
+
/// Adds or removes a signer from the multisig. Requires owner authorization.
|
|
61
|
+
fn set_signer(env: &Env, signer: &BytesN<20>, active: bool) {
|
|
62
|
+
auth::require_auth::<Self>(env);
|
|
63
|
+
match active {
|
|
64
|
+
true => add_signer(env, signer),
|
|
65
|
+
false => remove_signer(env, signer),
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
/// Sets the signature threshold (quorum). Requires owner authorization.
|
|
70
|
+
fn set_threshold(env: &Env, threshold: u32) {
|
|
71
|
+
auth::require_auth::<Self>(env);
|
|
72
|
+
set_threshold(env, threshold);
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
// ===========================================================================
|
|
76
|
+
// View functions
|
|
77
|
+
// ===========================================================================
|
|
78
|
+
|
|
79
|
+
/// Returns all registered signers.
|
|
80
|
+
fn get_signers(env: &Env) -> Vec<BytesN<20>> {
|
|
81
|
+
MultisigStorage::signers(env)
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
/// Returns the total number of registered signers.
|
|
85
|
+
fn total_signers(env: &Env) -> u32 {
|
|
86
|
+
MultisigStorage::signers(env).len()
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
/// Checks if an address is a registered signer.
|
|
90
|
+
fn is_signer(env: &Env, signer: &BytesN<20>) -> bool {
|
|
91
|
+
MultisigStorage::signers(env).iter().any(|s| &s == signer)
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
/// Returns the current signature threshold (quorum).
|
|
95
|
+
fn threshold(env: &Env) -> u32 {
|
|
96
|
+
MultisigStorage::threshold(env)
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
// ===========================================================================
|
|
100
|
+
// Verification functions
|
|
101
|
+
// ===========================================================================
|
|
102
|
+
|
|
103
|
+
/// Verifies signatures against the configured threshold.
|
|
104
|
+
fn verify_signatures(env: &Env, digest: &BytesN<32>, signatures: &Vec<BytesN<65>>) {
|
|
105
|
+
Self::verify_n_signatures(env, digest, signatures, MultisigStorage::threshold(env));
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
/// Verifies signatures against a custom threshold.
|
|
109
|
+
fn verify_n_signatures(env: &Env, digest: &BytesN<32>, signatures: &Vec<BytesN<65>>, threshold: u32) {
|
|
110
|
+
assert_with_error!(env, threshold > 0, MultisigError::ZeroThreshold);
|
|
111
|
+
assert_with_error!(env, signatures.len() >= threshold, MultisigError::SignatureError);
|
|
112
|
+
|
|
113
|
+
let signers = MultisigStorage::signers(env);
|
|
114
|
+
let mut last_signer: Option<BytesN<20>> = None;
|
|
115
|
+
for signature in signatures.iter() {
|
|
116
|
+
let signer = recover_signer(env, digest, &signature);
|
|
117
|
+
|
|
118
|
+
assert_with_error!(
|
|
119
|
+
env,
|
|
120
|
+
last_signer.as_ref().is_none_or(|last| &signer > last),
|
|
121
|
+
MultisigError::UnsortedSigners
|
|
122
|
+
);
|
|
123
|
+
assert_with_error!(env, signers.iter().any(|s| s == signer), MultisigError::SignerNotFound);
|
|
124
|
+
|
|
125
|
+
last_signer = Some(signer);
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
// ===========================================================================
|
|
131
|
+
// Public helper functions
|
|
132
|
+
// ===========================================================================
|
|
133
|
+
|
|
134
|
+
/// Initializes multisig with signers and threshold. Called from contract constructors.
|
|
135
|
+
pub fn init_multisig(env: &Env, signers: &Vec<BytesN<20>>, threshold: u32) {
|
|
136
|
+
assert_with_error!(env, !MultisigStorage::has_signers(env), MultisigError::AlreadyInitialized);
|
|
137
|
+
|
|
138
|
+
signers.iter().for_each(|signer| add_signer(env, &signer));
|
|
139
|
+
set_threshold(env, threshold);
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
/// Recovers Ethereum-style signer address from secp256k1 signature (65 bytes: r + s + v).
|
|
143
|
+
pub fn recover_signer(env: &Env, digest: &BytesN<32>, signature: &BytesN<65>) -> BytesN<20> {
|
|
144
|
+
let sig_bytes: Bytes = signature.into();
|
|
145
|
+
let v = sig_bytes.get(64).unwrap();
|
|
146
|
+
let recovery_id = if (27..=30).contains(&v) { v - 27 } else { v };
|
|
147
|
+
let sig_rs: BytesN<64> = sig_bytes.slice(0..64).try_into().unwrap();
|
|
148
|
+
|
|
149
|
+
let public_key = env.crypto_hazmat().secp256k1_recover(digest, &sig_rs, recovery_id as u32);
|
|
150
|
+
|
|
151
|
+
Bytes::from(env.crypto().keccak256(&Bytes::from(public_key).slice(1..65))).slice(12..32).try_into().unwrap()
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
// ===========================================================================
|
|
155
|
+
// Private helper functions
|
|
156
|
+
// ===========================================================================
|
|
157
|
+
|
|
158
|
+
/// Adds a new signer to the multisig.
|
|
159
|
+
fn add_signer(env: &Env, signer: &BytesN<20>) {
|
|
160
|
+
// Not allowed to add zero address as signer
|
|
161
|
+
assert_with_error!(env, signer != &BytesN::from_array(env, &[0u8; 20]), MultisigError::InvalidSigner);
|
|
162
|
+
// Not allowed to add same signer twice
|
|
163
|
+
let mut signers = MultisigStorage::signers(env);
|
|
164
|
+
assert_with_error!(env, !signers.iter().any(|s| &s == signer), MultisigError::SignerAlreadyExists);
|
|
165
|
+
|
|
166
|
+
// Add signer to list
|
|
167
|
+
signers.push_back(signer.clone());
|
|
168
|
+
MultisigStorage::set_signers(env, &signers);
|
|
169
|
+
|
|
170
|
+
SignerSet { signer: signer.clone(), active: true }.publish(env);
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
/// Removes a signer from the multisig.
|
|
174
|
+
fn remove_signer(env: &Env, signer: &BytesN<20>) {
|
|
175
|
+
let mut signers = MultisigStorage::signers(env);
|
|
176
|
+
let index = signers.first_index_of(signer);
|
|
177
|
+
// Not allowed to remove non-existent signer
|
|
178
|
+
assert_with_error!(env, index.is_some(), MultisigError::SignerNotFound);
|
|
179
|
+
|
|
180
|
+
// Remove signer from list
|
|
181
|
+
signers.remove(index.unwrap());
|
|
182
|
+
|
|
183
|
+
// Not allowed to remove signer if it would violate the threshold
|
|
184
|
+
assert_with_error!(
|
|
185
|
+
env,
|
|
186
|
+
signers.len() >= MultisigStorage::threshold(env),
|
|
187
|
+
MultisigError::TotalSignersLessThanThreshold
|
|
188
|
+
);
|
|
189
|
+
|
|
190
|
+
// Update signers list
|
|
191
|
+
MultisigStorage::set_signers(env, &signers);
|
|
192
|
+
|
|
193
|
+
SignerSet { signer: signer.clone(), active: false }.publish(env);
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
/// Sets the signature threshold (quorum).
|
|
197
|
+
fn set_threshold(env: &Env, threshold: u32) {
|
|
198
|
+
// Not allowed to set threshold to zero
|
|
199
|
+
assert_with_error!(env, threshold > 0, MultisigError::ZeroThreshold);
|
|
200
|
+
// Not allowed to set threshold to greater than the number of signers
|
|
201
|
+
assert_with_error!(
|
|
202
|
+
env,
|
|
203
|
+
MultisigStorage::signers(env).len() >= threshold,
|
|
204
|
+
MultisigError::TotalSignersLessThanThreshold
|
|
205
|
+
);
|
|
206
|
+
|
|
207
|
+
// Update threshold
|
|
208
|
+
MultisigStorage::set_threshold(env, &threshold);
|
|
209
|
+
|
|
210
|
+
ThresholdSet { threshold }.publish(env);
|
|
211
|
+
}
|