@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.
Files changed (42) hide show
  1. package/README.md +15 -0
  2. package/contracts/oapp/OApp.sol +39 -0
  3. package/contracts/oapp/OAppCore.sol +83 -0
  4. package/contracts/oapp/OAppRead.sol +18 -0
  5. package/contracts/oapp/OAppReceiver.sol +122 -0
  6. package/contracts/oapp/OAppSender.sol +124 -0
  7. package/contracts/oapp/examples/CmdCodecV1Mock.sol +31 -0
  8. package/contracts/oapp/examples/LzReadCounter.sol +160 -0
  9. package/contracts/oapp/examples/OmniCounter.sol +15 -0
  10. package/contracts/oapp/examples/OmniCounterAbstract.sol +285 -0
  11. package/contracts/oapp/examples/OmniCounterAlt.sol +90 -0
  12. package/contracts/oapp/examples/OmniCounterPreCrime.sol +102 -0
  13. package/contracts/oapp/interfaces/IOAppComposer.sol +12 -0
  14. package/contracts/oapp/interfaces/IOAppComputer.sol +8 -0
  15. package/contracts/oapp/interfaces/IOAppComputerMap.sol +7 -0
  16. package/contracts/oapp/interfaces/IOAppComputerReduce.sol +7 -0
  17. package/contracts/oapp/interfaces/IOAppCore.sol +52 -0
  18. package/contracts/oapp/interfaces/IOAppMsgInspector.sol +22 -0
  19. package/contracts/oapp/interfaces/IOAppOptionsType3.sol +43 -0
  20. package/contracts/oapp/interfaces/IOAppReceiver.sol +25 -0
  21. package/contracts/oapp/libs/OAppOptionsType3.sol +98 -0
  22. package/contracts/oapp/libs/OptionsBuilder.sol +218 -0
  23. package/contracts/oapp/libs/ReadCmdCodecV1.sol +231 -0
  24. package/contracts/oapp/utils/RateLimiter.sol +229 -0
  25. package/contracts/oft/OFT.sol +89 -0
  26. package/contracts/oft/OFTAdapter.sol +106 -0
  27. package/contracts/oft/OFTCore.sol +399 -0
  28. package/contracts/oft/OFTPrecrime.sol +99 -0
  29. package/contracts/oft/interfaces/IOFT.sol +149 -0
  30. package/contracts/oft/libs/OFTComposeMsgCodec.sol +91 -0
  31. package/contracts/oft/libs/OFTMsgCodec.sol +83 -0
  32. package/contracts/precrime/OAppPreCrimeSimulator.sol +125 -0
  33. package/contracts/precrime/PreCrime.sol +211 -0
  34. package/contracts/precrime/extensions/PreCrimeE1.sol +30 -0
  35. package/contracts/precrime/interfaces/IOAppPreCrimeSimulator.sol +55 -0
  36. package/contracts/precrime/interfaces/IPreCrime.sol +40 -0
  37. package/contracts/precrime/libs/Packet.sol +61 -0
  38. package/dist/index.d.ts +7 -0
  39. package/dist/index.d.ts.map +1 -0
  40. package/dist/index.js +6 -0
  41. package/dist/index.js.map +1 -0
  42. package/package.json +67 -0
