@layerzerolabs/protocol-stellar-v2 0.2.18 → 0.2.20

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 (213) hide show
  1. package/.turbo/turbo-build.log +303 -253
  2. package/.turbo/turbo-lint.log +66 -65
  3. package/.turbo/turbo-test.log +1312 -1282
  4. package/Cargo.lock +21 -8
  5. package/Cargo.toml +2 -0
  6. package/contracts/ERROR_SPEC.md +9 -2
  7. package/contracts/common-macros/src/contract_ttl.rs +18 -7
  8. package/contracts/common-macros/src/lib.rs +4 -4
  9. package/contracts/common-macros/src/tests/contract_ttl.rs +1 -1
  10. package/contracts/common-macros/src/tests/snapshots/common_macros__tests__contract_ttl__snapshot_generated_contractimpl_code.snap +2 -1
  11. package/contracts/common-macros/src/tests/snapshots/common_macros__tests__upgradeable__snapshot_generated_upgradeable_code.snap +7 -12
  12. package/contracts/common-macros/src/upgradeable.rs +15 -21
  13. package/contracts/message-libs/uln-302/src/events.rs +4 -0
  14. package/contracts/message-libs/uln-302/src/send_uln.rs +23 -7
  15. package/contracts/message-libs/uln-302/src/tests/send_uln302/send.rs +38 -64
  16. package/contracts/oapps/counter/Cargo.toml +1 -0
  17. package/contracts/oapps/counter/integration_tests/setup_uln.rs +1 -1
  18. package/contracts/oapps/oapp/src/oapp_receiver.rs +1 -1
  19. package/contracts/oapps/oapp/src/tests/test_oapp_core.rs +113 -65
  20. package/contracts/oapps/oapp/src/tests/test_oapp_options_type3.rs +111 -82
  21. package/contracts/oapps/oapp/src/tests/test_oapp_receiver.rs +293 -65
  22. package/contracts/oapps/oapp/src/tests/test_oapp_sender.rs +331 -56
  23. package/contracts/oapps/oft/Cargo.toml +10 -7
  24. package/contracts/oapps/{oft-std → oft}/integration-tests/extensions/test_oft_fee.rs +3 -4
  25. package/contracts/oapps/{oft-std → oft}/integration-tests/extensions/test_pausable.rs +2 -3
  26. package/contracts/oapps/{oft-std → oft}/integration-tests/extensions/test_rate_limiter.rs +1 -1
  27. package/contracts/oapps/oft/integration-tests/mod.rs +1 -1
  28. package/contracts/oapps/oft/integration-tests/setup.rs +28 -127
  29. package/contracts/oapps/oft/integration-tests/utils.rs +254 -21
  30. package/contracts/oapps/oft/src/extensions/oft_fee.rs +23 -8
  31. package/contracts/oapps/oft/src/extensions/pausable.rs +19 -4
  32. package/contracts/oapps/oft/src/extensions/rate_limiter.rs +52 -28
  33. package/contracts/oapps/oft/src/lib.rs +10 -14
  34. package/contracts/oapps/oft/src/oft.rs +143 -193
  35. package/contracts/oapps/oft/src/oft_types/lock_unlock.rs +9 -11
  36. package/contracts/oapps/oft/src/oft_types/mint_burn.rs +12 -14
  37. package/contracts/oapps/oft/src/oft_types/mod.rs +13 -0
  38. package/contracts/oapps/{oft-std → oft-core}/Cargo.toml +6 -4
  39. package/contracts/oapps/{oft-std → oft-core}/integration-tests/mod.rs +1 -1
  40. package/contracts/oapps/{oft-std → oft-core}/integration-tests/setup.rs +126 -29
  41. package/contracts/oapps/{oft → oft-core}/integration-tests/test_with_sml.rs +3 -3
  42. package/contracts/oapps/oft-core/integration-tests/utils.rs +201 -0
  43. package/contracts/oapps/oft-core/src/lib.rs +18 -0
  44. package/contracts/oapps/oft-core/src/oft_core.rs +479 -0
  45. package/contracts/oapps/{oft → oft-core}/src/tests/mod.rs +0 -2
  46. package/contracts/oapps/{oft → oft-core}/src/tests/test_lz_receive.rs +7 -7
  47. package/contracts/oapps/{oft → oft-core}/src/tests/test_oft_msg_codec.rs +4 -4
  48. package/contracts/oapps/{oft → oft-core}/src/tests/test_resolve_address.rs +3 -3
  49. package/contracts/oapps/{oft → oft-core}/src/tests/test_utils.rs +46 -27
  50. package/contracts/oapps/{oft → oft-core}/src/utils.rs +1 -1
  51. package/contracts/upgrader/src/lib.rs +30 -57
  52. package/contracts/upgrader/src/tests/test_data/test_upgradeable_contract1.wasm +0 -0
  53. package/contracts/upgrader/src/tests/test_data/test_upgradeable_contract2.wasm +0 -0
  54. package/contracts/upgrader/src/tests/test_upgrader.rs +44 -35
  55. package/contracts/utils/src/buffer_reader.rs +1 -0
  56. package/contracts/utils/src/errors.rs +8 -2
  57. package/contracts/utils/src/ownable.rs +125 -3
  58. package/contracts/utils/src/tests/option_ext.rs +1 -1
  59. package/contracts/utils/src/tests/ownable.rs +445 -7
  60. package/contracts/utils/src/tests/ttl_configurable.rs +2 -2
  61. package/contracts/utils/src/tests/upgradeable.rs +372 -175
  62. package/contracts/utils/src/ttl_configurable.rs +3 -3
  63. package/contracts/utils/src/upgradeable.rs +48 -23
  64. package/contracts/workers/dvn/Cargo.toml +1 -0
  65. package/contracts/workers/dvn/src/auth.rs +12 -42
  66. package/contracts/workers/dvn/src/dvn.rs +16 -31
  67. package/contracts/workers/dvn/src/errors.rs +0 -1
  68. package/contracts/workers/dvn/src/interfaces/dvn.rs +35 -0
  69. package/contracts/workers/dvn/src/lib.rs +4 -3
  70. package/contracts/workers/dvn/src/tests/auth.rs +1 -1
  71. package/contracts/workers/dvn/src/tests/dvn.rs +19 -15
  72. package/contracts/workers/dvn/src/tests/multisig/set_threshold.rs +2 -4
  73. package/contracts/workers/dvn/src/tests/multisig/verify_signatures.rs +1 -3
  74. package/contracts/workers/dvn/src/tests/setup.rs +5 -9
  75. package/contracts/workers/dvn-fee-lib/Cargo.toml +1 -1
  76. package/contracts/workers/dvn-fee-lib/src/dvn_fee_lib.rs +3 -5
  77. package/contracts/workers/dvn-fee-lib/src/tests/dvn_fee_lib.rs +2 -3
  78. package/contracts/workers/executor/Cargo.toml +1 -0
  79. package/contracts/workers/executor/src/executor.rs +15 -26
  80. package/contracts/workers/executor-fee-lib/Cargo.toml +2 -1
  81. package/contracts/workers/executor-fee-lib/src/executor_fee_lib.rs +63 -5
  82. package/contracts/workers/executor-fee-lib/src/executor_option.rs +28 -1
  83. package/contracts/workers/executor-fee-lib/src/lib.rs +3 -0
  84. package/contracts/workers/executor-fee-lib/src/tests/executor_fee_lib.rs +701 -0
  85. package/contracts/workers/executor-fee-lib/src/tests/executor_option.rs +370 -0
  86. package/contracts/workers/executor-fee-lib/src/tests/mod.rs +4 -0
  87. package/contracts/workers/executor-fee-lib/src/tests/setup.rs +60 -0
  88. package/contracts/workers/executor-helper/src/lib.rs +3 -0
  89. package/contracts/workers/executor-helper/src/tests/executor_helper.rs +184 -0
  90. package/contracts/workers/executor-helper/src/tests/mod.rs +2 -0
  91. package/contracts/workers/executor-helper/src/tests/setup.rs +366 -0
  92. package/contracts/workers/fee-lib-interfaces/Cargo.toml +14 -0
  93. package/contracts/workers/{worker/src/interfaces/mod.rs → fee-lib-interfaces/src/lib.rs} +4 -3
  94. package/contracts/workers/price-feed/Cargo.toml +2 -1
  95. package/contracts/workers/price-feed/src/events.rs +1 -1
  96. package/contracts/workers/price-feed/src/lib.rs +3 -0
  97. package/contracts/workers/price-feed/src/price_feed.rs +6 -12
  98. package/contracts/workers/price-feed/src/storage.rs +1 -1
  99. package/contracts/workers/price-feed/src/tests/mod.rs +2 -0
  100. package/contracts/workers/price-feed/src/tests/price_feed.rs +869 -0
  101. package/contracts/workers/price-feed/src/tests/setup.rs +70 -0
  102. package/contracts/workers/price-feed/src/types.rs +1 -1
  103. package/contracts/workers/worker/src/errors.rs +0 -3
  104. package/contracts/workers/worker/src/lib.rs +0 -2
  105. package/contracts/workers/worker/src/storage.rs +32 -29
  106. package/contracts/workers/worker/src/tests/setup.rs +1 -7
  107. package/contracts/workers/worker/src/tests/worker.rs +50 -42
  108. package/contracts/workers/worker/src/worker.rs +49 -58
  109. package/package.json +4 -5
  110. package/sdk/.turbo/turbo-test.log +229 -217
  111. package/sdk/dist/generated/bml.d.ts +39 -1
  112. package/sdk/dist/generated/bml.js +33 -8
  113. package/sdk/dist/generated/counter.d.ts +131 -3
  114. package/sdk/dist/generated/counter.js +41 -10
  115. package/sdk/dist/generated/dvn.d.ts +431 -362
  116. package/sdk/dist/generated/dvn.js +80 -55
  117. package/sdk/dist/generated/dvn_fee_lib.d.ts +327 -251
  118. package/sdk/dist/generated/dvn_fee_lib.js +55 -57
  119. package/sdk/dist/generated/endpoint.d.ts +131 -3
  120. package/sdk/dist/generated/endpoint.js +41 -10
  121. package/sdk/dist/generated/executor.d.ts +503 -339
  122. package/sdk/dist/generated/executor.js +80 -48
  123. package/sdk/dist/generated/executor_fee_lib.d.ts +395 -319
  124. package/sdk/dist/generated/executor_fee_lib.js +54 -56
  125. package/sdk/dist/generated/executor_helper.d.ts +53 -187
  126. package/sdk/dist/generated/executor_helper.js +47 -29
  127. package/sdk/dist/generated/layerzero_view.d.ts +1271 -0
  128. package/sdk/dist/generated/layerzero_view.js +294 -0
  129. package/sdk/dist/generated/oft.d.ts +1851 -0
  130. package/sdk/dist/generated/oft.js +347 -0
  131. package/sdk/dist/generated/price_feed.d.ts +329 -253
  132. package/sdk/dist/generated/price_feed.js +55 -57
  133. package/sdk/dist/generated/sml.d.ts +131 -3
  134. package/sdk/dist/generated/sml.js +41 -10
  135. package/sdk/dist/generated/treasury.d.ts +131 -3
  136. package/sdk/dist/generated/treasury.js +41 -10
  137. package/sdk/dist/generated/uln302.d.ts +131 -3
  138. package/sdk/dist/generated/uln302.js +43 -12
  139. package/sdk/dist/generated/upgrader.d.ts +201 -15
  140. package/sdk/dist/generated/upgrader.js +99 -1
  141. package/sdk/dist/index.d.ts +2 -2
  142. package/sdk/dist/index.js +3 -3
  143. package/sdk/package.json +3 -2
  144. package/sdk/src/index.ts +3 -3
  145. package/sdk/test/oft-sml.test.ts +20 -20
  146. package/sdk/test/upgrader.test.ts +2 -3
  147. package/sdk/turbo.json +8 -0
  148. package/tools/ts-bindings-gen/Cargo.toml +2 -0
  149. package/tools/ts-bindings-gen/src/main.rs +53 -5
  150. package/turbo.json +0 -2
  151. package/contracts/oapps/oft/src/interfaces/mint_burn_token.rs +0 -23
  152. package/contracts/oapps/oft/src/interfaces/mod.rs +0 -3
  153. package/contracts/oapps/oft/src/oft_impl.rs +0 -201
  154. package/contracts/oapps/oft/src/tests/extensions/mod.rs +0 -11
  155. package/contracts/oapps/oft/src/tests/extensions/setup.rs +0 -917
  156. package/contracts/oapps/oft/src/tests/extensions/test_oft_fee.rs +0 -751
  157. package/contracts/oapps/oft/src/tests/extensions/test_pausable.rs +0 -434
  158. package/contracts/oapps/oft/src/tests/extensions/test_rate_limiter.rs +0 -1080
  159. package/contracts/oapps/oft-std/integration-tests/utils.rs +0 -427
  160. package/contracts/oapps/oft-std/src/lib.rs +0 -16
  161. package/contracts/oapps/oft-std/src/oft.rs +0 -174
  162. package/sdk/dist/generated/oft_std.d.ts +0 -1722
  163. package/sdk/dist/generated/oft_std.js +0 -316
  164. package/sdk/dist/wasm/blocked-message-lib.d.ts +0 -1
  165. package/sdk/dist/wasm/blocked-message-lib.js +0 -2
  166. package/sdk/dist/wasm/counter.d.ts +0 -1
  167. package/sdk/dist/wasm/counter.js +0 -2
  168. package/sdk/dist/wasm/dvn-fee-lib.d.ts +0 -1
  169. package/sdk/dist/wasm/dvn-fee-lib.js +0 -2
  170. package/sdk/dist/wasm/dvn.d.ts +0 -1
  171. package/sdk/dist/wasm/dvn.js +0 -2
  172. package/sdk/dist/wasm/endpoint-v2.d.ts +0 -1
  173. package/sdk/dist/wasm/endpoint-v2.js +0 -2
  174. package/sdk/dist/wasm/executor-fee-lib.d.ts +0 -1
  175. package/sdk/dist/wasm/executor-fee-lib.js +0 -2
  176. package/sdk/dist/wasm/executor-helper.d.ts +0 -1
  177. package/sdk/dist/wasm/executor-helper.js +0 -2
  178. package/sdk/dist/wasm/executor.d.ts +0 -1
  179. package/sdk/dist/wasm/executor.js +0 -2
  180. package/sdk/dist/wasm/layerzero-views.d.ts +0 -1
  181. package/sdk/dist/wasm/layerzero-views.js +0 -2
  182. package/sdk/dist/wasm/oft-std.d.ts +0 -1
  183. package/sdk/dist/wasm/oft-std.js +0 -2
  184. package/sdk/dist/wasm/price-feed.d.ts +0 -1
  185. package/sdk/dist/wasm/price-feed.js +0 -2
  186. package/sdk/dist/wasm/simple-message-lib.d.ts +0 -1
  187. package/sdk/dist/wasm/simple-message-lib.js +0 -2
  188. package/sdk/dist/wasm/treasury.d.ts +0 -1
  189. package/sdk/dist/wasm/treasury.js +0 -2
  190. package/sdk/dist/wasm/uln302.d.ts +0 -1
  191. package/sdk/dist/wasm/uln302.js +0 -2
  192. package/sdk/dist/wasm/upgrader.d.ts +0 -1
  193. package/sdk/dist/wasm/upgrader.js +0 -2
  194. package/sdk/dist/wasm.d.ts +0 -15
  195. package/sdk/dist/wasm.js +0 -15
  196. /package/contracts/oapps/{oft-std → oft}/integration-tests/extensions/mod.rs +0 -0
  197. /package/contracts/oapps/{oft → oft-core}/src/codec/mod.rs +0 -0
  198. /package/contracts/oapps/{oft → oft-core}/src/codec/oft_compose_msg_codec.rs +0 -0
  199. /package/contracts/oapps/{oft → oft-core}/src/codec/oft_msg_codec.rs +0 -0
  200. /package/contracts/oapps/{oft → oft-core}/src/errors.rs +0 -0
  201. /package/contracts/oapps/{oft → oft-core}/src/events.rs +0 -0
  202. /package/contracts/oapps/{oft → oft-core}/src/storage.rs +0 -0
  203. /package/contracts/oapps/{oft → oft-core}/src/tests/test_decimals.rs +0 -0
  204. /package/contracts/oapps/{oft → oft-core}/src/tests/test_oft_compose_msg_codec.rs +0 -0
  205. /package/contracts/oapps/{oft → oft-core}/src/tests/test_oft_version.rs +0 -0
  206. /package/contracts/oapps/{oft → oft-core}/src/tests/test_quote_oft.rs +0 -0
  207. /package/contracts/oapps/{oft → oft-core}/src/tests/test_quote_send.rs +0 -0
  208. /package/contracts/oapps/{oft → oft-core}/src/tests/test_send.rs +0 -0
  209. /package/contracts/oapps/{oft → oft-core}/src/tests/test_token.rs +0 -0
  210. /package/contracts/oapps/{oft → oft-core}/src/types.rs +0 -0
  211. /package/contracts/workers/{worker/src/interfaces → fee-lib-interfaces/src}/dvn_fee_lib.rs +0 -0
  212. /package/contracts/workers/{worker/src/interfaces → fee-lib-interfaces/src}/executor_fee_lib.rs +0 -0
  213. /package/contracts/workers/{worker/src/interfaces → fee-lib-interfaces/src}/price_feed.rs +0 -0
