@layerzerolabs/protocol-v2-oapp-evm-contracts 1.2.95
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.
- package/README.md +15 -0
- package/contracts/oapp/OApp.sol +39 -0
- package/contracts/oapp/OAppCore.sol +83 -0
- package/contracts/oapp/OAppRead.sol +18 -0
- package/contracts/oapp/OAppReceiver.sol +122 -0
- package/contracts/oapp/OAppSender.sol +124 -0
- package/contracts/oapp/examples/CmdCodecV1Mock.sol +31 -0
- package/contracts/oapp/examples/LzReadCounter.sol +160 -0
- package/contracts/oapp/examples/OmniCounter.sol +15 -0
- package/contracts/oapp/examples/OmniCounterAbstract.sol +285 -0
- package/contracts/oapp/examples/OmniCounterAlt.sol +90 -0
- package/contracts/oapp/examples/OmniCounterPreCrime.sol +102 -0
- package/contracts/oapp/interfaces/IOAppComposer.sol +12 -0
- package/contracts/oapp/interfaces/IOAppComputer.sol +8 -0
- package/contracts/oapp/interfaces/IOAppComputerMap.sol +7 -0
- package/contracts/oapp/interfaces/IOAppComputerReduce.sol +7 -0
- package/contracts/oapp/interfaces/IOAppCore.sol +52 -0
- package/contracts/oapp/interfaces/IOAppMsgInspector.sol +22 -0
- package/contracts/oapp/interfaces/IOAppOptionsType3.sol +43 -0
- package/contracts/oapp/interfaces/IOAppReceiver.sol +25 -0
- package/contracts/oapp/libs/OAppOptionsType3.sol +98 -0
- package/contracts/oapp/libs/OptionsBuilder.sol +218 -0
- package/contracts/oapp/libs/ReadCmdCodecV1.sol +231 -0
- package/contracts/oapp/utils/RateLimiter.sol +229 -0
- package/contracts/oft/OFT.sol +89 -0
- package/contracts/oft/OFTAdapter.sol +106 -0
- package/contracts/oft/OFTCore.sol +399 -0
- package/contracts/oft/OFTPrecrime.sol +99 -0
- package/contracts/oft/interfaces/IOFT.sol +149 -0
- package/contracts/oft/libs/OFTComposeMsgCodec.sol +91 -0
- package/contracts/oft/libs/OFTMsgCodec.sol +83 -0
- package/contracts/precrime/OAppPreCrimeSimulator.sol +125 -0
- package/contracts/precrime/PreCrime.sol +211 -0
- package/contracts/precrime/extensions/PreCrimeE1.sol +30 -0
- package/contracts/precrime/interfaces/IOAppPreCrimeSimulator.sol +55 -0
- package/contracts/precrime/interfaces/IPreCrime.sol +40 -0
- package/contracts/precrime/libs/Packet.sol +61 -0
- package/dist/index.d.ts +7 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +6 -0
- package/dist/index.js.map +1 -0
- package/package.json +67 -0
|
@@ -0,0 +1,399 @@
|
|
|
1
|
+
// SPDX-License-Identifier: MIT
|
|
2
|
+
|
|
3
|
+
pragma solidity ^0.8.20;
|
|
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
|
+
event MsgInspectorSet(address inspector);
|
|
47
|
+
|
|
48
|
+
/**
|
|
49
|
+
* @dev Constructor.
|
|
50
|
+
* @param _localDecimals The decimals of the token on the local chain (this chain).
|
|
51
|
+
* @param _endpoint The address of the LayerZero endpoint.
|
|
52
|
+
* @param _delegate The delegate capable of making OApp configurations inside of the endpoint.
|
|
53
|
+
*/
|
|
54
|
+
constructor(uint8 _localDecimals, address _endpoint, address _delegate) OApp(_endpoint, _delegate) {
|
|
55
|
+
if (_localDecimals < sharedDecimals()) revert InvalidLocalDecimals();
|
|
56
|
+
decimalConversionRate = 10 ** (_localDecimals - sharedDecimals());
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
/**
|
|
60
|
+
* @notice Retrieves interfaceID and the version of the OFT.
|
|
61
|
+
* @return interfaceId The interface ID.
|
|
62
|
+
* @return version The version.
|
|
63
|
+
*
|
|
64
|
+
* @dev interfaceId: This specific interface ID is '0x02e49c2c'.
|
|
65
|
+
* @dev version: Indicates a cross-chain compatible msg encoding with other OFTs.
|
|
66
|
+
* @dev If a new feature is added to the OFT cross-chain msg encoding, the version will be incremented.
|
|
67
|
+
* ie. localOFT version(x,1) CAN send messages to remoteOFT version(x,1)
|
|
68
|
+
*/
|
|
69
|
+
function oftVersion() external pure virtual returns (bytes4 interfaceId, uint64 version) {
|
|
70
|
+
return (type(IOFT).interfaceId, 1);
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
/**
|
|
74
|
+
* @dev Retrieves the shared decimals of the OFT.
|
|
75
|
+
* @return The shared decimals of the OFT.
|
|
76
|
+
*
|
|
77
|
+
* @dev Sets an implicit cap on the amount of tokens, over uint64.max() will need some sort of outbound cap / totalSupply cap
|
|
78
|
+
* Lowest common decimal denominator between chains.
|
|
79
|
+
* Defaults to 6 decimal places to provide up to 18,446,744,073,709.551615 units (max uint64).
|
|
80
|
+
* For tokens exceeding this totalSupply(), they will need to override the sharedDecimals function with something smaller.
|
|
81
|
+
* ie. 4 sharedDecimals would be 1,844,674,407,370,955.1615
|
|
82
|
+
*/
|
|
83
|
+
function sharedDecimals() public view virtual returns (uint8) {
|
|
84
|
+
return 6;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
/**
|
|
88
|
+
* @dev Sets the message inspector address for the OFT.
|
|
89
|
+
* @param _msgInspector The address of the message inspector.
|
|
90
|
+
*
|
|
91
|
+
* @dev This is an optional contract that can be used to inspect both 'message' and 'options'.
|
|
92
|
+
* @dev Set it to address(0) to disable it, or set it to a contract address to enable it.
|
|
93
|
+
*/
|
|
94
|
+
function setMsgInspector(address _msgInspector) public virtual onlyOwner {
|
|
95
|
+
msgInspector = _msgInspector;
|
|
96
|
+
emit MsgInspectorSet(_msgInspector);
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
/**
|
|
100
|
+
* @notice Provides a quote for OFT-related operations.
|
|
101
|
+
* @param _sendParam The parameters for the send operation.
|
|
102
|
+
* @return oftLimit The OFT limit information.
|
|
103
|
+
* @return oftFeeDetails The details of OFT fees.
|
|
104
|
+
* @return oftReceipt The OFT receipt information.
|
|
105
|
+
*/
|
|
106
|
+
function quoteOFT(
|
|
107
|
+
SendParam calldata _sendParam
|
|
108
|
+
)
|
|
109
|
+
external
|
|
110
|
+
view
|
|
111
|
+
virtual
|
|
112
|
+
returns (OFTLimit memory oftLimit, OFTFeeDetail[] memory oftFeeDetails, OFTReceipt memory oftReceipt)
|
|
113
|
+
{
|
|
114
|
+
uint256 minAmountLD = 0; // Unused in the default implementation.
|
|
115
|
+
uint256 maxAmountLD = type(uint64).max; // Unused in the default implementation.
|
|
116
|
+
oftLimit = OFTLimit(minAmountLD, maxAmountLD);
|
|
117
|
+
|
|
118
|
+
// Unused in the default implementation; reserved for future complex fee details.
|
|
119
|
+
oftFeeDetails = new OFTFeeDetail[](0);
|
|
120
|
+
|
|
121
|
+
// @dev This is the same as the send() operation, but without the actual send.
|
|
122
|
+
// - amountSentLD is the amount in local decimals that would be sent from the sender.
|
|
123
|
+
// - amountReceivedLD is the amount in local decimals that will be credited to the recipient on the remote OFT instance.
|
|
124
|
+
// @dev The amountSentLD MIGHT not equal the amount the user actually receives. HOWEVER, the default does.
|
|
125
|
+
(uint256 amountSentLD, uint256 amountReceivedLD) = _debitView(
|
|
126
|
+
_sendParam.amountLD,
|
|
127
|
+
_sendParam.minAmountLD,
|
|
128
|
+
_sendParam.dstEid
|
|
129
|
+
);
|
|
130
|
+
oftReceipt = OFTReceipt(amountSentLD, amountReceivedLD);
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
/**
|
|
134
|
+
* @notice Provides a quote for the send() operation.
|
|
135
|
+
* @param _sendParam The parameters for the send() operation.
|
|
136
|
+
* @param _payInLzToken Flag indicating whether the caller is paying in the LZ token.
|
|
137
|
+
* @return msgFee The calculated LayerZero messaging fee from the send() operation.
|
|
138
|
+
*
|
|
139
|
+
* @dev MessagingFee: LayerZero msg fee
|
|
140
|
+
* - nativeFee: The native fee.
|
|
141
|
+
* - lzTokenFee: The lzToken fee.
|
|
142
|
+
*/
|
|
143
|
+
function quoteSend(
|
|
144
|
+
SendParam calldata _sendParam,
|
|
145
|
+
bool _payInLzToken
|
|
146
|
+
) external view virtual returns (MessagingFee memory msgFee) {
|
|
147
|
+
// @dev mock the amount to receive, this is the same operation used in the send().
|
|
148
|
+
// The quote is as similar as possible to the actual send() operation.
|
|
149
|
+
(, uint256 amountReceivedLD) = _debitView(_sendParam.amountLD, _sendParam.minAmountLD, _sendParam.dstEid);
|
|
150
|
+
|
|
151
|
+
// @dev Builds the options and OFT message to quote in the endpoint.
|
|
152
|
+
(bytes memory message, bytes memory options) = _buildMsgAndOptions(_sendParam, amountReceivedLD);
|
|
153
|
+
|
|
154
|
+
// @dev Calculates the LayerZero fee for the send() operation.
|
|
155
|
+
return _quote(_sendParam.dstEid, message, options, _payInLzToken);
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
/**
|
|
159
|
+
* @dev Executes the send operation.
|
|
160
|
+
* @param _sendParam The parameters for the send operation.
|
|
161
|
+
* @param _fee The calculated fee for the send() operation.
|
|
162
|
+
* - nativeFee: The native fee.
|
|
163
|
+
* - lzTokenFee: The lzToken fee.
|
|
164
|
+
* @param _refundAddress The address to receive any excess funds.
|
|
165
|
+
* @return msgReceipt The receipt for the send operation.
|
|
166
|
+
* @return oftReceipt The OFT receipt information.
|
|
167
|
+
*
|
|
168
|
+
* @dev MessagingReceipt: LayerZero msg receipt
|
|
169
|
+
* - guid: The unique identifier for the sent message.
|
|
170
|
+
* - nonce: The nonce of the sent message.
|
|
171
|
+
* - fee: The LayerZero fee incurred for the message.
|
|
172
|
+
*/
|
|
173
|
+
function send(
|
|
174
|
+
SendParam calldata _sendParam,
|
|
175
|
+
MessagingFee calldata _fee,
|
|
176
|
+
address _refundAddress
|
|
177
|
+
) external payable virtual returns (MessagingReceipt memory msgReceipt, OFTReceipt memory oftReceipt) {
|
|
178
|
+
// @dev Applies the token transfers regarding this send() operation.
|
|
179
|
+
// - amountSentLD is the amount in local decimals that was ACTUALLY sent/debited from the sender.
|
|
180
|
+
// - amountReceivedLD is the amount in local decimals that will be received/credited to the recipient on the remote OFT instance.
|
|
181
|
+
(uint256 amountSentLD, uint256 amountReceivedLD) = _debit(
|
|
182
|
+
msg.sender,
|
|
183
|
+
_sendParam.amountLD,
|
|
184
|
+
_sendParam.minAmountLD,
|
|
185
|
+
_sendParam.dstEid
|
|
186
|
+
);
|
|
187
|
+
|
|
188
|
+
// @dev Builds the options and OFT message to quote in the endpoint.
|
|
189
|
+
(bytes memory message, bytes memory options) = _buildMsgAndOptions(_sendParam, amountReceivedLD);
|
|
190
|
+
|
|
191
|
+
// @dev Sends the message to the LayerZero endpoint and returns the LayerZero msg receipt.
|
|
192
|
+
msgReceipt = _lzSend(_sendParam.dstEid, message, options, _fee, _refundAddress);
|
|
193
|
+
// @dev Formulate the OFT receipt.
|
|
194
|
+
oftReceipt = OFTReceipt(amountSentLD, amountReceivedLD);
|
|
195
|
+
|
|
196
|
+
emit OFTSent(msgReceipt.guid, _sendParam.dstEid, msg.sender, amountSentLD, amountReceivedLD);
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
/**
|
|
200
|
+
* @dev Internal function to build the message and options.
|
|
201
|
+
* @param _sendParam The parameters for the send() operation.
|
|
202
|
+
* @param _amountLD The amount in local decimals.
|
|
203
|
+
* @return message The encoded message.
|
|
204
|
+
* @return options The encoded options.
|
|
205
|
+
*/
|
|
206
|
+
function _buildMsgAndOptions(
|
|
207
|
+
SendParam calldata _sendParam,
|
|
208
|
+
uint256 _amountLD
|
|
209
|
+
) internal view virtual returns (bytes memory message, bytes memory options) {
|
|
210
|
+
bool hasCompose;
|
|
211
|
+
// @dev This generated message has the msg.sender encoded into the payload so the remote knows who the caller is.
|
|
212
|
+
(message, hasCompose) = OFTMsgCodec.encode(
|
|
213
|
+
_sendParam.to,
|
|
214
|
+
_toSD(_amountLD),
|
|
215
|
+
// @dev Must be include a non empty bytes if you want to compose, EVEN if you dont need it on the remote.
|
|
216
|
+
// EVEN if you dont require an arbitrary payload to be sent... eg. '0x01'
|
|
217
|
+
_sendParam.composeMsg
|
|
218
|
+
);
|
|
219
|
+
// @dev Change the msg type depending if its composed or not.
|
|
220
|
+
uint16 msgType = hasCompose ? SEND_AND_CALL : SEND;
|
|
221
|
+
// @dev Combine the callers _extraOptions with the enforced options via the OAppOptionsType3.
|
|
222
|
+
options = combineOptions(_sendParam.dstEid, msgType, _sendParam.extraOptions);
|
|
223
|
+
|
|
224
|
+
// @dev Optionally inspect the message and options depending if the OApp owner has set a msg inspector.
|
|
225
|
+
// @dev If it fails inspection, needs to revert in the implementation. ie. does not rely on return boolean
|
|
226
|
+
if (msgInspector != address(0)) IOAppMsgInspector(msgInspector).inspect(message, options);
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
/**
|
|
230
|
+
* @dev Internal function to handle the receive on the LayerZero endpoint.
|
|
231
|
+
* @param _origin The origin information.
|
|
232
|
+
* - srcEid: The source chain endpoint ID.
|
|
233
|
+
* - sender: The sender address from the src chain.
|
|
234
|
+
* - nonce: The nonce of the LayerZero message.
|
|
235
|
+
* @param _guid The unique identifier for the received LayerZero message.
|
|
236
|
+
* @param _message The encoded message.
|
|
237
|
+
* @dev _executor The address of the executor.
|
|
238
|
+
* @dev _extraData Additional data.
|
|
239
|
+
*/
|
|
240
|
+
function _lzReceive(
|
|
241
|
+
Origin calldata _origin,
|
|
242
|
+
bytes32 _guid,
|
|
243
|
+
bytes calldata _message,
|
|
244
|
+
address /*_executor*/, // @dev unused in the default implementation.
|
|
245
|
+
bytes calldata /*_extraData*/ // @dev unused in the default implementation.
|
|
246
|
+
) internal virtual override {
|
|
247
|
+
// @dev The src sending chain doesnt know the address length on this chain (potentially non-evm)
|
|
248
|
+
// Thus everything is bytes32() encoded in flight.
|
|
249
|
+
address toAddress = _message.sendTo().bytes32ToAddress();
|
|
250
|
+
// @dev Credit the amountLD to the recipient and return the ACTUAL amount the recipient received in local decimals
|
|
251
|
+
uint256 amountReceivedLD = _credit(toAddress, _toLD(_message.amountSD()), _origin.srcEid);
|
|
252
|
+
|
|
253
|
+
if (_message.isComposed()) {
|
|
254
|
+
// @dev Proprietary composeMsg format for the OFT.
|
|
255
|
+
bytes memory composeMsg = OFTComposeMsgCodec.encode(
|
|
256
|
+
_origin.nonce,
|
|
257
|
+
_origin.srcEid,
|
|
258
|
+
amountReceivedLD,
|
|
259
|
+
_message.composeMsg()
|
|
260
|
+
);
|
|
261
|
+
|
|
262
|
+
// @dev Stores the lzCompose payload that will be executed in a separate tx.
|
|
263
|
+
// Standardizes functionality for executing arbitrary contract invocation on some non-evm chains.
|
|
264
|
+
// @dev The off-chain executor will listen and process the msg based on the src-chain-callers compose options passed.
|
|
265
|
+
// @dev The index is used when a OApp needs to compose multiple msgs on lzReceive.
|
|
266
|
+
// For default OFT implementation there is only 1 compose msg per lzReceive, thus its always 0.
|
|
267
|
+
endpoint.sendCompose(toAddress, _guid, 0 /* the index of the composed message*/, composeMsg);
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
emit OFTReceived(_guid, _origin.srcEid, toAddress, amountReceivedLD);
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
/**
|
|
274
|
+
* @dev Internal function to handle the OAppPreCrimeSimulator simulated receive.
|
|
275
|
+
* @param _origin The origin information.
|
|
276
|
+
* - srcEid: The source chain endpoint ID.
|
|
277
|
+
* - sender: The sender address from the src chain.
|
|
278
|
+
* - nonce: The nonce of the LayerZero message.
|
|
279
|
+
* @param _guid The unique identifier for the received LayerZero message.
|
|
280
|
+
* @param _message The LayerZero message.
|
|
281
|
+
* @param _executor The address of the off-chain executor.
|
|
282
|
+
* @param _extraData Arbitrary data passed by the msg executor.
|
|
283
|
+
*
|
|
284
|
+
* @dev Enables the preCrime simulator to mock sending lzReceive() messages,
|
|
285
|
+
* routes the msg down from the OAppPreCrimeSimulator, and back up to the OAppReceiver.
|
|
286
|
+
*/
|
|
287
|
+
function _lzReceiveSimulate(
|
|
288
|
+
Origin calldata _origin,
|
|
289
|
+
bytes32 _guid,
|
|
290
|
+
bytes calldata _message,
|
|
291
|
+
address _executor,
|
|
292
|
+
bytes calldata _extraData
|
|
293
|
+
) internal virtual override {
|
|
294
|
+
_lzReceive(_origin, _guid, _message, _executor, _extraData);
|
|
295
|
+
}
|
|
296
|
+
|
|
297
|
+
/**
|
|
298
|
+
* @dev Check if the peer is considered 'trusted' by the OApp.
|
|
299
|
+
* @param _eid The endpoint ID to check.
|
|
300
|
+
* @param _peer The peer to check.
|
|
301
|
+
* @return Whether the peer passed is considered 'trusted' by the OApp.
|
|
302
|
+
*
|
|
303
|
+
* @dev Enables OAppPreCrimeSimulator to check whether a potential Inbound Packet is from a trusted source.
|
|
304
|
+
*/
|
|
305
|
+
function isPeer(uint32 _eid, bytes32 _peer) public view virtual override returns (bool) {
|
|
306
|
+
return peers[_eid] == _peer;
|
|
307
|
+
}
|
|
308
|
+
|
|
309
|
+
/**
|
|
310
|
+
* @dev Internal function to remove dust from the given local decimal amount.
|
|
311
|
+
* @param _amountLD The amount in local decimals.
|
|
312
|
+
* @return amountLD The amount after removing dust.
|
|
313
|
+
*
|
|
314
|
+
* @dev Prevents the loss of dust when moving amounts between chains with different decimals.
|
|
315
|
+
* @dev eg. uint(123) with a conversion rate of 100 becomes uint(100).
|
|
316
|
+
*/
|
|
317
|
+
function _removeDust(uint256 _amountLD) internal view virtual returns (uint256 amountLD) {
|
|
318
|
+
return (_amountLD / decimalConversionRate) * decimalConversionRate;
|
|
319
|
+
}
|
|
320
|
+
|
|
321
|
+
/**
|
|
322
|
+
* @dev Internal function to convert an amount from shared decimals into local decimals.
|
|
323
|
+
* @param _amountSD The amount in shared decimals.
|
|
324
|
+
* @return amountLD The amount in local decimals.
|
|
325
|
+
*/
|
|
326
|
+
function _toLD(uint64 _amountSD) internal view virtual returns (uint256 amountLD) {
|
|
327
|
+
return _amountSD * decimalConversionRate;
|
|
328
|
+
}
|
|
329
|
+
|
|
330
|
+
/**
|
|
331
|
+
* @dev Internal function to convert an amount from local decimals into shared decimals.
|
|
332
|
+
* @param _amountLD The amount in local decimals.
|
|
333
|
+
* @return amountSD The amount in shared decimals.
|
|
334
|
+
*/
|
|
335
|
+
function _toSD(uint256 _amountLD) internal view virtual returns (uint64 amountSD) {
|
|
336
|
+
return uint64(_amountLD / decimalConversionRate);
|
|
337
|
+
}
|
|
338
|
+
|
|
339
|
+
/**
|
|
340
|
+
* @dev Internal function to mock the amount mutation from a OFT debit() operation.
|
|
341
|
+
* @param _amountLD The amount to send in local decimals.
|
|
342
|
+
* @param _minAmountLD The minimum amount to send in local decimals.
|
|
343
|
+
* @dev _dstEid The destination endpoint ID.
|
|
344
|
+
* @return amountSentLD The amount sent, in local decimals.
|
|
345
|
+
* @return amountReceivedLD The amount to be received on the remote chain, in local decimals.
|
|
346
|
+
*
|
|
347
|
+
* @dev This is where things like fees would be calculated and deducted from the amount to be received on the remote.
|
|
348
|
+
*/
|
|
349
|
+
function _debitView(
|
|
350
|
+
uint256 _amountLD,
|
|
351
|
+
uint256 _minAmountLD,
|
|
352
|
+
uint32 /*_dstEid*/
|
|
353
|
+
) internal view virtual returns (uint256 amountSentLD, uint256 amountReceivedLD) {
|
|
354
|
+
// @dev Remove the dust so nothing is lost on the conversion between chains with different decimals for the token.
|
|
355
|
+
amountSentLD = _removeDust(_amountLD);
|
|
356
|
+
// @dev The amount to send is the same as amount received in the default implementation.
|
|
357
|
+
amountReceivedLD = amountSentLD;
|
|
358
|
+
|
|
359
|
+
// @dev Check for slippage.
|
|
360
|
+
if (amountReceivedLD < _minAmountLD) {
|
|
361
|
+
revert SlippageExceeded(amountReceivedLD, _minAmountLD);
|
|
362
|
+
}
|
|
363
|
+
}
|
|
364
|
+
|
|
365
|
+
/**
|
|
366
|
+
* @dev Internal function to perform a debit operation.
|
|
367
|
+
* @param _from The address to debit.
|
|
368
|
+
* @param _amountLD The amount to send in local decimals.
|
|
369
|
+
* @param _minAmountLD The minimum amount to send in local decimals.
|
|
370
|
+
* @param _dstEid The destination endpoint ID.
|
|
371
|
+
* @return amountSentLD The amount sent in local decimals.
|
|
372
|
+
* @return amountReceivedLD The amount received in local decimals on the remote.
|
|
373
|
+
*
|
|
374
|
+
* @dev Defined here but are intended to be overriden depending on the OFT implementation.
|
|
375
|
+
* @dev Depending on OFT implementation the _amountLD could differ from the amountReceivedLD.
|
|
376
|
+
*/
|
|
377
|
+
function _debit(
|
|
378
|
+
address _from,
|
|
379
|
+
uint256 _amountLD,
|
|
380
|
+
uint256 _minAmountLD,
|
|
381
|
+
uint32 _dstEid
|
|
382
|
+
) internal virtual returns (uint256 amountSentLD, uint256 amountReceivedLD);
|
|
383
|
+
|
|
384
|
+
/**
|
|
385
|
+
* @dev Internal function to perform a credit operation.
|
|
386
|
+
* @param _to The address to credit.
|
|
387
|
+
* @param _amountLD The amount to credit in local decimals.
|
|
388
|
+
* @param _srcEid The source endpoint ID.
|
|
389
|
+
* @return amountReceivedLD The amount ACTUALLY received in local decimals.
|
|
390
|
+
*
|
|
391
|
+
* @dev Defined here but are intended to be overriden depending on the OFT implementation.
|
|
392
|
+
* @dev Depending on OFT implementation the _amountLD could differ from the amountReceivedLD.
|
|
393
|
+
*/
|
|
394
|
+
function _credit(
|
|
395
|
+
address _to,
|
|
396
|
+
uint256 _amountLD,
|
|
397
|
+
uint32 _srcEid
|
|
398
|
+
) internal virtual returns (uint256 amountReceivedLD);
|
|
399
|
+
}
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
// SPDX-License-Identifier: MIT
|
|
2
|
+
|
|
3
|
+
pragma solidity ^0.8.20;
|
|
4
|
+
|
|
5
|
+
// import { IOApp } from "../../interfaces/IOApp.sol";
|
|
6
|
+
// import { IOFT } from "./interfaces/IOFT.sol";
|
|
7
|
+
// import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol";
|
|
8
|
+
// import { OFTAdapter } from "./OFTAdapter.sol";
|
|
9
|
+
|
|
10
|
+
//contract OFTPreCrime is PreCrime {
|
|
11
|
+
// address public oft;
|
|
12
|
+
// uint256 public EXPECTED_GLOBAL_SUPPLY;
|
|
13
|
+
//
|
|
14
|
+
// constructor(address _endpoint, address _oft) PreCrime(_endpoint) {
|
|
15
|
+
// oft = _oft;
|
|
16
|
+
// }
|
|
17
|
+
//
|
|
18
|
+
// struct SimulationResult {
|
|
19
|
+
// uint256 totalSupplyLD;
|
|
20
|
+
// bool isAdapter;
|
|
21
|
+
// }
|
|
22
|
+
//
|
|
23
|
+
// // @dev only necessary when its exclusive 'OFT', NOT 'OFTAdapter' type
|
|
24
|
+
// // sum of all tokens in the oft network, it can change, but this will need to be updated for pre-Crime to pass
|
|
25
|
+
// function setGlobalSupply(uint256 _globalSupply) public onlyPreCrimeAdmin {
|
|
26
|
+
// EXPECTED_GLOBAL_SUPPLY = _globalSupply;
|
|
27
|
+
// }
|
|
28
|
+
//
|
|
29
|
+
// // -------------------------------
|
|
30
|
+
// // PreCrime
|
|
31
|
+
// function _receiver() internal view override returns (address) {
|
|
32
|
+
// return address(oft);
|
|
33
|
+
// }
|
|
34
|
+
//
|
|
35
|
+
// function _preCrime(bytes[] memory _simulation) internal view override returns (uint16 code, bytes memory reason) {
|
|
36
|
+
// uint256 globalSupply;
|
|
37
|
+
// uint256 expectedGlobalSupply = EXPECTED_GLOBAL_SUPPLY;
|
|
38
|
+
//
|
|
39
|
+
// // @dev indicates that there is an 'OFTAdapter' on one of the chains, not necessarily this local chain
|
|
40
|
+
// bool isOFTAdapter;
|
|
41
|
+
//
|
|
42
|
+
// for (uint256 i = 0; i < _simulation.length; i++) {
|
|
43
|
+
// SimulationResult memory result = abi.decode(_simulation[i], (SimulationResult));
|
|
44
|
+
//
|
|
45
|
+
// if (result.isAdapter) {
|
|
46
|
+
// // @dev does not support multiple' 'OFTAdapter' contracts for a given oft mesh
|
|
47
|
+
// if (isOFTAdapter) return (CODE_PRECRIME_FAILURE, "OFTPreCrime: multiple OFTAdapters found");
|
|
48
|
+
// isOFTAdapter = true;
|
|
49
|
+
//
|
|
50
|
+
// expectedGlobalSupply = result.totalSupplyLD;
|
|
51
|
+
// } else {
|
|
52
|
+
// globalSupply += result.totalSupplyLD;
|
|
53
|
+
// }
|
|
54
|
+
// }
|
|
55
|
+
//
|
|
56
|
+
// if (isOFTAdapter && globalSupply > expectedGlobalSupply) {
|
|
57
|
+
// // @dev expectedGlobal supply for an 'OFTAdapter' can be slightly higher due to users sending tokens direct
|
|
58
|
+
// // to the OFTAdapter contract, cant check explicitly "=="
|
|
59
|
+
// return (CODE_PRECRIME_FAILURE, "OFTPreCrime: globalSupply > expectedGlobalSupply");
|
|
60
|
+
// } else if (globalSupply != expectedGlobalSupply) {
|
|
61
|
+
// // @dev exclusively 'OFT', NOT 'OFTAdapter' instances, balances should be exactly "=="
|
|
62
|
+
// return (CODE_PRECRIME_FAILURE, "OFTPreCrime: globalSupply != expectedGlobalSupply");
|
|
63
|
+
// } else {
|
|
64
|
+
// return (CODE_SUCCESS, "");
|
|
65
|
+
// }
|
|
66
|
+
// }
|
|
67
|
+
//
|
|
68
|
+
// function simulationCallback() external view override returns (bytes memory result) {
|
|
69
|
+
// address token = IOFT(oft).token();
|
|
70
|
+
//
|
|
71
|
+
// // @dev checks if the corresponding _oft on this chain is an adapter version, or returns false if its regular 'OFT'
|
|
72
|
+
// // eg. 'OFTAdapter' lock/unlock tokens from an external token contract, vs. regular 'OFT' mints/burns
|
|
73
|
+
// bool isAdapter = token != oft;
|
|
74
|
+
//
|
|
75
|
+
// // @dev for 'OFTAdapter' the total supply is the total amount locked, otherwise its the totalSupply of oft tokens on the chain
|
|
76
|
+
// uint256 totalSupply = isAdapter ? IERC20(token).balanceOf(oft) : IERC20(oft).totalSupply();
|
|
77
|
+
//
|
|
78
|
+
// return abi.encode(SimulationResult(totalSupply, isAdapter));
|
|
79
|
+
// }
|
|
80
|
+
//
|
|
81
|
+
// function _simulate(Packet[] calldata _packets) internal override returns (uint16 code, bytes memory simulation) {
|
|
82
|
+
// (bool success, bytes memory result) = oft.call{value: msg.value}(
|
|
83
|
+
// abi.encodeWithSelector(IOApp.lzReceiveAndRevert.selector, _packets)
|
|
84
|
+
// );
|
|
85
|
+
// require(!success, "OFTPreCrime: simulationCallback should be called via revert");
|
|
86
|
+
//
|
|
87
|
+
// (, result) = _parseRevertResult(result, LzReceiveRevert.selector);
|
|
88
|
+
// return (CODE_SUCCESS, result);
|
|
89
|
+
// }
|
|
90
|
+
//
|
|
91
|
+
// // @dev need to ensure that all preCrimePeers are present inside of the results passed into _checkResultsCompleteness()
|
|
92
|
+
// // when checking oft preCrime we always want every simulation/result from the remote peers
|
|
93
|
+
// function _getPreCrimePeers(
|
|
94
|
+
// Packet[] calldata /*_packets*/
|
|
95
|
+
// ) internal view override returns (uint32[] memory eids, bytes32[] memory peers) {
|
|
96
|
+
// // @dev assumes that the preCrimeEids is the full list of oft eids for this oft mesh
|
|
97
|
+
// return (preCrimeEids, preCrimePeers);
|
|
98
|
+
// }
|
|
99
|
+
//}
|
|
@@ -0,0 +1,149 @@
|
|
|
1
|
+
// SPDX-License-Identifier: MIT
|
|
2
|
+
|
|
3
|
+
pragma solidity ^0.8.20;
|
|
4
|
+
|
|
5
|
+
import { MessagingReceipt, MessagingFee } from "../../oapp/OAppSender.sol";
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* @dev Struct representing token parameters for the OFT send() operation.
|
|
9
|
+
*/
|
|
10
|
+
struct SendParam {
|
|
11
|
+
uint32 dstEid; // Destination endpoint ID.
|
|
12
|
+
bytes32 to; // Recipient address.
|
|
13
|
+
uint256 amountLD; // Amount to send in local decimals.
|
|
14
|
+
uint256 minAmountLD; // Minimum amount to send in local decimals.
|
|
15
|
+
bytes extraOptions; // Additional options supplied by the caller to be used in the LayerZero message.
|
|
16
|
+
bytes composeMsg; // The composed message for the send() operation.
|
|
17
|
+
bytes oftCmd; // The OFT command to be executed, unused in default OFT implementations.
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* @dev Struct representing OFT limit information.
|
|
22
|
+
* @dev These amounts can change dynamically and are up the the specific oft implementation.
|
|
23
|
+
*/
|
|
24
|
+
struct OFTLimit {
|
|
25
|
+
uint256 minAmountLD; // Minimum amount in local decimals that can be sent to the recipient.
|
|
26
|
+
uint256 maxAmountLD; // Maximum amount in local decimals that can be sent to the recipient.
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* @dev Struct representing OFT receipt information.
|
|
31
|
+
*/
|
|
32
|
+
struct OFTReceipt {
|
|
33
|
+
uint256 amountSentLD; // Amount of tokens ACTUALLY debited from the sender in local decimals.
|
|
34
|
+
// @dev In non-default implementations, the amountReceivedLD COULD differ from this value.
|
|
35
|
+
uint256 amountReceivedLD; // Amount of tokens to be received on the remote side.
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* @dev Struct representing OFT fee details.
|
|
40
|
+
* @dev Future proof mechanism to provide a standardized way to communicate fees to things like a UI.
|
|
41
|
+
*/
|
|
42
|
+
struct OFTFeeDetail {
|
|
43
|
+
int256 feeAmountLD; // Amount of the fee in local decimals.
|
|
44
|
+
string description; // Description of the fee.
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
/**
|
|
48
|
+
* @title IOFT
|
|
49
|
+
* @dev Interface for the OftChain (OFT) token.
|
|
50
|
+
* @dev Does not inherit ERC20 to accommodate usage by OFTAdapter as well.
|
|
51
|
+
* @dev This specific interface ID is '0x02e49c2c'.
|
|
52
|
+
*/
|
|
53
|
+
interface IOFT {
|
|
54
|
+
// Custom error messages
|
|
55
|
+
error InvalidLocalDecimals();
|
|
56
|
+
error SlippageExceeded(uint256 amountLD, uint256 minAmountLD);
|
|
57
|
+
|
|
58
|
+
// Events
|
|
59
|
+
event OFTSent(
|
|
60
|
+
bytes32 indexed guid, // GUID of the OFT message.
|
|
61
|
+
uint32 dstEid, // Destination Endpoint ID.
|
|
62
|
+
address indexed fromAddress, // Address of the sender on the src chain.
|
|
63
|
+
uint256 amountSentLD, // Amount of tokens sent in local decimals.
|
|
64
|
+
uint256 amountReceivedLD // Amount of tokens received in local decimals.
|
|
65
|
+
);
|
|
66
|
+
event OFTReceived(
|
|
67
|
+
bytes32 indexed guid, // GUID of the OFT message.
|
|
68
|
+
uint32 srcEid, // Source Endpoint ID.
|
|
69
|
+
address indexed toAddress, // Address of the recipient on the dst chain.
|
|
70
|
+
uint256 amountReceivedLD // Amount of tokens received in local decimals.
|
|
71
|
+
);
|
|
72
|
+
|
|
73
|
+
/**
|
|
74
|
+
* @notice Retrieves interfaceID and the version of the OFT.
|
|
75
|
+
* @return interfaceId The interface ID.
|
|
76
|
+
* @return version The version.
|
|
77
|
+
*
|
|
78
|
+
* @dev interfaceId: This specific interface ID is '0x02e49c2c'.
|
|
79
|
+
* @dev version: Indicates a cross-chain compatible msg encoding with other OFTs.
|
|
80
|
+
* @dev If a new feature is added to the OFT cross-chain msg encoding, the version will be incremented.
|
|
81
|
+
* ie. localOFT version(x,1) CAN send messages to remoteOFT version(x,1)
|
|
82
|
+
*/
|
|
83
|
+
function oftVersion() external view returns (bytes4 interfaceId, uint64 version);
|
|
84
|
+
|
|
85
|
+
/**
|
|
86
|
+
* @notice Retrieves the address of the token associated with the OFT.
|
|
87
|
+
* @return token The address of the ERC20 token implementation.
|
|
88
|
+
*/
|
|
89
|
+
function token() external view returns (address);
|
|
90
|
+
|
|
91
|
+
/**
|
|
92
|
+
* @notice Indicates whether the OFT contract requires approval of the 'token()' to send.
|
|
93
|
+
* @return requiresApproval Needs approval of the underlying token implementation.
|
|
94
|
+
*
|
|
95
|
+
* @dev Allows things like wallet implementers to determine integration requirements,
|
|
96
|
+
* without understanding the underlying token implementation.
|
|
97
|
+
*/
|
|
98
|
+
function approvalRequired() external view returns (bool);
|
|
99
|
+
|
|
100
|
+
/**
|
|
101
|
+
* @notice Retrieves the shared decimals of the OFT.
|
|
102
|
+
* @return sharedDecimals The shared decimals of the OFT.
|
|
103
|
+
*/
|
|
104
|
+
function sharedDecimals() external view returns (uint8);
|
|
105
|
+
|
|
106
|
+
/**
|
|
107
|
+
* @notice Provides a quote for OFT-related operations.
|
|
108
|
+
* @param _sendParam The parameters for the send operation.
|
|
109
|
+
* @return limit The OFT limit information.
|
|
110
|
+
* @return oftFeeDetails The details of OFT fees.
|
|
111
|
+
* @return receipt The OFT receipt information.
|
|
112
|
+
*/
|
|
113
|
+
function quoteOFT(
|
|
114
|
+
SendParam calldata _sendParam
|
|
115
|
+
) external view returns (OFTLimit memory, OFTFeeDetail[] memory oftFeeDetails, OFTReceipt memory);
|
|
116
|
+
|
|
117
|
+
/**
|
|
118
|
+
* @notice Provides a quote for the send() operation.
|
|
119
|
+
* @param _sendParam The parameters for the send() operation.
|
|
120
|
+
* @param _payInLzToken Flag indicating whether the caller is paying in the LZ token.
|
|
121
|
+
* @return fee The calculated LayerZero messaging fee from the send() operation.
|
|
122
|
+
*
|
|
123
|
+
* @dev MessagingFee: LayerZero msg fee
|
|
124
|
+
* - nativeFee: The native fee.
|
|
125
|
+
* - lzTokenFee: The lzToken fee.
|
|
126
|
+
*/
|
|
127
|
+
function quoteSend(SendParam calldata _sendParam, bool _payInLzToken) external view returns (MessagingFee memory);
|
|
128
|
+
|
|
129
|
+
/**
|
|
130
|
+
* @notice Executes the send() operation.
|
|
131
|
+
* @param _sendParam The parameters for the send operation.
|
|
132
|
+
* @param _fee The fee information supplied by the caller.
|
|
133
|
+
* - nativeFee: The native fee.
|
|
134
|
+
* - lzTokenFee: The lzToken fee.
|
|
135
|
+
* @param _refundAddress The address to receive any excess funds from fees etc. on the src.
|
|
136
|
+
* @return receipt The LayerZero messaging receipt from the send() operation.
|
|
137
|
+
* @return oftReceipt The OFT receipt information.
|
|
138
|
+
*
|
|
139
|
+
* @dev MessagingReceipt: LayerZero msg receipt
|
|
140
|
+
* - guid: The unique identifier for the sent message.
|
|
141
|
+
* - nonce: The nonce of the sent message.
|
|
142
|
+
* - fee: The LayerZero fee incurred for the message.
|
|
143
|
+
*/
|
|
144
|
+
function send(
|
|
145
|
+
SendParam calldata _sendParam,
|
|
146
|
+
MessagingFee calldata _fee,
|
|
147
|
+
address _refundAddress
|
|
148
|
+
) external payable returns (MessagingReceipt memory, OFTReceipt memory);
|
|
149
|
+
}
|