@layerzerolabs/layerzero-v2-ton 3.0.19-ton.0 → 3.0.21-ton.0

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 (209) hide show
  1. package/build/AllStorages.compiled.json +1 -1
  2. package/build/AllStorages.test.compiled.json +1 -1
  3. package/build/BaseContract.test.compiled.json +1 -1
  4. package/build/Channel.compiled.json +1 -1
  5. package/build/Channel.permissions.test.compiled.json +1 -1
  6. package/build/ChannelBurn.test.compiled.json +1 -1
  7. package/build/ChannelCommitPacket.test.compiled.json +1 -1
  8. package/build/ChannelConfig.test.compiled.json +1 -1
  9. package/build/ChannelInitialize.test.compiled.json +1 -1
  10. package/build/ChannelMsglibIntegration.test.compiled.json +1 -1
  11. package/build/ChannelMsglibSendCallback.test.compiled.json +1 -1
  12. package/build/ChannelNilify.test.compiled.json +1 -1
  13. package/build/ChannelReceive.test.compiled.json +1 -1
  14. package/build/ChannelReceiveCallback.test.compiled.json +1 -1
  15. package/build/ChannelReceiveView.test.compiled.json +1 -1
  16. package/build/ChannelSend.test.compiled.json +1 -1
  17. package/build/Classlib.test.compiled.json +1 -1
  18. package/build/ComputeDataSizeGas.test.compiled.json +1 -1
  19. package/build/Connection.compiled.json +1 -1
  20. package/build/Controller.assertions.test.compiled.json +1 -1
  21. package/build/Controller.compiled.json +1 -1
  22. package/build/Controller.permissions.test.compiled.json +1 -1
  23. package/build/Controller.test.compiled.json +1 -1
  24. package/build/Counter.compiled.json +1 -1
  25. package/build/Counter.permissions.test.compiled.json +1 -1
  26. package/build/Counter.setters.test.compiled.json +1 -1
  27. package/build/Counter.test.compiled.json +1 -1
  28. package/build/Dvn.compiled.json +1 -1
  29. package/build/Dvn.test.compiled.json +1 -1
  30. package/build/DvnFeeLib.compiled.json +1 -1
  31. package/build/DvnPermissions.test.compiled.json +1 -1
  32. package/build/Endpoint.compiled.json +1 -1
  33. package/build/Endpoint.permissions.test.compiled.json +1 -1
  34. package/build/Endpoint.test.compiled.json +1 -1
  35. package/build/EndpointSetEpConfigDefaults.test.compiled.json +1 -1
  36. package/build/Executor.compiled.json +1 -1
  37. package/build/Executor.test.compiled.json +1 -1
  38. package/build/ExecutorFeeLib.compiled.json +1 -1
  39. package/build/ExecutorPermissions.test.compiled.json +1 -1
  40. package/build/LzClasses.test.compiled.json +1 -1
  41. package/build/LzUtil.test.compiled.json +1 -1
  42. package/build/MsgData.test.compiled.json +1 -1
  43. package/build/MsglibPacketCodec.test.compiled.json +1 -1
  44. package/build/PipelinedOutOfOrder.test.compiled.json +1 -1
  45. package/build/PriceFeedCache.compiled.json +1 -1
  46. package/build/PriceFeedCache.test.compiled.json +1 -1
  47. package/build/Proxy.compiled.json +1 -1
  48. package/build/Proxy.permissions.test.compiled.json +1 -1
  49. package/build/Proxy.test.compiled.json +1 -1
  50. package/build/SmlConnection.compiled.json +1 -1
  51. package/build/SmlConnection.permissions.test.compiled.json +1 -1
  52. package/build/SmlConnection.test.compiled.json +1 -1
  53. package/build/SmlManager.compiled.json +1 -1
  54. package/build/SmlManager.permissions.test.compiled.json +1 -1
  55. package/build/SmlManager.test.compiled.json +1 -1
  56. package/build/Uln.compiled.json +1 -1
  57. package/build/Uln.test.compiled.json +1 -1
  58. package/build/UlnConnection.compiled.json +1 -1
  59. package/build/UlnConnection.test.compiled.json +1 -1
  60. package/build/UlnConnectionPermissions.test.compiled.json +1 -1
  61. package/build/UlnManagement.test.compiled.json +1 -1
  62. package/build/UlnManager.compiled.json +1 -1
  63. package/build/UlnManager.test.compiled.json +1 -1
  64. package/build/UlnManagerPermissions.test.compiled.json +1 -1
  65. package/build/UlnManagerUtil.test.compiled.json +1 -1
  66. package/build/UlnPermissions.test.compiled.json +1 -1
  67. package/build/UlnReceiveConfig.test.compiled.json +1 -1
  68. package/build/UlnSend.test.compiled.json +1 -1
  69. package/build/UlnSendConfig.test.compiled.json +1 -1
  70. package/build/UlnSendWithDvnFeeLib.test.compiled.json +1 -1
  71. package/build/UlnSendWithExecFeeLib.test.compiled.json +1 -1
  72. package/build/UlnSendWorkerFactory.test.compiled.json +1 -1
  73. package/build/UlnUtil.test.compiled.json +1 -1
  74. package/build/WorkerCore.test.compiled.json +1 -1
  75. package/build/badFeeLib1.test.compiled.json +1 -1
  76. package/build/badFeeLib10.test.compiled.json +1 -1
  77. package/build/badFeeLib11.test.compiled.json +1 -1
  78. package/build/badFeeLib12.test.compiled.json +1 -1
  79. package/build/badFeeLib2.test.compiled.json +1 -1
  80. package/build/badFeeLib3.test.compiled.json +1 -1
  81. package/build/badFeeLib4.test.compiled.json +1 -1
  82. package/build/badFeeLib5.test.compiled.json +1 -1
  83. package/build/badFeeLib6.test.compiled.json +1 -1
  84. package/build/badFeeLib7.test.compiled.json +1 -1
  85. package/build/badFeeLib8.test.compiled.json +1 -1
  86. package/build/badFeeLib9.test.compiled.json +1 -1
  87. package/package.json +6 -6
  88. package/src/classes/lz/EpConfig.fc +1 -1
  89. package/src/classes/msgdata/LzReceiveStatus.fc +0 -1
  90. package/src/funC++/actions/call.fc +3 -2
  91. package/src/funC++/actions/deploy.fc +2 -3
  92. package/src/funC++/actions/destroy.fc +1 -2
  93. package/src/funC++/actions/dispatch.fc +2 -3
  94. package/src/funC++/actions/event.fc +10 -5
  95. package/src/funC++/actions/payment.fc +2 -3
  96. package/src/funC++/actions/sendJettons.fc +2 -3
  97. package/src/funC++/actions/utils.fc +0 -2
  98. package/src/funC++/baseInterface.fc +0 -2
  99. package/src/funC++/classlib.fc +5 -37
  100. package/src/funC++/constants.fc +2 -2
  101. package/src/funC++/contractMain.fc +2 -8
  102. package/src/funC++/dataStructures/AddressList.fc +2 -1
  103. package/src/funC++/dataStructures/DeterministicInsertionCircularQueue.fc +0 -1
  104. package/src/funC++/dataStructures/PipelinedOutOfOrder.fc +0 -1
  105. package/src/funC++/handlerCore.fc +2 -6
  106. package/src/funC++/stringlib.fc +0 -2
  107. package/src/funC++/testutils.fc +0 -1
  108. package/src/funC++/txnContext.fc +1 -1
  109. package/src/funC++/utils.fc +35 -0
  110. package/src/protocol/channel/callbackOpcodes.fc +10 -0
  111. package/src/protocol/channel/handler.fc +1054 -0
  112. package/src/protocol/channel/interface.fc +61 -0
  113. package/src/protocol/channel/main.fc +39 -0
  114. package/src/protocol/channel/storage.fc +55 -0
  115. package/src/protocol/controller/handler.fc +347 -0
  116. package/src/protocol/controller/interface.fc +25 -0
  117. package/src/protocol/controller/main.fc +29 -0
  118. package/src/protocol/controller/storage.fc +31 -0
  119. package/src/protocol/core/abstract/protocolHandler.fc +110 -0
  120. package/src/protocol/core/abstract/protocolMain.fc +30 -0
  121. package/src/protocol/core/baseStorage.fc +1 -2
  122. package/src/protocol/endpoint/handler.fc +426 -0
  123. package/src/protocol/endpoint/interface.fc +20 -0
  124. package/src/protocol/endpoint/main.fc +23 -0
  125. package/src/protocol/interfaces.fc +4 -0
  126. package/src/protocol/msglibs/BytesDecoder.fc +135 -0
  127. package/src/protocol/msglibs/BytesEncoder.fc +150 -0
  128. package/src/protocol/msglibs/interface.fc +16 -0
  129. package/src/protocol/msglibs/simpleMsglib/smlConnection/handler.fc +125 -0
  130. package/src/protocol/msglibs/simpleMsglib/smlConnection/interface.fc +3 -0
  131. package/src/protocol/msglibs/simpleMsglib/smlConnection/main.fc +19 -0
  132. package/src/protocol/msglibs/simpleMsglib/smlConnection/storage.fc +20 -0
  133. package/src/protocol/msglibs/simpleMsglib/smlManager/handler.fc +281 -0
  134. package/src/protocol/msglibs/simpleMsglib/smlManager/interface.fc +14 -0
  135. package/src/protocol/msglibs/simpleMsglib/smlManager/main.fc +24 -0
  136. package/src/protocol/msglibs/simpleMsglib/smlManager/storage.fc +38 -0
  137. package/src/protocol/msglibs/ultralightnode/callbackOpcodes.fc +1 -0
  138. package/src/protocol/msglibs/ultralightnode/feeLibInterface.fc +10 -0
  139. package/src/protocol/msglibs/ultralightnode/feeLibUtils.fc +51 -0
  140. package/src/protocol/msglibs/ultralightnode/msgdata/Attestation.fc +49 -0
  141. package/src/protocol/msglibs/ultralightnode/msgdata/DvnFeesPaidEvent.fc +26 -0
  142. package/src/protocol/msglibs/ultralightnode/msgdata/ExecutorFeePaidEvent.fc +23 -0
  143. package/src/protocol/msglibs/ultralightnode/msgdata/InitUln.fc +18 -0
  144. package/src/protocol/msglibs/ultralightnode/msgdata/InitUlnConnection.fc +62 -0
  145. package/src/protocol/msglibs/ultralightnode/msgdata/InitUlnManager.fc +18 -0
  146. package/src/protocol/msglibs/ultralightnode/msgdata/RentRefill.fc +18 -0
  147. package/src/protocol/msglibs/ultralightnode/msgdata/SetAdminWorkerAddresses.fc +18 -0
  148. package/src/protocol/msglibs/ultralightnode/msgdata/TreasuryFeeBps.fc +16 -0
  149. package/src/protocol/msglibs/ultralightnode/msgdata/UlnEvents.fc +26 -0
  150. package/src/protocol/msglibs/ultralightnode/msgdata/UlnReceiveConfig.fc +249 -0
  151. package/src/protocol/msglibs/ultralightnode/msgdata/UlnSend.fc +27 -0
  152. package/src/protocol/msglibs/ultralightnode/msgdata/UlnSendConfig.fc +170 -0
  153. package/src/protocol/msglibs/ultralightnode/msgdata/UlnVerification.fc +21 -0
  154. package/src/protocol/msglibs/ultralightnode/msgdata/UlnWorkerFeelibBytecode.fc +16 -0
  155. package/src/protocol/msglibs/ultralightnode/msgdata/UlnWorkerFeelibEvents.fc +58 -0
  156. package/src/protocol/msglibs/ultralightnode/msgdata/UlnWorkerFeelibInfo.fc +56 -0
  157. package/src/protocol/msglibs/ultralightnode/msgdata/VerificationStatus.fc +18 -0
  158. package/src/protocol/msglibs/ultralightnode/uln/handler.fc +803 -0
  159. package/src/protocol/msglibs/ultralightnode/uln/interface.fc +63 -0
  160. package/src/protocol/msglibs/ultralightnode/uln/main.fc +37 -0
  161. package/src/protocol/msglibs/ultralightnode/uln/storage.fc +43 -0
  162. package/src/protocol/msglibs/ultralightnode/ulnConnection/handler.fc +600 -0
  163. package/src/protocol/msglibs/ultralightnode/ulnConnection/interface.fc +36 -0
  164. package/src/protocol/msglibs/ultralightnode/ulnConnection/main.fc +32 -0
  165. package/src/protocol/msglibs/ultralightnode/ulnConnection/storage.fc +49 -0
  166. package/src/protocol/msglibs/ultralightnode/ulnConnection/utils.fc +133 -0
  167. package/src/protocol/msglibs/ultralightnode/ulnManager/handler.fc +495 -0
  168. package/src/protocol/msglibs/ultralightnode/ulnManager/interface.fc +59 -0
  169. package/src/protocol/msglibs/ultralightnode/ulnManager/main.fc +40 -0
  170. package/src/protocol/msglibs/ultralightnode/ulnManager/storage.fc +44 -0
  171. package/src/protocol/msglibs/ultralightnode/workerFeeLibs/common.fc +27 -0
  172. package/src/protocol/msglibs/ultralightnode/workerFeeLibs/dvnFeeLib/handler.fc +80 -0
  173. package/src/protocol/msglibs/ultralightnode/workerFeeLibs/dvnFeeLib/main.fc +4 -0
  174. package/src/protocol/msglibs/ultralightnode/workerFeeLibs/dvnFeeLib/storage.fc +26 -0
  175. package/src/protocol/msglibs/ultralightnode/workerFeeLibs/executorFeeLib/handler.fc +123 -0
  176. package/src/protocol/msglibs/ultralightnode/workerFeeLibs/executorFeeLib/main.fc +4 -0
  177. package/src/protocol/msglibs/ultralightnode/workerFeeLibs/executorFeeLib/storage.fc +29 -0
  178. package/src/protocol/msglibs/ultralightnode/workerFeeLibs/main.fc +3 -0
  179. package/src/protocol/msglibs/ultralightnode/workerFeeLibs/priceFeedFeeLib/main.fc +1 -0
  180. package/src/protocol/msglibs/ultralightnode/workerFeeLibs/priceFeedFeeLib/storage.fc +39 -0
  181. package/src/protocol/msglibs/ultralightnode/workerFeeLibs/ulnSendWorkerV1.fc +363 -0
  182. package/src/workers/core/abstract/workerHandler.fc +150 -0
  183. package/src/workers/core/interface.fc +25 -0
  184. package/src/workers/core/workerCoreStorage.fc +44 -0
  185. package/src/workers/dvn/handler.fc +332 -0
  186. package/src/workers/dvn/interface.fc +25 -0
  187. package/src/workers/dvn/main.fc +36 -0
  188. package/src/workers/dvn/storage.fc +27 -0
  189. package/src/workers/executor/handler.fc +110 -0
  190. package/src/workers/executor/interface.fc +19 -0
  191. package/src/workers/executor/main.fc +26 -0
  192. package/src/workers/executor/storage.fc +19 -0
  193. package/src/workers/msgdata/ExecuteParams.fc +29 -0
  194. package/src/workers/msgdata/NativeDrop.fc +16 -0
  195. package/src/workers/msgdata/ProxyMessage.fc +20 -0
  196. package/src/workers/msgdata/SetDict.fc +20 -0
  197. package/src/workers/msgdata/SetQuorum.fc +20 -0
  198. package/src/workers/msgdata/SignedRequest.fc +18 -0
  199. package/src/workers/priceFeedCache/handler.fc +114 -0
  200. package/src/workers/priceFeedCache/interface.fc +4 -0
  201. package/src/workers/priceFeedCache/main.fc +25 -0
  202. package/src/workers/priceFeedCache/storage.fc +21 -0
  203. package/src/workers/proxy/handler.fc +81 -0
  204. package/src/workers/proxy/interface.fc +11 -0
  205. package/src/workers/proxy/main.fc +17 -0
  206. package/src/workers/proxy/storage.fc +21 -0
  207. package/tests/testMain.fc +0 -1
  208. package/CHANGELOG.md +0 -7
  209. package/build/PriceFeedCache.permissions.test.compiled.json +0 -1
