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

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