@layerzerolabs/lz-evm-oapp-v2 2.0.2

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 (51) hide show
  1. package/artifacts/contracts/oapp/OApp.sol/OApp.json +332 -0
  2. package/artifacts/contracts/oapp/OAppCore.sol/OAppCore.json +195 -0
  3. package/artifacts/contracts/oapp/OAppReceiver.sol/OAppReceiver.json +316 -0
  4. package/artifacts/contracts/oapp/OAppSender.sol/OAppSender.json +211 -0
  5. package/artifacts/contracts/oapp/examples/OmniCounter.sol/MsgCodec.json +10 -0
  6. package/artifacts/contracts/oapp/examples/OmniCounter.sol/OmniCounter.json +874 -0
  7. package/artifacts/contracts/oapp/examples/OmniCounterPreCrime.sol/OmniCounterPreCrime.json +373 -0
  8. package/artifacts/contracts/oapp/interfaces/IOAppComposer.sol/IOAppComposer.json +44 -0
  9. package/artifacts/contracts/oapp/interfaces/IOAppCore.sol/IOAppCore.json +143 -0
  10. package/artifacts/contracts/oapp/interfaces/IOAppMsgInspector.sol/IOAppMsgInspector.json +51 -0
  11. package/artifacts/contracts/oapp/interfaces/IOAppOptionsType3.sol/IOAppOptionsType3.json +111 -0
  12. package/artifacts/contracts/oapp/libs/OAppOptionsType3.sol/OAppOptionsType3.json +187 -0
  13. package/artifacts/contracts/oapp/libs/OptionsBuilder.sol/OptionsBuilder.json +38 -0
  14. package/artifacts/contracts/oft/OFT.sol/OFT.json +1466 -0
  15. package/artifacts/contracts/oft/OFTAdapter.sol/OFTAdapter.json +1204 -0
  16. package/artifacts/contracts/oft/OFTCore.sol/OFTCore.json +1170 -0
  17. package/artifacts/contracts/oft/interfaces/IOFT.sol/IOFT.json +472 -0
  18. package/artifacts/contracts/oft/libs/OFTComposeMsgCodec.sol/OFTComposeMsgCodec.json +10 -0
  19. package/artifacts/contracts/oft/libs/OFTMsgCodec.sol/OFTMsgCodec.json +10 -0
  20. package/artifacts/contracts/precrime/OAppPreCrimeSimulator.sol/OAppPreCrimeSimulator.json +277 -0
  21. package/artifacts/contracts/precrime/PreCrime.sol/PreCrime.json +352 -0
  22. package/artifacts/contracts/precrime/extensions/PreCrimeE1.sol/PreCrimeE1.json +352 -0
  23. package/artifacts/contracts/precrime/interfaces/IOAppPreCrimeSimulator.sol/IOAppPreCrimeSimulator.json +175 -0
  24. package/artifacts/contracts/precrime/interfaces/IPreCrime.sol/IPreCrime.json +188 -0
  25. package/artifacts/contracts/precrime/libs/Packet.sol/PacketDecoder.json +10 -0
  26. package/contracts/oapp/OApp.sol +39 -0
  27. package/contracts/oapp/OAppCore.sol +68 -0
  28. package/contracts/oapp/OAppReceiver.sol +101 -0
  29. package/contracts/oapp/OAppSender.sol +124 -0
  30. package/contracts/oapp/examples/OmniCounter.sol +283 -0
  31. package/contracts/oapp/examples/OmniCounterPreCrime.sol +102 -0
  32. package/contracts/oapp/interfaces/IOAppComposer.sol +12 -0
  33. package/contracts/oapp/interfaces/IOAppCore.sol +51 -0
  34. package/contracts/oapp/interfaces/IOAppMsgInspector.sol +22 -0
  35. package/contracts/oapp/interfaces/IOAppOptionsType3.sol +43 -0
  36. package/contracts/oapp/libs/OAppOptionsType3.sol +82 -0
  37. package/contracts/oapp/libs/OptionsBuilder.sol +200 -0
  38. package/contracts/oft/OFT.sol +116 -0
  39. package/contracts/oft/OFTAdapter.sol +131 -0
  40. package/contracts/oft/OFTCore.sol +456 -0
  41. package/contracts/oft/OFTPrecrime.sol +99 -0
  42. package/contracts/oft/interfaces/IOFT.sol +168 -0
  43. package/contracts/oft/libs/OFTComposeMsgCodec.sol +91 -0
  44. package/contracts/oft/libs/OFTMsgCodec.sol +83 -0
  45. package/contracts/precrime/OAppPreCrimeSimulator.sol +125 -0
  46. package/contracts/precrime/PreCrime.sol +208 -0
  47. package/contracts/precrime/extensions/PreCrimeE1.sol +30 -0
  48. package/contracts/precrime/interfaces/IOAppPreCrimeSimulator.sol +55 -0
  49. package/contracts/precrime/interfaces/IPreCrime.sol +40 -0
  50. package/contracts/precrime/libs/Packet.sol +61 -0
  51. package/package.json +35 -0
