@layerzerolabs/protocol-stellar-v2 0.2.51 → 0.2.53

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.
Files changed (55) hide show
  1. package/.turbo/turbo-build.log +281 -185
  2. package/.turbo/turbo-lint.log +69 -70
  3. package/.turbo/turbo-test.log +2010 -1754
  4. package/Cargo.lock +16 -0
  5. package/Cargo.toml +1 -0
  6. package/contracts/oapps/console-oft/Cargo.toml +30 -0
  7. package/contracts/oapps/console-oft/integration-tests/extensions/mod.rs +5 -0
  8. package/contracts/oapps/console-oft/integration-tests/extensions/test_combined.rs +90 -0
  9. package/contracts/oapps/console-oft/integration-tests/extensions/test_oft_fee.rs +186 -0
  10. package/contracts/oapps/console-oft/integration-tests/extensions/test_ownership.rs +161 -0
  11. package/contracts/oapps/console-oft/integration-tests/extensions/test_pausable.rs +154 -0
  12. package/contracts/oapps/console-oft/integration-tests/extensions/test_rate_limiter.rs +479 -0
  13. package/contracts/oapps/console-oft/integration-tests/mod.rs +3 -0
  14. package/contracts/oapps/console-oft/integration-tests/setup.rs +303 -0
  15. package/contracts/oapps/console-oft/integration-tests/utils.rs +685 -0
  16. package/contracts/oapps/console-oft/src/errors.rs +7 -0
  17. package/contracts/oapps/console-oft/src/extensions/mod.rs +3 -0
  18. package/contracts/oapps/console-oft/src/extensions/oft_fee.rs +239 -0
  19. package/contracts/oapps/console-oft/src/extensions/pausable.rs +185 -0
  20. package/contracts/oapps/console-oft/src/extensions/rate_limiter.rs +478 -0
  21. package/contracts/oapps/console-oft/src/interfaces/mintable.rs +14 -0
  22. package/contracts/oapps/console-oft/src/interfaces/mod.rs +3 -0
  23. package/contracts/oapps/console-oft/src/lib.rs +26 -0
  24. package/contracts/oapps/console-oft/src/oft.rs +208 -0
  25. package/contracts/oapps/console-oft/src/oft_access_control.rs +93 -0
  26. package/contracts/oapps/console-oft/src/oft_types/lock_unlock.rs +50 -0
  27. package/contracts/oapps/console-oft/src/oft_types/mint_burn.rs +50 -0
  28. package/contracts/oapps/console-oft/src/oft_types/mod.rs +24 -0
  29. package/contracts/oapps/console-oft/src/tests/extensions/mod.rs +3 -0
  30. package/contracts/oapps/console-oft/src/tests/extensions/oft_fee.rs +255 -0
  31. package/contracts/oapps/console-oft/src/tests/extensions/pausable.rs +212 -0
  32. package/contracts/oapps/console-oft/src/tests/extensions/rate_limiter.rs +992 -0
  33. package/contracts/oapps/console-oft/src/tests/mod.rs +2 -0
  34. package/contracts/oapps/console-oft/src/tests/oft_types/lock_unlock.rs +185 -0
  35. package/contracts/oapps/console-oft/src/tests/oft_types/mod.rs +1 -0
  36. package/contracts/oapps/oft/src/extensions/oft_fee.rs +5 -2
  37. package/contracts/oapps/oft/src/tests/extensions/oft_fee.rs +1 -1
  38. package/contracts/oapps/sac-manager/src/sac_manager.rs +8 -0
  39. package/contracts/workers/worker/src/worker.rs +8 -1
  40. package/docs/oft-guide.md +2 -2
  41. package/package.json +4 -4
  42. package/sdk/.turbo/turbo-test.log +359 -423
  43. package/sdk/dist/generated/dvn.d.ts +9 -3
  44. package/sdk/dist/generated/dvn.js +4 -4
  45. package/sdk/dist/generated/executor.d.ts +9 -3
  46. package/sdk/dist/generated/executor.js +4 -4
  47. package/sdk/package.json +1 -1
  48. package/sdk/test/oft-sml.test.ts +22 -41
  49. package/sdk/test/sac-manager.test.ts +23 -22
  50. package/sdk/test/secp256k1.ts +59 -0
  51. package/sdk/test/suites/constants.ts +5 -1
  52. package/sdk/test/suites/deploy.ts +14 -8
  53. package/sdk/test/suites/globalSetup.ts +144 -60
  54. package/sdk/test/suites/localnet.ts +20 -25
  55. package/sdk/test/utils.ts +1 -61
