@layerzerolabs/protocol-stellar-v2 0.2.15 → 0.2.18
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 +350 -309
- package/.turbo/turbo-lint.log +146 -108
- package/.turbo/turbo-test.log +1423 -1238
- package/Cargo.lock +12 -0
- package/Cargo.toml +3 -0
- 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 +23 -3
- 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/integration-tests/setup.rs +25 -7
- package/contracts/oapps/oft/src/errors.rs +6 -1
- package/contracts/oapps/oft/src/extensions/oft_fee.rs +8 -8
- 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 +4 -2
- package/contracts/oapps/oft/src/oft.rs +24 -64
- package/contracts/oapps/oft/src/oft_impl.rs +201 -0
- package/contracts/oapps/oft/src/oft_types/lock_unlock.rs +1 -3
- package/contracts/oapps/oft/src/oft_types/mint_burn.rs +1 -4
- package/contracts/oapps/oft/src/storage.rs +2 -0
- package/contracts/oapps/oft/src/tests/extensions/setup.rs +36 -22
- package/contracts/oapps/oft/src/tests/extensions/test_oft_fee.rs +5 -3
- package/contracts/oapps/oft/src/tests/extensions/test_pausable.rs +5 -3
- package/contracts/oapps/oft/src/tests/extensions/test_rate_limiter.rs +5 -3
- package/contracts/oapps/oft/src/tests/test_decimals.rs +2 -2
- package/contracts/oapps/oft/src/tests/test_oft_msg_codec.rs +1 -2
- package/contracts/oapps/oft/src/tests/test_utils.rs +45 -23
- package/contracts/oapps/oft/src/types.rs +20 -0
- package/contracts/oapps/oft-std/integration-tests/setup.rs +4 -2
- package/contracts/oapps/oft-std/src/oft.rs +24 -6
- package/contracts/upgrader/src/lib.rs +4 -4
- package/contracts/utils/src/auth.rs +44 -0
- package/contracts/utils/src/errors.rs +27 -5
- package/contracts/utils/src/lib.rs +3 -0
- package/contracts/utils/src/multisig.rs +211 -0
- package/contracts/utils/src/ownable.rs +12 -10
- 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 +16 -5
- 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 +8 -5
- package/sdk/.turbo/turbo-build.log +1 -0
- package/sdk/.turbo/turbo-test.log +1009 -0
- package/sdk/dist/generated/bml.d.ts +65 -8
- package/sdk/dist/generated/bml.js +70 -34
- package/sdk/dist/generated/counter.d.ts +167 -42
- package/sdk/dist/generated/counter.js +86 -45
- package/sdk/dist/generated/dvn.d.ts +282 -229
- package/sdk/dist/generated/dvn.js +119 -81
- package/sdk/dist/generated/dvn_fee_lib.d.ts +142 -67
- package/sdk/dist/generated/dvn_fee_lib.js +64 -24
- package/sdk/dist/generated/endpoint.d.ts +97 -22
- package/sdk/dist/generated/endpoint.js +75 -37
- package/sdk/dist/generated/executor.d.ts +117 -85
- package/sdk/dist/generated/executor.js +102 -59
- package/sdk/dist/generated/executor_fee_lib.d.ts +162 -78
- package/sdk/dist/generated/executor_fee_lib.js +104 -57
- package/sdk/dist/generated/executor_helper.d.ts +133 -21
- package/sdk/dist/generated/executor_helper.js +99 -50
- package/sdk/dist/generated/oft_std.d.ts +233 -55
- package/sdk/dist/generated/oft_std.js +99 -54
- package/sdk/dist/generated/price_feed.d.ts +142 -67
- package/sdk/dist/generated/price_feed.js +64 -24
- package/sdk/dist/generated/sml.d.ts +113 -32
- package/sdk/dist/generated/sml.js +93 -49
- package/sdk/dist/generated/treasury.d.ts +896 -0
- package/sdk/dist/generated/treasury.js +219 -0
- package/sdk/dist/generated/uln302.d.ts +113 -32
- package/sdk/dist/generated/uln302.js +93 -49
- package/sdk/dist/generated/upgrader.d.ts +2 -2
- package/sdk/dist/generated/upgrader.js +1 -1
- package/sdk/dist/index.d.ts +2 -0
- package/sdk/dist/index.js +3 -0
- package/sdk/dist/wasm/blocked-message-lib.d.ts +1 -0
- package/sdk/dist/wasm/blocked-message-lib.js +2 -0
- package/sdk/dist/wasm/counter.d.ts +1 -0
- package/sdk/dist/wasm/counter.js +2 -0
- package/sdk/dist/wasm/dvn-fee-lib.d.ts +1 -0
- package/sdk/dist/wasm/dvn-fee-lib.js +2 -0
- package/sdk/dist/wasm/dvn.d.ts +1 -0
- package/sdk/dist/wasm/dvn.js +2 -0
- package/sdk/dist/wasm/endpoint-v2.d.ts +1 -0
- package/sdk/dist/wasm/endpoint-v2.js +2 -0
- package/sdk/dist/wasm/executor-fee-lib.d.ts +1 -0
- package/sdk/dist/wasm/executor-fee-lib.js +2 -0
- package/sdk/dist/wasm/executor-helper.d.ts +1 -0
- package/sdk/dist/wasm/executor-helper.js +2 -0
- package/sdk/dist/wasm/executor.d.ts +1 -0
- package/sdk/dist/wasm/executor.js +2 -0
- package/sdk/dist/wasm/layerzero-views.d.ts +1 -0
- package/sdk/dist/wasm/layerzero-views.js +2 -0
- package/sdk/dist/wasm/oft-std.d.ts +1 -0
- package/sdk/dist/wasm/oft-std.js +2 -0
- package/sdk/dist/wasm/price-feed.d.ts +1 -0
- package/sdk/dist/wasm/price-feed.js +2 -0
- package/sdk/dist/wasm/simple-message-lib.d.ts +1 -0
- package/sdk/dist/wasm/simple-message-lib.js +2 -0
- package/sdk/dist/wasm/treasury.d.ts +1 -0
- package/sdk/dist/wasm/treasury.js +2 -0
- package/sdk/dist/wasm/uln302.d.ts +1 -0
- package/sdk/dist/wasm/uln302.js +2 -0
- package/sdk/dist/wasm/upgrader.d.ts +1 -0
- package/sdk/dist/wasm/upgrader.js +2 -0
- package/sdk/dist/wasm.d.ts +15 -0
- package/sdk/dist/wasm.js +15 -0
- package/sdk/package.json +4 -2
- package/sdk/src/index.ts +4 -0
- 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} +185 -310
- 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/vitest.config.ts +21 -0
- package/tools/ts-bindings-gen/src/main.rs +1 -0
- package/turbo.json +2 -0
- 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/workers/dvn/src/interfaces/multisig.rs +0 -56
- package/contracts/workers/dvn/src/multisig.rs +0 -157
- package/sdk/test/index.test.ts +0 -375
- /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::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};
|
|
@@ -104,9 +106,13 @@ pub fn create_origin(src_eid: u32, sender: &BytesN<32>, nonce: u64) -> Origin {
|
|
|
104
106
|
mod test_mint_burn_oft {
|
|
105
107
|
extern crate self as oft;
|
|
106
108
|
|
|
107
|
-
use crate::
|
|
109
|
+
use crate::initialize_oft;
|
|
110
|
+
use crate::oft::{OFTInternal, OFT};
|
|
111
|
+
use crate::oft_impl;
|
|
108
112
|
use crate::types::OFTReceipt;
|
|
109
|
-
use
|
|
113
|
+
use endpoint_v2::Origin;
|
|
114
|
+
use oapp::oapp_receiver::LzReceiveInternal;
|
|
115
|
+
use soroban_sdk::{contractimpl, Address, Bytes, BytesN, Env};
|
|
110
116
|
|
|
111
117
|
#[oapp_macros::oapp]
|
|
112
118
|
pub struct TestMintBurnOFT;
|
|
@@ -121,13 +127,27 @@ mod test_mint_burn_oft {
|
|
|
121
127
|
delegate: &Option<Address>,
|
|
122
128
|
shared_decimals: u32,
|
|
123
129
|
) {
|
|
124
|
-
|
|
130
|
+
initialize_oft::<Self>(env, owner, token, endpoint, delegate, shared_decimals)
|
|
125
131
|
}
|
|
126
132
|
}
|
|
127
133
|
|
|
128
134
|
#[contractimpl(contracttrait)]
|
|
129
135
|
impl OFT for TestMintBurnOFT {}
|
|
130
136
|
|
|
137
|
+
impl LzReceiveInternal for TestMintBurnOFT {
|
|
138
|
+
fn __lz_receive(
|
|
139
|
+
env: &Env,
|
|
140
|
+
origin: &Origin,
|
|
141
|
+
guid: &BytesN<32>,
|
|
142
|
+
message: &Bytes,
|
|
143
|
+
extra_data: &Bytes,
|
|
144
|
+
executor: &Address,
|
|
145
|
+
value: i128,
|
|
146
|
+
) {
|
|
147
|
+
oft_impl::lz_receive::<Self>(env, executor, origin, guid, message, extra_data, value)
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
|
|
131
151
|
impl OFTInternal for TestMintBurnOFT {
|
|
132
152
|
fn __debit(env: &Env, sender: &Address, amount_ld: i128, min_amount_ld: i128, dst_eid: u32) -> OFTReceipt {
|
|
133
153
|
crate::oft_types::mint_burn::debit::<Self>(env, sender, amount_ld, min_amount_ld, dst_eid)
|
|
@@ -143,15 +163,15 @@ pub use test_mint_burn_oft::TestMintBurnOFT;
|
|
|
143
163
|
mod test_lock_unlock_oft {
|
|
144
164
|
extern crate self as oft;
|
|
145
165
|
|
|
146
|
-
use crate::
|
|
166
|
+
use crate::initialize_oft;
|
|
167
|
+
use crate::oft::{OFTInternal, OFT};
|
|
168
|
+
use crate::oft_impl;
|
|
147
169
|
use crate::types::OFTReceipt;
|
|
148
170
|
use endpoint_v2::Origin;
|
|
149
|
-
use oapp::oapp_receiver::OAppReceiver;
|
|
150
|
-
use oapp_macros::oapp_manual_impl;
|
|
171
|
+
use oapp::oapp_receiver::{LzReceiveInternal, OAppReceiver};
|
|
151
172
|
use soroban_sdk::{contractimpl, Address, Bytes, BytesN, Env};
|
|
152
173
|
|
|
153
|
-
#[oapp_macros::oapp]
|
|
154
|
-
#[oapp_manual_impl(receiver)]
|
|
174
|
+
#[oapp_macros::oapp(custom = [receiver])]
|
|
155
175
|
pub struct TestLockUnlockOFT;
|
|
156
176
|
|
|
157
177
|
#[contractimpl]
|
|
@@ -164,29 +184,31 @@ mod test_lock_unlock_oft {
|
|
|
164
184
|
delegate: &Option<Address>,
|
|
165
185
|
shared_decimals: u32,
|
|
166
186
|
) {
|
|
167
|
-
|
|
187
|
+
initialize_oft::<Self>(env, owner, token, endpoint, delegate, shared_decimals)
|
|
168
188
|
}
|
|
169
189
|
}
|
|
170
190
|
|
|
171
191
|
#[contractimpl(contracttrait)]
|
|
172
192
|
impl OFT for TestLockUnlockOFT {}
|
|
173
193
|
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
fn lz_receive(
|
|
194
|
+
impl LzReceiveInternal for TestLockUnlockOFT {
|
|
195
|
+
fn __lz_receive(
|
|
177
196
|
env: &Env,
|
|
178
|
-
executor: &Address,
|
|
179
197
|
origin: &Origin,
|
|
180
198
|
guid: &BytesN<32>,
|
|
181
199
|
message: &Bytes,
|
|
182
200
|
extra_data: &Bytes,
|
|
201
|
+
executor: &Address,
|
|
183
202
|
value: i128,
|
|
184
203
|
) {
|
|
185
|
-
|
|
186
|
-
Self::__lz_receive(env, executor, origin, guid, message, extra_data, value);
|
|
204
|
+
oft_impl::lz_receive::<Self>(env, executor, origin, guid, message, extra_data, value)
|
|
187
205
|
}
|
|
188
206
|
}
|
|
189
207
|
|
|
208
|
+
// Custom receiver to demonstrate overriding next_nonce or other methods
|
|
209
|
+
#[contractimpl(contracttrait)]
|
|
210
|
+
impl OAppReceiver for TestLockUnlockOFT {}
|
|
211
|
+
|
|
190
212
|
impl OFTInternal for TestLockUnlockOFT {
|
|
191
213
|
fn __debit(env: &Env, sender: &Address, amount_ld: i128, min_amount_ld: i128, dst_eid: u32) -> OFTReceipt {
|
|
192
214
|
crate::oft_types::lock_unlock::debit::<Self>(env, sender, amount_ld, min_amount_ld, dst_eid)
|
|
@@ -265,12 +287,12 @@ impl MockEndpointWithCompose {
|
|
|
265
287
|
env.storage().instance().set(&symbol_short!("zro"), &zro_token);
|
|
266
288
|
}
|
|
267
289
|
|
|
268
|
-
/// Returns the native token address (required by
|
|
290
|
+
/// Returns the native token address (required by OAppSenderInternal)
|
|
269
291
|
pub fn native_token(env: Env) -> Address {
|
|
270
292
|
env.storage().instance().get(&symbol_short!("ntk")).unwrap()
|
|
271
293
|
}
|
|
272
294
|
|
|
273
|
-
/// Returns the ZRO token address (required by
|
|
295
|
+
/// Returns the ZRO token address (required by OAppSenderInternal)
|
|
274
296
|
pub fn zro(env: Env) -> Option<Address> {
|
|
275
297
|
env.storage().instance().get(&symbol_short!("zro"))
|
|
276
298
|
}
|
|
@@ -1,15 +1,28 @@
|
|
|
1
1
|
use soroban_sdk::{contracttype, Bytes, BytesN};
|
|
2
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
|
+
|
|
3
9
|
/// Parameters for sending OFT tokens cross-chain
|
|
4
10
|
#[contracttype]
|
|
5
11
|
#[derive(Clone, PartialEq, Eq, Debug)]
|
|
6
12
|
pub struct SendParam {
|
|
13
|
+
/// The destination endpoint ID
|
|
7
14
|
pub dst_eid: u32,
|
|
15
|
+
/// The recipient address on the destination chain (32 bytes)
|
|
8
16
|
pub to: BytesN<32>,
|
|
17
|
+
/// The amount to send in local decimals
|
|
9
18
|
pub amount_ld: i128,
|
|
19
|
+
/// The minimum amount to receive in local decimals (slippage protection)
|
|
10
20
|
pub min_amount_ld: i128,
|
|
21
|
+
/// Additional options for the LayerZero message (Optional)
|
|
11
22
|
pub extra_options: Bytes,
|
|
23
|
+
/// Compose message to execute on the destination (Optional)
|
|
12
24
|
pub compose_msg: Bytes,
|
|
25
|
+
/// OFT command for custom behavior (Optional)
|
|
13
26
|
pub oft_cmd: Bytes,
|
|
14
27
|
}
|
|
15
28
|
|
|
@@ -17,7 +30,9 @@ pub struct SendParam {
|
|
|
17
30
|
#[contracttype]
|
|
18
31
|
#[derive(Clone, PartialEq, Eq, Debug)]
|
|
19
32
|
pub struct OFTLimit {
|
|
33
|
+
/// The minimum amount to send in local decimals
|
|
20
34
|
pub min_amount_ld: i128,
|
|
35
|
+
/// The maximum amount to send in local decimals
|
|
21
36
|
pub max_amount_ld: i128,
|
|
22
37
|
}
|
|
23
38
|
|
|
@@ -25,7 +40,9 @@ pub struct OFTLimit {
|
|
|
25
40
|
#[contracttype]
|
|
26
41
|
#[derive(Clone, PartialEq, Eq, Debug)]
|
|
27
42
|
pub struct OFTReceipt {
|
|
43
|
+
/// The amount sent in local decimals
|
|
28
44
|
pub amount_sent_ld: i128,
|
|
45
|
+
/// The amount received in local decimals on the remote
|
|
29
46
|
pub amount_received_ld: i128,
|
|
30
47
|
}
|
|
31
48
|
|
|
@@ -33,6 +50,9 @@ pub struct OFTReceipt {
|
|
|
33
50
|
#[contracttype]
|
|
34
51
|
#[derive(Clone, PartialEq, Eq, Debug)]
|
|
35
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.
|
|
36
55
|
pub fee_amount_ld: i128,
|
|
56
|
+
/// The description of the fee
|
|
37
57
|
pub description: Bytes,
|
|
38
58
|
}
|
|
@@ -5,8 +5,10 @@
|
|
|
5
5
|
extern crate self as oft_std;
|
|
6
6
|
extern crate std;
|
|
7
7
|
|
|
8
|
-
use crate::
|
|
9
|
-
|
|
8
|
+
use crate::{
|
|
9
|
+
integration_tests::utils::{address_to_peer_bytes32, peer_bytes32_to_address},
|
|
10
|
+
oft::{OFTMode, OFTStd, OFTStdClient},
|
|
11
|
+
};
|
|
10
12
|
use endpoint_v2::{EndpointV2, EndpointV2Client};
|
|
11
13
|
use simple_message_lib::{SimpleMessageLib, SimpleMessageLibClient};
|
|
12
14
|
use soroban_sdk::{
|
|
@@ -1,20 +1,23 @@
|
|
|
1
1
|
use common_macros::{contract_impl, storage};
|
|
2
|
+
use endpoint_v2::Origin;
|
|
3
|
+
use oapp::oapp_receiver::LzReceiveInternal;
|
|
2
4
|
use oapp_macros::oapp;
|
|
3
5
|
use oft::{
|
|
4
|
-
default_oft_impl::{default_quote_oft, default_quote_send},
|
|
5
6
|
errors::OFTError,
|
|
6
7
|
extensions::{
|
|
7
8
|
oft_fee::{OFTFee, OFTFeeInternal},
|
|
8
9
|
pausable::{OFTPausable, OFTPausableInternal},
|
|
9
10
|
rate_limiter::{Direction, RateLimiter, RateLimiterInternal},
|
|
10
11
|
},
|
|
11
|
-
|
|
12
|
+
initialize_oft,
|
|
13
|
+
oft::{OFTInternal, OFT},
|
|
14
|
+
oft_impl,
|
|
12
15
|
oft_types::{lock_unlock, mint_burn},
|
|
13
16
|
storage::OFTStorage,
|
|
14
17
|
types::{OFTFeeDetail, OFTLimit, OFTReceipt, SendParam},
|
|
15
18
|
utils::remove_dust,
|
|
16
19
|
};
|
|
17
|
-
use soroban_sdk::{assert_with_error, contracttype, Address, Env, Vec};
|
|
20
|
+
use soroban_sdk::{assert_with_error, contracttype, Address, Bytes, BytesN, Env, Vec};
|
|
18
21
|
|
|
19
22
|
/// The mode of operation for the OFT contract
|
|
20
23
|
#[contracttype]
|
|
@@ -47,7 +50,7 @@ impl OFTStd {
|
|
|
47
50
|
shared_decimals: u32,
|
|
48
51
|
mode: OFTMode,
|
|
49
52
|
) {
|
|
50
|
-
|
|
53
|
+
initialize_oft::<Self>(env, owner, token, endpoint, delegate, shared_decimals);
|
|
51
54
|
OFTStdStorage::set_mode(env, &mode);
|
|
52
55
|
}
|
|
53
56
|
|
|
@@ -57,12 +60,27 @@ impl OFTStd {
|
|
|
57
60
|
}
|
|
58
61
|
}
|
|
59
62
|
|
|
63
|
+
/// LzReceiveInternal implementation using default OFT receive logic
|
|
64
|
+
impl LzReceiveInternal for OFTStd {
|
|
65
|
+
fn __lz_receive(
|
|
66
|
+
env: &Env,
|
|
67
|
+
origin: &Origin,
|
|
68
|
+
guid: &BytesN<32>,
|
|
69
|
+
message: &Bytes,
|
|
70
|
+
extra_data: &Bytes,
|
|
71
|
+
executor: &Address,
|
|
72
|
+
value: i128,
|
|
73
|
+
) {
|
|
74
|
+
oft_impl::lz_receive::<Self>(env, executor, origin, guid, message, extra_data, value)
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
|
|
60
78
|
/// OFT trait implementation for standard OFT with extensions
|
|
61
79
|
#[contract_impl(contracttrait)]
|
|
62
80
|
impl OFT for OFTStd {
|
|
63
81
|
fn quote_oft(env: &Env, send_param: &SendParam) -> (OFTLimit, Vec<OFTFeeDetail>, OFTReceipt) {
|
|
64
82
|
Self::__assert_not_paused(env);
|
|
65
|
-
let (_, fee_details, oft_receipt) =
|
|
83
|
+
let (_, fee_details, oft_receipt) = oft_impl::quote_oft::<Self>(env, send_param);
|
|
66
84
|
let capacity = Self::rate_limit_capacity(env, &Direction::Outbound, send_param.dst_eid);
|
|
67
85
|
let oft_limit = OFTLimit { min_amount_ld: 0, max_amount_ld: capacity };
|
|
68
86
|
(oft_limit, fee_details, oft_receipt)
|
|
@@ -70,7 +88,7 @@ impl OFT for OFTStd {
|
|
|
70
88
|
|
|
71
89
|
fn quote_send(env: &Env, sender: &Address, send_param: &SendParam, pay_in_zro: bool) -> endpoint_v2::MessagingFee {
|
|
72
90
|
Self::__assert_not_paused(env);
|
|
73
|
-
|
|
91
|
+
oft_impl::quote_send::<Self>(env, sender, send_param, pay_in_zro)
|
|
74
92
|
}
|
|
75
93
|
}
|
|
76
94
|
|
|
@@ -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,57 @@
|
|
|
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
|
-
OwnerAlreadySet =
|
|
30
|
+
OwnerAlreadySet = 1030,
|
|
24
31
|
OwnerNotSet,
|
|
25
32
|
}
|
|
26
33
|
|
|
34
|
+
/// BytesExtError: 1040-1049
|
|
27
35
|
#[contract_error]
|
|
28
36
|
pub enum BytesExtError {
|
|
29
|
-
LengthMismatch =
|
|
37
|
+
LengthMismatch = 1040,
|
|
30
38
|
}
|
|
31
39
|
|
|
40
|
+
/// UpgradeableError: 1050-1059
|
|
32
41
|
#[contract_error]
|
|
33
42
|
pub enum UpgradeableError {
|
|
34
|
-
MigrationNotAllowed =
|
|
43
|
+
MigrationNotAllowed = 1050,
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
/// MultisigError: 1060-1069
|
|
47
|
+
#[contract_error]
|
|
48
|
+
pub enum MultisigError {
|
|
49
|
+
AlreadyInitialized = 1060,
|
|
50
|
+
InvalidSigner,
|
|
51
|
+
SignatureError,
|
|
52
|
+
SignerAlreadyExists,
|
|
53
|
+
SignerNotFound,
|
|
54
|
+
TotalSignersLessThanThreshold,
|
|
55
|
+
UnsortedSigners,
|
|
56
|
+
ZeroThreshold,
|
|
35
57
|
}
|
|
@@ -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
|
+
}
|