@@ -0,0 +1,1054 @@
1
+ #include "callbackOpcodes.fc";
2
+
3
+ #include "../core/abstract/protocolHandler.fc";
4
+
5
+ #include "../../funC++/actions/dispatch.fc";
6
+ #include "../../funC++/actions/event.fc";
7
+
8
+ #include "../../classes/lz/EpConfig.fc";
9
+ #include "../../classes/lz/Packet.fc";
10
+ #include "../../classes/lz/Path.fc";
11
+ #include "../../classes/lz/ReceiveEpConfig.fc";
12
+ #include "../../classes/lz/SendEpConfig.fc";
13
+
14
+ #include "../../classes/msgdata/ChannelNonceInfo.fc";
15
+ #include "../../classes/msgdata/CoinsAmount.fc";
16
+ #include "../../classes/msgdata/ExtendedMd.fc";
17
+ #include "../../classes/msgdata/LzReceivePrepare.fc";
18
+ #include "../../classes/msgdata/LzReceiveStatus.fc";
19
+ #include "../../classes/msgdata/LzReceivePrepare.fc";
20
+ #include "../../classes/msgdata/LzSend.fc";
21
+ #include "../../classes/msgdata/MdAddress.fc";
22
+ #include "../../classes/msgdata/MdObj.fc";
23
+ #include "../../classes/msgdata/MessagingReceipt.fc";
24
+ #include "../../classes/msgdata/MsglibSendCallback.fc";
25
+ #include "../../classes/msgdata/Nonce.fc";
26
+ #include "../../classes/msgdata/PacketId.fc";
27
+ #include "../../classes/msgdata/PacketSent.fc";
28
+
29
+
30
+ #include "../../funC++/dataStructures/DeterministicInsertionCircularQueue.fc";
31
+ #include "../../funC++/dataStructures/PipelinedOutOfOrder.fc";
32
+
33
+ #include "../interfaces.fc";
34
+ #include "../msglibs/interface.fc";
35
+ #include "interface.fc";
36
+ #include "storage.fc";
37
+
38
+ ;;; ================INTERFACE FUNCTIONS=====================
39
+
40
+ int _getEventSink() inline {
41
+ return getContractStorage()
42
+ .cl::get<objRef>(Channel::baseStorage)
43
+ .cl::get<address>(BaseStorage::owner);
44
+ }
45
+
46
+ ;;; ==========================HELPER FUNCTIONS=====================================
47
+
48
+ () _assertEqualPaths(cell $path1, cell $path2) impure inline {
49
+ throw_unless(Channel::ERROR::wrongPath, $path1.cl::hash() == $path2.cl::hash());
50
+ }
51
+
52
+ ;; @info The send request queue (Channel::sendRequestQueue) is a DeterministicInsertionCircularQueue
53
+ ;; that stores a mapping from requestId => hash of LzSend object.
54
+ ;; {_build, _read}SendRequestQueueEntry functions are helper functions that
55
+ ;; serialize and deserialize the 256-bit hash that is stored in the DICQueue
56
+ cell _buildSendRequestQueueEntry(cell $lzSend) inline method_id {
57
+ return begin_cell().store_uint256($lzSend.cl::hash()).end_cell();
58
+ }
59
+
60
+ int _readSendRequestQueueEntry(cell contents) inline method_id {
61
+ if (contents.is_null()) {
62
+ return 0;
63
+ } elseif (contents.cell_is_empty()) {
64
+ return 0;
65
+ }
66
+ return contents.begin_parse().preload_uint(256);
67
+ }
68
+
69
+ ;; returns boolean committable, (packet or null)
70
+ (int, cell) _nonceCommittable(int incomingNonce) impure inline method_id {
71
+ throw_if(Channel::ERROR::invalidNonce, incomingNonce <= 0);
72
+
73
+ cell $storage = getContractStorage();
74
+
75
+ cell $executePOOO = $storage.cl::get<objRef>(Channel::executePOOO);
76
+ int firstUnexecutedNonce = $executePOOO.cl::get<uint64>(POOO::nextEmpty);
77
+
78
+ (int actualKey, cell $packet, int status, int exists) = DeterministicInsertionCircularQueue::get(
79
+ $storage.cl::get<cellRef>(Channel::executionQueue),
80
+ incomingNonce
81
+ );
82
+
83
+ if (
84
+ (incomingNonce == firstUnexecutedNonce)
85
+ & (actualKey == incomingNonce)
86
+ & (status != ExecutionQueue::executing)
87
+ ) {
88
+ ;; short-circuit for efficiency in the common case
89
+ return (true, exists ? $packet : null());
90
+ }
91
+
92
+ ;; condition 1 & 2: must be within the window
93
+ ;; condition 3: must not be executing
94
+ if (
95
+ (incomingNonce >= firstUnexecutedNonce)
96
+ & (incomingNonce <= POOO::maxSettableBit($executePOOO))
97
+ & (status != ExecutionQueue::executing)
98
+ ) {
99
+ ;; this is nested because funC doesn't support short-circuiting boolean/bitwise ops
100
+ ;; condition 4: must not be executed
101
+ ifnot (POOO::isBitSet($executePOOO, incomingNonce)) {
102
+ return (true, exists ? $packet : null());
103
+ }
104
+ }
105
+
106
+ return (false, null());
107
+ }
108
+
109
+ cell _getExecutablePacket(int incomingNonce) impure inline method_id {
110
+ (int isCommittable, cell $packet) = _nonceCommittable(incomingNonce);
111
+ int firstUncommittedNonce = getContractStorage()
112
+ .cl::get<objRef>(Channel::commitPOOO)
113
+ .cl::get<uint64>(POOO::nextEmpty);
114
+
115
+ throw_if(
116
+ Channel::ERROR::notExecutable,
117
+ ((~ isCommittable) | (incomingNonce >= firstUncommittedNonce) | $packet.is_null())
118
+ );
119
+
120
+ return $packet;
121
+ }
122
+
123
+ () _assertNonceCommittable(int incomingNonce) impure inline {
124
+ ;; Split into multiple lines to fix false-positive linter warning
125
+ (
126
+ int isCommittable,
127
+ _
128
+ ) = _nonceCommittable(incomingNonce);
129
+
130
+ throw_unless(Channel::ERROR::notCommittable, isCommittable);
131
+ }
132
+
133
+ ;;; ==========================VIEW FUNCTIONS=====================================
134
+
135
+ int _viewInboundNonce() impure method_id {
136
+ return getContractStorage()
137
+ .cl::get<objRef>(Channel::commitPOOO)
138
+ .cl::get<uint64>(POOO::nextEmpty) - 1;
139
+ }
140
+
141
+ int _viewExecutionStatus(int incomingNonce) impure method_id {
142
+ cell $storage = getContractStorage();
143
+
144
+ cell $executePOOO = $storage.cl::get<objRef>(Channel::executePOOO);
145
+ int firstUnexecutedNonce = $executePOOO.cl::get<uint64>(POOO::nextEmpty);
146
+ cell $commitPOOO = $storage.cl::get<objRef>(Channel::commitPOOO);
147
+ int firstUncommittedNonce = $commitPOOO.cl::get<uint64>(POOO::nextEmpty);
148
+ int inboundNonce = _viewInboundNonce();
149
+
150
+ int executed = incomingNonce < firstUnexecutedNonce;
151
+ if ((~ executed) & (incomingNonce < (firstUnexecutedNonce + MAX_CELL_BITS))) {
152
+ executed = executed | $executePOOO.POOO::isBitSet(incomingNonce);
153
+ }
154
+
155
+ int committed = incomingNonce < firstUncommittedNonce;
156
+ if ((~ committed) & (incomingNonce < (firstUncommittedNonce + MAX_CELL_BITS))) {
157
+ committed = committed | $commitPOOO.POOO::isBitSet(incomingNonce);
158
+ }
159
+
160
+ ifnot (committed) {
161
+ return ExecutionStatus::uncommitted;
162
+ } elseif (executed) {
163
+ return ExecutionStatus::executed;
164
+ }
165
+
166
+ (_, _, int status, _) = DeterministicInsertionCircularQueue::get(
167
+ $storage.cl::get<cellRef>(Channel::executionQueue),
168
+ incomingNonce
169
+ );
170
+ if (status == ExecutionQueue::executing) {
171
+ return ExecutionStatus::executing;
172
+ } elseif (incomingNonce <= inboundNonce) {
173
+ return ExecutionStatus::executable;
174
+ }
175
+ return ExecutionStatus::committedNotExecutable;
176
+ }
177
+
178
+ ;;; ================INTERFACE FUNCTIONS=====================
179
+
180
+ (cell, tuple) _initialize(cell $md) impure inline {
181
+ (cell $storage, tuple actions) = preamble();
182
+ cell $path = $storage.cl::get<objRef>(Channel::path);
183
+
184
+ throw_if(
185
+ Channel::ERROR::wrongPath,
186
+ ($path.cl::get<uint32>(lz::Path::srcEid) == 0)
187
+ | ($path.cl::get<address>(lz::Path::srcOApp) == NULLADDRESS)
188
+ | ($path.cl::get<uint32>(lz::Path::dstEid) == 0)
189
+ | ($path.cl::get<address>(lz::Path::dstOApp) == NULLADDRESS)
190
+ );
191
+
192
+ return (
193
+ $storage
194
+ .cl::set(Channel::executionQueue, DeterministicInsertionCircularQueue::create())
195
+ .cl::set(Channel::sendRequestQueue, DeterministicInsertionCircularQueue::create()),
196
+ actions
197
+ );
198
+ }
199
+
200
+ ;;; ================PERMISSION FUNCTIONS=====================
201
+
202
+ () _assertEndpoint() impure inline {
203
+ throw_unless(
204
+ Channel::ERROR::onlyEndpoint,
205
+ getCaller() == getContractStorage().cl::get<address>(Channel::endpointAddress)
206
+ );
207
+ }
208
+
209
+ ;; this function is purposely designed to be maximally efficient when using a
210
+ ;; custom configuration and less efficient when using a default configuration
211
+ () _assertSendMsglib(cell $mdAddress) impure inline {
212
+ cell epConfigOApp = getContractStorage().cl::get<objRef>(Channel::epConfigOApp);
213
+
214
+ ;; Resolve the actual sendMsglib address at the time of request.
215
+ ;; This function assumes the messagelib is not malicious or man-in-the-middle attacking,
216
+ ;; as those cases are asserted in the handler itself.
217
+ int sendMsglibAddress = $mdAddress
218
+ .cl::get<objRef>(md::MdAddress::md)
219
+ .cl::get<objRef>(md::MsglibSendCallback::lzSend)
220
+ .cl::get<address>(md::LzSend::sendMsglib);
221
+
222
+ throw_unless(Channel::ERROR::onlyApprovedSendMsglib, getCaller() == sendMsglibAddress);
223
+ }
224
+
225
+ () _assertOApp() impure inline {
226
+ throw_unless(
227
+ Channel::ERROR::onlyOApp,
228
+ getCaller() == getContractStorage()
229
+ .cl::get<objRef>(Channel::path)
230
+ .cl::get<uint256>(lz::Path::srcOApp)
231
+ );
232
+ }
233
+
234
+ () _checkPermissions(int op, cell $md) impure inline {
235
+ if (op == Channel::OP::LZ_RECEIVE_PREPARE) {
236
+ ;; open and public calls
237
+ return ();
238
+ } elseif (
239
+ (op == Channel::OP::CHANNEL_SEND)
240
+ | (op == Channel::OP::CHANNEL_COMMIT_PACKET)
241
+ ) {
242
+ return _assertEndpoint();
243
+ } elseif (op == Channel::OP::MSGLIB_SEND_CALLBACK) {
244
+ return _assertSendMsglib($md);
245
+ } elseif (
246
+ (op == Channel::OP::LZ_RECEIVE_LOCK)
247
+ | (op == Channel::OP::LZ_RECEIVE_EXECUTE_CALLBACK)
248
+ ) {
249
+ return _assertOApp();
250
+ } elseif (op == Channel::OP::DEPOSIT_ZRO) {
251
+ return assertOwner();
252
+ } elseif (
253
+ (op == Channel::OP::NOTIFY_PACKET_EXECUTED)
254
+ | (op == Channel::OP::SYNC_MSGLIB_CONNECTION)
255
+ ) {
256
+ return ();
257
+ } elseif (op == Channel::OP::SET_EP_CONFIG_OAPP) {
258
+ return _assertEndpoint();
259
+ } elseif (
260
+ ;; Management functions are all gated by OApp
261
+ (op == Channel::OP::NILIFY)
262
+ | (op == Channel::OP::BURN)
263
+ | (op == Channel::OP::FORCE_ABORT)
264
+ ) {
265
+ return _assertOApp();
266
+ } elseif (op == Channel::OP::EMIT_LZ_RECEIVE_ALERT) {
267
+ return ();
268
+ } else {
269
+ ;; we must put a check for all opcodes to make sure we don't
270
+ ;; mistakenly miss an opp code's permissions
271
+ throw(BaseInterface::ERROR::invalidOpcode);
272
+ }
273
+ }
274
+
275
+ ;;; ==========================HANDLERS=====================================
276
+
277
+ ;; @in endpoint/handler.fc/setEpConfig
278
+ ;; @out controller/handler.fc/emit_event
279
+ ;; @md EpConfig
280
+ tuple setEpConfigOApp(cell $epConfigOApp) impure inline method_id {
281
+ (cell $storage, tuple actions) = preamble();
282
+
283
+ int configValidity = $epConfigOApp.lz::EpConfig::isValid();
284
+ throw_if(configValidity, configValidity != lz::EpConfig::VALID);
285
+
286
+ setContractStorage($storage.cl::set(Channel::epConfigOApp, $epConfigOApp));
287
+
288
+ actions~pushAction<event>(Channel::event::EP_CFG_OAPP_SET, $epConfigOApp);
289
+ return actions;
290
+ }
291
+
292
+ ;;; ==========================================
293
+ ;; Send flow
294
+ ;; @in: endpoint/handler.fc/quote
295
+ ;; @in_md: MdObj(lzSend, defaultEpConfig)
296
+ ;; @out: msglib/handler.fc/quote
297
+ ;; @out_md: $lzSend
298
+ tuple channelSend(cell $mdObj) impure inline method_id {
299
+ (cell $storage, tuple actions) = preamble();
300
+
301
+ cell $lzSend = $mdObj.cl::get<objRef>(md::MdObj::md);
302
+ ;; assert the size and structure of the incoming lzSend message
303
+ lz::Packet::assertValidSendMessage($lzSend.cl::get<objRef>(md::LzSend::packet));
304
+
305
+ ;; Resolve the desired send msglib and send msglib connection
306
+ cell $epConfigOApp = $storage.cl::get<objRef>(Channel::epConfigOApp);
307
+ int sendMsglib = $epConfigOApp.cl::get<address>(lz::EpConfig::sendMsglib);
308
+ int sendMsglibConnection = $epConfigOApp.cl::get<address>(lz::EpConfig::sendMsglibConnection);
309
+ cell $sendPath = $storage.cl::get<objRef>(Channel::path);
310
+
311
+ if ($epConfigOApp.cl::get<bool>(lz::EpConfig::isNull)) {
312
+ cell $defaultSendEpConfig = $mdObj.cl::get<objRef>(md::MdObj::obj);
313
+
314
+ sendMsglib = $defaultSendEpConfig.cl::get<address>(lz::SendEpConfig::sendMsglibAddress);
315
+
316
+ sendMsglibConnection = $defaultSendEpConfig
317
+ .cl::get<address>(lz::SendEpConfig::sendMsglibConnectionAddress);
318
+ }
319
+
320
+ if ((sendMsglib == NULLADDRESS) | (sendMsglibConnection == NULLADDRESS)) {
321
+ actions~pushAction<call>(
322
+ $sendPath.cl::get<address>(lz::Path::srcOApp),
323
+ Layerzero::OP::CHANNEL_SEND_CALLBACK,
324
+ md::MdObj::New(
325
+ md::MessagingReceipt::New(
326
+ $lzSend,
327
+ 0,
328
+ 0,
329
+ Channel::ERROR::MsglibBlocked
330
+ ),
331
+ getInitialStorage()
332
+ )
333
+ );
334
+ return actions;
335
+ }
336
+
337
+ ;; Each send request is assigned a unique request ID, which is also used as the key into
338
+ ;; the sendRequestQueue
339
+ int curRequestId = $storage.cl::get<uint64>(Channel::lastSendRequestId) + 1;
340
+
341
+ $lzSend = md::lzSend::fillRequestInfo($lzSend, curRequestId, sendMsglib, sendMsglibConnection);
342
+
343
+ cell sendRequestQueue = $storage.cl::get<cellRef>(Channel::sendRequestQueue);
344
+ (_, _, _, int exists) = DeterministicInsertionCircularQueue::get(sendRequestQueue, curRequestId);
345
+ ifnot (exists) {
346
+ ;; submit to the msglib
347
+ setContractStorage(
348
+ $storage
349
+ .cl::set(Channel::lastSendRequestId, curRequestId)
350
+ .cl::set(
351
+ Channel::sendRequestQueue,
352
+ DeterministicInsertionCircularQueue::set(
353
+ sendRequestQueue,
354
+ curRequestId,
355
+ _buildSendRequestQueueEntry($lzSend),
356
+ SendRequestQueue::sending
357
+ )
358
+ )
359
+ );
360
+
361
+ actions~pushAction<call>(
362
+ sendMsglibConnection,
363
+ MsglibConnection::OP::MSGLIB_CONNECTION_SEND,
364
+ $lzSend
365
+ );
366
+ } else {
367
+ ;; callback to the oApp with a failure and emit an event
368
+ actions~pushAction<event>(Channel::ERROR::sendQueueCongested, $lzSend);
369
+ actions~pushAction<call>(
370
+ $storage.cl::get<objRef>(Channel::path).cl::get<address>(lz::Path::srcOApp),
371
+ Layerzero::OP::CHANNEL_SEND_CALLBACK,
372
+ md::MdObj::New(
373
+ md::MessagingReceipt::New($lzSend, 0, 0, Channel::ERROR::sendQueueCongested),
374
+ getInitialStorage()
375
+ )
376
+ );
377
+ }
378
+
379
+ return actions;
380
+ }
381
+
382
+ ;; in: msglib/handler.fc/msglibSend
383
+ ;; in_md: MsglibSendCallback
384
+ ;; out: OApp/handler.fc/sendCallback
385
+ tuple msglibSendCallback(cell $mdAddress) impure inline method_id {
386
+ (cell $storage, tuple actions) = preamble();
387
+
388
+ cell $mdMsglibSendCallback = $mdAddress.cl::get<objRef>(md::MdAddress::md);
389
+
390
+ int errorCode = $mdMsglibSendCallback.cl::get<uint8>(md::MsglibSendCallback::errorCode);
391
+
392
+ cell $lzSend = $mdMsglibSendCallback.cl::get<objRef>(md::MsglibSendCallback::lzSend);
393
+ cell sendRequestQueue = $storage.cl::get<cellRef>(Channel::sendRequestQueue);
394
+
395
+ int requestId = $lzSend.cl::get<uint64>(md::LzSend::sendRequestId);
396
+
397
+ ;; Read the requestId from the sendRequestQueue to ensure this send request is genuine
398
+ ;; and is not being double-executed
399
+ (_, cell contents, _, int exists) = DeterministicInsertionCircularQueue::get(
400
+ sendRequestQueue,
401
+ requestId
402
+ );
403
+
404
+ if (exists) {
405
+ if (_readSendRequestQueueEntry(contents) == $lzSend.cl::hash()) {
406
+ $storage = $storage.cl::set(
407
+ Channel::sendRequestQueue,
408
+ DeterministicInsertionCircularQueue::delete(sendRequestQueue, requestId)
409
+ );
410
+ } else {
411
+ ;; See below comment, this else case is logically the same as the below else block,
412
+ ;; but needs to be split due to lack of short-circuiting boolean expressions in funC
413
+ return actions;
414
+ }
415
+ } else {
416
+ ;; if the send request doesn't exist, there are two cases
417
+ ;; 1. a legitimate request was frontrun by a force-abort
418
+ ;; in this case, we can safely refund all the funds to the origin
419
+ ;; 2. a malicious MITM attack by ULN
420
+ ;; in this case, we can't refund the funds, but we can still emit an event
421
+
422
+ ;; This technically silently reverts, by not processing any output actions,
423
+ ;; thus providing a refund, instead of hard reverting
424
+ return actions;
425
+ }
426
+
427
+ ;; verify that cumulative fees quoted by the msglib <= the fee cap specified by the user/app
428
+ int zroQuote = $mdMsglibSendCallback.cl::get<coins>(md::MsglibSendCallback::zroFee);
429
+ int nativeQuote = $mdMsglibSendCallback.cl::get<coins>(md::MsglibSendCallback::nativeFee);
430
+
431
+ if ($lzSend.cl::get<coins>(md::LzSend::nativeFee) < nativeQuote) {
432
+ errorCode = Channel::ERROR::notEnoughNative;
433
+ }
434
+ if ($lzSend.cl::get<coins>(md::LzSend::zroFee) < zroQuote) {
435
+ errorCode = Channel::ERROR::notEnoughZroToken;
436
+ }
437
+
438
+ ;; Verify that the ZRO token credits in the Channel is sufficient to cover the
439
+ ;; quoted ZRO cost of the message.
440
+ int zroBalance = $storage.cl::get<coins>(Channel::zroBalance);
441
+ if (zroBalance < zroQuote) {
442
+ errorCode = Channel::ERROR::notEnoughZroTokenBalance;
443
+ }
444
+
445
+ cell $sendPath = $storage.cl::get<objRef>(Channel::path);
446
+
447
+ int packetNonce = 0;
448
+ int packetGuid = 0;
449
+ if (errorCode == Channel::NO_ERROR) {
450
+ ;; Assign a nonce to the packet and calculate the resulting GUID
451
+ packetNonce = $storage.cl::get<uint64>(Channel::outboundNonce) + 1;
452
+ packetGuid = lz::Packet::calculateGuid($sendPath, packetNonce);
453
+
454
+ ;; native payments
455
+ tuple payees = deserializePayees(
456
+ $mdMsglibSendCallback.cl::get<cellRef>(md::MsglibSendCallback::payees)
457
+ );
458
+
459
+ ;; If the TON message does not contain sufficient value to perform the payments,
460
+ ;; the transaction will revert and the send channel will eventually get blocked.
461
+ ;; It is the responsibility of the OApp to assert sufficient gas + value to cover the
462
+ ;; entire transaction and avoid this failure.
463
+ repeat (payees.tlen()) {
464
+ [int payeeAddress, int nativeAmount] = payees~tpopPayee();
465
+ actions~pushAction<payment>(payeeAddress, nativeAmount, 0);
466
+ }
467
+
468
+ ;; Due to asynchrony between the Msglib and the Channel, the nonce and guid
469
+ ;; cannot be
470
+ cell encodedPacket = $mdMsglibSendCallback
471
+ .cl::get<cellRef>(md::MsglibSendCallback::packetEncoded);
472
+
473
+ int nonceByteOffset = $mdMsglibSendCallback
474
+ .cl::get<uint16>(md::MsglibSendCallback::nonceByteOffset);
475
+
476
+ int nonceBytes = $mdMsglibSendCallback
477
+ .cl::get<uint8>(md::MsglibSendCallback::nonceBytes);
478
+
479
+ int guidByteOffset = $mdMsglibSendCallback
480
+ .cl::get<uint16>(md::MsglibSendCallback::guidByteOffset);
481
+
482
+ int guidBytes = $mdMsglibSendCallback.cl::get<uint8>(md::MsglibSendCallback::guidBytes);
483
+
484
+ cell completedEncodedPacket = null();
485
+
486
+ if (guidByteOffset > nonceByteOffset) {
487
+ completedEncodedPacket = encodedPacket
488
+ .lz::Packet::replaceTwoFieldsAtOffsets(
489
+ packetNonce,
490
+ nonceByteOffset,
491
+ nonceBytes,
492
+ packetGuid,
493
+ guidByteOffset,
494
+ guidBytes
495
+ );
496
+ } else {
497
+ completedEncodedPacket = encodedPacket
498
+ .lz::Packet::replaceTwoFieldsAtOffsets(
499
+ packetGuid,
500
+ guidByteOffset,
501
+ guidBytes,
502
+ packetNonce,
503
+ nonceByteOffset,
504
+ nonceBytes
505
+ );
506
+ }
507
+
508
+ actions~pushAction<event>(
509
+ Channel::event::PACKET_SENT,
510
+ md::PacketSent::New(
511
+ nativeQuote,
512
+ zroQuote,
513
+ $lzSend.cl::get<objRef>(md::LzSend::extraOptions),
514
+ $lzSend.cl::get<objRef>(md::LzSend::enforcedOptions),
515
+ completedEncodedPacket,
516
+ packetNonce,
517
+ $mdAddress.cl::get<address>(md::MdAddress::address), ;; msglib manager address
518
+ $mdMsglibSendCallback.cl::get<objRef>(md::MsglibSendCallback::msglibSendEvents)
519
+ )
520
+ );
521
+
522
+ $storage = $storage
523
+ .cl::set(Channel::zroBalance, zroBalance - zroQuote)
524
+ .cl::set(Channel::outboundNonce, packetNonce);
525
+ }
526
+
527
+ ;; If the quote was unsuccessful, delete the hash from storage to prevent hol blocking
528
+ ;; If the quote was successful, additionally update the ZRO balance and outbound nonce
529
+ setContractStorage($storage);
530
+
531
+ actions~pushAction<call>(
532
+ $sendPath.cl::get<address>(lz::Path::srcOApp),
533
+ Layerzero::OP::CHANNEL_SEND_CALLBACK,
534
+ md::MdObj::New(
535
+ md::MessagingReceipt::New(
536
+ $lzSend.cl::set(
537
+ md::LzSend::packet,
538
+ $lzSend
539
+ .cl::get<objRef>(md::LzSend::packet)
540
+ .cl::set(lz::Packet::nonce, packetNonce)
541
+ .cl::set(lz::Packet::guid, packetGuid)
542
+ ),
543
+ nativeQuote,
544
+ zroQuote,
545
+ errorCode
546
+ ),
547
+ getInitialStorage()
548
+ )
549
+ );
550
+
551
+ return actions;
552
+ }
553
+
554
+ ;;; ==========================================
555
+ ;; Receive flow
556
+ ;; @in endpoint/handler.fc/verify
557
+ ;; @in_md ExtendedMd(msglibConnectionAddress, defaultEpConfig, verify)
558
+ ;; @out packet_receive/handler.fc/verify
559
+ ;; @out_md ExtendedMd(msglib_addr, _, verify)
560
+ ;; @out controller/handler.fc/emit_event
561
+ tuple channelCommitPacket(cell $mdExtended) impure inline method_id {
562
+ (cell $storage, tuple actions) = preamble();
563
+
564
+ cell $packet = $mdExtended.cl::get<objRef>(md::ExtendedMd::md);
565
+ ;; assert the size of the incoming packet
566
+ lz::Packet::assertValidReceiveMessage($packet);
567
+
568
+ cell $epConfigOApp = $storage.cl::get<objRef>(Channel::epConfigOApp);
569
+ int receiveMsglibConnection = $epConfigOApp.cl::get<address>(
570
+ lz::EpConfig::receiveMsglibConnection
571
+ );
572
+
573
+ int useDefaults = $epConfigOApp.cl::get<bool>(lz::EpConfig::isNull);
574
+
575
+ if (useDefaults) {
576
+ cell $defaultConfig = $mdExtended.cl::get<objRef>(md::MdObj::obj);
577
+ receiveMsglibConnection = $defaultConfig
578
+ .cl::get<address>(lz::ReceiveEpConfig::receiveMsglibConnectionAddress);
579
+ }
580
+
581
+ int callerMsglibConnectionAddress = $mdExtended
582
+ .cl::get<address>(md::ExtendedMd::forwardingAddress);
583
+
584
+ if (receiveMsglibConnection != callerMsglibConnectionAddress) {
585
+ ;; grossly inefficient, but this will (almost) never happen
586
+ ;; so we can optimize the happy path by isolating this logic into this block
587
+ cell $defaultConfig = $mdExtended.cl::get<objRef>(md::MdObj::obj);
588
+ int timeoutReceiveMsglibConnection = useDefaults
589
+ ? $defaultConfig
590
+ .cl::get<address>(lz::ReceiveEpConfig::timeoutReceiveMsglibConnectionAddress)
591
+ : $epConfigOApp.cl::get<address>(lz::EpConfig::timeoutReceiveMsglibConnection);
592
+
593
+ int expiry = useDefaults
594
+ ? $defaultConfig.cl::get<uint64>(lz::ReceiveEpConfig::expiry)
595
+ : $epConfigOApp.cl::get<uint64>(lz::EpConfig::timeoutReceiveMsglibExpiry);
596
+
597
+ if ((timeoutReceiveMsglibConnection != callerMsglibConnectionAddress) | (expiry < now())) {
598
+ throw(Channel::ERROR::onlyApprovedReceiveMsglib);
599
+ }
600
+ }
601
+
602
+ int incomingNonce = $packet.cl::get<uint64>(lz::Packet::nonce);
603
+ cell $commitPOOO = $storage.cl::get<objRef>(Channel::commitPOOO);
604
+
605
+ (
606
+ int isCommittable,
607
+ _
608
+ ) = _nonceCommittable(incomingNonce);
609
+
610
+ if (isCommittable) {
611
+ setContractStorage(
612
+ $storage
613
+ .cl::set(Channel::commitPOOO, POOO::set($commitPOOO, incomingNonce))
614
+ .cl::set(Channel::executionQueue,
615
+ DeterministicInsertionCircularQueue::set(
616
+ $storage.cl::get<cellRef>(Channel::executionQueue),
617
+ incomingNonce,
618
+ $packet,
619
+ ExecutionQueue::committed
620
+ )
621
+ )
622
+ );
623
+ actions~pushAction<event>(Channel::event::PACKET_COMMITTED, $packet);
624
+ }
625
+
626
+ if (incomingNonce <= POOO::maxSettableBit($storage.cl::get<objRef>(Channel::executePOOO))) {
627
+ ;; Cannot respond back to msglib if the packet is not currently committable but
628
+ ;; will be committable in the future
629
+ ;; Caveat: if the packet is currently executing, we treat it as uncommittable.
630
+ ;; There exists a race condition where a uncommitted re-committable packet
631
+ ;; can be marked as committed. If the packet needs to be re-committed for a good reason
632
+ ;; (e.g., malicious DVN), the OApp owner must first nilify the packet
633
+
634
+ actions~pushAction<call>(
635
+ callerMsglibConnectionAddress,
636
+ MsglibConnection::OP::MSGLIB_CONNECTION_COMMIT_PACKET_CALLBACK,
637
+ md::ChannelNonceInfo::New(
638
+ incomingNonce,
639
+ $storage.cl::get<objRef>(Channel::executePOOO).cl::get<uint64>(POOO::nextEmpty)
640
+ )
641
+ );
642
+ }
643
+
644
+
645
+ return actions;
646
+ }
647
+
648
+ ;;; ==========================================
649
+ ;; Execution step 1
650
+ ;; @in_opcode Channel::OP::LZ_RECEIVE_PREPARE
651
+ ;; @in_from (external in) permissionless
652
+ ;; @in_md nonce
653
+ ;; @out_opcode Layerzero::OP::LZ_RECEIVE_PREPARE
654
+ ;; @out_to srcOApp
655
+ ;; @out_md ExtendedMd(md=packetId, obj=channel_init_state, forwarding_addr=NULLADDRESS)
656
+ ;; @permissions: permissonless
657
+ tuple lzReceivePrepare(cell $lzReceivePrepareMd) impure inline method_id {
658
+ (cell $storage, tuple actions) = preamble();
659
+ int nonce = $lzReceivePrepareMd.cl::get<uint64>(md::LzReceivePrepare::nonce);
660
+ int nanotons = $lzReceivePrepareMd.cl::get<coins>(md::LzReceivePrepare::nanotons);
661
+
662
+ ;; extract oApp from path
663
+ actions~pushAction<dispatch>(
664
+ $storage.cl::get<objRef>(Channel::path).cl::get<uint256>(lz::Path::srcOApp),
665
+ Layerzero::OP::LZ_RECEIVE_PREPARE,
666
+ ;; Throws if the Packet is not executable
667
+ _getExecutablePacket(nonce),
668
+ nanotons
669
+ );
670
+
671
+ return actions;
672
+ }
673
+
674
+ ;; @in_opcode Channel::OP::LZ_RECEIVE_LOCK
675
+ ;; @in_from oApp
676
+ ;; @in_md nonce
677
+ ;; @out_opcode Layerzero::OP::LZ_RECEIVE_EXECUTE
678
+ ;; @out_to oApp
679
+ ;; @out_md ExtendedMd(md=Packet, obj=channel_init_state, forwarding_addr=NULLADDRESS)
680
+ ;; @permissions: only oApp
681
+ tuple lzReceiveLock(cell $nonceMd) impure inline method_id {
682
+ (cell $storage, tuple actions) = preamble();
683
+
684
+ int incomingNonce = $nonceMd.cl::get<uint64>(md::Nonce::nonce);
685
+
686
+ throw_if(Channel::ERROR::invalidNonce, incomingNonce <= 0);
687
+ cell executionQueue = $storage.cl::get<cellRef>(Channel::executionQueue);
688
+
689
+ (int actualKey, cell $packet, int status, _) = DeterministicInsertionCircularQueue::get(
690
+ executionQueue,
691
+ incomingNonce
692
+ );
693
+
694
+ int firstUncommittedNonce = getContractStorage()
695
+ .cl::get<objRef>(Channel::commitPOOO)
696
+ .cl::get<uint64>(POOO::nextEmpty);
697
+
698
+ ;; executable if present and all preceding nonces are committed, executing, or executed
699
+ if (
700
+ (actualKey == incomingNonce)
701
+ & (status == ExecutionQueue::committed)
702
+ & (incomingNonce < firstUncommittedNonce)
703
+ ) {
704
+ ;; set state to executing
705
+ setContractStorage(
706
+ $storage.cl::set(
707
+ Channel::executionQueue,
708
+ DeterministicInsertionCircularQueue::set(
709
+ executionQueue,
710
+ incomingNonce,
711
+ $packet,
712
+ ExecutionQueue::executing
713
+ )
714
+ )
715
+ );
716
+
717
+ actions~pushAction<call>(
718
+ $storage.cl::get<objRef>(Channel::path).cl::get<uint256>(lz::Path::srcOApp),
719
+ Layerzero::OP::LZ_RECEIVE_EXECUTE,
720
+ md::MdObj::New($packet, getInitialStorage())
721
+ );
722
+ } else {
723
+ actions~pushAction<event>(
724
+ Channel::event::NOT_EXECUTABLE,
725
+ md::PacketId::New($storage.cl::get<objRef>(Channel::path), incomingNonce)
726
+ );
727
+ }
728
+
729
+ return actions;
730
+ }
731
+
732
+ ;; @in_opcode Channel::OP::LZ_RECEIVE_EXECUTE_CALLBACK
733
+ ;; @in_from oApp
734
+ ;; @in_md LzReceiveStatus
735
+ ;; @out_opcode OP::PACKET_RECEIVE_DESTROYED_CALLBACK
736
+ ;; @out_to oApp
737
+ ;; @out_md ExtendedMd(md=packetId, obj=pr_init_state, forwarding_addr=address_std_hashpart_null())
738
+ ;; @failure => unlock the Packet
739
+ ;; @success => destroy the Packet and refund rent
740
+ ;; @permissions: only oApp
741
+ tuple lzReceiveExecuteCallback(cell $lzReceiveStatus) impure inline method_id {
742
+ (cell $storage, tuple actions) = preamble();
743
+
744
+ int packetNonce = $lzReceiveStatus.cl::get<uint64>(md::LzReceiveStatus::nonce);
745
+ cell executionQueue = $storage.cl::get<cellRef>(Channel::executionQueue);
746
+
747
+ (int actualKey, cell $packet, int status, _) = DeterministicInsertionCircularQueue::get(
748
+ executionQueue,
749
+ packetNonce
750
+ );
751
+
752
+ throw_unless(
753
+ Channel::ERROR::notExecuting,
754
+ (actualKey == packetNonce) & (status == ExecutionQueue::executing)
755
+ );
756
+
757
+ ;; check for success/failure
758
+ if ($lzReceiveStatus.cl::get<bool>(md::LzReceiveStatus::success)) {
759
+ executionQueue = DeterministicInsertionCircularQueue::delete(executionQueue, packetNonce);
760
+
761
+ $storage = $storage.cl::set(
762
+ Channel::executePOOO,
763
+ POOO::set($storage.cl::get<objRef>(Channel::executePOOO), packetNonce)
764
+ );
765
+
766
+ ;; emit Packet in the manager
767
+ actions~pushAction<event>(
768
+ Channel::event::DELIVERED,
769
+ md::PacketId::New($storage.cl::get<objRef>(Channel::path), packetNonce)
770
+ );
771
+ } else {
772
+ executionQueue = DeterministicInsertionCircularQueue::set(
773
+ executionQueue,
774
+ packetNonce,
775
+ $packet, ;; same packet object that we extracted from the queue
776
+ ExecutionQueue::committed
777
+ );
778
+
779
+ ;; emit Packet so we know its unlocked
780
+ actions~pushAction<event>(
781
+ Channel::event::LZ_RECEIVE_ALERT,
782
+ md::LzReceiveStatus::NewFull(
783
+ false,
784
+ packetNonce,
785
+ $lzReceiveStatus.cl::get<coins>(md::LzReceiveStatus::value),
786
+ $lzReceiveStatus.cl::get<cellRef>(md::LzReceiveStatus::extraData),
787
+ $lzReceiveStatus.cl::get<cellRef>(md::LzReceiveStatus::reason),
788
+ getOrigin(),
789
+ $packet,
790
+ ExecutionStatus::executable
791
+ )
792
+ );
793
+ }
794
+
795
+ setContractStorage($storage.cl::set(Channel::executionQueue, executionQueue));
796
+
797
+ return actions;
798
+ }
799
+
800
+ ;;; ====================== Management Helper ===================================
801
+ () _commitFakePacket(cell $storage, int nonce, cell $receivePath) impure inline method_id {
802
+ cell $mockPacket = lz::Packet::New($receivePath, empty_cell(), nonce);
803
+
804
+ ;; Because this is not originating from the endpoint, we dont have the defaults
805
+ ;; Actual defaults and the msglib address arent required because the call is direct from the OApp
806
+ cell $mockEpConfigDefaults = lz::ReceiveEpConfig::New(
807
+ 0xdeadbeef, ;; any non-null dummy value for the receive msglib connection address
808
+ NULLADDRESS, ;; timeout never has to be used for burn
809
+ 0 ;; as above, timeout never has to be used for burn
810
+ );
811
+ cell $epConfigOApp = $storage.cl::get<objRef>(Channel::epConfigOApp);
812
+
813
+ ;; Step 1: Commit the 'mockPacket'
814
+ ;; This is safe because we are going to do the following steps (2 and 3) atomically.
815
+ ;; channelCommitPacket will not revert if the packet is not committed, but lzReceiveLock will.
816
+ ;; Basically lying to channelCommitPacket to say the "correct" msglib is committing
817
+ channelCommitPacket(
818
+ md::ExtendedMd::New(
819
+ $mockPacket,
820
+ $mockEpConfigDefaults, ;; this is completely ignored if useDefaults is false
821
+ $epConfigOApp.cl::get<bool>(lz::EpConfig::isNull)
822
+ ? $mockEpConfigDefaults.cl::get<address>(lz::EpConfig::receiveMsglibConnection)
823
+ : $epConfigOApp.cl::get<address>(lz::EpConfig::receiveMsglibConnection)
824
+ )
825
+ );
826
+ }
827
+
828
+ ;; @permissions only-oApp
829
+ tuple nilify(cell $packetId) impure inline method_id {
830
+ (cell $storage, tuple actions) = preamble();
831
+
832
+ cell $receivePath = $storage.cl::get<objRef>(Channel::path).lz::Path::optimizedReverse();
833
+ _assertEqualPaths($receivePath, $packetId.cl::get<objRef>(md::PacketId::path));
834
+
835
+ int incomingNonce = $packetId.cl::get<uint64>(md::PacketId::nonce);
836
+ _assertNonceCommittable(incomingNonce);
837
+
838
+ (_, cell $previousPacket) = _nonceCommittable(incomingNonce);
839
+
840
+ _commitFakePacket($storage, incomingNonce, $receivePath);
841
+
842
+ setContractStorage(
843
+ getContractStorage().cl::set(
844
+ Channel::executionQueue,
845
+ DeterministicInsertionCircularQueue::delete(
846
+ $storage.cl::get<cellRef>(Channel::executionQueue),
847
+ incomingNonce
848
+ )
849
+ )
850
+ );
851
+
852
+ if ($previousPacket.is_null()) {
853
+ $previousPacket = lz::Packet::New($receivePath, empty_cell(), incomingNonce);
854
+ }
855
+ actions~pushAction<event>(Channel::event::PACKET_NILIFIED, $previousPacket);
856
+
857
+ actions~pushAction<call>(
858
+ $receivePath.cl::get<uint256>(lz::Path::dstOApp),
859
+ Layerzero::OP::NILIFY_CALLBACK,
860
+ md::MdObj::New($packetId, getInitialStorage())
861
+ );
862
+
863
+ return actions;
864
+ }
865
+
866
+ tuple burn(cell $packetId) impure inline method_id {
867
+ (cell $storage, tuple actions) = preamble();
868
+
869
+ ;; reverse the path because this is from a receive perspective
870
+ cell $receivePath = lz::Path::reverse($storage.cl::get<objRef>(Channel::path));
871
+ _assertEqualPaths($receivePath, $packetId.cl::get<objRef>(md::PacketId::path));
872
+
873
+ int nonce = $packetId.cl::get<uint64>(md::PacketId::nonce);
874
+
875
+ cell $nonceMd = md::Nonce::New(nonce);
876
+
877
+ (_, cell $previousPacket) = _nonceCommittable(nonce);
878
+
879
+ ;; Step 1: Commit a 'mockPacket' to be used when we 'burn' this nonce
880
+ _commitFakePacket($storage, nonce, $receivePath);
881
+
882
+ ;; Step 2: Put the packet into 'executing'
883
+ lzReceiveLock($nonceMd);
884
+ ;; Step 3: Mock the lzReceiveExecuteCallback, which marks/flags that given nonce as used and 'executed'
885
+ lzReceiveExecuteCallback(md::LzReceiveStatus::New(true, nonce));
886
+
887
+
888
+ if ($previousPacket.is_null()) {
889
+ $previousPacket = lz::Packet::New($receivePath, empty_cell(), nonce);
890
+ }
891
+
892
+ ;; Emit an event so we are able to observe offchain that this nonce has been 'burned'
893
+ actions~pushAction<event>(
894
+ Channel::event::PACKET_BURNED,
895
+ $previousPacket
896
+ );
897
+
898
+ cell $packetId = md::PacketId::New($receivePath, nonce);
899
+ actions~pushAction<call>(
900
+ $receivePath.cl::get<uint256>(lz::Path::dstOApp),
901
+ Layerzero::OP::BURN_CALLBACK,
902
+ md::MdObj::New($packetId, getInitialStorage())
903
+ );
904
+
905
+ return actions;
906
+ }
907
+
908
+ ;;; ==========================================
909
+ ;; ZRO management
910
+ ;; only controller
911
+ tuple depositZro(cell $coinsAmount) impure inline method_id {
912
+ (cell $storage, tuple actions) = preamble();
913
+
914
+ setContractStorage(
915
+ $storage.cl::set(
916
+ Channel::zroBalance,
917
+ $storage.cl::get<coins>(Channel::zroBalance)
918
+ + $coinsAmount.cl::get<coins>(md::CoinsAmount::amount)
919
+ )
920
+ );
921
+
922
+ actions~pushAction<event>(Channel::event::ZRO_DEPOSITED, $coinsAmount);
923
+
924
+ return actions;
925
+ }
926
+
927
+ ;; Attempt to abort a send request. Check if hash still present, if present delete and send
928
+ ;; @in: oApp
929
+ ;; @in_opcode Channel::OP::FORCE_ABORT
930
+ ;; @in_md lzSend
931
+ ;; @out_opcode
932
+ ;; @out_to oApp
933
+ ;; @out_md lzSend
934
+ ;; @permissions: only oApp
935
+ tuple forceAbort(cell $lzSend) impure inline method_id {
936
+ (cell $storage, tuple actions) = preamble();
937
+
938
+ cell $path = $storage.cl::get<objRef>(Channel::path);
939
+ _assertEqualPaths(
940
+ $path,
941
+ $lzSend
942
+ .cl::get<objRef>(md::LzSend::packet)
943
+ .cl::get<objRef>(lz::Packet::path)
944
+ );
945
+
946
+ int requestId = $lzSend.cl::get<uint64>(md::LzSend::sendRequestId);
947
+
948
+ cell sendRequestQueue = $storage.cl::get<cellRef>(Channel::sendRequestQueue);
949
+
950
+ (_, cell request, int status, _) = DeterministicInsertionCircularQueue::get(sendRequestQueue, requestId);
951
+
952
+ throw_if(
953
+ Channel::ERROR::cannotAbortSend,
954
+ (status != SendRequestQueue::sending) | (_readSendRequestQueueEntry(request) != $lzSend.cl::hash())
955
+ );
956
+
957
+ ;; delete the reservation and update the storage
958
+ setContractStorage(
959
+ $storage.cl::set(
960
+ Channel::sendRequestQueue,
961
+ DeterministicInsertionCircularQueue::delete(sendRequestQueue, requestId)
962
+ )
963
+ );
964
+
965
+ actions~pushAction<call>(
966
+ $path.cl::get<uint256>(lz::Path::srcOApp),
967
+ Layerzero::OP::CHANNEL_SEND_CALLBACK,
968
+ md::MdObj::New(
969
+ md::MessagingReceipt::New($lzSend, 0, 0, Channel::ERROR::sendAborted),
970
+ getInitialStorage()
971
+ )
972
+ );
973
+
974
+ return actions;
975
+ }
976
+
977
+ ;; Send the current state of the channel to the MsglibConnection
978
+ ;; @in: permissionless
979
+ ;; @in_opcode Channel::OP::MSGLIB_CONNECTION_SYNC_CHANNEL_STATE
980
+ ;; @in_md mdAddress ( MsglibConnectionAddress, Path )
981
+ tuple syncMsglibConnection(cell $mdAddress) impure inline method_id {
982
+ (cell $storage, tuple actions) = preamble();
983
+
984
+ actions~pushAction<call>(
985
+ $mdAddress.cl::get<address>(md::MdAddress::address), ;; msglibConnectionAddress
986
+ MsglibConnection::OP::MSGLIB_CONNECTION_SYNC_CHANNEL_STATE,
987
+ md::MdObj::New(
988
+ md::ChannelNonceInfo::New(
989
+ $storage
990
+ .cl::get<objRef>(Channel::commitPOOO)
991
+ .cl::get<uint64>(POOO::nextEmpty),
992
+ $storage
993
+ .cl::get<objRef>(Channel::executePOOO)
994
+ .cl::get<uint64>(POOO::nextEmpty)
995
+ ),
996
+ getInitialStorage()
997
+ )
998
+ );
999
+
1000
+ return actions;
1001
+ }
1002
+
1003
+ tuple notifyPacketExecuted(cell $mdAddress) impure inline method_id {
1004
+ (cell $storage, tuple actions) = preamble();
1005
+
1006
+ cell $nonceMd = $mdAddress.cl::get<objRef>(md::MdAddress::md);
1007
+
1008
+ int executionStatus = _viewExecutionStatus($nonceMd.cl::get<uint64>(md::Nonce::nonce));
1009
+
1010
+ if (executionStatus != ExecutionStatus::executed) {
1011
+ return actions;
1012
+ }
1013
+
1014
+ actions~pushAction<call>(
1015
+ $mdAddress.cl::get<address>(md::MdAddress::address),
1016
+ MsglibConnection::OP::MSGLIB_CONNECTION_COMMIT_PACKET_CALLBACK,
1017
+ md::ChannelNonceInfo::New(
1018
+ $nonceMd.cl::get<uint64>(md::Nonce::nonce),
1019
+ $storage.cl::get<objRef>(Channel::executePOOO).cl::get<uint64>(POOO::nextEmpty)
1020
+ )
1021
+ );
1022
+ return actions;
1023
+ }
1024
+
1025
+ tuple emitLzReceiveAlert(cell $lzReceiveStatus) impure inline method_id {
1026
+ (cell $storage, tuple actions) = preamble();
1027
+ int nonce = $lzReceiveStatus.cl::get<uint64>(md::LzReceiveStatus::nonce);
1028
+ throw_if(Channel::ERROR::invalidNonce, nonce == 0);
1029
+ int executionStatus = _viewExecutionStatus(nonce);
1030
+ (int actualNonce, cell $packet, _, int exists) = DeterministicInsertionCircularQueue::get(
1031
+ $storage.cl::get<cellRef>(Channel::executionQueue),
1032
+ nonce
1033
+ );
1034
+
1035
+ throw_unless(
1036
+ Channel::ERROR::invalidNonce,
1037
+ (actualNonce == nonce) & (exists)
1038
+ );
1039
+
1040
+ actions~pushAction<event>(
1041
+ Channel::event::LZ_RECEIVE_ALERT,
1042
+ md::LzReceiveStatus::NewFull(
1043
+ $lzReceiveStatus.cl::get<bool>(md::LzReceiveStatus::success),
1044
+ nonce,
1045
+ $lzReceiveStatus.cl::get<coins>(md::LzReceiveStatus::value),
1046
+ $lzReceiveStatus.cl::get<cellRef>(md::LzReceiveStatus::extraData),
1047
+ $lzReceiveStatus.cl::get<cellRef>(md::LzReceiveStatus::reason),
1048
+ getCaller(),
1049
+ $packet,
1050
+ executionStatus
1051
+ )
1052
+ );
1053
+ return actions;
1054
+ }