@@ -2,6 +2,10 @@ use common_macros::{contract_error, contract_trait, only_auth, storage};
2
2
  use soroban_sdk::{assert_with_error, contractevent, contracttype, panic_with_error, Env};
3
3
  use utils::ownable::Ownable;
4
4
 
5
+ // =========================================================================
6
+ // Types
7
+ // =========================================================================
8
+
5
9
  #[contracttype]
6
10
  #[derive(Clone, Debug, Eq, PartialEq)]
7
11
  #[repr(u8)]
@@ -19,21 +23,33 @@ pub struct RateLimit {
19
23
  last_update: u64,
20
24
  }
21
25
 
26
+ // =========================================================================
27
+ // Storage
28
+ // =========================================================================
29
+
22
30
  #[storage]
23
31
  pub enum RateLimitStorage {
24
32
  #[persistent(RateLimit)]
25
33
  RateLimit { direction: Direction, eid: u32 },
26
34
  }
27
35
 
36
+ // =========================================================================
37
+ // Errors
38
+ // =========================================================================
39
+
28
40
  #[contract_error]
29
41
  pub enum RateLimitError {
30
- ExceededRateLimit = 2400,
42
+ ExceededRateLimit = 3120,
31
43
  InvalidTimestamp,
32
44
  InvalidWindowSeconds,
33
45
  InvalidLimit,
34
46
  SameValue,
35
47
  }
