@layerzerolabs/protocol-stellar-v2 0.2.8 → 0.2.10

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 (239) hide show
  1. package/.turbo/turbo-build.log +443 -302
  2. package/.turbo/turbo-lint.log +118 -96
  3. package/.turbo/turbo-test.log +853 -731
  4. package/Cargo.lock +120 -37
  5. package/Cargo.toml +8 -5
  6. package/contracts/common-macros/src/contract_impl.rs +44 -0
  7. package/contracts/common-macros/src/lib.rs +86 -40
  8. package/contracts/common-macros/src/ownable.rs +24 -32
  9. package/contracts/common-macros/src/storage.rs +95 -120
  10. package/contracts/common-macros/src/tests/contract_impl.rs +289 -0
  11. package/contracts/common-macros/src/tests/mod.rs +9 -0
  12. package/contracts/common-macros/src/tests/ownable.rs +151 -0
  13. package/contracts/common-macros/src/tests/snapshots/common_macros__tests__contract_impl__snapshot_generated_contract_impl_code.snap +85 -0
  14. package/contracts/common-macros/src/tests/snapshots/common_macros__tests__ownable__snapshot_generated_ownable_code.snap +30 -0
  15. package/contracts/common-macros/src/tests/snapshots/common_macros__tests__ownable__snapshot_only_owner_preserves_function_signature.snap +9 -0
  16. package/contracts/common-macros/src/tests/snapshots/common_macros__tests__storage__snapshot_generated_storage_code.snap +1072 -0
  17. package/contracts/common-macros/src/tests/snapshots/common_macros__tests__ttl_configurable__snapshot_generated_ttl_configurable_code.snap +45 -0
  18. package/contracts/common-macros/src/tests/storage.rs +485 -0
  19. package/contracts/common-macros/src/tests/test_helpers.rs +93 -0
  20. package/contracts/common-macros/src/tests/ttl_configurable.rs +34 -0
  21. package/contracts/common-macros/src/ttl_configurable.rs +31 -14
  22. package/contracts/common-macros/src/utils.rs +27 -0
  23. package/contracts/endpoint-v2/ARCHITECTURE.md +4 -4
  24. package/contracts/endpoint-v2/src/endpoint_v2.rs +18 -15
  25. package/contracts/endpoint-v2/src/interfaces/message_lib.rs +2 -3
  26. package/contracts/endpoint-v2/src/interfaces/message_lib_manager.rs +5 -3
  27. package/contracts/endpoint-v2/src/interfaces/messaging_channel.rs +2 -2
  28. package/contracts/endpoint-v2/src/interfaces/messaging_composer.rs +2 -2
  29. package/contracts/endpoint-v2/src/interfaces/send_lib.rs +4 -4
  30. package/contracts/endpoint-v2/src/lib.rs +6 -5
  31. package/contracts/endpoint-v2/src/message_lib_manager.rs +14 -6
  32. package/contracts/endpoint-v2/src/messaging_channel.rs +6 -2
  33. package/contracts/endpoint-v2/src/messaging_composer.rs +6 -2
  34. package/contracts/endpoint-v2/src/storage.rs +10 -7
  35. package/contracts/endpoint-v2/src/tests/endpoint_v2/pay_messaging_fees.rs +16 -16
  36. package/contracts/endpoint-v2/src/tests/endpoint_v2/ttl_config.rs +46 -46
  37. package/contracts/endpoint-v2/src/tests/mock.rs +2 -2
  38. package/contracts/endpoint-v2/src/util.rs +8 -2
  39. package/contracts/message-libs/block-message-lib/Cargo.toml +1 -0
  40. package/contracts/message-libs/block-message-lib/src/lib.rs +5 -5
  41. package/contracts/message-libs/message-lib-common/src/errors.rs +8 -8
  42. package/contracts/message-libs/message-lib-common/src/interfaces/dvn.rs +0 -1
  43. package/contracts/message-libs/message-lib-common/src/interfaces/mod.rs +3 -3
  44. package/contracts/message-libs/message-lib-common/src/lib.rs +0 -2
  45. package/contracts/message-libs/message-lib-common/src/packet_codec_v1.rs +4 -6
  46. package/contracts/message-libs/message-lib-common/src/tests/packet_codec_v1.rs +2 -2
  47. package/contracts/message-libs/message-lib-common/src/tests/worker_options.rs +11 -11
  48. package/contracts/message-libs/message-lib-common/src/worker_options.rs +10 -16
  49. package/contracts/message-libs/simple-message-lib/src/errors.rs +0 -4
  50. package/contracts/message-libs/simple-message-lib/src/simple_message_lib.rs +49 -34
  51. package/contracts/message-libs/simple-message-lib/src/storage.rs +3 -7
  52. package/contracts/message-libs/simple-message-lib/src/test.rs +3 -3
  53. package/contracts/message-libs/treasury/src/storage.rs +1 -2
  54. package/contracts/message-libs/treasury/src/tests/setup.rs +3 -2
  55. package/contracts/message-libs/treasury/src/tests/treasury_tests.rs +0 -13
  56. package/contracts/message-libs/treasury/src/treasury.rs +18 -21
  57. package/contracts/message-libs/uln-302/Cargo.toml +1 -0
  58. package/contracts/message-libs/uln-302/src/interfaces/mod.rs +4 -4
  59. package/contracts/message-libs/uln-302/src/interfaces/{receive.rs → receive_uln.rs} +3 -3
  60. package/contracts/message-libs/uln-302/src/interfaces/{send.rs → send_uln.rs} +8 -80
  61. package/contracts/message-libs/uln-302/src/lib.rs +5 -4
  62. package/contracts/message-libs/uln-302/src/{receive.rs → receive_uln.rs} +20 -12
  63. package/contracts/message-libs/uln-302/src/{send.rs → send_uln.rs} +19 -13
  64. package/contracts/message-libs/uln-302/src/storage.rs +1 -2
  65. package/contracts/message-libs/uln-302/src/tests/config/uln_config.rs +3 -2
  66. package/contracts/message-libs/uln-302/src/tests/send_uln302/send.rs +30 -30
  67. package/contracts/message-libs/uln-302/src/tests/setup.rs +12 -11
  68. package/contracts/message-libs/uln-302/src/tests/uln302/set_config.rs +1 -1
  69. package/contracts/message-libs/uln-302/src/{config_validation.rs → types.rs} +79 -11
  70. package/contracts/message-libs/uln-302/src/uln302.rs +15 -10
  71. package/contracts/oapp-macros/Cargo.toml +2 -8
  72. package/contracts/oapp-macros/src/lib.rs +57 -311
  73. package/contracts/oapp-macros/src/oapp_core.rs +23 -32
  74. package/contracts/oapp-macros/src/oapp_full.rs +8 -2
  75. package/contracts/oapp-macros/src/oapp_options_type3.rs +21 -36
  76. package/contracts/oapp-macros/src/oapp_receiver.rs +38 -57
  77. package/contracts/oapp-macros/src/oapp_sender.rs +12 -14
  78. package/contracts/oapp-macros/src/util.rs +14 -10
  79. package/contracts/oapps/counter/Cargo.toml +2 -1
  80. package/contracts/oapps/counter/integration_tests/utils.rs +4 -4
  81. package/contracts/oapps/counter/src/codec.rs +8 -9
  82. package/contracts/oapps/counter/src/counter.rs +156 -147
  83. package/contracts/oapps/counter/src/storage.rs +1 -2
  84. package/contracts/oapps/counter/src/tests/test_codec.rs +5 -5
  85. package/contracts/oapps/counter/src/tests/test_counter.rs +11 -13
  86. package/contracts/oapps/oapp/Cargo.toml +1 -0
  87. package/contracts/oapps/oapp/src/errors.rs +1 -1
  88. package/contracts/oapps/oapp/src/lib.rs +3 -0
  89. package/contracts/oapps/oapp/src/macro_tests/mod.rs +1 -0
  90. package/contracts/oapps/oapp/src/macro_tests/test_macros.rs +312 -0
  91. package/contracts/oapps/oapp/src/oapp_core.rs +52 -53
  92. package/contracts/oapps/oapp/src/oapp_options_type3.rs +18 -28
  93. package/contracts/oapps/oapp/src/oapp_receiver.rs +82 -31
  94. package/contracts/oapps/oapp/src/oapp_sender.rs +55 -13
  95. package/contracts/oapps/oapp/src/tests/test_oapp_core.rs +16 -3
  96. package/contracts/oapps/oapp/src/tests/test_oapp_options_type3.rs +33 -8
  97. package/contracts/oapps/oapp/src/tests/test_oapp_receiver.rs +6 -9
  98. package/contracts/oapps/oapp/src/tests/test_oapp_sender.rs +28 -15
  99. package/contracts/oapps/oft/Cargo.toml +27 -0
  100. package/contracts/oapps/oft/integration-tests/mod.rs +3 -0
  101. package/contracts/oapps/oft/integration-tests/setup.rs +320 -0
  102. package/contracts/oapps/oft/integration-tests/test_with_sml.rs +155 -0
  103. package/contracts/oapps/oft/integration-tests/utils.rs +201 -0
  104. package/contracts/oapps/oft/src/codec/mod.rs +2 -0
  105. package/contracts/oapps/oft/src/codec/oft_compose_msg_codec.rs +55 -0
  106. package/contracts/oapps/oft/src/codec/oft_msg_codec.rs +62 -0
  107. package/contracts/oapps/oft/src/constants.rs +5 -0
  108. package/contracts/oapps/oft/src/errors.rs +8 -0
  109. package/contracts/oapps/oft/src/events.rs +19 -0
  110. package/contracts/oapps/oft/src/interfaces/mint_burn_token.rs +23 -0
  111. package/contracts/oapps/oft/src/interfaces/mod.rs +3 -0
  112. package/contracts/oapps/oft/src/lib.rs +22 -0
  113. package/contracts/oapps/oft/src/macro_tests/mod.rs +2 -0
  114. package/contracts/oapps/oft/src/macro_tests/test_all_default.rs +41 -0
  115. package/contracts/oapps/oft/src/macro_tests/test_override.rs +83 -0
  116. package/contracts/oapps/oft/src/oft.rs +320 -0
  117. package/contracts/oapps/oft/src/oft_types/lock_unlock.rs +50 -0
  118. package/contracts/oapps/oft/src/oft_types/mint_burn.rs +50 -0
  119. package/contracts/oapps/oft/src/oft_types/mod.rs +10 -0
  120. package/contracts/oapps/oft/src/storage.rs +11 -0
  121. package/contracts/oapps/oft/src/tests/mod.rs +13 -0
  122. package/contracts/oapps/oft/src/tests/test_decimals.rs +89 -0
  123. package/contracts/oapps/oft/src/tests/test_lz_receive.rs +282 -0
  124. package/contracts/oapps/oft/src/tests/test_oft_compose_msg_codec.rs +68 -0
  125. package/contracts/oapps/oft/src/tests/test_oft_msg_codec.rs +136 -0
  126. package/contracts/oapps/oft/src/tests/test_oft_version.rs +13 -0
  127. package/contracts/oapps/oft/src/tests/test_quote_oft.rs +159 -0
  128. package/contracts/oapps/oft/src/tests/test_quote_send.rs +195 -0
  129. package/contracts/oapps/oft/src/tests/test_resolve_address.rs +37 -0
  130. package/contracts/oapps/oft/src/tests/test_send.rs +915 -0
  131. package/contracts/oapps/oft/src/tests/test_token.rs +47 -0
  132. package/contracts/oapps/oft/src/tests/test_utils.rs +789 -0
  133. package/contracts/oapps/oft/src/types.rs +38 -0
  134. package/contracts/oapps/oft/src/utils.rs +67 -0
  135. package/contracts/oapps/oft-mint-burn/Cargo.toml +26 -0
  136. package/contracts/oapps/oft-mint-burn/src/lib.rs +3 -0
  137. package/contracts/oapps/oft-mint-burn/src/oft.rs +28 -0
  138. package/contracts/oapps/oft-mint-burn/src/tests/mod.rs +1 -0
  139. package/contracts/utils/src/buffer_reader.rs +8 -9
  140. package/contracts/utils/src/buffer_writer.rs +11 -5
  141. package/contracts/utils/src/errors.rs +5 -5
  142. package/contracts/utils/src/ownable.rs +14 -6
  143. package/contracts/utils/src/testing_utils.rs +11 -1
  144. package/contracts/utils/src/tests/buffer_reader.rs +491 -730
  145. package/contracts/utils/src/tests/buffer_writer.rs +336 -148
  146. package/contracts/utils/src/tests/bytes_ext.rs +125 -40
  147. package/contracts/utils/src/tests/mod.rs +3 -0
  148. package/contracts/utils/src/tests/ownable.rs +379 -27
  149. package/contracts/utils/src/tests/test_helper.rs +47 -0
  150. package/contracts/utils/src/tests/testing_utils.rs +555 -0
  151. package/contracts/utils/src/tests/ttl.rs +421 -0
  152. package/contracts/utils/src/ttl.rs +29 -89
  153. package/contracts/workers/dvn/Cargo.toml +31 -0
  154. package/contracts/workers/dvn/src/auth.rs +66 -0
  155. package/contracts/workers/dvn/src/dvn.rs +143 -0
  156. package/contracts/workers/dvn/src/errors.rs +21 -0
  157. package/contracts/workers/dvn/src/events.rs +19 -0
  158. package/contracts/workers/dvn/src/interfaces/dvn.rs +12 -0
  159. package/contracts/workers/dvn/src/interfaces/mod.rs +5 -0
  160. package/contracts/workers/dvn/src/interfaces/multisig.rs +15 -0
  161. package/contracts/workers/dvn/src/lib.rs +24 -0
  162. package/contracts/workers/dvn/src/multisig.rs +127 -0
  163. package/contracts/workers/dvn/src/storage.rs +35 -0
  164. package/contracts/workers/dvn/src/tests/auth.rs +237 -0
  165. package/contracts/workers/dvn/src/tests/dvn.rs +349 -0
  166. package/contracts/workers/dvn/src/tests/key_pair.rs +66 -0
  167. package/contracts/workers/dvn/src/tests/mod.rs +5 -0
  168. package/contracts/workers/dvn/src/tests/multisig/mod.rs +3 -0
  169. package/contracts/workers/dvn/src/tests/multisig/set_signer.rs +133 -0
  170. package/contracts/workers/dvn/src/tests/multisig/set_threshold.rs +108 -0
  171. package/contracts/workers/dvn/src/tests/multisig/verify_signatures.rs +109 -0
  172. package/contracts/workers/dvn/src/tests/setup.rs +109 -0
  173. package/contracts/workers/dvn/src/types.rs +26 -0
  174. package/contracts/workers/dvn-fee-lib/Cargo.toml +24 -0
  175. package/contracts/workers/dvn-fee-lib/src/dvn_fee_lib.rs +113 -0
  176. package/contracts/workers/dvn-fee-lib/src/errors.rs +8 -0
  177. package/contracts/workers/dvn-fee-lib/src/lib.rs +17 -0
  178. package/contracts/workers/dvn-fee-lib/src/tests/dvn_fee_lib.rs +282 -0
  179. package/contracts/workers/dvn-fee-lib/src/tests/mod.rs +1 -0
  180. package/contracts/workers/executor/Cargo.toml +10 -7
  181. package/contracts/workers/executor/src/errors.rs +8 -0
  182. package/contracts/workers/executor/src/events.rs +4 -7
  183. package/contracts/workers/executor/src/interfaces/executor.rs +72 -22
  184. package/contracts/workers/executor/src/interfaces/mod.rs +0 -2
  185. package/contracts/workers/executor/src/lib.rs +16 -7
  186. package/contracts/workers/executor/src/lz_executor.rs +308 -0
  187. package/contracts/workers/executor/src/storage.rs +24 -16
  188. package/contracts/workers/executor-fee-lib/Cargo.toml +22 -0
  189. package/contracts/workers/executor-fee-lib/src/errors.rs +15 -0
  190. package/contracts/workers/executor-fee-lib/src/executor_fee_lib.rs +215 -0
  191. package/contracts/workers/executor-fee-lib/src/executor_option.rs +203 -0
  192. package/contracts/workers/executor-fee-lib/src/lib.rs +7 -0
  193. package/contracts/workers/executor-helper/Cargo.toml +29 -0
  194. package/contracts/workers/executor-helper/src/executor_helper.rs +161 -0
  195. package/contracts/workers/executor-helper/src/lib.rs +11 -0
  196. package/contracts/workers/{worker-common → worker}/Cargo.toml +1 -4
  197. package/contracts/workers/worker/src/errors.rs +24 -0
  198. package/contracts/workers/worker/src/events.rs +62 -0
  199. package/contracts/workers/worker/src/interfaces/dvn_fee_lib.rs +75 -0
  200. package/contracts/workers/worker/src/interfaces/executor_fee_lib.rs +84 -0
  201. package/contracts/workers/{worker-common → worker}/src/interfaces/mod.rs +2 -2
  202. package/contracts/workers/worker/src/interfaces/price_feed.rs +85 -0
  203. package/contracts/workers/worker/src/lib.rs +14 -0
  204. package/contracts/workers/worker/src/storage.rs +63 -0
  205. package/contracts/workers/worker/src/worker.rs +459 -0
  206. package/package.json +3 -3
  207. package/sdk/dist/generated/bml.d.ts +88 -17
  208. package/sdk/dist/generated/bml.js +62 -16
  209. package/sdk/dist/generated/counter.d.ts +281 -102
  210. package/sdk/dist/generated/counter.js +93 -41
  211. package/sdk/dist/generated/endpoint.d.ts +128 -105
  212. package/sdk/dist/generated/endpoint.js +47 -45
  213. package/sdk/dist/generated/sml.d.ts +212 -69
  214. package/sdk/dist/generated/sml.js +103 -53
  215. package/sdk/dist/generated/uln302.d.ts +270 -173
  216. package/sdk/dist/generated/uln302.js +112 -64
  217. package/sdk/package.json +11 -11
  218. package/sdk/test/index.test.ts +147 -42
  219. package/sdk/test/suites/constants.ts +7 -3
  220. package/sdk/test/suites/deploy.ts +65 -42
  221. package/sdk/test/suites/localnet.ts +2 -2
  222. package/sdk/test/suites/scan.ts +28 -25
  223. package/sdk/test/utils.ts +199 -0
  224. package/sdk/tsconfig.json +93 -95
  225. package/tools/ts-bindings-gen/src/main.rs +2 -0
  226. package/contracts/common-macros/src/snapshots/common_macros__tests__tests__snapshot_generated_storage_code.snap +0 -310
  227. package/contracts/common-macros/src/tests.rs +0 -287
  228. package/contracts/oapp-macros/tests/test_macros.rs +0 -522
  229. package/contracts/workers/executor/src/executor.rs +0 -347
  230. package/contracts/workers/executor/src/interfaces/types.rs +0 -51
  231. package/contracts/workers/worker-common/src/constants.rs +0 -17
  232. package/contracts/workers/worker-common/src/errors.rs +0 -6
  233. package/contracts/workers/worker-common/src/events.rs +0 -34
  234. package/contracts/workers/worker-common/src/interfaces/executor_fee_lib.rs +0 -35
  235. package/contracts/workers/worker-common/src/interfaces/price_feed.rs +0 -40
  236. package/contracts/workers/worker-common/src/interfaces/worker.rs +0 -60
  237. package/contracts/workers/worker-common/src/lib.rs +0 -19
  238. package/contracts/workers/worker-common/src/storage.rs +0 -32
  239. package/contracts/workers/worker-common/src/worker_common.rs +0 -166