@@ -0,0 +1,131 @@
1
+ // SPDX-License-Identifier: MIT
2
+
3
+ pragma solidity ^0.8.22;
4
+
5
+ import { IERC20Metadata, IERC20 } from "@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol";
6
+ import { SafeERC20 } from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
7
+ import { OFTCore } from "./OFTCore.sol";
8
+
9
+ /**
10
+ * @title OFTAdapter Contract
11
+ * @dev OFTAdapter is a contract that adapts an ERC-20 token to the OFT functionality.
12
+ *
13
+ * @dev For existing ERC20 tokens, this can be used to convert the token to crosschain compatibility.
14
+ * @dev WARNING: ONLY 1 of these should exist for a given global mesh,
15
+ * unless you make a NON-default implementation of OFT and needs to be done very carefully
16
+ */
17
+ contract OFTAdapter is OFTCore {
18
+ using SafeERC20 for IERC20;
19
+
20
+ IERC20 internal immutable innerToken;
21
+
22
+ // @dev The amount of tokens locked inside this contract.
23
+ // @dev This SHOULD equal the total amount of OFTs in circulation on all the NON OFTAdapter chains
24
+ uint256 public outboundAmount;
25
+
26
+ /**
27
+ * @dev Constructor for the OFTAdapter contract.
28
+ * @param _token The address of the ERC-20 token to be adapted.
29
+ * @param _lzEndpoint The LayerZero endpoint address.
30
+ * @param _owner The owner of the contract.
31
+ */
32
+ constructor(
33
+ address _token,
34
+ address _lzEndpoint,
35
+ address _owner
36
+ ) OFTCore(IERC20Metadata(_token).decimals(), _lzEndpoint, _owner) {
37
+ innerToken = IERC20(_token);
38
+ }
39
+
40
+ /**
41
+ * @dev Retrieves the OFTAdapter contract version.
42
+ * @return major The major version.
43
+ * @return minor The minor version.
44
+ *
45
+ * @dev major version: Indicates a cross-chain compatible msg encoding with other OFTs.
46
+ * @dev minor version: Indicates a version within the local chains context. eg. OFTAdapter vs. OFT
47
+ * @dev For example, if a new feature is added to the OFT contract, the minor version will be incremented.
48
+ * @dev If a new feature is added to the OFT cross-chain msg encoding, the major version will be incremented.
49
+ * ie. localOFT version(1,1) CAN send messages to remoteOFT version(1,2)
50
+ */
51
+ function oftVersion() external pure returns (uint64 major, uint64 minor) {
52
+ return (1, 2);
53
+ }
54
+
55
+ /**
56
+ * @dev Retrieves the address of the underlying ERC20 implementation.
57
+ * @return The address of the adapted ERC-20 token.
58
+ *
59
+ * @dev In the case of OFTAdapter, address(this) and erc20 are NOT the same contract.
60
+ */
61
+ function token() public view virtual returns (address) {
62
+ return address(innerToken);
63
+ }
64
+
65
+ /**
66
+ * @dev Burns tokens from the sender's specified balance, ie. pull method.
67
+ * @param _amountToSendLD The amount of tokens to send in local decimals.
68
+ * @param _minAmountToCreditLD The minimum amount to credit in local decimals.
69
+ * @param _dstEid The destination chain ID.
70
+ * @return amountDebitedLD The amount of tokens ACTUALLY debited in local decimals.
71
+ * @return amountToCreditLD The amount of tokens to credit in local decimals.
72
+ */
73
+ function _debitSender(
74
+ uint256 _amountToSendLD,
75
+ uint256 _minAmountToCreditLD,
76
+ uint32 _dstEid
77
+ ) internal virtual override returns (uint256 amountDebitedLD, uint256 amountToCreditLD) {
78
+ (amountDebitedLD, amountToCreditLD) = _debitView(_amountToSendLD, _minAmountToCreditLD, _dstEid);
79
+ // @dev msg.sender will need to approve this amountLD of tokens to be locked inside of the contract.
80
+ // @dev Move all of the debited tokens into this contract.
81
+ innerToken.safeTransferFrom(msg.sender, address(this), amountDebitedLD);
82
+
83
+ // @dev In NON-default OFTAdapter, amountDebited could be 100, with a 10% fee, the credited amount is 90,
84
+ // so technically the amountToCredit would be locked as outboundAmount. Therefore amountDebited CAN differ from amountToCredit.
85
+ // @dev Due to OFTs containing both push/pull methods, the reserved amount needs to be tracked so _debitThis() cant spend it.
86
+ outboundAmount += amountToCreditLD;
87
+ }
88
+
89
+ /**
90
+ * @dev Allows a sender to send tokens that are inside the contract but are NOT accounted for in outboundAmount, ie. push method.
91
+ * @param _minAmountToCreditLD The minimum amount to credit in local decimals.
92
+ * @param _dstEid The destination chain ID.
93
+ * @return amountDebitedLD The amount of tokens ACTUALLY debited in local decimals.
94
+ * @return amountToCreditLD The amount of tokens to credit in local decimals.
95
+ */
96
+ function _debitThis(
97
+ uint256 _minAmountToCreditLD,
98
+ uint32 _dstEid
99
+ ) internal virtual override returns (uint256 amountDebitedLD, uint256 amountToCreditLD) {
100
+ // @dev This is the push method, where at any point in the transaction, the OFT receives tokens and they can be sent by the caller.
101
+ // @dev This SHOULD be done atomically, otherwise any caller can spend tokens that are owned by the contract.
102
+ uint256 availableToSend = innerToken.balanceOf(address(this)) - outboundAmount;
103
+ (amountDebitedLD, amountToCreditLD) = _debitView(availableToSend, _minAmountToCreditLD, _dstEid);
104
+
105
+ // @dev Due to OFTs containing both push/pull methods, the reserved amount needs to be tracked so _debitThis() cant spend it.
106
+ outboundAmount += amountToCreditLD;
107
+
108
+ // @dev When sending tokens direct to the OFTAdapter contract,
109
+ // there is NOT a default mechanism to capture the dust that MIGHT get left in the contract.
110
+ // If you want to refund this dust, will need to add another function to return it.
111
+ }
112
+
113
+ /**
114
+ * @dev Credits tokens to the specified address.
115
+ * @param _to The address to credit the tokens to.
116
+ * @param _amountToCreditLD The amount of tokens to credit in local decimals.
117
+ * @dev _srcEid The source chain ID.
118
+ * @return amountReceivedLD The amount of tokens ACTUALLY received in local decimals.
119
+ */
120
+ function _credit(
121
+ address _to,
122
+ uint256 _amountToCreditLD,
123
+ uint32 /*_srcEid*/
124
+ ) internal virtual override returns (uint256 amountReceivedLD) {
125
+ outboundAmount -= _amountToCreditLD;
126
+ // @dev Unlock the tokens and transfer to the recipient.
127
+ innerToken.safeTransfer(_to, _amountToCreditLD);
128
+ // @dev In the case of NON-default OFTAdapter, the amountToCreditLD MIGHT not == amountReceivedLD.
129
+ return _amountToCreditLD;
130
+ }
131
+ }
@@ -0,0 +1,456 @@
1
+ // SPDX-License-Identifier: MIT
2
+
3
+ pragma solidity ^0.8.22;
4
+
5
+ import { OApp, Origin } from "../oapp/OApp.sol";
6
+ import { OAppOptionsType3 } from "../oapp/libs/OAppOptionsType3.sol";
7
+ import { IOAppMsgInspector } from "../oapp/interfaces/IOAppMsgInspector.sol";
8
+
9
+ import { OAppPreCrimeSimulator } from "../precrime/OAppPreCrimeSimulator.sol";
10
+
11
+ import { IOFT, SendParam, OFTLimit, OFTReceipt, OFTFeeDetail, MessagingReceipt, MessagingFee } from "./interfaces/IOFT.sol";
12
+ import { OFTMsgCodec } from "./libs/OFTMsgCodec.sol";
13
+ import { OFTComposeMsgCodec } from "./libs/OFTComposeMsgCodec.sol";
14
+
15
+ /**
16
+ * @title OFTCore
17
+ * @dev Abstract contract for the OftChain (OFT) token.
18
+ */
19
+ abstract contract OFTCore is IOFT, OApp, OAppPreCrimeSimulator, OAppOptionsType3 {
20
+ using OFTMsgCodec for bytes;
21
+ using OFTMsgCodec for bytes32;
22
+
23
+ // @notice Provides a conversion rate when swapping between denominations of SD and LD
24
+ // - shareDecimals == SD == shared Decimals
25
+ // - localDecimals == LD == local decimals
26
+ // @dev Considers that tokens have different decimal amounts on various chains.
27
+ // @dev eg.
28
+ // For a token
29
+ // - locally with 4 decimals --> 1.2345 => uint(12345)
30
+ // - remotely with 2 decimals --> 1.23 => uint(123)
31
+ // - The conversion rate would be 10 ** (4 - 2) = 100
32
+ // @dev If you want to send 1.2345 -> (uint 12345), you CANNOT represent that value on the remote,
33
+ // you can only display 1.23 -> uint(123).
34
+ // @dev To preserve the dust that would otherwise be lost on that conversion,
35
+ // we need to unify a denomination that can be represented on ALL chains inside of the OFT mesh
36
+ uint256 public immutable decimalConversionRate;
37
+
38
+ // @notice Msg types that are used to identify the various OFT operations.
39
+ // @dev This can be extended in child contracts for non-default oft operations
40
+ // @dev These values are used in things like combineOptions() in OAppOptionsType3.sol.
41
+ uint16 public constant SEND = 1;
42
+ uint16 public constant SEND_AND_CALL = 2;
43
+
44
+ // Address of an optional contract to inspect both 'message' and 'options'
45
+ address public msgInspector;
46
+
47
+ /**
48
+ * @dev Constructor.
49
+ * @param _localDecimals The decimals of the token on the local chain (this chain).
50
+ * @param _endpoint The address of the LayerZero endpoint.
51
+ * @param _owner The address of the OFT owner.
52
+ */
53
+ constructor(uint8 _localDecimals, address _endpoint, address _owner) OApp(_endpoint, _owner) {
54
+ if (_localDecimals < sharedDecimals()) revert InvalidLocalDecimals();
55
+ decimalConversionRate = 10 ** (_localDecimals - sharedDecimals());
56
+ }
57
+
58
+ /**
59
+ * @dev Retrieves the shared decimals of the OFT.
60
+ * @return The shared decimals of the OFT.
61
+ *
62
+ * @dev Sets an implicit cap on the amount of tokens, over uint64.max() will need some sort of outbound cap / totalSupply cap
63
+ * Lowest common decimal denominator between chains.
64
+ * Defaults to 6 decimal places to provide up to 18,446,744,073,709.551615 units (max uint64).
65
+ * For tokens exceeding this totalSupply(), they will need to override the sharedDecimals function with something smaller.
66
+ * ie. 4 sharedDecimals would be 1,844,674,407,370,955.1615
67
+ */
68
+ function sharedDecimals() public pure virtual returns (uint8) {
69
+ return 6;
70
+ }
71
+
72
+ /**
73
+ * @dev Sets the message inspector address for the OFT.
74
+ * @param _msgInspector The address of the message inspector.
75
+ *
76
+ * @dev This is an optional contract that can be used to inspect both 'message' and 'options'.
77
+ * @dev Set it to address(0) to disable it, or set it to a contract address to enable it.
78
+ */
79
+ function setMsgInspector(address _msgInspector) public virtual onlyOwner {
80
+ msgInspector = _msgInspector;
81
+ emit MsgInspectorSet(_msgInspector);
82
+ }
83
+
84
+ /**
85
+ * @notice Provides a quote for OFT-related operations.
86
+ * @param _sendParam The parameters for the send operation.
87
+ * @dev _oftCmd The OFT command to be executed.
88
+ * @return oftLimit The OFT limit information.
89
+ * @return oftFeeDetails The details of OFT fees.
90
+ * @return oftReceipt The OFT receipt information.
91
+ */
92
+ function quoteOFT(
93
+ SendParam calldata _sendParam,
94
+ bytes calldata /*_oftCmd*/ // @dev unused in the default implementation.
95
+ )
96
+ external
97
+ view
98
+ virtual
99
+ returns (OFTLimit memory oftLimit, OFTFeeDetail[] memory oftFeeDetails, OFTReceipt memory oftReceipt)
100
+ {
101
+ uint256 minAmountLD = 0; // Unused in the default implementation.
102
+ uint256 maxAmountLD = type(uint64).max; // Unused in the default implementation.
103
+ oftLimit = OFTLimit(minAmountLD, maxAmountLD);
104
+
105
+ // Unused in the default implementation; reserved for future complex fee details.
106
+ oftFeeDetails = new OFTFeeDetail[](0);
107
+
108
+ // @dev This is the same as the send() operation, but without the actual send.
109
+ // - amountToDebitLD is the amount in local decimals that was be debited from the sender.
110
+ // - amountToCreditLD is the amount in local decimals that will be credited to the recipient on the remote OFT instance.
111
+ // @dev The amount credited does NOT always equal the amount the user actually receives.
112
+ // HOWEVER, In the default implementation it is.
113
+ (uint256 amountToDebitLD, uint256 amountToCreditLD) = _debitView(
114
+ _sendParam.amountToSendLD,
115
+ _sendParam.minAmountToCreditLD,
116
+ _sendParam.dstEid
117
+ );
118
+ oftReceipt = OFTReceipt(amountToDebitLD, amountToCreditLD);
119
+ }
120
+
121
+ /**
122
+ * @notice Provides a quote for the send() operation.
123
+ * @param _sendParam The parameters for the send() operation.
124
+ * @param _extraOptions Additional options supplied by the caller to be used in the LayerZero message.
125
+ * @param _payInLzToken Flag indicating whether the caller is paying in the LZ token.
126
+ * @param _composeMsg The composed message for the send() operation.
127
+ * @dev _oftCmd The OFT command to be executed.
128
+ * @return msgFee The calculated LayerZero messaging fee from the send() operation.
129
+ *
130
+ * @dev MessagingFee: LayerZero msg fee
131
+ * - nativeFee: The native fee.
132
+ * - lzTokenFee: The lzToken fee.
133
+ */
134
+ function quoteSend(
135
+ SendParam calldata _sendParam,
136
+ bytes calldata _extraOptions,
137
+ bool _payInLzToken,
138
+ bytes calldata _composeMsg,
139
+ bytes calldata /*_oftCmd*/ // @dev unused in the default implementation.
140
+ ) external view virtual returns (MessagingFee memory msgFee) {
141
+ // @dev mock the amount to credit, this is the same operation used in the send().
142
+ // The quote is as similar as possible to the actual send() operation.
143
+ (, uint256 amountToCreditLD) = _debitView(
144
+ _sendParam.amountToSendLD,
145
+ _sendParam.minAmountToCreditLD,
146
+ _sendParam.dstEid
147
+ );
148
+
149
+ // @dev Builds the options and OFT message to quote in the endpoint.
150
+ (bytes memory message, bytes memory options) = _buildMsgAndOptions(
151
+ _sendParam,
152
+ _extraOptions,
153
+ _composeMsg,
154
+ amountToCreditLD
155
+ );
156
+
157
+ // @dev Calculates the LayerZero fee for the send() operation.
158
+ return _quote(_sendParam.dstEid, message, options, _payInLzToken);
159
+ }
160
+
161
+ /**
162
+ * @dev Executes the send operation.
163
+ * @param _sendParam The parameters for the send operation.
164
+ * @param _extraOptions Additional options for the send() operation.
165
+ * @param _fee The calculated fee for the send() operation.
166
+ * - nativeFee: The native fee.
167
+ * - lzTokenFee: The lzToken fee.
168
+ * @param _refundAddress The address to receive any excess funds.
169
+ * @param _composeMsg The composed message for the send() operation.
170
+ * @dev _oftCmd The OFT command to be executed.
171
+ * @return msgReceipt The receipt for the send operation.
172
+ * @return oftReceipt The OFT receipt information.
173
+ *
174
+ * @dev MessagingReceipt: LayerZero msg receipt
175
+ * - guid: The unique identifier for the sent message.
176
+ * - nonce: The nonce of the sent message.
177
+ * - fee: The LayerZero fee incurred for the message.
178
+ */
179
+ function send(
180
+ SendParam calldata _sendParam,
181
+ bytes calldata _extraOptions,
182
+ MessagingFee calldata _fee,
183
+ address _refundAddress,
184
+ bytes calldata _composeMsg,
185
+ bytes calldata /*_oftCmd*/ // @dev unused in the default implementation.
186
+ ) external payable virtual returns (MessagingReceipt memory msgReceipt, OFTReceipt memory oftReceipt) {
187
+ // @dev Applies the token transfers regarding this send() operation.
188
+ // - amountDebitedLD is the amount in local decimals that was ACTUALLY debited from the sender.
189
+ // - amountToCreditLD is the amount in local decimals that will be credited to the recipient on the remote OFT instance.
190
+ (uint256 amountDebitedLD, uint256 amountToCreditLD) = _debit(
191
+ _sendParam.amountToSendLD,
192
+ _sendParam.minAmountToCreditLD,
193
+ _sendParam.dstEid
194
+ );
195
+
196
+ // @dev Builds the options and OFT message to quote in the endpoint.
197
+ (bytes memory message, bytes memory options) = _buildMsgAndOptions(
198
+ _sendParam,
199
+ _extraOptions,
200
+ _composeMsg,
201
+ amountToCreditLD
202
+ );
203
+
204
+ // @dev Sends the message to the LayerZero endpoint and returns the LayerZero msg receipt.
205
+ msgReceipt = _lzSend(_sendParam.dstEid, message, options, _fee, _refundAddress);
206
+ // @dev Formulate the OFT receipt.
207
+ oftReceipt = OFTReceipt(amountDebitedLD, amountToCreditLD);
208
+
209
+ emit OFTSent(msgReceipt.guid, msg.sender, amountDebitedLD, amountToCreditLD, _composeMsg);
210
+ }
211
+
212
+ /**
213
+ * @dev Internal function to build the message and options.
214
+ * @param _sendParam The parameters for the send() operation.
215
+ * @param _extraOptions Additional options for the send() operation.
216
+ * @param _composeMsg The composed message for the send() operation.
217
+ * @param _amountToCreditLD The amount to credit in local decimals.
218
+ * @return message The encoded message.
219
+ * @return options The encoded options.
220
+ */
221
+ function _buildMsgAndOptions(
222
+ SendParam calldata _sendParam,
223
+ bytes calldata _extraOptions,
224
+ bytes calldata _composeMsg,
225
+ uint256 _amountToCreditLD
226
+ ) internal view virtual returns (bytes memory message, bytes memory options) {
227
+ bool hasCompose;
228
+ // @dev This generated message has the msg.sender encoded into the payload so the remote knows who the caller is.
229
+ (message, hasCompose) = OFTMsgCodec.encode(
230
+ _sendParam.to,
231
+ _toSD(_amountToCreditLD),
232
+ // @dev Must be include a non empty bytes if you want to compose, EVEN if you dont need it on the remote.
233
+ // EVEN if you dont require an arbitrary payload to be sent... eg. '0x01'
234
+ _composeMsg
235
+ );
236
+ // @dev Change the msg type depending if its composed or not.
237
+ uint16 msgType = hasCompose ? SEND_AND_CALL : SEND;
238
+ // @dev Combine the callers _extraOptions with the enforced options via the OAppOptionsType3.
239
+ options = combineOptions(_sendParam.dstEid, msgType, _extraOptions);
240
+
241
+ // @dev Optionally inspect the message and options depending if the OApp owner has set a msg inspector.
242
+ // @dev If it fails inspection, needs to revert in the implementation. ie. does not rely on return boolean
243
+ if (msgInspector != address(0)) IOAppMsgInspector(msgInspector).inspect(message, options);
244
+ }
245
+
246
+ /**
247
+ * @dev Internal function to handle the receive on the LayerZero endpoint.
248
+ * @param _origin The origin information.
249
+ * - srcEid: The source chain endpoint ID.
250
+ * - sender: The sender address from the src chain.
251
+ * - nonce: The nonce of the LayerZero message.
252
+ * @param _guid The unique identifier for the received LayerZero message.
253
+ * @param _message The encoded message.
254
+ * @dev _executor The address of the executor.
255
+ * @dev _extraData Additional data.
256
+ */
257
+ function _lzReceive(
258
+ Origin calldata _origin,
259
+ bytes32 _guid,
260
+ bytes calldata _message,
261
+ address /*_executor*/, // @dev unused in the default implementation.
262
+ bytes calldata /*_extraData*/ // @dev unused in the default implementation.
263
+ ) internal virtual override {
264
+ // @dev The src sending chain doesnt know the address length on this chain (potentially non-evm)
265
+ // Thus everything is bytes32() encoded in flight.
266
+ address toAddress = _message.sendTo().bytes32ToAddress();
267
+ // @dev Convert the amount to credit into local decimals.
268
+ uint256 amountToCreditLD = _toLD(_message.amountSD());
269
+ // @dev Credit the amount to the recipient and return the ACTUAL amount the recipient received in local decimals
270
+ uint256 amountReceivedLD = _credit(toAddress, amountToCreditLD, _origin.srcEid);
271
+
272
+ if (_message.isComposed()) {
273
+ // @dev Proprietary composeMsg format for the OFT.
274
+ bytes memory composeMsg = OFTComposeMsgCodec.encode(
275
+ _origin.nonce,
276
+ _origin.srcEid,
277
+ amountReceivedLD,
278
+ _message.composeMsg()
279
+ );
280
+
281
+ // @dev Stores the lzCompose payload that will be executed in a separate tx.
282
+ // Standardizes functionality for executing arbitrary contract invocation on some non-evm chains.
283
+ // @dev The off-chain executor will listen and process the msg based on the src-chain-callers compose options passed.
284
+ // @dev The index is used when a OApp needs to compose multiple msgs on lzReceive.
285
+ // For default OFT implementation there is only 1 compose msg per lzReceive, thus its always 0.
286
+ endpoint.sendCompose(toAddress, _guid, 0 /* the index of the composed message*/, composeMsg);
287
+ }
288
+
289
+ emit OFTReceived(_guid, toAddress, amountToCreditLD, amountReceivedLD);
290
+ }
291
+
292
+ /**
293
+ * @dev Internal function to handle the OAppPreCrimeSimulator simulated receive.
294
+ * @param _origin The origin information.
295
+ * - srcEid: The source chain endpoint ID.
296
+ * - sender: The sender address from the src chain.
297
+ * - nonce: The nonce of the LayerZero message.
298
+ * @param _guid The unique identifier for the received LayerZero message.
299
+ * @param _message The LayerZero message.
300
+ * @param _executor The address of the off-chain executor.
301
+ * @param _extraData Arbitrary data passed by the msg executor.
302
+ *
303
+ * @dev Enables the preCrime simulator to mock sending lzReceive() messages,
304
+ * routes the msg down from the OAppPreCrimeSimulator, and back up to the OAppReceiver.
305
+ */
306
+ function _lzReceiveSimulate(
307
+ Origin calldata _origin,
308
+ bytes32 _guid,
309
+ bytes calldata _message,
310
+ address _executor,
311
+ bytes calldata _extraData
312
+ ) internal virtual override {
313
+ _lzReceive(_origin, _guid, _message, _executor, _extraData);
314
+ }
315
+
316
+ /**
317
+ * @dev Internal function to check if peer is considered 'trusted' by the OApp.
318
+ * @param _eid The endpoint ID to check.
319
+ * @param _peer The peer to check.
320
+ * @return Whether the peer passed is considered 'trusted' by the OApp.
321
+ *
322
+ * @dev Enables OAppPreCrimeSimulator to check whether a potential Inbound Packet is from a trusted source.
323
+ */
324
+ function isPeer(uint32 _eid, bytes32 _peer) public view virtual override returns (bool) {
325
+ return peers[_eid] == _peer;
326
+ }
327
+
328
+ /**
329
+ * @dev Internal function to remove dust from the given local decimal amount.
330
+ * @param _amountLD The amount in local decimals.
331
+ * @return amountLD The amount after removing dust.
332
+ *
333
+ * @dev Prevents the loss of dust when moving amounts between chains with different decimals.
334
+ * @dev eg. uint(123) with a conversion rate of 100 becomes uint(100).
335
+ */
336
+ function _removeDust(uint256 _amountLD) internal view virtual returns (uint256 amountLD) {
337
+ return (_amountLD / decimalConversionRate) * decimalConversionRate;
338
+ }
339
+
340
+ /**
341
+ * @dev Internal function to convert an amount from shared decimals into local decimals.
342
+ * @param _amountSD The amount in shared decimals.
343
+ * @return amountLD The amount in local decimals.
344
+ */
345
+ function _toLD(uint64 _amountSD) internal view virtual returns (uint256 amountLD) {
346
+ return _amountSD * decimalConversionRate;
347
+ }
348
+
349
+ /**
350
+ * @dev Internal function to convert an amount from local decimals into shared decimals.
351
+ * @param _amountLD The amount in local decimals.
352
+ * @return amountSD The amount in shared decimals.
353
+ */
354
+ function _toSD(uint256 _amountLD) internal view virtual returns (uint64 amountSD) {
355
+ return uint64(_amountLD / decimalConversionRate);
356
+ }
357
+
358
+ /**
359
+ * @dev Internal function to mock the amount mutation from a OFT debit() operation.
360
+ * @param _amountToSendLD The amount to send in local decimals.
361
+ * @param _minAmountToCreditLD The minimum amount to credit in local decimals.
362
+ * @dev _dstEid The destination endpoint ID.
363
+ * @return amountToDebitLD The amount to ACTUALLY debit, in local decimals.
364
+ * @return amountToCreditLD The amount to credit on the remote chain, in local decimals.
365
+ *
366
+ * @dev This is where things like fees would be calculated and deducted from the amount to credit on the remote.
367
+ */
368
+ function _debitView(
369
+ uint256 _amountToSendLD,
370
+ uint256 _minAmountToCreditLD,
371
+ uint32 /*_dstEid*/
372
+ ) internal view virtual returns (uint256 amountToDebitLD, uint256 amountToCreditLD) {
373
+ // @dev Remove the dust so nothing is lost on the conversion between chains with different decimals for the token.
374
+ amountToDebitLD = _removeDust(_amountToSendLD);
375
+ // @dev The amount to credit is the same as the amount to debit in the default implementation.
376
+ amountToCreditLD = amountToDebitLD;
377
+
378
+ // @dev Check for slippage.
379
+ if (amountToCreditLD < _minAmountToCreditLD) {
380
+ revert SlippageExceeded(amountToCreditLD, _minAmountToCreditLD);
381
+ }
382
+ }
383
+
384
+ /**
385
+ * @dev Internal function to perform a debit operation.
386
+ * @param _amountToSendLD The amount to send in local decimals.
387
+ * @param _minAmountToCreditLD The minimum amount to credit in local decimals.
388
+ * @param _dstEid The destination endpoint ID.
389
+ * @return amountDebitedLD The amount ACTUALLY debited in local decimals.
390
+ * @return amountToCreditLD The amount to credit in local decimals on the remote.
391
+ */
392
+ function _debit(
393
+ uint256 _amountToSendLD,
394
+ uint256 _minAmountToCreditLD,
395
+ uint32 _dstEid
396
+ ) internal virtual returns (uint256 amountDebitedLD, uint256 amountToCreditLD) {
397
+ // @dev Caller can indicate it wants to use push vs. pull method by passing an _amountToSendLD of 0.
398
+ if (_amountToSendLD > 0) {
399
+ // @dev Pull the tokens from the caller.
400
+ (amountDebitedLD, amountToCreditLD) = _debitSender(_amountToSendLD, _minAmountToCreditLD, _dstEid);
401
+ } else {
402
+ // @dev Caller has pushed tokens.
403
+ (amountDebitedLD, amountToCreditLD) = _debitThis(_minAmountToCreditLD, _dstEid);
404
+ }
405
+ }
406
+
407
+ /**
408
+ * @dev Internal function to perform a debit operation for this chain.
409
+ * @param _amountToSendLD The amount to send in local decimals.
410
+ * @param _minAmountToCreditLD The minimum amount to credit in local decimals.
411
+ * @param _dstEid The destination endpoint ID.
412
+ * @return amountDebitedLD The amount ACTUALLY debited in local decimals.
413
+ * @return amountToCreditLD The amount to credit in local decimals.
414
+ *
415
+ * @dev Defined here but are intended to be override depending on the OFT implementation.
416
+ * @dev This is used when the OFT pulls the tokens from the caller.
417
+ * ie. A user sends has approved the OFT to spend on its behalf.
418
+ */
419
+ function _debitSender(
420
+ uint256 _amountToSendLD,
421
+ uint256 _minAmountToCreditLD,
422
+ uint32 _dstEid
423
+ ) internal virtual returns (uint256 amountDebitedLD, uint256 amountToCreditLD);
424
+
425
+ /**
426
+ * @dev Internal function to perform a debit operation for this chain.
427
+ * @param _minAmountToCreditLD The minimum amount to credit in local decimals.
428
+ * @param _dstEid The destination endpoint ID.
429
+ * @return amountDebitedLD The amount ACTUALLY debited in local decimals.
430
+ * @return amountToCreditLD The amount to credit in local decimals.
431
+ *
432
+ * @dev Defined here but are intended to be override depending on the OFT implementation.
433
+ * @dev This is used when the OFT is the recipient of a push operation.
434
+ * ie. A user sends tokens direct to the OFT contract address.
435
+ */
436
+ function _debitThis(
437
+ uint256 _minAmountToCreditLD,
438
+ uint32 _dstEid
439
+ ) internal virtual returns (uint256 amountDebitedLD, uint256 amountToCreditLD);
440
+
441
+ /**
442
+ * @dev Internal function to perform a credit operation.
443
+ * @param _to The address to credit.
444
+ * @param _amountToCreditLD The amount to credit in local decimals.
445
+ * @param _srcEid The source endpoint ID.
446
+ * @return amountReceivedLD The amount ACTUALLY received in local decimals.
447
+ *
448
+ * @dev Defined here but are intended to be override depending on the OFT implementation.
449
+ * @dev Depending on OFT implementation the _amountToCreditLD could differ from the amountReceivedLD.
450
+ */
451
+ function _credit(
452
+ address _to,
453
+ uint256 _amountToCreditLD,
454
+ uint32 _srcEid
455
+ ) internal virtual returns (uint256 amountReceivedLD);
456
+ }