36
48
 
49
+ // =========================================================================
50
+ // Events
51
+ // =========================================================================
52
+
37
53
  #[contractevent]
38
54
  #[derive(Clone, Debug, Eq, PartialEq)]
39
55
  pub struct RateLimitSet {
@@ -59,33 +75,9 @@ pub struct RateLimitUnset {
59
75
  pub eid: u32,
60
76
  }
61
77
 
62
- /// Helper function to calculate the current in-flight amount with decay.
63
- /// Used by both public trait methods and internal implementations.
64
- fn calculate_in_flight(env: &Env, direction: &Direction, eid: u32) -> i128 {
65
- if !RateLimitStorage::has_rate_limit(env, direction, eid) {
66
- return 0;
67
- }
68
- let rate_limit = RateLimitStorage::rate_limit(env, direction, eid).unwrap();
69
- let timestamp = env.ledger().timestamp();
70
- assert_with_error!(env, timestamp >= rate_limit.last_update, RateLimitError::InvalidTimestamp);
71
- let elapsed = timestamp - rate_limit.last_update;
72
- let decay = (elapsed as i128) * rate_limit.limit / (rate_limit.window_seconds as i128);
73
- if decay < rate_limit.in_flight_on_last_update {
74
- rate_limit.in_flight_on_last_update - decay
75
- } else {
76
- 0
77
- }
78
- }
79
-
80
- /// Checkpoints the current in-flight amount by applying decay and updating timestamp.
81
- /// Used internally before modifying rate limit state.
82
- fn checkpoint_rate_limit_in_flight(env: &Env, direction: &Direction, eid: u32) {
83
- let in_flight = calculate_in_flight(env, direction, eid);
84
- let mut rate_limit = RateLimitStorage::rate_limit(env, direction, eid).unwrap();
85
- rate_limit.in_flight_on_last_update = in_flight;
86
- rate_limit.last_update = env.ledger().timestamp();
87
- RateLimitStorage::set_rate_limit(env, direction, eid, &rate_limit);
88
- }
78
+ // =========================================================================
79
+ // Trait With Default Implementations
80
+ // =========================================================================
89
81
 
90
82
  #[contract_trait]
91
83
  pub trait RateLimiter: RateLimiterInternal + Ownable + Sized {
@@ -198,3 +190,35 @@ pub trait RateLimiterInternal {
198
190
  RateLimitStorage::set_rate_limit(env, direction, eid, &rate_limit);
199
191
  }
200
192
  }
193
+
194
+ // =========================================================================
195
+ // Helper Functions
196
+ // =========================================================================
197
+
198
+ /// Helper function to calculate the current in-flight amount with decay.
199
+ /// Used by both public trait methods and internal implementations.
200
+ fn calculate_in_flight(env: &Env, direction: &Direction, eid: u32) -> i128 {
201
+ if !RateLimitStorage::has_rate_limit(env, direction, eid) {
202
+ return 0;
203
+ }
204
+ let rate_limit = RateLimitStorage::rate_limit(env, direction, eid).unwrap();
205
+ let timestamp = env.ledger().timestamp();
206
+ assert_with_error!(env, timestamp >= rate_limit.last_update, RateLimitError::InvalidTimestamp);
207
+ let elapsed = timestamp - rate_limit.last_update;
208
+ let decay = (elapsed as i128) * rate_limit.limit / (rate_limit.window_seconds as i128);
209
+ if decay < rate_limit.in_flight_on_last_update {
210
+ rate_limit.in_flight_on_last_update - decay
211
+ } else {
212
+ 0
213
+ }
214
+ }
215
+
216
+ /// Checkpoints the current in-flight amount by applying decay and updating timestamp.
217
+ /// Used internally before modifying rate limit state.
218
+ fn checkpoint_rate_limit_in_flight(env: &Env, direction: &Direction, eid: u32) {
219
+ let in_flight = calculate_in_flight(env, direction, eid);
220
+ let mut rate_limit = RateLimitStorage::rate_limit(env, direction, eid).unwrap();
221
+ rate_limit.in_flight_on_last_update = in_flight;
222
+ rate_limit.last_update = env.ledger().timestamp();
223
+ RateLimitStorage::set_rate_limit(env, direction, eid, &rate_limit);
224
+ }
@@ -1,23 +1,19 @@
1
1
  #![no_std]
2
2
 
3
- pub mod codec;
4
- pub mod errors;
5
- pub mod events;
6
3
  pub mod extensions;
7
- pub mod interfaces;
8
- pub mod oft;
9
- pub mod oft_impl;
10
4
  pub mod oft_types;
11
- pub mod storage;
12
- pub mod types;
13
- pub mod utils;
14
5
 
15
- // Re-export commonly used items
16
- pub use oft_impl::initialize_oft;
6
+ pub use extensions::*;
7
+ pub use oft_types::*;
8
+
9
+ cfg_if::cfg_if! {
10
+ // Include implementation when NOT in library mode, OR when testutils is enabled (for tests)
11
+ if #[cfg(any(not(feature = "library"), feature = "testutils"))] {
12
+ mod oft;
13
+ pub use oft::*;
14
+ }
15
+ }
17
16
 