@@ -0,0 +1,143 @@
1
+ use crate::{
2
+ errors::{DvnError, MultisigError},
3
+ events::SetDstConfig,
4
+ storage::DvnStorage,
5
+ types::{DstConfig, DstConfigParam},
6
+ IDVN,
7
+ };
8
+ use common_macros::ttl_configurable;
9
+ use endpoint_v2::FeeRecipient;
10
+ use message_lib_common::interfaces::ILayerZeroDVN;
11
+ use soroban_sdk::{
12
+ assert_with_error, contract, contractimpl, crypto::Hash, xdr::ToXdr, Address, Bytes, BytesN, Env, Vec,
13
+ };
14
+ use utils::{buffer_writer::BufferWriter, option_ext::OptionExt};
15
+ use worker::{
16
+ assert_acl, assert_not_paused, assert_supported_message_lib, init_worker, require_admin_auth, set_admin_by_admin,
17
+ set_admin_by_owner, storage::WorkerStorage, DvnFeeLibClient, DvnFeeParams, Worker,
18
+ };
19
+ #[contract]
20
+ #[ttl_configurable]
21
+ pub struct Dvn;
22
+
23
+ #[contractimpl]
24
+ impl Dvn {
25
+ pub fn __constructor(
26
+ env: &Env,
27
+ vid: u32,
28
+ signers: &Vec<BytesN<20>>,
29
+ threshold: u32,
30
+ admins: &Vec<Address>,
31
+ supported_msglibs: &Vec<Address>,
32
+ price_feed: &Address,
33
+ worker_fee_lib: &Address,
34
+ default_multiplier_bps: u32,
35
+ deposit_address: &Address,
36
+ ) {
37
+ init_multisig(env, signers, threshold);
38
+ Self::init_owner(env, &env.current_contract_address());
39
+ init_worker::<Self>(env, admins, supported_msglibs, price_feed, default_multiplier_bps);
40
+ WorkerStorage::set_worker_fee_lib(env, worker_fee_lib);
41
+ WorkerStorage::set_deposit_address(env, deposit_address);
42
+ DvnStorage::set_vid(env, &vid);
43
+ }
44
+
45
+ /// Sets admin status for an address. Can be called by an existing admin.
46
+ ///
47
+ /// This allows existing admins to add or remove other admins without going through
48
+ /// the owner/multisig path.
49
+ ///
50
+ /// # Arguments
51
+ /// * `caller` - The admin calling this function (must provide authorization)
52
+ /// * `admin` - The address to set admin status for
53
+ /// * `active` - `true` to add admin, `false` to remove
54
+ pub fn set_admin(env: &Env, caller: &Address, admin: &Address, active: bool) {
55
+ set_admin_by_admin::<Self>(env, caller, admin, active);
56
+ }
57
+
58
+ /// Function for quorum to change the admin without going through the execute function
59
+ ///
60
+ /// # Arguments
61
+ ///
62
+ /// * `admin` - The address to set admin status for
63
+ /// * `active` - `true` to add admin, `false` to remove
64
+ pub fn quorum_change_admin(env: &Env, admin: &Address, active: bool) {
65
+ set_admin_by_owner::<Self>(env, admin, active);
66
+ }
67
+ }
68
+
69
+ #[contractimpl]
70
+ impl IDVN for Dvn {
71
+ fn set_dst_config(env: &Env, admin: &Address, params: &Vec<DstConfigParam>) {
72
+ require_admin_auth::<Self>(env, admin);
73
+ for param in params {
74
+ DvnStorage::set_dst_config(env, param.dst_eid, &param.config);
75
+ }
76
+
77
+ SetDstConfig { params: params.clone() }.publish(env);
78
+ }
79
+
80
+ fn dst_config(env: &Env, dst_eid: u32) -> DstConfig {
81
+ DvnStorage::dst_config(env, dst_eid).unwrap_or_panic(env, DvnError::EidNotSupported)
82
+ }
83
+
84
+ fn vid(env: &Env) -> u32 {
85
+ DvnStorage::vid(env).unwrap()
86
+ }
87
+ }
88
+
89
+ #[contractimpl]
90
+ impl ILayerZeroDVN for Dvn {
91
+ fn get_fee(
92
+ env: &Env,
93
+ _send_lib: &Address,
94
+ sender: &Address,
95
+ dst_eid: u32,
96
+ _packet_header: &Bytes,
97
+ _payload_hash: &BytesN<32>,
98
+ confirmations: u64,
99
+ options: &Bytes,
100
+ ) -> i128 {
101
+ assert_not_paused::<Self>(env);
102
+ assert_acl::<Self>(env, sender);
103
+
104
+ let dst_config = Self::dst_config(env, dst_eid);
105
+ let params = DvnFeeParams {
106
+ sender: sender.clone(),
107
+ dst_eid,
108
+ confirmations,
109
+ options: options.clone(),
110
+ price_feed: Self::price_feed(env),
111
+ default_multiplier_bps: Self::default_multiplier_bps(env),
112
+ quorum: Self::threshold(env),
113
+ gas: dst_config.gas,
114
+ multiplier_bps: dst_config.multiplier_bps,
115
+ floor_margin_usd: dst_config.floor_margin_usd,
116
+ };
117
+
118
+ DvnFeeLibClient::new(env, &Self::worker_fee_lib(env)).get_fee(&params)
119
+ }
120
+
121
+ fn assign_job(
122
+ env: &Env,
123
+ send_lib: &Address,
124
+ sender: &Address,
125
+ dst_eid: u32,
126
+ packet_header: &Bytes,
127
+ payload_hash: &BytesN<32>,
128
+ confirmations: u64,
129
+ options: &Bytes,
130
+ ) -> FeeRecipient {
131
+ send_lib.require_auth();
132
+ assert_supported_message_lib::<Self>(env, send_lib);
133
+
134
+ let fee = Self::get_fee(env, send_lib, sender, dst_eid, packet_header, payload_hash, confirmations, options);
135
+ FeeRecipient { amount: fee, to: Self::deposit_address(env) }
136
+ }
137
+ }
138
+
139
+ #[contractimpl(contracttrait)]
140
+ impl Worker for Dvn {}
141
+
142
+ include!("multisig.rs");
143
+ include!("auth.rs");
@@ -0,0 +1,21 @@
1
+ use common_macros::contract_error;
2
+
3
+ #[contract_error]
4
+ pub enum MultisigError {
5
+ ZeroThreshold,
6
+ TotalSignersLessThanThreshold,
7
+ InvalidSigner,
8
+ SignerAlreadyExists,
9
+ SignerNotFound,
10
+ UnsortedSigners,
11
+ SignatureError,
12
+ }
13
+
14
+ #[contract_error]
15
+ pub enum DvnError {
16
+ InvalidVid,
17
+ AuthDataExpired,
18
+ HashAlreadyUsed,
19
+ OnlyAdmin,
20
+ EidNotSupported,
21
+ }
@@ -0,0 +1,19 @@
1
+ use crate::DstConfigParam;
2
+ use common_macros::event;
3
+ use soroban_sdk::{BytesN, Vec};
4
+
5
+ #[event]
6
+ pub struct SignerSet {
7
+ pub signer: BytesN<20>,
8
+ pub active: bool,
9
+ }
10
+
11
+ #[event]
12
+ pub struct ThresholdSet {
13
+ pub threshold: u32,
14
+ }
15
+
16
+ #[event]
17
+ pub struct SetDstConfig {
18
+ pub params: Vec<DstConfigParam>,
19
+ }
@@ -0,0 +1,12 @@
1
+ use crate::types::{DstConfig, DstConfigParam};
2
+ use crate::IMultisig;
3
+ use message_lib_common::interfaces::ILayerZeroDVN;
4
+ use soroban_sdk::{contractclient, Address, Env, Vec};
5
+ use worker::Worker;
6
+
7
+ #[contractclient(name = "DVNClient")]
8
+ pub trait IDVN: ILayerZeroDVN + Worker + IMultisig {
9
+ fn set_dst_config(env: &Env, admin: &Address, params: &Vec<DstConfigParam>);
10
+ fn dst_config(env: &Env, dst_eid: u32) -> DstConfig;
11
+ fn vid(env: &Env) -> u32;
12
+ }
@@ -0,0 +1,5 @@
1
+ mod dvn;
2
+ mod multisig;
3
+
4
+ pub use dvn::*;
5
+ pub use multisig::*;
@@ -0,0 +1,15 @@
1
+ use soroban_sdk::{contractclient, BytesN, Env, Vec};
2
+
3
+ pub const SIGNATURE_LENGTH: usize = 65;
4
+
5
+ #[contractclient(name = "MultiSigClient")]
6
+ pub trait IMultisig {
7
+ fn set_signer(env: &Env, signer: &BytesN<20>, active: bool);
8
+ fn get_signers(env: &Env) -> Vec<BytesN<20>>;
9
+ fn total_signers(env: &Env) -> u32;
10
+ fn is_signer(env: &Env, signer: &BytesN<20>) -> bool;
11
+ fn threshold(env: &Env) -> u32;
12
+ fn set_threshold(env: &Env, threshold: u32);
13
+ fn verify_signatures(env: &Env, hash: &BytesN<32>, signatures: &Vec<BytesN<SIGNATURE_LENGTH>>);
14
+ fn verify_n_signatures(env: &Env, hash: &BytesN<32>, signatures: &Vec<BytesN<SIGNATURE_LENGTH>>, threshold: u32);
15
+ }
@@ -0,0 +1,24 @@
1
+ #![no_std]
2
+ #[cfg(test)]
3
+ extern crate std;
4
+
5
+ mod errors;
6
+ pub mod events;
7
+ mod interfaces;
8
+ mod types;
9
+
10
+ pub use errors::*;
11
+ pub use interfaces::*;
12
+ pub use types::*;
13
+
14
+ cfg_if::cfg_if! {
15
+ if #[cfg(any(not(feature = "library"), feature = "testutils"))] {
16
+ mod storage;
17
+ mod dvn;
18
+
19
+ pub use dvn::Dvn;
20
+ }
21
+ }
22
+
23
+ #[cfg(test)]
24
+ mod tests;
@@ -0,0 +1,127 @@
1
+ use crate::{
2
+ events::{SignerSet, ThresholdSet},
3
+ storage::MultisigStorage,
4
+ IMultisig,
5
+ };
6
+
7
+ #[contractimpl]
8
+ impl IMultisig for Dvn {
9
+ fn set_signer(env: &Env, signer: &BytesN<20>, active: bool) {
10
+ env.current_contract_address().require_auth();
11
+
12
+ if active {
13
+ add_signer(env, signer);
14
+ } else {
15
+ remove_signer(env, signer);
16
+ }
17
+ }
18
+
19
+ fn set_threshold(env: &Env, threshold: u32) {
20
+ env.current_contract_address().require_auth();
21
+
22
+ set_threshold(env, threshold);
23
+ }
24
+
25
+ fn get_signers(env: &Env) -> Vec<BytesN<20>> {
26
+ MultisigStorage::signers(env)
27
+ }
28
+
29
+ fn total_signers(env: &Env) -> u32 {
30
+ MultisigStorage::signers(env).len()
31
+ }
32
+
33
+ fn is_signer(env: &Env, signer: &BytesN<20>) -> bool {
34
+ MultisigStorage::signers(env).iter().any(|s| &s == signer)
35
+ }
36
+
37
+ fn threshold(env: &Env) -> u32 {
38
+ MultisigStorage::threshold(env)
39
+ }
40
+
41
+ fn verify_signatures(env: &Env, hash: &BytesN<32>, signatures: &Vec<BytesN<65>>) {
42
+ Self::verify_n_signatures(env, hash, signatures, Self::threshold(env));
43
+ }
44
+
45
+ fn verify_n_signatures(env: &Env, hash: &BytesN<32>, signatures: &Vec<BytesN<65>>, threshold: u32) {
46
+ assert_with_error!(env, threshold > 0, MultisigError::ZeroThreshold);
47
+ assert_with_error!(env, signatures.len() >= threshold, MultisigError::SignatureError);
48
+
49
+ let mut last_signer: Option<BytesN<20>> = None;
50
+ signatures.iter().for_each(|signature| {
51
+ let signer = recover_signer(env, hash, &signature);
52
+
53
+ // Signers must be strictly increasing
54
+ assert_with_error!(
55
+ env,
56
+ last_signer.as_ref().is_none_or(|last| &signer > last),
57
+ MultisigError::UnsortedSigners
58
+ );
59
+ assert_with_error!(env, Self::is_signer(env, &signer), MultisigError::SignerNotFound);
60
+
61
+ last_signer = Some(signer);
62
+ });
63
+ }
64
+ }
65
+
66
+ // ============================================================================
67
+ // Internal Helper Functions
68
+ // ============================================================================
69
+
70
+ fn add_signer(env: &Env, signer: &BytesN<20>) {
71
+ let zero_signer = BytesN::from_array(env, &[0u8; 20]);
72
+ assert_with_error!(env, signer != &zero_signer, MultisigError::InvalidSigner);
73
+
74
+ let mut signers = MultisigStorage::signers(env);
75
+ assert_with_error!(env, !signers.iter().any(|s| &s == signer), MultisigError::SignerAlreadyExists);
76
+ signers.push_back(signer.clone());
77
+ MultisigStorage::set_signers(env, &signers);
78
+
79
+ SignerSet { signer: signer.clone(), active: true }.publish(env);
80
+ }
81
+
82
+ fn remove_signer(env: &Env, signer: &BytesN<20>) {
83
+ let mut signers = MultisigStorage::signers(env);
84
+ let index = signers.first_index_of(signer);
85
+ assert_with_error!(env, index.is_some(), MultisigError::SignerNotFound);
86
+
87
+ signers.remove(index.unwrap());
88
+ // Check that removing didn't violate threshold constraint
89
+ assert_with_error!(
90
+ env,
91
+ signers.len() >= MultisigStorage::threshold(env),
92
+ MultisigError::TotalSignersLessThanThreshold
93
+ );
94
+ MultisigStorage::set_signers(env, &signers);
95
+
96
+ SignerSet { signer: signer.clone(), active: false }.publish(env);
97
+ }
98
+
99
+ fn set_threshold(env: &Env, threshold: u32) {
100
+ assert_with_error!(env, threshold > 0, MultisigError::ZeroThreshold);
101
+ assert_with_error!(
102
+ env,
103
+ MultisigStorage::signers(env).len() >= threshold,
104
+ MultisigError::TotalSignersLessThanThreshold
105
+ );
106
+
107
+ MultisigStorage::set_threshold(env, &threshold);
108
+
109
+ ThresholdSet { threshold }.publish(env);
110
+ }
111
+
112
+ fn init_multisig(env: &Env, signers: &Vec<BytesN<20>>, threshold: u32) {
113
+ signers.iter().for_each(|signer| add_signer(env, &signer));
114
+
115
+ set_threshold(env, threshold);
116
+ }
117
+
118
+ fn recover_signer(env: &Env, digest: &BytesN<32>, signature: &BytesN<65>) -> BytesN<20> {
119
+ let sig_bytes: Bytes = signature.into();
120
+ let v = sig_bytes.get(64).unwrap();
121
+ let recovery_id = if (27..=30).contains(&v) { v - 27 } else { v };
122
+ let sig_rs: BytesN<64> = sig_bytes.slice(0..64).try_into().unwrap();
123
+
124
+ let public_key = env.crypto_hazmat().secp256k1_recover(digest, &sig_rs, recovery_id as u32);
125
+
126
+ Bytes::from(env.crypto().keccak256(&Bytes::from(public_key).slice(1..65))).slice(12..32).try_into().unwrap()
127
+ }
@@ -0,0 +1,35 @@
1
+ use crate::DstConfig;
2
+ use common_macros::storage;
3
+ use soroban_sdk::{BytesN, Vec};
4
+
5
+ // ============================================================================
6
+ // Multisig Storage
7
+ // ============================================================================
8
+
9
+ #[storage]
10
+ pub enum MultisigStorage {
11
+ #[persistent(Vec<BytesN<20>>)]
12
+ #[default(Vec::new(env))]
13
+ Signers,
14
+
15
+ #[instance(u32)]
16
+ #[default(0)]
17
+ Threshold,
18
+ }
19
+
20
+ // ============================================================================
21
+ // DVN Storage
22
+ // ============================================================================
23
+
24
+ #[storage]
25
+ pub enum DvnStorage {
26
+ #[instance(u32)]
27
+ Vid,
28
+
29
+ #[persistent(DstConfig)]
30
+ DstConfig { dst_eid: u32 },
31
+
32
+ #[persistent(bool)]
33
+ #[default(false)]
34
+ UsedHash { hash: BytesN<32> },
35
+ }
@@ -0,0 +1,237 @@
1
+ use crate::tests::setup::{TestSetup, VID};
2
+ use crate::{errors::DvnError, errors::MultisigError, TransactionAuthData};
3
+ use ed25519_dalek::{Signer, SigningKey};
4
+ use rand::thread_rng;
5
+ use soroban_sdk::{auth::Context, vec, Bytes, BytesN, Env, IntoVal, Vec};
6
+
7
+ struct Ed25519KeyPair {
8
+ signing_key: SigningKey,
9
+ }
10
+
11
+ impl Ed25519KeyPair {
12
+ fn generate() -> Self {
13
+ Self { signing_key: SigningKey::generate(&mut thread_rng()) }
14
+ }
15
+
16
+ fn public_key_bytes(&self) -> [u8; 32] {
17
+ self.signing_key.verifying_key().to_bytes()
18
+ }
19
+
20
+ fn public_key(&self, env: &Env) -> BytesN<32> {
21
+ self.public_key_bytes().into_val(env)
22
+ }
23
+
24
+ fn sign(&self, env: &Env, message: &[u8; 32]) -> BytesN<64> {
25
+ let sig = self.signing_key.sign(message);
26
+ BytesN::from_array(env, &sig.to_bytes())
27
+ }
28
+ }
29
+
30
+ fn hash_auth_data(env: &Env, vid: u32, expiration: u64, auth_contexts: &Vec<Context>) -> BytesN<32> {
31
+ use soroban_sdk::xdr::ToXdr;
32
+ let mut data = Bytes::new(env);
33
+ data.extend_from_array(&vid.to_be_bytes());
34
+ data.extend_from_array(&expiration.to_be_bytes());
35
+ data.append(&auth_contexts.to_xdr(env));
36
+ let hash = env.crypto().keccak256(&data);
37
+ BytesN::from_array(env, &hash.to_array())
38
+ }
39
+
40
+ #[test]
41
+ fn test_check_auth_success() {
42
+ extern crate std;
43
+ let admin_kp = Ed25519KeyPair::generate();
44
+ let admin_bytes = admin_kp.public_key_bytes();
45
+
46
+ let setup = TestSetup::with_admin_bytes(1, std::vec![admin_bytes]);
47
+ let env = setup.env.clone();
48
+ let expiration = env.ledger().timestamp() + 1000;
49
+ let auth_contexts: Vec<Context> = Vec::new(&env);
50
+
51
+ let payload = BytesN::from_array(&env, &[0u8; 32]);
52
+ let admin = admin_kp.public_key(&env);
53
+ let admin_signature = admin_kp.sign(&env, &payload.to_array());
54
+
55
+ let hash = hash_auth_data(&env, VID, expiration, &auth_contexts);
56
+ let sig = setup.key_pairs[0].sign_bytes(&env, &hash);
57
+
58
+ let tx_auth = TransactionAuthData { vid: VID, expiration, signatures: vec![&env, sig], admin, admin_signature };
59
+
60
+ let res = env.try_invoke_contract_check_auth::<DvnError>(
61
+ &setup.contract_id,
62
+ &payload,
63
+ tx_auth.into_val(&env),
64
+ &auth_contexts,
65
+ );
66
+
67
+ assert!(res.is_ok(), "Expected success, got {:?}", res);
68
+ }
69
+
70
+ #[test]
71
+ fn test_check_auth_not_admin() {
72
+ extern crate std;
73
+ let non_admin_kp = Ed25519KeyPair::generate();
74
+
75
+ let setup = TestSetup::new(1);
76
+ let env = setup.env.clone();
77
+ let expiration = env.ledger().timestamp() + 1000;
78
+ let auth_contexts: Vec<Context> = Vec::new(&env);
79
+
80
+ let payload = BytesN::from_array(&env, &[0u8; 32]);
81
+ let admin = non_admin_kp.public_key(&env);
82
+ let admin_signature = non_admin_kp.sign(&env, &payload.to_array());
83
+
84
+ let hash = hash_auth_data(&env, VID, expiration, &auth_contexts);
85
+ let sig = setup.key_pairs[0].sign_bytes(&env, &hash);
86
+
87
+ let tx_auth = TransactionAuthData { vid: VID, expiration, signatures: vec![&env, sig], admin, admin_signature };
88
+
89
+ let res = env.try_invoke_contract_check_auth::<DvnError>(
90
+ &setup.contract_id,
91
+ &payload,
92
+ tx_auth.into_val(&env),
93
+ &auth_contexts,
94
+ );
95
+
96
+ assert_eq!(res, Err(Ok(DvnError::OnlyAdmin)));
97
+ }
98
+
99
+ #[test]
100
+ fn test_check_auth_wrong_signer_fails() {
101
+ extern crate std;
102
+ let admin_kp = Ed25519KeyPair::generate();
103
+ let admin_bytes = admin_kp.public_key_bytes();
104
+
105
+ let setup = TestSetup::with_admin_bytes(1, std::vec![admin_bytes]);
106
+ let env = setup.env.clone();
107
+ let expiration = env.ledger().timestamp() + 1000;
108
+ let auth_contexts: Vec<Context> = Vec::new(&env);
109
+
110
+ let payload = BytesN::from_array(&env, &[0u8; 32]);
111
+ let admin = admin_kp.public_key(&env);
112
+ let admin_signature = admin_kp.sign(&env, &payload.to_array());
113
+
114
+ let hash = hash_auth_data(&env, VID, expiration, &auth_contexts);
115
+ let wrong_sig = crate::tests::key_pair::KeyPair::generate().sign_bytes(&env, &hash);
116
+
117
+ let tx_auth =
118
+ TransactionAuthData { vid: VID, expiration, signatures: vec![&env, wrong_sig], admin, admin_signature };
119
+
120
+ // verify_signatures panics with MultisigError::SignerNotFound when signer is not found
121
+ let res = env.try_invoke_contract_check_auth::<MultisigError>(
122
+ &setup.contract_id,
123
+ &payload,
124
+ tx_auth.into_val(&env),
125
+ &auth_contexts,
126
+ );
127
+
128
+ assert_eq!(res, Err(Ok(MultisigError::SignerNotFound)));
129
+ }
130
+
131
+ #[test]
132
+ fn test_check_auth_invalid_vid_fails() {
133
+ extern crate std;
134
+ let admin_kp = Ed25519KeyPair::generate();
135
+ let admin_bytes = admin_kp.public_key_bytes();
136
+
137
+ let setup = TestSetup::with_admin_bytes(1, std::vec![admin_bytes]);
138
+ let env = setup.env.clone();
139
+ let expiration = env.ledger().timestamp() + 1000;
140
+ let wrong_vid = VID + 1;
141
+ let auth_contexts: Vec<Context> = Vec::new(&env);
142
+
143
+ let payload = BytesN::from_array(&env, &[0u8; 32]);
144
+ let admin = admin_kp.public_key(&env);
145
+ let admin_signature = admin_kp.sign(&env, &payload.to_array());
146
+
147
+ let hash = hash_auth_data(&env, wrong_vid, expiration, &auth_contexts);
148
+ let sig = setup.key_pairs[0].sign_bytes(&env, &hash);
149
+
150
+ let tx_auth =
151
+ TransactionAuthData { vid: wrong_vid, expiration, signatures: vec![&env, sig], admin, admin_signature };
152
+
153
+ let res = env.try_invoke_contract_check_auth::<DvnError>(
154
+ &setup.contract_id,
155
+ &payload,
156
+ tx_auth.into_val(&env),
157
+ &auth_contexts,
158
+ );
159
+
160
+ assert_eq!(res, Err(Ok(DvnError::InvalidVid)));
161
+ }
162
+
163
+ #[test]
164
+ fn test_check_auth_expired_fails() {
165
+ extern crate std;
166
+ let admin_kp = Ed25519KeyPair::generate();
167
+ let admin_bytes = admin_kp.public_key_bytes();
168
+
169
+ let setup = TestSetup::with_admin_bytes(1, std::vec![admin_bytes]);
170
+ let env = setup.env.clone();
171
+ let expiration = env.ledger().timestamp();
172
+ let auth_contexts: Vec<Context> = Vec::new(&env);
173
+
174
+ let payload = BytesN::from_array(&env, &[0u8; 32]);
175
+ let admin = admin_kp.public_key(&env);
176
+ let admin_signature = admin_kp.sign(&env, &payload.to_array());
177
+
178
+ let hash = hash_auth_data(&env, VID, expiration, &auth_contexts);
179
+ let sig = setup.key_pairs[0].sign_bytes(&env, &hash);
180
+
181
+ let tx_auth = TransactionAuthData { vid: VID, expiration, signatures: vec![&env, sig], admin, admin_signature };
182
+
183
+ let res = env.try_invoke_contract_check_auth::<DvnError>(
184
+ &setup.contract_id,
185
+ &payload,
186
+ tx_auth.into_val(&env),
187
+ &auth_contexts,
188
+ );
189
+
190
+ assert_eq!(res, Err(Ok(DvnError::AuthDataExpired)));
191
+ }
192
+
193
+ #[test]
194
+ fn test_check_auth_hash_already_used_fails() {
195
+ extern crate std;
196
+ let admin_kp = Ed25519KeyPair::generate();
197
+ let admin_bytes = admin_kp.public_key_bytes();
198
+
199
+ let setup = TestSetup::with_admin_bytes(1, std::vec![admin_bytes]);
200
+ let env = setup.env.clone();
201
+ let expiration = env.ledger().timestamp() + 1000;
202
+ let auth_contexts: Vec<Context> = Vec::new(&env);
203
+
204
+ let payload = BytesN::from_array(&env, &[0u8; 32]);
205
+ let admin = admin_kp.public_key(&env);
206
+ let admin_signature = admin_kp.sign(&env, &payload.to_array());
207
+
208
+ let hash = hash_auth_data(&env, VID, expiration, &auth_contexts);
209
+ let sig = setup.key_pairs[0].sign_bytes(&env, &hash);
210
+
211
+ let tx_auth = TransactionAuthData {
212
+ vid: VID,
213
+ expiration,
214
+ signatures: vec![&env, sig.clone()],
215
+ admin: admin.clone(),
216
+ admin_signature: admin_signature.clone(),
217
+ };
218
+
219
+ let res = env.try_invoke_contract_check_auth::<DvnError>(
220
+ &setup.contract_id,
221
+ &payload,
222
+ tx_auth.into_val(&env),
223
+ &auth_contexts,
224
+ );
225
+ assert!(res.is_ok());
226
+
227
+ let tx_auth2 = TransactionAuthData { vid: VID, expiration, signatures: vec![&env, sig], admin, admin_signature };
228
+
229
+ let res2 = env.try_invoke_contract_check_auth::<DvnError>(
230
+ &setup.contract_id,
231
+ &payload,
232
+ tx_auth2.into_val(&env),
233
+ &auth_contexts,
234
+ );
235
+
236
+ assert_eq!(res2, Err(Ok(DvnError::HashAlreadyUsed)));
237
+ }