@@ -0,0 +1,229 @@
1
+ // SPDX-License-Identifier: MIT
2
+ pragma solidity ^0.8.0;
3
+
4
+ /**
5
+ * @title RateLimiter
6
+ * @dev Abstract contract for implementing rate limiting functionality. This contract provides a basic framework for
7
+ * rate limiting how often a function can be executed. It is designed to be inherited by other contracts requiring rate
8
+ * limiting capabilities to protect resources or services from excessive use.
9
+ *
10
+ * Example 1: Max rate limit reached at beginning of window. As time continues the amount of in flights comes down.
11
+ *
12
+ * Rate Limit Config:
13
+ * limit: 100 units
14
+ * window: 60 seconds
15
+ *
16
+ * Amount in Flight (units) vs. Time Graph (seconds)
17
+ *
18
+ * 100 | * - (Max limit reached at beginning of window)
19
+ * | *
20
+ * | *
21
+ * | *
22
+ * 50 | * (After 30 seconds only 50 units in flight)
23
+ * | *
24
+ * | *
25
+ * | *
26
+ * 0 +--|---|---|---|---|-->(After 60 seconds 0 units are in flight)
27
+ * 0 15 30 45 60 (seconds)
28
+ *
29
+ * Example 2: Max rate limit reached at beginning of window. As time continues the amount of in flights comes down
30
+ * allowing for more to be sent. At the 90 second mark, more in flights come in.
31
+ *
32
+ * Rate Limit Config:
33
+ * limit: 100 units
34
+ * window: 60 seconds
35
+ *
36
+ * Amount in Flight (units) vs. Time Graph (seconds)
37
+ *
38
+ * 100 | * - (Max limit reached at beginning of window)
39
+ * | *
40
+ * | *
41
+ * | *
42
+ * 50 | * * (50 inflight)
43
+ * | * *
44
+ * | * *
45
+ * | * *
46
+ * 0 +--|--|--|--|--|--|--|--|--|--> Time
47
+ * 0 15 30 45 60 75 90 105 120 (seconds)
48
+ *
49
+ * Example 3: Max rate limit reached at beginning of window. At the 15 second mark, the window gets updated to 60
50
+ * seconds and the limit gets updated to 50 units. This scenario shows the direct depiction of "in flight" from the
51
+ * previous window affecting the current window.
52
+ *
53
+ * Initial Rate Limit Config: For first 15 seconds
54
+ * limit: 100 units
55
+ * window: 30 seconds
56
+ *
57
+ * Updated Rate Limit Config: Updated at 15 second mark
58
+ * limit: 50 units
59
+ * window: 60 seconds
60
+ *
61
+ * Amount in Flight (units) vs. Time Graph (seconds)
62
+ * 100 - *
63
+ * |*
64
+ * | *
65
+ * | *
66
+ * | *
67
+ * | *
68
+ * | *
69
+ * 75 - | *
70
+ * | *
71
+ * | *
72
+ * | *
73
+ * | *
74
+ * | *
75
+ * | *
76
+ * | *
77
+ * 50 - | 𐫰 <--(Slope changes at the 15 second mark because of the update.
78
+ * | ✧ * Window extended to 60 seconds and limit reduced to 50 units.
79
+ * | ✧ ︎ * Because amountInFlight/lastUpdated do not reset, 50 units are
80
+ * | ✧ * considered in flight from the previous window and the corresponding
81
+ * | ✧ ︎ * decay from the previous rate.)
82
+ * | ✧ *
83
+ * 25 - | ✧ *
84
+ * | ✧ *
85
+ * | ✧ *
86
+ * | ✧ *
87
+ * | ✧ *
88
+ * | ✧ *
89
+ * | ✧ *
90
+ * | ✧ *
91
+ * 0 - +---|----|----|----|----|----|----|----|----|----|----|----|----|----|----|----|----|----|----> Time
92
+ * 0 5 10 15 20 25 30 35 40 45 50 55 60 65 70 75 80 85 90 (seconds)
93
+ * [ Initial 30 Second Window ]
94
+ * [ --------------- Extended 60 Second Window --------------- ]
95
+ */
96
+ abstract contract RateLimiter {
97
+ /**
98
+ * @notice Rate Limit struct.
99
+ * @param amountInFlight The amount in the current window.
100
+ * @param lastUpdated Timestamp representing the last time the rate limit was checked or updated.
101
+ * @param limit This represents the maximum allowed amount within a given window.
102
+ * @param window Defines the duration of the rate limiting window.
103
+ */
104
+ struct RateLimit {
105
+ uint256 amountInFlight;
106
+ uint256 lastUpdated;
107
+ uint256 limit;
108
+ uint256 window;
109
+ }
110
+
111
+ /**
112
+ * @notice Rate Limit Configuration struct.
113
+ * @param dstEid The destination endpoint id.
114
+ * @param limit This represents the maximum allowed amount within a given window.
115
+ * @param window Defines the duration of the rate limiting window.
116
+ */
117
+ struct RateLimitConfig {
118
+ uint32 dstEid;
119
+ uint256 limit;
120
+ uint256 window;
121
+ }
122
+
123
+ /**
124
+ * @dev Mapping from destination endpoint id to RateLimit Configurations.
125
+ */
126
+ mapping(uint32 dstEid => RateLimit limit) public rateLimits;
127
+
128
+ /**
129
+ * @notice Emitted when _setRateLimits occurs.
130
+ * @param rateLimitConfigs An array of `RateLimitConfig` structs representing the rate limit configurations set.
131
+ * - `dstEid`: The destination endpoint id.
132
+ * - `limit`: This represents the maximum allowed amount within a given window.
133
+ * - `window`: Defines the duration of the rate limiting window.
134
+ */
135
+ event RateLimitsChanged(RateLimitConfig[] rateLimitConfigs);
136
+
137
+ /**
138
+ * @notice Error that is thrown when an amount exceeds the rate_limit.
139
+ */
140
+ error RateLimitExceeded();
141
+
142
+ /**
143
+ * @notice Get the current amount that can be sent to this destination endpoint id for the given rate limit window.
144
+ * @param _dstEid The destination endpoint id.
145
+ * @return currentAmountInFlight The current amount that was sent.
146
+ * @return amountCanBeSent The amount that can be sent.
147
+ */
148
+ function getAmountCanBeSent(
149
+ uint32 _dstEid
150
+ ) external view virtual returns (uint256 currentAmountInFlight, uint256 amountCanBeSent) {
151
+ RateLimit memory rl = rateLimits[_dstEid];
152
+ return _amountCanBeSent(rl.amountInFlight, rl.lastUpdated, rl.limit, rl.window);
153
+ }
154
+
155
+ /**
156
+ * @notice Sets the Rate Limit.
157
+ * @param _rateLimitConfigs A `RateLimitConfig` struct representing the rate limit configuration.
158
+ * - `dstEid`: The destination endpoint id.
159
+ * - `limit`: This represents the maximum allowed amount within a given window.
160
+ * - `window`: Defines the duration of the rate limiting window.
161
+ */
162
+ function _setRateLimits(RateLimitConfig[] memory _rateLimitConfigs) internal virtual {
163
+ unchecked {
164
+ for (uint256 i = 0; i < _rateLimitConfigs.length; i++) {
165
+ RateLimit storage rl = rateLimits[_rateLimitConfigs[i].dstEid];
166
+
167
+ // @dev Ensure we checkpoint the existing rate limit as to not retroactively apply the new decay rate.
168
+ _checkAndUpdateRateLimit(_rateLimitConfigs[i].dstEid, 0);
169
+
170
+ // @dev Does NOT reset the amountInFlight/lastUpdated of an existing rate limit.
171
+ rl.limit = _rateLimitConfigs[i].limit;
172
+ rl.window = _rateLimitConfigs[i].window;
173
+ }
174
+ }
175
+ emit RateLimitsChanged(_rateLimitConfigs);
176
+ }
177
+
178
+ /**
179
+ * @notice Checks current amount in flight and amount that can be sent for a given rate limit window.
180
+ * @param _amountInFlight The amount in the current window.
181
+ * @param _lastUpdated Timestamp representing the last time the rate limit was checked or updated.
182
+ * @param _limit This represents the maximum allowed amount within a given window.
183
+ * @param _window Defines the duration of the rate limiting window.
184
+ * @return currentAmountInFlight The amount in the current window.
185
+ * @return amountCanBeSent The amount that can be sent.
186
+ */
187
+ function _amountCanBeSent(
188
+ uint256 _amountInFlight,
189
+ uint256 _lastUpdated,
190
+ uint256 _limit,
191
+ uint256 _window
192
+ ) internal view virtual returns (uint256 currentAmountInFlight, uint256 amountCanBeSent) {
193
+ uint256 timeSinceLastDeposit = block.timestamp - _lastUpdated;
194
+ if (timeSinceLastDeposit >= _window) {
195
+ currentAmountInFlight = 0;
196
+ amountCanBeSent = _limit;
197
+ } else {
198
+ // @dev Presumes linear decay.
199
+ uint256 decay = (_limit * timeSinceLastDeposit) / _window;
200
+ currentAmountInFlight = _amountInFlight <= decay ? 0 : _amountInFlight - decay;
201
+ // @dev In the event the _limit is lowered, and the 'in-flight' amount is higher than the _limit, set to 0.
202
+ amountCanBeSent = _limit <= currentAmountInFlight ? 0 : _limit - currentAmountInFlight;
203
+ }
204
+ }
205
+
206
+ /**
207
+ * @notice Verifies whether the specified amount falls within the rate limit constraints for the targeted
208
+ * endpoint ID. On successful verification, it updates amountInFlight and lastUpdated. If the amount exceeds
209
+ * the rate limit, the operation reverts.
210
+ * @param _dstEid The destination endpoint id.
211
+ * @param _amount The amount to check for rate limit constraints.
212
+ */
213
+ function _checkAndUpdateRateLimit(uint32 _dstEid, uint256 _amount) internal virtual {
214
+ // @dev By default dstEid that have not been explicitly set will return amountCanBeSent == 0.
215
+ RateLimit storage rl = rateLimits[_dstEid];
216
+
217
+ (uint256 currentAmountInFlight, uint256 amountCanBeSent) = _amountCanBeSent(
218
+ rl.amountInFlight,
219
+ rl.lastUpdated,
220
+ rl.limit,
221
+ rl.window
222
+ );
223
+ if (_amount > amountCanBeSent) revert RateLimitExceeded();
224
+
225
+ // @dev Update the storage to contain the new amount and current timestamp.
226
+ rl.amountInFlight = currentAmountInFlight + _amount;
227
+ rl.lastUpdated = block.timestamp;
228
+ }
229
+ }
@@ -0,0 +1,89 @@
1
+ // SPDX-License-Identifier: MIT
2
+
3
+ pragma solidity ^0.8.20;
4
+
5
+ import { ERC20 } from "@openzeppelin/contracts/token/ERC20/ERC20.sol";
6
+ import { IOFT, OFTCore } from "./OFTCore.sol";
7
+
8
+ /**
9
+ * @title OFT Contract
10
+ * @dev OFT is an ERC-20 token that extends the functionality of the OFTCore contract.
11
+ */
12
+ abstract contract OFT is OFTCore, ERC20 {
13
+ /**
14
+ * @dev Constructor for the OFT contract.
15
+ * @param _name The name of the OFT.
16
+ * @param _symbol The symbol of the OFT.
17
+ * @param _lzEndpoint The LayerZero endpoint address.
18
+ * @param _delegate The delegate capable of making OApp configurations inside of the endpoint.
19
+ */
20
+ constructor(
21
+ string memory _name,
22
+ string memory _symbol,
23
+ address _lzEndpoint,
24
+ address _delegate
25
+ ) ERC20(_name, _symbol) OFTCore(decimals(), _lzEndpoint, _delegate) {}
26
+
27
+ /**
28
+ * @dev Retrieves the address of the underlying ERC20 implementation.
29
+ * @return The address of the OFT token.
30
+ *
31
+ * @dev In the case of OFT, address(this) and erc20 are the same contract.
32
+ */
33
+ function token() public view returns (address) {
34
+ return address(this);
35
+ }
36
+
37
+ /**
38
+ * @notice Indicates whether the OFT contract requires approval of the 'token()' to send.
39
+ * @return requiresApproval Needs approval of the underlying token implementation.
40
+ *
41
+ * @dev In the case of OFT where the contract IS the token, approval is NOT required.
42
+ */
43
+ function approvalRequired() external pure virtual returns (bool) {
44
+ return false;
45
+ }
46
+
47
+ /**
48
+ * @dev Burns tokens from the sender's specified balance.
49
+ * @param _from The address to debit the tokens from.
50
+ * @param _amountLD The amount of tokens to send in local decimals.
51
+ * @param _minAmountLD The minimum amount to send in local decimals.
52
+ * @param _dstEid The destination chain ID.
53
+ * @return amountSentLD The amount sent in local decimals.
54
+ * @return amountReceivedLD The amount received in local decimals on the remote.
55
+ */
56
+ function _debit(
57
+ address _from,
58
+ uint256 _amountLD,
59
+ uint256 _minAmountLD,
60
+ uint32 _dstEid
61
+ ) internal virtual override returns (uint256 amountSentLD, uint256 amountReceivedLD) {
62
+ (amountSentLD, amountReceivedLD) = _debitView(_amountLD, _minAmountLD, _dstEid);
63
+
64
+ // @dev In NON-default OFT, amountSentLD could be 100, with a 10% fee, the amountReceivedLD amount is 90,
65
+ // therefore amountSentLD CAN differ from amountReceivedLD.
66
+
67
+ // @dev Default OFT burns on src.
68
+ _burn(_from, amountSentLD);
69
+ }
70
+
71
+ /**
72
+ * @dev Credits tokens to the specified address.
73
+ * @param _to The address to credit the tokens to.
74
+ * @param _amountLD The amount of tokens to credit in local decimals.
75
+ * @dev _srcEid The source chain ID.
76
+ * @return amountReceivedLD The amount of tokens ACTUALLY received in local decimals.
77
+ */
78
+ function _credit(
79
+ address _to,
80
+ uint256 _amountLD,
81
+ uint32 /*_srcEid*/
82
+ ) internal virtual override returns (uint256 amountReceivedLD) {
83
+ if (_to == address(0x0)) _to = address(0xdead); // _mint(...) does not support address(0x0)
84
+ // @dev Default OFT mints on dst.
85
+ _mint(_to, _amountLD);
86
+ // @dev In the case of NON-default OFT, the _amountLD MIGHT not be == amountReceivedLD.
87
+ return _amountLD;
88
+ }
89
+ }
@@ -0,0 +1,106 @@
1
+ // SPDX-License-Identifier: MIT
2
+
3
+ pragma solidity ^0.8.20;
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 { IOFT, 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
+ * @dev WARNING: The default OFTAdapter implementation assumes LOSSLESS transfers, ie. 1 token in, 1 token out.
17
+ * IF the 'innerToken' applies something like a transfer fee, the default will NOT work...
18
+ * a pre/post balance check will need to be done to calculate the amountSentLD/amountReceivedLD.
19
+ */
20
+ abstract contract OFTAdapter is OFTCore {
21
+ using SafeERC20 for IERC20;
22
+
23
+ IERC20 internal immutable innerToken;
24
+
25
+ /**
26
+ * @dev Constructor for the OFTAdapter contract.
27
+ * @param _token The address of the ERC-20 token to be adapted.
28
+ * @param _lzEndpoint The LayerZero endpoint address.
29
+ * @param _delegate The delegate capable of making OApp configurations inside of the endpoint.
30
+ */
31
+ constructor(
32
+ address _token,
33
+ address _lzEndpoint,
34
+ address _delegate
35
+ ) OFTCore(IERC20Metadata(_token).decimals(), _lzEndpoint, _delegate) {
36
+ innerToken = IERC20(_token);
37
+ }
38
+
39
+ /**
40
+ * @dev Retrieves the address of the underlying ERC20 implementation.
41
+ * @return The address of the adapted ERC-20 token.
42
+ *
43
+ * @dev In the case of OFTAdapter, address(this) and erc20 are NOT the same contract.
44
+ */
45
+ function token() public view returns (address) {
46
+ return address(innerToken);
47
+ }
48
+
49
+ /**
50
+ * @notice Indicates whether the OFT contract requires approval of the 'token()' to send.
51
+ * @return requiresApproval Needs approval of the underlying token implementation.
52
+ *
53
+ * @dev In the case of default OFTAdapter, approval is required.
54
+ * @dev In non-default OFTAdapter contracts with something like mint and burn privileges, it would NOT need approval.
55
+ */
56
+ function approvalRequired() external pure virtual returns (bool) {
57
+ return true;
58
+ }
59
+
60
+ /**
61
+ * @dev Burns tokens from the sender's specified balance, ie. pull method.
62
+ * @param _from The address to debit from.
63
+ * @param _amountLD The amount of tokens to send in local decimals.
64
+ * @param _minAmountLD The minimum amount to send in local decimals.
65
+ * @param _dstEid The destination chain ID.
66
+ * @return amountSentLD The amount sent in local decimals.
67
+ * @return amountReceivedLD The amount received in local decimals on the remote.
68
+ *
69
+ * @dev msg.sender will need to approve this _amountLD of tokens to be locked inside of the contract.
70
+ * @dev WARNING: The default OFTAdapter implementation assumes LOSSLESS transfers, ie. 1 token in, 1 token out.
71
+ * IF the 'innerToken' applies something like a transfer fee, the default will NOT work...
72
+ * a pre/post balance check will need to be done to calculate the amountReceivedLD.
73
+ */
74
+ function _debit(
75
+ address _from,
76
+ uint256 _amountLD,
77
+ uint256 _minAmountLD,
78
+ uint32 _dstEid
79
+ ) internal virtual override returns (uint256 amountSentLD, uint256 amountReceivedLD) {
80
+ (amountSentLD, amountReceivedLD) = _debitView(_amountLD, _minAmountLD, _dstEid);
81
+ // @dev Lock tokens by moving them into this contract from the caller.
82
+ innerToken.safeTransferFrom(_from, address(this), amountSentLD);
83
+ }
84
+
85
+ /**
86
+ * @dev Credits tokens to the specified address.
87
+ * @param _to The address to credit the tokens to.
88
+ * @param _amountLD The amount of tokens to credit in local decimals.
89
+ * @dev _srcEid The source chain ID.
90
+ * @return amountReceivedLD The amount of tokens ACTUALLY received in local decimals.
91
+ *
92
+ * @dev WARNING: The default OFTAdapter implementation assumes LOSSLESS transfers, ie. 1 token in, 1 token out.
93
+ * IF the 'innerToken' applies something like a transfer fee, the default will NOT work...
94
+ * a pre/post balance check will need to be done to calculate the amountReceivedLD.
95
+ */
96
+ function _credit(
97
+ address _to,
98
+ uint256 _amountLD,
99
+ uint32 /*_srcEid*/
100
+ ) internal virtual override returns (uint256 amountReceivedLD) {
101
+ // @dev Unlock the tokens and transfer to the recipient.
102
+ innerToken.safeTransfer(_to, _amountLD);
103
+ // @dev In the case of NON-default OFTAdapter, the amountLD MIGHT not be == amountReceivedLD.
104
+ return _amountLD;
105
+ }
106
+ }