@layerzerolabs/protocol-stellar-v2 0.2.10 → 0.2.12
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 +273 -219
- package/.turbo/turbo-lint.log +79 -107
- package/.turbo/turbo-test.log +1016 -840
- package/Cargo.lock +14 -6
- package/contracts/common-macros/src/contract_impl.rs +6 -3
- package/contracts/common-macros/src/error.rs +9 -17
- package/contracts/common-macros/src/lib.rs +4 -37
- package/contracts/common-macros/src/ownable.rs +9 -5
- package/contracts/common-macros/src/tests/contract_impl.rs +178 -86
- package/contracts/common-macros/src/tests/error.rs +168 -0
- package/contracts/common-macros/src/tests/mod.rs +2 -4
- package/contracts/common-macros/src/tests/ownable.rs +37 -60
- package/contracts/common-macros/src/tests/snapshots/common_macros__tests__contract_impl__snapshot_generated_contract_impl_code.snap +16 -6
- package/contracts/common-macros/src/tests/snapshots/common_macros__tests__error__snapshot_generated_contract_error_code.snap +20 -0
- package/contracts/common-macros/src/tests/snapshots/common_macros__tests__ownable__snapshot_generated_ownable_code.snap +3 -1
- package/contracts/common-macros/src/tests/snapshots/common_macros__tests__ownable__snapshot_only_owner_preserves_function_signature.snap +12 -2
- package/contracts/common-macros/src/tests/snapshots/common_macros__tests__ttl_configurable__snapshot_generated_ttl_configurable_code.snap +5 -1
- package/contracts/common-macros/src/tests/utils.rs +267 -0
- package/contracts/common-macros/src/ttl_configurable.rs +15 -12
- package/contracts/common-macros/src/utils.rs +35 -6
- package/contracts/endpoint-v2/src/endpoint_v2.rs +4 -4
- package/contracts/endpoint-v2/src/events.rs +40 -22
- package/contracts/endpoint-v2/src/interfaces/message_lib.rs +2 -2
- package/contracts/endpoint-v2/src/interfaces/message_lib_manager.rs +2 -2
- package/contracts/endpoint-v2/src/interfaces/messaging_channel.rs +2 -2
- package/contracts/endpoint-v2/src/interfaces/messaging_composer.rs +2 -2
- package/contracts/endpoint-v2/src/interfaces/send_lib.rs +2 -2
- package/contracts/endpoint-v2/src/message_lib_manager.rs +3 -3
- package/contracts/endpoint-v2/src/messaging_channel.rs +1 -1
- package/contracts/endpoint-v2/src/messaging_composer.rs +1 -1
- package/contracts/endpoint-v2/src/tests/message_lib_manager/set_default_receive_lib_timeout.rs +4 -8
- package/contracts/endpoint-v2/src/tests/message_lib_manager/set_default_receive_library.rs +3 -7
- package/contracts/message-libs/{block-message-lib → blocked-message-lib}/Cargo.toml +1 -1
- package/contracts/message-libs/treasury/src/events.rs +9 -6
- package/contracts/message-libs/uln-302/src/events.rs +19 -11
- package/contracts/message-libs/uln-302/src/interfaces/receive_uln.rs +2 -2
- package/contracts/message-libs/uln-302/src/interfaces/send_uln.rs +2 -2
- package/contracts/message-libs/uln-302/src/receive_uln.rs +2 -2
- package/contracts/message-libs/uln-302/src/send_uln.rs +3 -3
- package/contracts/message-libs/uln-302/src/tests/receive_uln302/set_default_receive_uln_configs.rs +5 -5
- package/contracts/message-libs/uln-302/src/tests/send_uln302/set_default_send_uln_configs.rs +5 -5
- package/contracts/message-libs/uln-302/src/tests/setup.rs +3 -3
- package/contracts/message-libs/uln-302/src/types.rs +24 -24
- package/contracts/message-libs/uln-302/src/uln302.rs +2 -2
- package/contracts/oapp-macros/src/oapp_core.rs +1 -1
- package/contracts/oapps/counter/integration_tests/utils.rs +1 -1
- package/contracts/oapps/oapp/src/oapp_core.rs +4 -3
- package/contracts/oapps/oapp/src/oapp_options_type3.rs +4 -3
- package/contracts/oapps/oft/integration-tests/setup.rs +4 -3
- package/contracts/oapps/oft/integration-tests/utils.rs +1 -1
- package/contracts/oapps/oft/src/default_oft_impl.rs +146 -0
- package/contracts/oapps/oft/src/events.rs +5 -4
- package/contracts/oapps/oft/src/extensions/mod.rs +3 -0
- package/contracts/oapps/oft/src/extensions/oft_fee.rs +168 -0
- package/contracts/oapps/oft/src/extensions/pausable.rs +50 -0
- package/contracts/oapps/oft/src/extensions/rate_limiter.rs +200 -0
- package/contracts/oapps/oft/src/lib.rs +2 -3
- package/contracts/oapps/oft/src/oft.rs +16 -85
- package/contracts/oapps/oft/src/oft_types/mint_burn.rs +1 -1
- package/contracts/oapps/oft/src/tests/extensions/mod.rs +11 -0
- package/contracts/oapps/oft/src/tests/extensions/setup.rs +888 -0
- package/contracts/oapps/oft/src/tests/extensions/test_oft_fee.rs +749 -0
- package/contracts/oapps/oft/src/tests/extensions/test_pausable.rs +432 -0
- package/contracts/oapps/oft/src/tests/extensions/test_rate_limiter.rs +1078 -0
- package/contracts/oapps/oft/src/tests/mod.rs +2 -0
- package/contracts/oapps/oft/src/tests/test_utils.rs +24 -6
- package/contracts/oapps/{oft-mint-burn → oft-std}/Cargo.toml +1 -8
- package/contracts/oapps/oft-std/src/lib.rs +5 -0
- package/contracts/oapps/oft-std/src/oft.rs +59 -0
- package/contracts/utils/src/ownable.rs +8 -6
- package/contracts/utils/src/tests/ownable.rs +0 -63
- package/contracts/utils/src/tests/testing_utils.rs +7 -5
- package/contracts/utils/src/ttl.rs +21 -2
- package/contracts/workers/dvn/src/auth.rs +108 -30
- package/contracts/workers/dvn/src/dvn.rs +103 -33
- package/contracts/workers/dvn/src/errors.rs +10 -13
- package/contracts/workers/dvn/src/events.rs +7 -5
- package/contracts/workers/dvn/src/interfaces/dvn.rs +76 -3
- package/contracts/workers/dvn/src/interfaces/multisig.rs +41 -0
- package/contracts/workers/dvn/src/lib.rs +6 -8
- package/contracts/workers/dvn/src/multisig.rs +98 -72
- package/contracts/workers/dvn/src/storage.rs +9 -12
- package/contracts/workers/dvn/src/tests/auth.rs +56 -26
- package/contracts/workers/dvn/src/tests/dvn.rs +40 -41
- package/contracts/workers/dvn/src/tests/multisig/set_signer.rs +8 -8
- package/contracts/workers/dvn/src/tests/multisig/set_threshold.rs +9 -9
- package/contracts/workers/dvn/src/tests/multisig/verify_signatures.rs +6 -6
- package/contracts/workers/dvn/src/tests/setup.rs +5 -5
- package/contracts/workers/dvn-fee-lib/Cargo.toml +2 -1
- package/contracts/workers/dvn-fee-lib/src/dvn_fee_lib.rs +4 -3
- package/contracts/workers/dvn-fee-lib/src/tests/dvn_fee_lib.rs +8 -6
- package/contracts/workers/executor/src/auth.rs +93 -0
- package/contracts/workers/executor/src/events.rs +5 -4
- package/contracts/workers/executor/src/{lz_executor.rs → executor.rs} +30 -103
- package/contracts/workers/executor/src/interfaces/executor.rs +5 -2
- package/contracts/workers/executor/src/interfaces/mod.rs +1 -1
- package/contracts/workers/executor/src/lib.rs +6 -5
- package/contracts/workers/price-feed/Cargo.toml +21 -0
- package/contracts/workers/price-feed/src/errors.rs +9 -0
- package/contracts/workers/price-feed/src/events.rs +30 -0
- package/contracts/workers/price-feed/src/lib.rs +11 -0
- package/contracts/workers/price-feed/src/price_feed.rs +265 -0
- package/contracts/workers/price-feed/src/storage.rs +42 -0
- package/contracts/workers/price-feed/src/types.rs +59 -0
- package/contracts/workers/worker/src/events.rs +23 -13
- package/contracts/workers/worker/src/interfaces/dvn_fee_lib.rs +2 -1
- package/contracts/workers/worker/src/worker.rs +32 -21
- package/package.json +3 -3
- package/sdk/dist/generated/bml.js +24 -22
- package/sdk/dist/generated/counter.d.ts +102 -0
- package/sdk/dist/generated/counter.js +36 -24
- package/sdk/dist/generated/endpoint.js +24 -22
- package/sdk/dist/generated/sml.js +24 -22
- package/sdk/dist/generated/uln302.d.ts +1 -1
- package/sdk/dist/generated/uln302.js +34 -32
- package/sdk/package.json +1 -1
- package/sdk/test/index.test.ts +1 -1
- package/sdk/test/oft.test.ts +847 -0
- package/sdk/test/suites/scan.ts +20 -4
- package/tools/ts-bindings-gen/src/main.rs +2 -1
- package/contracts/common-macros/src/event.rs +0 -16
- package/contracts/oapps/oft/src/macro_tests/mod.rs +0 -2
- package/contracts/oapps/oft/src/macro_tests/test_all_default.rs +0 -41
- package/contracts/oapps/oft/src/macro_tests/test_override.rs +0 -83
- package/contracts/oapps/oft-mint-burn/src/lib.rs +0 -3
- package/contracts/oapps/oft-mint-burn/src/oft.rs +0 -28
- package/contracts/oapps/oft-mint-burn/src/tests/mod.rs +0 -1
- package/contracts/workers/dvn/src/types.rs +0 -26
- /package/contracts/message-libs/{block-message-lib → blocked-message-lib}/src/lib.rs +0 -0
|
@@ -110,8 +110,15 @@ pub struct TestMintBurnOFT;
|
|
|
110
110
|
|
|
111
111
|
#[contractimpl]
|
|
112
112
|
impl TestMintBurnOFT {
|
|
113
|
-
pub fn __constructor(
|
|
114
|
-
|
|
113
|
+
pub fn __constructor(
|
|
114
|
+
env: &Env,
|
|
115
|
+
token: &Address,
|
|
116
|
+
owner: &Address,
|
|
117
|
+
endpoint: &Address,
|
|
118
|
+
delegate: &Option<Address>,
|
|
119
|
+
shared_decimals: u32,
|
|
120
|
+
) {
|
|
121
|
+
oft_initialize::<Self>(env, owner, token, endpoint, delegate, shared_decimals)
|
|
115
122
|
}
|
|
116
123
|
}
|
|
117
124
|
|
|
@@ -134,8 +141,15 @@ pub struct TestLockUnlockOFT;
|
|
|
134
141
|
|
|
135
142
|
#[contractimpl]
|
|
136
143
|
impl TestLockUnlockOFT {
|
|
137
|
-
pub fn __constructor(
|
|
138
|
-
|
|
144
|
+
pub fn __constructor(
|
|
145
|
+
env: &Env,
|
|
146
|
+
token: &Address,
|
|
147
|
+
owner: &Address,
|
|
148
|
+
endpoint: &Address,
|
|
149
|
+
delegate: &Option<Address>,
|
|
150
|
+
shared_decimals: u32,
|
|
151
|
+
) {
|
|
152
|
+
oft_initialize::<Self>(env, owner, token, endpoint, delegate, shared_decimals)
|
|
139
153
|
}
|
|
140
154
|
}
|
|
141
155
|
|
|
@@ -477,8 +491,12 @@ impl<'a> OFTTestSetupBuilder<'a> {
|
|
|
477
491
|
// Register OFT based on type
|
|
478
492
|
let delegate: Option<Address> = Some(owner.clone());
|
|
479
493
|
let oft_address = match oft_type {
|
|
480
|
-
OFTType::MintBurn =>
|
|
481
|
-
|
|
494
|
+
OFTType::MintBurn => {
|
|
495
|
+
env.register(TestMintBurnOFT, (&token, &owner, &endpoint_address, &delegate, &self.shared_decimals))
|
|
496
|
+
}
|
|
497
|
+
OFTType::LockUnlock => {
|
|
498
|
+
env.register(TestLockUnlockOFT, (&token, &owner, &endpoint_address, &delegate, &self.shared_decimals))
|
|
499
|
+
}
|
|
482
500
|
};
|
|
483
501
|
let oft = OFTClient::new(env, &oft_address);
|
|
484
502
|
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
[package]
|
|
2
|
-
name = "oft-
|
|
2
|
+
name = "oft-std"
|
|
3
3
|
version.workspace = true
|
|
4
4
|
edition.workspace = true
|
|
5
5
|
license.workspace = true
|
|
@@ -17,10 +17,3 @@ common-macros = { workspace = true }
|
|
|
17
17
|
oapp-macros = { workspace = true }
|
|
18
18
|
oft = { workspace = true }
|
|
19
19
|
|
|
20
|
-
[dev-dependencies]
|
|
21
|
-
soroban-sdk = { workspace = true, features = ["testutils"] }
|
|
22
|
-
assert_unordered = "0.3.5"
|
|
23
|
-
simple-message-lib = { workspace = true }
|
|
24
|
-
message-lib-common = { workspace = true, features = ["testutils"] }
|
|
25
|
-
endpoint-v2 = { workspace = true, features = ["testutils"] }
|
|
26
|
-
executor = { workspace = true, features = ["testutils"] }
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
use common_macros::{contract_impl, storage};
|
|
2
|
+
use oapp_macros::oapp;
|
|
3
|
+
use oft::oft::{oft_initialize, OFTInner, OFT};
|
|
4
|
+
use oft::oft_types::{lock_unlock, mint_burn};
|
|
5
|
+
use oft::types::OFTReceipt;
|
|
6
|
+
use soroban_sdk::{Address, Env};
|
|
7
|
+
|
|
8
|
+
#[storage]
|
|
9
|
+
enum OFTStdStorage {
|
|
10
|
+
#[instance(bool)]
|
|
11
|
+
IsLockUnlock,
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
#[oapp]
|
|
15
|
+
pub struct OFTStd;
|
|
16
|
+
|
|
17
|
+
#[contract_impl]
|
|
18
|
+
impl OFTStd {
|
|
19
|
+
pub fn __constructor(
|
|
20
|
+
env: &Env,
|
|
21
|
+
token: &Address,
|
|
22
|
+
owner: &Address,
|
|
23
|
+
endpoint: &Address,
|
|
24
|
+
delegate: &Option<Address>,
|
|
25
|
+
shared_decimals: u32,
|
|
26
|
+
is_lock_unlock: bool,
|
|
27
|
+
) {
|
|
28
|
+
oft_initialize::<Self>(env, owner, token, endpoint, delegate, shared_decimals);
|
|
29
|
+
OFTStdStorage::set_is_lock_unlock(env, &is_lock_unlock);
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
/// Whether this OFT uses lock/unlock mode (true) or mint/burn mode (false)
|
|
33
|
+
pub fn is_lock_unlock(env: &Env) -> bool {
|
|
34
|
+
OFTStdStorage::is_lock_unlock(env).unwrap()
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
/// OFT trait implementation for standard OFT
|
|
39
|
+
#[contract_impl(contracttrait)]
|
|
40
|
+
impl OFT for OFTStd {}
|
|
41
|
+
|
|
42
|
+
/// OFT behavior for standard OFT
|
|
43
|
+
impl OFTInner for OFTStd {
|
|
44
|
+
fn __debit(env: &Env, sender: &Address, amount_ld: i128, min_amount_ld: i128, dst_eid: u32) -> OFTReceipt {
|
|
45
|
+
if Self::is_lock_unlock(env) {
|
|
46
|
+
lock_unlock::debit::<Self>(env, sender, amount_ld, min_amount_ld, dst_eid)
|
|
47
|
+
} else {
|
|
48
|
+
mint_burn::debit::<Self>(env, sender, amount_ld, min_amount_ld, dst_eid)
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
fn __credit(env: &Env, to: &Address, amount_ld: i128, src_eid: u32) -> i128 {
|
|
53
|
+
if Self::is_lock_unlock(env) {
|
|
54
|
+
lock_unlock::credit::<Self>(env, to, amount_ld, src_eid)
|
|
55
|
+
} else {
|
|
56
|
+
mint_burn::credit::<Self>(env, to, amount_ld, src_eid)
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
use crate::errors::OwnableError;
|
|
2
2
|
use crate::option_ext::OptionExt;
|
|
3
|
-
use common_macros::
|
|
4
|
-
use soroban_sdk::{assert_with_error, contractclient, Address, Env};
|
|
3
|
+
use common_macros::storage;
|
|
4
|
+
use soroban_sdk::{assert_with_error, contractclient, contractevent, Address, Env};
|
|
5
5
|
|
|
6
6
|
// ============================================
|
|
7
7
|
// Ownable Initializer Interface
|
|
@@ -44,14 +44,16 @@ pub fn require_owner_auth<T: Ownable>(env: &Env) {
|
|
|
44
44
|
}
|
|
45
45
|
|
|
46
46
|
/// Event emitted when ownership is transferred.
|
|
47
|
-
#[
|
|
47
|
+
#[contractevent]
|
|
48
|
+
#[derive(Clone, Debug, Eq, PartialEq)]
|
|
48
49
|
pub struct OwnershipTransferred {
|
|
49
50
|
pub old_owner: Address,
|
|
50
51
|
pub new_owner: Address,
|
|
51
52
|
}
|
|
52
53
|
|
|
53
54
|
/// Event emitted when ownership is renounced.
|
|
54
|
-
#[
|
|
55
|
+
#[contractevent]
|
|
56
|
+
#[derive(Clone, Debug, Eq, PartialEq)]
|
|
55
57
|
pub struct OwnershipRenounced {
|
|
56
58
|
pub old_owner: Address,
|
|
57
59
|
}
|
|
@@ -76,13 +78,13 @@ impl Ownable for DefaultOwnable {
|
|
|
76
78
|
}
|
|
77
79
|
|
|
78
80
|
fn transfer_ownership(env: &Env, new_owner: &Address) {
|
|
79
|
-
let old_owner =
|
|
81
|
+
let old_owner = Self::owner(env).unwrap_or_panic(env, OwnableError::OwnerNotSet);
|
|
80
82
|
DefaultOwnableStorage::set_owner(env, new_owner);
|
|
81
83
|
OwnershipTransferred { old_owner, new_owner: new_owner.clone() }.publish(env);
|
|
82
84
|
}
|
|
83
85
|
|
|
84
86
|
fn renounce_ownership(env: &Env) {
|
|
85
|
-
let old_owner =
|
|
87
|
+
let old_owner = Self::owner(env).unwrap_or_panic(env, OwnableError::OwnerNotSet);
|
|
86
88
|
DefaultOwnableStorage::remove_owner(env);
|
|
87
89
|
OwnershipRenounced { old_owner }.publish(env);
|
|
88
90
|
}
|
|
@@ -186,20 +186,6 @@ fn transfer_ownership_to_same_owner() {
|
|
|
186
186
|
assert_eq!(client.owner(), Some(owner));
|
|
187
187
|
}
|
|
188
188
|
|
|
189
|
-
#[test]
|
|
190
|
-
#[should_panic(expected = "Error(Auth, InvalidAction)")]
|
|
191
|
-
fn transfer_ownership_requires_auth() {
|
|
192
|
-
let env = Env::default();
|
|
193
|
-
let owner = Address::generate(&env);
|
|
194
|
-
let new_owner = Address::generate(&env);
|
|
195
|
-
|
|
196
|
-
let contract = env.register(Contract, (&owner,));
|
|
197
|
-
let client = ContractClient::new(&env, &contract);
|
|
198
|
-
|
|
199
|
-
// Try to transfer without auth should fail
|
|
200
|
-
client.transfer_ownership(&new_owner);
|
|
201
|
-
}
|
|
202
|
-
|
|
203
189
|
#[test]
|
|
204
190
|
#[should_panic(expected = "Error(Contract, #1301)")]
|
|
205
191
|
fn transfer_after_renounce_fails() {
|
|
@@ -264,19 +250,6 @@ fn renounce_ownership_with_event() {
|
|
|
264
250
|
assert_eq!(client.owner(), None);
|
|
265
251
|
}
|
|
266
252
|
|
|
267
|
-
#[test]
|
|
268
|
-
#[should_panic(expected = "Error(Auth, InvalidAction)")]
|
|
269
|
-
fn renounce_ownership_requires_auth() {
|
|
270
|
-
let env = Env::default();
|
|
271
|
-
let owner = Address::generate(&env);
|
|
272
|
-
|
|
273
|
-
let contract = env.register(Contract, (&owner,));
|
|
274
|
-
let client = ContractClient::new(&env, &contract);
|
|
275
|
-
|
|
276
|
-
// Try to renounce without auth should fail
|
|
277
|
-
client.renounce_ownership();
|
|
278
|
-
}
|
|
279
|
-
|
|
280
253
|
#[test]
|
|
281
254
|
#[should_panic(expected = "Error(Contract, #1301)")]
|
|
282
255
|
fn renounce_after_renounce_fails() {
|
|
@@ -352,42 +325,6 @@ fn chain_new_owner_can_transfer() {
|
|
|
352
325
|
assert_eq!(client.owner(), Some(third_owner));
|
|
353
326
|
}
|
|
354
327
|
|
|
355
|
-
#[test]
|
|
356
|
-
#[should_panic(expected = "Error(Auth, InvalidAction)")]
|
|
357
|
-
fn chain_old_owner_cannot_transfer_after_transfer() {
|
|
358
|
-
let env = Env::default();
|
|
359
|
-
let owner = Address::generate(&env);
|
|
360
|
-
let new_owner = Address::generate(&env);
|
|
361
|
-
let third_owner = Address::generate(&env);
|
|
362
|
-
|
|
363
|
-
let contract = env.register(Contract, (&owner,));
|
|
364
|
-
let client = ContractClient::new(&env, &contract);
|
|
365
|
-
|
|
366
|
-
// Transfer to new_owner
|
|
367
|
-
env.mock_auths(&[MockAuth {
|
|
368
|
-
address: &owner,
|
|
369
|
-
invoke: &MockAuthInvoke {
|
|
370
|
-
contract: &contract,
|
|
371
|
-
args: (&new_owner,).into_val(&env),
|
|
372
|
-
fn_name: "transfer_ownership",
|
|
373
|
-
sub_invokes: &[],
|
|
374
|
-
},
|
|
375
|
-
}]);
|
|
376
|
-
client.transfer_ownership(&new_owner);
|
|
377
|
-
|
|
378
|
-
// Old owner tries to transfer again - should fail
|
|
379
|
-
env.mock_auths(&[MockAuth {
|
|
380
|
-
address: &owner,
|
|
381
|
-
invoke: &MockAuthInvoke {
|
|
382
|
-
contract: &contract,
|
|
383
|
-
args: (&third_owner,).into_val(&env),
|
|
384
|
-
fn_name: "transfer_ownership",
|
|
385
|
-
sub_invokes: &[],
|
|
386
|
-
},
|
|
387
|
-
}]);
|
|
388
|
-
client.transfer_ownership(&third_owner);
|
|
389
|
-
}
|
|
390
|
-
|
|
391
328
|
// ============================================
|
|
392
329
|
// init: DefaultOwnable::init_owner tests
|
|
393
330
|
// ============================================
|
|
@@ -1,23 +1,25 @@
|
|
|
1
1
|
use crate::testing_utils::{assert_event, assert_events, ExpectedEvent, IntoExpectedEvent};
|
|
2
|
-
use
|
|
3
|
-
use soroban_sdk::{contract, contractimpl, testutils::Address as _, Address, Env, IntoVal, Val, Vec};
|
|
2
|
+
use soroban_sdk::{contract, contractevent, contractimpl, testutils::Address as _, Address, Env, IntoVal, Val, Vec};
|
|
4
3
|
|
|
5
4
|
// ============================================
|
|
6
5
|
// Test Fixtures
|
|
7
6
|
// ============================================
|
|
8
7
|
|
|
9
|
-
#[
|
|
8
|
+
#[contractevent]
|
|
9
|
+
#[derive(Clone, Debug, Eq, PartialEq)]
|
|
10
10
|
pub struct TestEvent1 {
|
|
11
11
|
pub value: u32,
|
|
12
12
|
}
|
|
13
13
|
|
|
14
|
-
#[
|
|
14
|
+
#[contractevent]
|
|
15
|
+
#[derive(Clone, Debug, Eq, PartialEq)]
|
|
15
16
|
pub struct TestEvent2 {
|
|
16
17
|
pub name: u32,
|
|
17
18
|
pub count: u64,
|
|
18
19
|
}
|
|
19
20
|
|
|
20
|
-
#[
|
|
21
|
+
#[contractevent]
|
|
22
|
+
#[derive(Clone, Debug, Eq, PartialEq)]
|
|
21
23
|
pub struct TestEvent3 {
|
|
22
24
|
pub address: Address,
|
|
23
25
|
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
use crate::errors::TtlError;
|
|
2
|
-
use soroban_sdk::{assert_with_error, contractclient, contracttype, Env};
|
|
2
|
+
use soroban_sdk::{assert_with_error, contractclient, contractevent, contracttype, Env};
|
|
3
3
|
|
|
4
4
|
/// Number of ledgers per day (~5 second ledger close time).
|
|
5
5
|
pub const LEDGERS_PER_DAY: u32 = (24 * 3600) / 5;
|
|
@@ -85,6 +85,8 @@ impl TtlConfigurable for DefaultTtlConfigurable {
|
|
|
85
85
|
|
|
86
86
|
TtlConfigStorage::set_or_remove_instance(env, instance);
|
|
87
87
|
TtlConfigStorage::set_or_remove_persistent(env, persistent);
|
|
88
|
+
|
|
89
|
+
TtlConfigsSet { instance: *instance, persistent: *persistent }.publish(env);
|
|
88
90
|
}
|
|
89
91
|
|
|
90
92
|
fn ttl_configs(env: &Env) -> (Option<TtlConfig>, Option<TtlConfig>) {
|
|
@@ -94,6 +96,8 @@ impl TtlConfigurable for DefaultTtlConfigurable {
|
|
|
94
96
|
fn freeze_ttl_configs(env: &Env) {
|
|
95
97
|
assert_with_error!(env, !Self::is_ttl_configs_frozen(env), TtlError::TtlConfigAlreadyFrozen);
|
|
96
98
|
TtlConfigStorage::set_frozen(env, &true);
|
|
99
|
+
|
|
100
|
+
TtlConfigsFrozen {}.publish(env);
|
|
97
101
|
}
|
|
98
102
|
|
|
99
103
|
fn is_ttl_configs_frozen(env: &Env) -> bool {
|
|
@@ -101,4 +105,19 @@ impl TtlConfigurable for DefaultTtlConfigurable {
|
|
|
101
105
|
}
|
|
102
106
|
}
|
|
103
107
|
|
|
104
|
-
//
|
|
108
|
+
// ============================================
|
|
109
|
+
// Events
|
|
110
|
+
// ============================================
|
|
111
|
+
|
|
112
|
+
/// Event emitted when TTL configs are set.
|
|
113
|
+
#[contractevent]
|
|
114
|
+
#[derive(Clone, Debug, Eq, PartialEq)]
|
|
115
|
+
pub struct TtlConfigsSet {
|
|
116
|
+
pub instance: Option<TtlConfig>,
|
|
117
|
+
pub persistent: Option<TtlConfig>,
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
/// Event emitted when TTL configs are frozen.
|
|
121
|
+
#[contractevent]
|
|
122
|
+
#[derive(Clone, Debug, Eq, PartialEq)]
|
|
123
|
+
pub struct TtlConfigsFrozen {}
|
|
@@ -1,66 +1,144 @@
|
|
|
1
|
-
use
|
|
1
|
+
use super::*;
|
|
2
|
+
|
|
2
3
|
use soroban_sdk::{
|
|
3
4
|
address_payload::AddressPayload,
|
|
4
5
|
auth::{Context, CustomAccountInterface},
|
|
6
|
+
contractimpl, contracttype,
|
|
7
|
+
crypto::Hash,
|
|
8
|
+
vec, Symbol,
|
|
5
9
|
};
|
|
6
10
|
|
|
11
|
+
// ============================================================================
|
|
12
|
+
// Authentication Data Types
|
|
13
|
+
// ============================================================================
|
|
14
|
+
|
|
15
|
+
#[contracttype]
|
|
16
|
+
#[derive(Clone, Debug, Eq, PartialEq)]
|
|
17
|
+
pub enum Sender {
|
|
18
|
+
/// No explicit sender (permissionless execution).
|
|
19
|
+
None,
|
|
20
|
+
/// A registered admin (ed25519) submitting the transaction.
|
|
21
|
+
/// The tuple is `(public_key, signature)` where the signature covers the Soroban payload.
|
|
22
|
+
Admin(BytesN<32>, BytesN<64>),
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
/// Authentication data for DVN contract transactions.
|
|
26
|
+
///
|
|
27
|
+
/// This struct is used with Soroban's custom account interface to authorize
|
|
28
|
+
/// transactions through a combination of admin signature and multisig quorum.
|
|
29
|
+
#[contracttype]
|
|
30
|
+
#[derive(Clone, Debug, Eq, PartialEq)]
|
|
31
|
+
pub struct TransactionAuthData {
|
|
32
|
+
/// Verifier ID - must match the DVN's configured VID.
|
|
33
|
+
pub vid: u32,
|
|
34
|
+
/// Expiration timestamp (ledger time) after which this auth is invalid.
|
|
35
|
+
pub expiration: u64,
|
|
36
|
+
/// Signatures from multisig signers (secp256k1, 65 bytes each).
|
|
37
|
+
pub signatures: Vec<BytesN<65>>,
|
|
38
|
+
/// Entity submitting the transaction (admin, or permissionless).
|
|
39
|
+
pub sender: Sender,
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
// ============================================================================
|
|
43
|
+
// Custom Account Interface Implementation
|
|
44
|
+
// ============================================================================
|
|
45
|
+
|
|
7
46
|
#[contractimpl]
|
|
8
|
-
impl CustomAccountInterface for
|
|
47
|
+
impl CustomAccountInterface for LzDVN {
|
|
9
48
|
type Signature = TransactionAuthData;
|
|
10
49
|
type Error = DvnError;
|
|
11
50
|
|
|
12
|
-
|
|
51
|
+
/// Validates authorization for DVN contract operations.
|
|
13
52
|
fn __check_auth(
|
|
14
53
|
env: Env,
|
|
15
54
|
signature_payload: Hash<32>,
|
|
16
55
|
auth_data: Self::Signature,
|
|
17
56
|
auth_contexts: Vec<Context>,
|
|
18
57
|
) -> Result<(), Self::Error> {
|
|
19
|
-
let TransactionAuthData { vid, expiration, signatures,
|
|
20
|
-
|
|
21
|
-
verify_admin(&env, &admin, &admin_signature, &signature_payload)?;
|
|
58
|
+
let TransactionAuthData { vid, expiration, signatures, sender } = auth_data;
|
|
22
59
|
|
|
23
|
-
|
|
24
|
-
if vid !=
|
|
60
|
+
// 1. Check VID and expiration
|
|
61
|
+
if vid != Self::vid(&env) {
|
|
25
62
|
return Err(DvnError::InvalidVid);
|
|
26
63
|
}
|
|
27
|
-
|
|
28
64
|
if expiration <= env.ledger().timestamp() {
|
|
29
65
|
return Err(DvnError::AuthDataExpired);
|
|
30
66
|
}
|
|
31
67
|
|
|
32
|
-
|
|
68
|
+
// 2. Admin verification (skip for quorum_change_admin)
|
|
69
|
+
if !Self::is_invoking_quorum_change_admin(&env, &auth_contexts) {
|
|
70
|
+
let Sender::Admin(public_key, signature) = sender else {
|
|
71
|
+
return Err(DvnError::OnlyAdmin);
|
|
72
|
+
};
|
|
73
|
+
Self::verify_admin_signature(&env, &public_key, &signature, &signature_payload)?;
|
|
74
|
+
}
|
|
33
75
|
|
|
76
|
+
// 3. Replay protection
|
|
77
|
+
let calls = Self::extract_execution_calls(&env, &auth_contexts)?;
|
|
78
|
+
let hash = Self::hash_call_data(&env, vid, expiration, &calls);
|
|
34
79
|
if DvnStorage::used_hash(&env, &hash) {
|
|
35
80
|
return Err(DvnError::HashAlreadyUsed);
|
|
36
81
|
}
|
|
37
|
-
|
|
38
|
-
Dvn::verify_signatures(&env, &hash, &signatures);
|
|
39
|
-
|
|
40
82
|
DvnStorage::set_used_hash(&env, &hash, &true);
|
|
41
83
|
|
|
84
|
+
// 4. Multisig verification (most expensive - do last)
|
|
85
|
+
Self::verify_signatures(&env, &hash, &signatures);
|
|
86
|
+
|
|
42
87
|
Ok(())
|
|
43
88
|
}
|
|
44
89
|
}
|
|
45
90
|
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
admin_signature: &BytesN<64>,
|
|
50
|
-
signature_payload: &Hash<32>,
|
|
51
|
-
) -> Result<(), DvnError> {
|
|
52
|
-
let admin_address = Address::from_payload(env, AddressPayload::AccountIdPublicKeyEd25519(admin.clone()));
|
|
53
|
-
if !Dvn::is_admin(env, &admin_address) {
|
|
54
|
-
return Err(DvnError::OnlyAdmin);
|
|
55
|
-
}
|
|
91
|
+
// ============================================================================
|
|
92
|
+
// Internal Helper Functions
|
|
93
|
+
// ============================================================================
|
|
56
94
|
|
|
57
|
-
|
|
95
|
+
impl LzDVN {
|
|
96
|
+
/// Verifies that the admin signature is valid and from a registered admin.
|
|
97
|
+
///
|
|
98
|
+
/// # Arguments
|
|
99
|
+
/// * `public_key` - The admin's Ed25519 public key (32 bytes)
|
|
100
|
+
/// * `signature` - The admin's signature over the signature payload (64 bytes)
|
|
101
|
+
/// * `signature_payload` - The payload that was signed
|
|
102
|
+
///
|
|
103
|
+
/// # Errors
|
|
104
|
+
/// Returns `DvnError::OnlyAdmin` if the signer is not a registered admin.
|
|
105
|
+
fn verify_admin_signature(
|
|
106
|
+
env: &Env,
|
|
107
|
+
public_key: &BytesN<32>,
|
|
108
|
+
signature: &BytesN<64>,
|
|
109
|
+
signature_payload: &Hash<32>,
|
|
110
|
+
) -> Result<(), DvnError> {
|
|
111
|
+
let admin_address = Address::from_payload(env, AddressPayload::AccountIdPublicKeyEd25519(public_key.clone()));
|
|
112
|
+
if !Self::is_admin(env, &admin_address) {
|
|
113
|
+
return Err(DvnError::OnlyAdmin);
|
|
114
|
+
}
|
|
58
115
|
|
|
59
|
-
|
|
60
|
-
}
|
|
116
|
+
env.crypto().ed25519_verify(public_key, &signature_payload.clone().into(), signature);
|
|
61
117
|
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
118
|
+
Ok(())
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
/// Extracts the execution calls from the auth contexts.
|
|
122
|
+
fn extract_execution_calls(env: &Env, auth_contexts: &Vec<Context>) -> Result<Vec<Call>, DvnError> {
|
|
123
|
+
auth_contexts.iter().try_fold(vec![env], |mut calls, context| {
|
|
124
|
+
let Context::Contract(ctx) = context else {
|
|
125
|
+
return Err(DvnError::NonContractInvoke);
|
|
126
|
+
};
|
|
127
|
+
calls.push_back(Call { to: ctx.contract, func: ctx.fn_name, args: ctx.args });
|
|
128
|
+
Ok(calls)
|
|
129
|
+
})
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
/// Checks if the auth context is for `quorum_change_admin` on this contract.
|
|
133
|
+
/// This function doesn't require admin verification (quorum-only).
|
|
134
|
+
fn is_invoking_quorum_change_admin(env: &Env, auth_contexts: &Vec<Context>) -> bool {
|
|
135
|
+
// Must be exactly one call (no bundling with other operations)
|
|
136
|
+
if auth_contexts.len() != 1 {
|
|
137
|
+
return false;
|
|
138
|
+
}
|
|
139
|
+
let Context::Contract(ctx) = auth_contexts.first().unwrap() else {
|
|
140
|
+
return false;
|
|
141
|
+
};
|
|
142
|
+
ctx.contract == env.current_contract_address() && ctx.fn_name == Symbol::new(env, "quorum_change_admin")
|
|
143
|
+
}
|
|
66
144
|
}
|