@layerzerolabs/protocol-stellar-v2 0.2.15 → 0.2.19

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