18
17
  #[cfg(test)]
19
18
  #[path = "../integration-tests/mod.rs"]
20
19
  pub mod integration_tests;
21
-
22
- #[cfg(test)]
23
- pub mod tests;
@@ -1,211 +1,161 @@
1
- //! OFT traits - the main interface for OFT contracts.
2
- //!
3
- //! This module provides two traits:
4
- //! - `OFTInternal`: Internal methods NOT exposed as contract endpoints (`__debit`, `__credit`, etc.)
5
- //! - `OFT`: Public methods exposed as contract endpoints (using `#[contracttrait]`)
6
- //!
7
- //! ## Usage
8
- //!
9
- //! ```ignore
10
- //! use oapp_macros::{oapp, oapp_options_type3};
11
- //! use oft::oft::{OFTInternal, OFT};
12
- //! use oft::initialize_oft;
13
- //!
14
- //! #[oapp]
15
- //! pub struct MyOFT;
16
- //!
17
- //! #[contractimpl]
18
- //! impl MyOFT {
19
- //! pub fn __constructor(env: &Env, token: &Address, owner: &Address, endpoint: &Address, delegate: &Option<Address>) {
20
- //! initialize_oft::<Self>(env, owner, token, endpoint, delegate)
21
- //! }
22
- //! }
23
- //!
24
- //! // Public methods - exposed as contract endpoints
25
- //! #[contractimpl(contracttrait)]
26
- //! impl OFT for MyOFT {}
27
- //!
28
- //! // Internal methods - NOT exposed as contract endpoints
29
- //! // IMPORTANT: Do NOT use #[contractimpl] here to keep methods internal
30
- //! impl OFTInternal for MyOFT {
31
- //! fn __debit(env: &Env, sender: &Address, amount_ld: i128, min_amount_ld: i128, dst_eid: u32) -> OFTReceipt {
32
- //! // Your debit logic (e.g., burn or lock tokens)
33
- //! oft::oft_types::mint_burn::debit::<Self>(env, sender, amount_ld, min_amount_ld, dst_eid)
34
- //! }
35
- //!
36
- //! fn __credit(env: &Env, to: &Address, amount_ld: i128, src_eid: u32) -> i128 {
37
- //! // Your credit logic (e.g., mint or unlock tokens)
38
- //! oft::oft_types::mint_burn::credit::<Self>(env, to, amount_ld, src_eid)
39
- //! }
40
- //! }
41
- //! ```
42
-
43
- // Alias for the current crate, allowing `oft::types::SendParam` paths to work both
44
- // inside this crate and in external crates implementing the OFT trait.
45
- extern crate self as oft;
46
-
47
- use crate::{oft_impl, storage::OFTStorage, types::OFTReceipt};
48
- use common_macros::contract_trait;
49
- use oapp::{
50
- oapp_core::OAppCore, oapp_options_type3::OAppOptionsType3, oapp_receiver::OAppReceiver,
51
- oapp_sender::OAppSenderInternal,
1
+ use crate::{
2
+ extensions::{
3
+ oft_fee::{OFTFee, OFTFeeInternal},
4
+ pausable::{OFTPausable, OFTPausableInternal},
5
+ rate_limiter::{Direction, RateLimiter, RateLimiterInternal},
6
+ },
7
+ oft_types::{lock_unlock, mint_burn, OftType},
52
8
  };
53
- use soroban_sdk::{Address, Bytes, Env};
54
-
55
- // =====================================================
56
- // OFTInternal Trait (NOT exposed as contract endpoints)
57
- // =====================================================
58
-
59
- /// Internal OFT trait containing methods that should NOT be exposed as contract endpoints.
60
- ///
61
- /// **IMPORTANT**: Implement this trait WITHOUT the `#[contractimpl]` macro to keep
62
- /// `__debit`, `__credit`, and other internal methods private to the contract.
63
- ///
64
- /// ```ignore
65
- /// // Correct - methods stay internal
66
- /// impl OFTInternal for MyOFT { ... }
67
- ///
68
- /// // WRONG - would expose methods as endpoints
69
- /// #[contractimpl]
70
- /// impl OFTInternal for MyOFT { ... }
71
- /// ```
72
- ///
73
- /// Internal OFT trait for token debit/credit operations.
74
- ///
75
- /// This trait contains only the internal token operations. The OApp supertraits
76
- /// are on `OFT` instead, keeping this trait focused on token logic.
77
- pub trait OFTInternal: OAppCore {
78
- // =========================================================================
79
- // Required Methods (no defaults - user MUST implement)
80
- // =========================================================================
81
-
82
- /// Debits tokens from the specified address for cross-chain transfer.
83
- ///
84
- /// # Arguments
85
- /// * `from` - The address to debit the tokens from
86
- /// * `amount_ld` - The amount of tokens to send in local decimals
87
- /// * `min_amount_ld` - The minimum amount to send in local decimals
88
- /// * `dst_eid` - The destination chain ID
89
- ///
90
- /// # Returns
91
- /// `OFTReceipt` containing the amount sent and amount received
92
- fn __debit(env: &Env, from: &Address, amount_ld: i128, min_amount_ld: i128, dst_eid: u32) -> OFTReceipt;
93
-
94
- /// Credits tokens to recipient after receiving cross-chain transfer.
95
- ///
96
- /// # Arguments
97
- /// * `to` - The address to credit tokens to
98
- /// * `amount_ld` - Amount in local decimals to credit
99
- /// * `src_eid` - Source endpoint ID
100
- ///
101
- /// # Returns
102
- /// The amount actually credited
103
- fn __credit(env: &Env, to: &Address, amount_ld: i128, src_eid: u32) -> i128;
104
-
105
- // =========================================================================
106
- // Optional Methods (have defaults - override as needed)
107
- // =========================================================================
108
-
109
- /// Calculates debit amounts without executing (view function).
110
- fn __debit_view(env: &Env, amount_ld: i128, min_amount_ld: i128, dst_eid: u32) -> OFTReceipt {
111
- oft_impl::debit_view(env, amount_ld, min_amount_ld, dst_eid)
112
- }
9
+ use common_macros::{contract_impl, storage};
10
+ use endpoint_v2::Origin;
11
+ use oapp_macros::oapp;
12
+ use oft_core::{
13
+ errors::OFTError,
14
+ impl_oft_lz_receive,
15
+ types::{OFTFeeDetail, OFTLimit, OFTReceipt, SendParam},
16
+ utils as oft_utils, OFTCore, OFTInternal,
17
+ };
18
+ use soroban_sdk::{assert_with_error, vec, Address, Bytes, BytesN, Env, Vec};
113
19
 
114
- /// Builds OFT message and combines options for cross-chain transfer.
115
- fn __build_msg_and_options(
116
- env: &Env,
117
- from: &Address,
118
- send_param: &oft::types::SendParam,
119
- receive_amount_ld: i128,
120
- ) -> (Bytes, Bytes)
121
- where
122
- Self: OAppOptionsType3,
123
- {
124
- oft_impl::build_msg_and_options::<Self>(env, from, send_param, receive_amount_ld)
125
- }
20
+ // =========================================================================
21
+ // Storage
22
+ // =========================================================================
23
+
24
+ #[storage]
25
+ enum OFTStorage {
26
+ #[instance(OftType)]
27
+ OftType,
126
28
  }
127
29
 
128
- // =====================================================
129
- // OFT Trait (exposed as contract endpoints)
130
- // =====================================================
131
-
132
- /// The public OFT trait defining the cross-chain token transfer interface.
133
- ///
134
- /// This trait is marked with `#[contracttrait]` so all its methods are exposed as
135
- /// contract endpoints. Users implement this with `#[contractimpl(contracttrait)]`.
136
- ///
137
- /// Internal methods like `__debit`, `__credit`, `__debit_view`, and `__build_msg_and_options`
138
- /// are in the `OFTInternal` trait and are NOT exposed as contract endpoints.
139
- #[contract_trait]
140
- pub trait OFT: OFTInternal + OAppReceiver + OAppSenderInternal + OAppOptionsType3 {
141
- /// Retrieves the token address associated with this OFT.
142
- fn token(env: &Env) -> Address {
143
- OFTStorage::token(env).unwrap()
144
- }
30
+ // =========================================================================
31
+ // OFT Contract
32
+ // =========================================================================
145
33
 
146
- /// Returns OFT version as (major, minor).
147
- fn oft_version(_env: &Env) -> (u64, u64) {
148
- (1, 1)
149
- }
34
+ #[oapp]
35
+ pub struct OFT;
36
+
37
+ // LzReceiveInternal implementation using default OFT receive logic
38
+ impl_oft_lz_receive!(OFT);
150
39
 
151
- /// Retrieves the shared decimals used for cross-chain normalization.
152
- fn shared_decimals(env: &Env) -> u32 {
153
- let token = Self::token(env);
154
- let local_decimals = soroban_sdk::token::TokenClient::new(env, &token).decimals();
155
- let conversion_rate = Self::decimal_conversion_rate(env);
156
- local_decimals - conversion_rate.ilog10()
40
+ #[contract_impl]
41
+ impl OFT {
42
+ pub fn __constructor(
43
+ env: &Env,
44
+ token: &Address,
45
+ owner: &Address,
46
+ endpoint: &Address,
47
+ delegate: &Option<Address>,
48
+ shared_decimals: u32,
49
+ oft_type: OftType,
50
+ ) {
51
+ Self::__initialize_oft(env, owner, token, endpoint, delegate, shared_decimals);
52
+ OFTStorage::set_oft_type(env, &oft_type);
157
53
  }
158
54
 
159
- /// Retrieves the decimal conversion rate used for cross-chain normalization.
160
- fn decimal_conversion_rate(env: &Env) -> i128 {
161
- OFTStorage::decimal_conversion_rate(env).unwrap()
55
+ /// Returns the type of operation for this OFT (LockUnlock or MintBurn)
56
+ pub fn oft_type(env: &Env) -> OftType {
57
+ OFTStorage::oft_type(env).unwrap()
162
58
  }
59
+ }
163
60
 
164
- /// Whether a separate token approval is required before sending.
165
- ///
166
- /// Helps wallet implementers determine integration requirements.
167
- ///
168
- /// # Returns
169
- /// - `true` if a separate token approval step is required
170
- /// - `false` if no separate approval is needed
171
- fn approval_required(_env: &Env) -> bool {
172
- false
61
+ /// OFTCore trait implementation for standard OFT with extensions
62
+ #[contract_impl(contracttrait)]
63
+ impl OFTCore for OFT {
64
+ fn quote_oft(env: &Env, send_param: &SendParam) -> (OFTLimit, Vec<OFTFeeDetail>, OFTReceipt) {
65
+ let (_, _, oft_receipt) = Self::__quote_oft(env, send_param);
66
+
67
+ // fee details (only include if there's an actual fee)
68
+ let fee_amount_ld = oft_receipt.amount_sent_ld - oft_receipt.amount_received_ld;
69
+ let fee_details = if fee_amount_ld > 0 {
70
+ vec![env, OFTFeeDetail { fee_amount_ld, description: Bytes::from_slice(env, b"OFT Fee") }]
71
+ } else {
72
+ vec![env]
73
+ };
74
+
75
+ // rate limit capacity
76
+ let capacity = Self::rate_limit_capacity(env, &Direction::Outbound, send_param.dst_eid);
77
+ let oft_limit = OFTLimit { min_amount_ld: 0, max_amount_ld: capacity };
78
+
79
+ (oft_limit, fee_details, oft_receipt)
173
80
  }
81
+ }
174
82
 
175
- /// Quotes an OFT transfer without executing.
176
- ///
177
- /// # Returns
178
- /// (OFTLimit, fee details, receipt with estimated amounts)
179
- fn quote_oft(
180
- env: &Env,
181
- send_param: &oft::types::SendParam,
182
- ) -> (oft::types::OFTLimit, soroban_sdk::Vec<oft::types::OFTFeeDetail>, oft::types::OFTReceipt) {
183
- oft_impl::quote_oft::<Self>(env, send_param)
83
+ /// OFT behavior for standard OFT with extension hooks
84
+ impl OFTInternal for OFT {
85
+ /// Overrides default to add pausable check and fee calculation.
86
+ fn __debit_view(env: &Env, amount_ld: i128, min_amount_ld: i128, dst_eid: u32) -> OFTReceipt {
87
+ Self::__assert_not_paused(env);
88
+
89
+ let conversion_rate = Self::__decimal_conversion_rate(env);
90
+
91
+ // Apply the fee before dust removal to ensure the fee is calculated on the full amount and dust is not transferred
92
+ let fee = Self::__fee_view(env, dst_eid, amount_ld);
93
+ let amount_after_fee = amount_ld - fee;
94
+ let amount_received_ld = oft_utils::remove_dust(amount_after_fee, conversion_rate);
95
+
96
+ // amount_sent_ld = what recipient receives + fee charged
97
+ // Dust is excluded (stays with sender)
98
+ let amount_sent_ld = amount_received_ld + fee;
99
+
100
+ assert_with_error!(env, amount_received_ld >= min_amount_ld, OFTError::SlippageExceeded);
101
+
102
+ OFTReceipt { amount_sent_ld, amount_received_ld }
184
103
  }
185
104
 
186
- /// Quotes a send operation including LayerZero messaging fees.
187
- fn quote_send(
188
- env: &Env,
189
- sender: &Address,
190
- send_param: &oft::types::SendParam,
191
- pay_in_zro: bool,
192
- ) -> endpoint_v2::MessagingFee {
193
- oft_impl::quote_send::<Self>(env, sender, send_param, pay_in_zro)
105
+ fn __debit(env: &Env, sender: &Address, amount_ld: i128, min_amount_ld: i128, dst_eid: u32) -> OFTReceipt {
106
+ // Core debit logic (based on oft_type)
107
+ let oft_receipt = match Self::oft_type(env) {
108
+ OftType::LockUnlock => lock_unlock::debit::<Self>(env, sender, amount_ld, min_amount_ld, dst_eid),
109
+ OftType::MintBurn => mint_burn::debit::<Self>(env, sender, amount_ld, min_amount_ld, dst_eid),
110
+ };
111
+
112
+ // Rate limit checks (using amount_received_ld - the actual cross-chain amount)
113
+ Self::__consume_rate_limit_capacity(env, &Direction::Outbound, dst_eid, oft_receipt.amount_received_ld);
114
+ Self::__release_rate_limit_capacity(env, &Direction::Inbound, dst_eid, oft_receipt.amount_received_ld);
115
+
116
+ // Charge fee
117
+ let fee = oft_receipt.amount_sent_ld - oft_receipt.amount_received_ld;
118
+ Self::__charge_fee(env, &Self::__token(env), sender, fee);
119
+
120
+ oft_receipt
194
121
  }
195
122
 
196
- /// Sends tokens cross-chain to another endpoint.
197
- ///
198
- /// Sender must be authenticated.
199
- ///
200
- /// # Returns
201
- /// (MessagingReceipt, OFTReceipt)
202
- fn send(
203
- env: &Env,
204
- sender: &Address,
205
- send_param: &oft::types::SendParam,
206
- fee: &endpoint_v2::MessagingFee,
207
- refund_address: &Address,
208
- ) -> (endpoint_v2::MessagingReceipt, oft::types::OFTReceipt) {
209
- oft_impl::send::<Self>(env, sender, send_param, fee, refund_address)
123
+ fn __credit(env: &Env, to: &Address, amount_ld: i128, src_eid: u32) -> i128 {
124
+ // Pausable check
125
+ Self::__assert_not_paused(env);
126
+
127
+ // Core credit logic (based on mode)
128
+ let amount_credited = match Self::oft_type(env) {
129
+ OftType::LockUnlock => lock_unlock::credit::<Self>(env, to, amount_ld, src_eid),
130
+ OftType::MintBurn => mint_burn::credit::<Self>(env, to, amount_ld, src_eid),
131
+ };
132
+
133
+ // Rate limit checks (using amount_credited - the actual credited amount)
134
+ Self::__consume_rate_limit_capacity(env, &Direction::Inbound, src_eid, amount_credited);
135
+ Self::__release_rate_limit_capacity(env, &Direction::Outbound, src_eid, amount_credited);
136
+
137
+ amount_credited
210
138
  }
211
139
  }
140
+
141
+ // =========================================================================
142
+ // Extension Trait Implementations
143
+ // =========================================================================
144
+
145
+ /// Pausable extension - allows pausing/unpausing the OFT
146
+ /// Default state: unpaused (all operations allowed)
147
+ #[contract_impl(contracttrait)]
148
+ impl OFTPausable for OFT {}
149
+ impl OFTPausableInternal for OFT {}
150
+
151
+ /// OFT Fee extension - allows collecting fees on transfers
152
+ /// Default state: 0 BPS (no fee collected)
153
+ #[contract_impl(contracttrait)]
154
+ impl OFTFee for OFT {}
155
+ impl OFTFeeInternal for OFT {}
156
+
157
+ /// Rate Limiter extension - allows rate limiting transfers
158
+ /// Default state: not set (rate_limit_capacity returns i128::MAX)
159
+ #[contract_impl(contracttrait)]
160
+ impl RateLimiter for OFT {}
161
+ impl RateLimiterInternal for OFT {}
@@ -4,7 +4,7 @@
4
4
  //! tokens from the contract on credit (receive).
5
5
  //! Used for OFT adapters that wrap existing tokens.
6
6
 
7
- use crate::{oft::OFT, types::OFTReceipt};
7
+ use oft_core::{oft_core::OFTCore, types::OFTReceipt};
8
8
  use soroban_sdk::{token::TokenClient, Address, Env};
9
9
 
10
10
  /// Debit tokens using LockUnlock OFT type (locks tokens in contract).
@@ -18,7 +18,13 @@ use soroban_sdk::{token::TokenClient, Address, Env};
18
18
  ///
19
19
  /// # Returns
20
20
  /// `OFTReceipt` containing the amount sent and amount received
21
- pub fn debit<T: OFT>(env: &Env, sender: &Address, amount_ld: i128, min_amount_ld: i128, dst_eid: u32) -> OFTReceipt {
21
+ pub fn debit<T: OFTCore>(
22
+ env: &Env,
23
+ sender: &Address,
24
+ amount_ld: i128,
25
+ min_amount_ld: i128,
26
+ dst_eid: u32,
27
+ ) -> OFTReceipt {
22
28
  let receipt: OFTReceipt = T::__debit_view(env, amount_ld, min_amount_ld, dst_eid);
23
29
  TokenClient::new(env, &T::token(env)).transfer(sender, env.current_contract_address(), &receipt.amount_received_ld);
24
30
  receipt
@@ -34,15 +40,7 @@ pub fn debit<T: OFT>(env: &Env, sender: &Address, amount_ld: i128, min_amount_ld
34
40
  ///
35
41
  /// # Returns
36
42
  /// The amount credited
37
- pub fn credit<T: OFT>(env: &Env, to: &Address, amount_ld: i128, _src_eid: u32) -> i128 {
43
+ pub fn credit<T: OFTCore>(env: &Env, to: &Address, amount_ld: i128, _src_eid: u32) -> i128 {
38
44
  TokenClient::new(env, &T::token(env)).transfer(&env.current_contract_address(), to, &amount_ld);
39
45
  amount_ld
40
46
  }
41
-
42
- /// Returns whether approval is required for LockUnlock OFT type.
43
- ///
44
- /// # Returns
45
- /// Always `false` - approval not needed for transfer operations
46
- pub fn approval_required() -> bool {
47
- false
48
- }
@@ -3,8 +3,8 @@
3
3
  //! This OFT type burns tokens on debit (send) and mints tokens on credit (receive).
4
4
  //! Used when the OFT contract has mint/burn authority over the token.
5
5
 
6
- use crate::{interfaces::MintBurnTokenClient, oft::OFT, types::OFTReceipt};
7
- use soroban_sdk::{Address, Env};
6
+ use oft_core::{oft_core::OFTCore, types::OFTReceipt};
7
+ use soroban_sdk::{token::StellarAssetClient, Address, Env};
8
8
 
9
9
  /// Debit tokens using MintBurn OFT type (burns tokens from sender).
10
10
  ///
@@ -17,9 +17,15 @@ use soroban_sdk::{Address, Env};
17
17
  ///
18
18
  /// # Returns
19
19
  /// `OFTReceipt` containing the amount sent and amount received
20
- pub fn debit<T: OFT>(env: &Env, sender: &Address, amount_ld: i128, min_amount_ld: i128, dst_eid: u32) -> OFTReceipt {
20
+ pub fn debit<T: OFTCore>(
21
+ env: &Env,
22
+ sender: &Address,
23
+ amount_ld: i128,
24
+ min_amount_ld: i128,
25
+ dst_eid: u32,
26
+ ) -> OFTReceipt {
21
27
  let receipt = T::__debit_view(env, amount_ld, min_amount_ld, dst_eid);
22
- MintBurnTokenClient::new(env, &T::token(env)).burn(sender, &receipt.amount_received_ld);
28
+ StellarAssetClient::new(env, &T::token(env)).burn(sender, &receipt.amount_received_ld);
23
29
  receipt
24
30
  }
25
31
 
@@ -33,15 +39,7 @@ pub fn debit<T: OFT>(env: &Env, sender: &Address, amount_ld: i128, min_amount_ld
33
39
  ///
34
40
  /// # Returns
35
41
  /// The amount credited
36
- pub fn credit<T: OFT>(env: &Env, to: &Address, amount_ld: i128, _src_eid: u32) -> i128 {
37
- MintBurnTokenClient::new(env, &T::token(env)).mint(to, &amount_ld);
42
+ pub fn credit<T: OFTCore>(env: &Env, to: &Address, amount_ld: i128, _src_eid: u32) -> i128 {
43
+ StellarAssetClient::new(env, &T::token(env)).mint(to, &amount_ld);
38
44
  amount_ld
39
45
  }
40
-
41
- /// Returns whether approval is required for MintBurn OFT type.
42
- ///
43
- /// # Returns
44
- /// Always `false` - approval not needed for mint/burn operations.
45
- pub fn approval_required() -> bool {
46
- false
47
- }
@@ -6,5 +6,18 @@
6
6
  //! - **LockUnlock**: Locks tokens on send, unlocks on receive. Approval not required.
7
7
  //!
8
8
 
9
+ use soroban_sdk::contracttype;
10
+
9
11
  pub mod lock_unlock;
10
12
  pub mod mint_burn;
13
+
14
+ /// The type of OFT operation mode
15
+ #[contracttype]
16
+ #[derive(Clone, Copy, Debug, Eq, PartialEq)]
17
+ #[repr(u8)]
18
+ pub enum OftType {
19
+ /// Lock tokens on send, unlock on receive
20
+ LockUnlock = 0,
21
+ /// Burn tokens on send, mint on receive
22
+ MintBurn = 1,
23
+ }
@@ -1,11 +1,11 @@
1
1
  [package]
2
- name = "oft-std"
2
+ name = "oft-core"
3
3
  version.workspace = true
4
4
  edition.workspace = true
5
5
  license.workspace = true
6
6
 
7
7
  [lib]
8
- crate-type = ["cdylib"]
8
+ crate-type = ["rlib"]
9
9
  doctest = false
10
10
 
11
11
  [dependencies]
@@ -14,8 +14,6 @@ endpoint-v2 = { workspace = true, features = ["library"] }
14
14
  utils = { workspace = true }
15
15
  oapp = { workspace = true }
16
16
  common-macros = { workspace = true }
17
- oapp-macros = { workspace = true }
18
- oft = { workspace = true }
19
17
 
20
18
  [dev-dependencies]
21
19
  soroban-sdk = { workspace = true, features = ["testutils"] }
@@ -23,3 +21,7 @@ simple-message-lib = { workspace = true }
23
21
  message-lib-common = { workspace = true, features = ["testutils"] }
24
22
  endpoint-v2 = { workspace = true, features = ["testutils"] }
25
23
  utils = { workspace = true, features = ["testutils"] }
24
+ insta = { workspace = true }
25
+ oapp-macros = { workspace = true }
26
+ stellar-macros = { workspace = true }
27
+ stellar-tokens = { workspace = true }
@@ -1,3 +1,3 @@
1
- pub mod extensions;
2
1
  pub mod setup;
2
+ pub mod test_with_sml;
3
3
  pub mod utils;