@@ -0,0 +1,2 @@
1
+ mod extensions;
2
+ mod oft_types;
@@ -0,0 +1,185 @@
1
+ extern crate std;
2
+
3
+ use crate::oft_types::lock_unlock;
4
+ use endpoint_v2::Origin;
5
+ use oapp::oapp_receiver::{LzReceiveInternal, OAppReceiver};
6
+ use oft_core::{OFTCore, OFTInternal, OFTReceipt};
7
+ use soroban_sdk::{
8
+ contract, contractimpl, contracttype,
9
+ testutils::Address as _,
10
+ token::{StellarAssetClient, TokenClient},
11
+ Address, Bytes, BytesN, Env,
12
+ };
13
+
14
+ // ============================================================================
15
+ // Mock Contracts
16
+ // ============================================================================
17
+
18
+ #[contract]
19
+ struct DummyEndpoint;
20
+
21
+ #[derive(Clone)]
22
+ #[contracttype]
23
+ enum DummyEndpointDataKey {
24
+ Delegate(Address),
25
+ }
26
+
27
+ #[contractimpl]
28
+ impl DummyEndpoint {
29
+ pub fn set_delegate(env: Env, oapp: &Address, delegate: &Option<Address>) {
30
+ let key = DummyEndpointDataKey::Delegate(oapp.clone());
31
+ match delegate {
32
+ Some(d) => env.storage().persistent().set(&key, d),
33
+ None => env.storage().persistent().remove(&key),
34
+ }
35
+ }
36
+ }
37
+
38
+ // ============================================================================
39
+ // LockUnlock OFT Harness Contract
40
+ // ============================================================================
41
+
42
+ #[common_macros::lz_contract]
43
+ #[oapp_macros::oapp(custom = [receiver])]
44
+ pub struct LockUnlockHarnessOFT;
45
+
46
+ #[contractimpl]
47
+ impl LockUnlockHarnessOFT {
48
+ pub fn __constructor(
49
+ env: &Env,
50
+ token: &Address,
51
+ owner: &Address,
52
+ endpoint: &Address,
53
+ delegate: &Address,
54
+ shared_decimals: u32,
55
+ ) {
56
+ Self::__initialize_oft(env, token, shared_decimals, owner, endpoint, delegate);
57
+ }
58
+
59
+ pub fn debit(env: Env, sender: Address, amount_ld: i128, min_amount_ld: i128, dst_eid: u32) -> OFTReceipt {
60
+ let (amount_sent_ld, amount_received_ld) =
61
+ <Self as OFTInternal>::__debit(&env, &sender, amount_ld, min_amount_ld, dst_eid);
62
+ OFTReceipt { amount_sent_ld, amount_received_ld }
63
+ }
64
+
65
+ pub fn credit(env: Env, to: Address, amount_ld: i128, src_eid: u32) -> i128 {
66
+ <Self as OFTInternal>::__credit(&env, &to, amount_ld, src_eid)
67
+ }
68
+ }
69
+
70
+ #[contractimpl(contracttrait)]
71
+ impl OFTCore for LockUnlockHarnessOFT {}
72
+
73
+ impl LzReceiveInternal for LockUnlockHarnessOFT {
74
+ fn __lz_receive(
75
+ env: &Env,
76
+ origin: &Origin,
77
+ guid: &BytesN<32>,
78
+ message: &Bytes,
79
+ extra_data: &Bytes,
80
+ executor: &Address,
81
+ value: i128,
82
+ ) {
83
+ <Self as OFTInternal>::__receive(env, origin, guid, message, extra_data, executor, value)
84
+ }
85
+ }
86
+
87
+ #[contractimpl(contracttrait)]
88
+ impl OAppReceiver for LockUnlockHarnessOFT {}
89
+
90
+ impl OFTInternal for LockUnlockHarnessOFT {
91
+ fn __debit(env: &Env, sender: &Address, amount_ld: i128, min_amount_ld: i128, dst_eid: u32) -> (i128, i128) {
92
+ let target = Self::token(env);
93
+ lock_unlock::debit::<Self>(env, &target, sender, amount_ld, min_amount_ld, dst_eid)
94
+ }
95
+
96
+ fn __credit(env: &Env, to: &Address, amount_ld: i128, src_eid: u32) -> i128 {
97
+ let target = Self::token(env);
98
+ lock_unlock::credit::<Self>(env, &target, to, amount_ld, src_eid)
99
+ }
100
+ }
101
+
102
+ // ============================================================================
103
+ // Test Setup
104
+ // ============================================================================
105
+
106
+ struct TestSetup {
107
+ env: Env,
108
+ client: LockUnlockHarnessOFTClient<'static>,
109
+ oft_address: Address,
110
+ token: Address,
111
+ }
112
+
113
+ fn setup() -> TestSetup {
114
+ let env = Env::default();
115
+ // Enable mock_all_auths_allowing_non_root_auth for all tests to bypass authorization checks
116
+ // including sub-contract invocations like token transfers
117
+ env.mock_all_auths_allowing_non_root_auth();
118
+
119
+ let token_admin = Address::generate(&env);
120
+ let sac = env.register_stellar_asset_contract_v2(token_admin.clone());
121
+ let token = sac.address();
122
+ let endpoint = env.register(DummyEndpoint, ());
123
+
124
+ let owner = Address::generate(&env);
125
+ let delegate = owner.clone();
126
+ let shared_decimals: u32 = 6;
127
+
128
+ let oft_address = env.register(LockUnlockHarnessOFT, (&token, &owner, &endpoint, &delegate, &shared_decimals));
129
+ let client = LockUnlockHarnessOFTClient::new(&env, &oft_address);
130
+
131
+ TestSetup { env, client, oft_address, token }
132
+ }
133
+
134
+ // ============================================================================
135
+ // Tests
136
+ // ============================================================================
137
+
138
+ #[test]
139
+ fn test_debit_transfers_to_contract() {
140
+ let TestSetup { env, client, oft_address, token, .. } = setup();
141
+
142
+ let sender = Address::generate(&env);
143
+
144
+ // Auth is automatically mocked by mock_all_auths_allowing_non_root_auth
145
+ StellarAssetClient::new(&env, &token).mint(&sender, &1_000_000i128);
146
+
147
+ let token_client = TokenClient::new(&env, &token);
148
+ let sender_before = token_client.balance(&sender);
149
+ let contract_before = token_client.balance(&oft_address);
150
+
151
+ // With shared_decimals=6 and typical SAC decimals=7, conversion_rate=10 => 105 -> 100.
152
+ // debit transfers from sender to OFT contract
153
+ let amount_ld = 105i128;
154
+
155
+ let receipt = client.debit(&sender, &amount_ld, &0i128, &999u32);
156
+ assert_eq!(receipt.amount_sent_ld, receipt.amount_received_ld);
157
+
158
+ // LockUnlock transfers `amount_received_ld` from sender -> contract.
159
+ assert_eq!(token_client.balance(&sender), sender_before - receipt.amount_received_ld);
160
+ assert_eq!(token_client.balance(&oft_address), contract_before + receipt.amount_received_ld);
161
+ }
162
+
163
+ #[test]
164
+ fn test_credit_transfers_from_contract() {
165
+ let TestSetup { env, client, oft_address, token, .. } = setup();
166
+
167
+ let recipient = Address::generate(&env);
168
+
169
+ // Auth is automatically mocked by mock_all_auths_allowing_non_root_auth
170
+ StellarAssetClient::new(&env, &token).mint(&oft_address, &1_000_000i128);
171
+
172
+ let token_client = TokenClient::new(&env, &token);
173
+ let contract_before = token_client.balance(&oft_address);
174
+ let recipient_before = token_client.balance(&recipient);
175
+
176
+ // credit transfers from OFT contract to recipient
177
+ let amount = 123i128;
178
+
179
+ let credited = client.credit(&recipient, &amount, &1u32);
180
+ assert_eq!(credited, amount);
181
+
182
+ // LockUnlock transfers `amount` from contract -> recipient.
183
+ assert_eq!(token_client.balance(&oft_address), contract_before - amount);
184
+ assert_eq!(token_client.balance(&recipient), recipient_before + amount);
185
+ }
@@ -0,0 +1 @@
1
+ mod lock_unlock;
@@ -1,8 +1,11 @@
1
1
  use common_macros::{contract_error, contract_trait, only_role, storage};
2
2
  use soroban_sdk::{assert_with_error, contractevent, token::TokenClient, Address, Env};
3
- use utils::{option_ext::OptionExt, rbac::{RoleBasedAccessControl, AUTHORIZER}};
3
+ use utils::{
4
+ option_ext::OptionExt,
5
+ rbac::{RoleBasedAccessControl, AUTHORIZER},
6
+ };
4
7
 
5
- /// Role for fee configuration (set_default_fee_bps, set_fee_bps, set_fee_deposit_address).
8
+ /// Role for fee configuration (set_default_fee_bps, set_fee_bps).
6
9
  pub const FEE_CONFIG_MANAGER_ROLE: &str = "FEE_CONFIG_MANAGER_ROLE";
7
10
 
8
11
  /// Base fee in basis points (10,000 BPS = 100%)
@@ -1,7 +1,7 @@
1
1
  extern crate std;
2
2
 
3
- use crate::extensions::oft_fee::{OFTFee, OFTFeeError, OFTFeeInternal};
4
3
  use crate::extensions::oft_fee::FEE_CONFIG_MANAGER_ROLE;
4
+ use crate::extensions::oft_fee::{OFTFee, OFTFeeError, OFTFeeInternal};
5
5
  use soroban_sdk::{
6
6
  contract, contractimpl,
7
7
  testutils::{Address as _, MockAuth, MockAuthInvoke},
@@ -4,6 +4,14 @@
4
4
  //! - Mintable interface for OFT (mint on credit only; OFT burns on the token directly)
5
5
  //! - Role-based access control operations (clawback, set_admin, set_authorized)
6
6
  //!
7
+ //! ## Trust Model Requirement
8
+ //!
9
+ //! **The issuer account must be locked (master weight set to 0).** In Stellar classic assets,
10
+ //! transfers from/to the issuer are equivalent to minting/burning. The issuer can always mint
11
+ //! more tokens and perform other classic operations directly, even when an explicit admin (this
12
+ //! contract) is set. If the issuer account is not locked, the RBAC model enforced by this
13
+ //! contract can be bypassed, breaking the trust model.
14
+ //!
7
15
  //! ## Authorization Model
8
16
  //!
9
17
  //! - **Owner** (via Ownable): The deployer/admin address. Can manage TTL and grant/revoke roles.
@@ -46,6 +46,12 @@ pub trait Worker: Auth {
46
46
  /// Admins can configure worker settings like fee multipliers, deposit addresses,
47
47
  /// and supported option types.
48
48
  ///
49
+ /// **Address type requirement:** Admins used for execute/compose flows (Executor)
50
+ /// or custom account auth (DVN) must be Ed25519 accounts. Contract-type addresses
51
+ /// cannot participate in custom account authorization. Only Ed25519 account
52
+ /// addresses can sign for execute/compose and DVN admin operations. Contract-type
53
+ /// admins are not supported for these flows;
54
+ ///
49
55
  /// # Arguments
50
56
  /// * `admin` - The address to set admin status for
51
57
  /// * `active` - `true` to add admin, `false` to remove
@@ -306,7 +312,8 @@ pub trait Worker: Auth {
306
312
  /// This function should be called only once to initialize the worker once.
307
313
  ///
308
314
  /// # Arguments
309
- /// * `admins` - Initial admin addresses (must not be empty)
315
+ /// * `admins` - Initial admin addresses (must not be empty). Admins used for
316
+ /// execute/compose or custom account auth must be Ed25519 (see `set_admin`).
310
317
  /// * `message_libs` - Supported message library addresses
311
318
  /// * `price_feed` - Price feed contract address
312
319
  /// * `default_multiplier_bps` - Default fee multiplier in basis points
package/docs/oft-guide.md CHANGED
@@ -256,7 +256,7 @@ impl OFTFeeInternal for MyOFT {}
256
256
 
257
257
  // Override __debit_view to apply fee:
258
258
  fn __debit_view(env: &Env, amount_ld: i128, min_amount_ld: i128, dst_eid: u32) -> OFTReceipt {
259
- let fee = Self::__fee_view(env, dst_eid, amount_ld);
259
+ let fee = Self::__get_fee(env, dst_eid, amount_ld);
260
260
  let amount_after_fee = amount_ld - fee;
261
261
  // ... rest of logic
262
262
  }
@@ -267,7 +267,7 @@ Usage:
267
267
  ```rust
268
268
  oft.set_default_fee_bps(100); // 1% default fee (owner only)
269
269
  oft.set_fee_bps(dst_eid, Some(50)); // 0.5% for specific destination
270
- oft.set_fee_deposit_address(fee_addr); // Where fees go
270
+ oft.set_fee_deposit(fee_addr); // Where fees go
271
271
  ```
272
272
 
273
273
  ### Rate limiter
package/package.json CHANGED
@@ -1,15 +1,15 @@
1
1
  {
2
2
  "name": "@layerzerolabs/protocol-stellar-v2",
3
- "version": "0.2.51",
3
+ "version": "0.2.53",
4
4
  "private": false,
5
5
  "license": "LZBL-1.2",
6
6
  "devDependencies": {
7
7
  "@types/node": "^22.18.6",
8
8
  "tsx": "^4.19.3",
9
9
  "typescript": "^5.8.2",
10
- "@layerzerolabs/common-node-utils": "0.2.51",
11
- "@layerzerolabs/vm-tooling-stellar": "0.2.51",
12
- "@layerzerolabs/stellar-ts-bindings-gen": "0.2.51"
10
+ "@layerzerolabs/common-node-utils": "0.2.53",
11
+ "@layerzerolabs/stellar-ts-bindings-gen": "0.2.53",
12
+ "@layerzerolabs/vm-tooling-stellar": "0.2.53"
13
13
  },
14
14
  "publishConfig": {
15
15
  "access": "restricted",