@layerzerolabs/lz-evm-oapp-v2 2.1.1 → 2.1.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.
@@ -0,0 +1,284 @@
1
+ // SPDX-License-Identifier: MIT
2
+
3
+ pragma solidity ^0.8.20;
4
+
5
+ import { ILayerZeroEndpointV2, MessagingFee, MessagingReceipt, Origin } from "@layerzerolabs/lz-evm-protocol-v2/contracts/interfaces/ILayerZeroEndpointV2.sol";
6
+ import { ILayerZeroComposer } from "@layerzerolabs/lz-evm-protocol-v2/contracts/interfaces/ILayerZeroComposer.sol";
7
+
8
+ import { OApp } from "../OApp.sol";
9
+ import { OptionsBuilder } from "../libs/OptionsBuilder.sol";
10
+ import { OAppPreCrimeSimulator } from "../../precrime/OAppPreCrimeSimulator.sol";
11
+
12
+ library MsgCodec {
13
+ uint8 internal constant VANILLA_TYPE = 1;
14
+ uint8 internal constant COMPOSED_TYPE = 2;
15
+ uint8 internal constant ABA_TYPE = 3;
16
+ uint8 internal constant COMPOSED_ABA_TYPE = 4;
17
+
18
+ uint8 internal constant MSG_TYPE_OFFSET = 0;
19
+ uint8 internal constant SRC_EID_OFFSET = 1;
20
+ uint8 internal constant VALUE_OFFSET = 5;
21
+
22
+ function encode(uint8 _type, uint32 _srcEid) internal pure returns (bytes memory) {
23
+ return abi.encodePacked(_type, _srcEid);
24
+ }
25
+
26
+ function encode(uint8 _type, uint32 _srcEid, uint256 _value) internal pure returns (bytes memory) {
27
+ return abi.encodePacked(_type, _srcEid, _value);
28
+ }
29
+
30
+ function msgType(bytes calldata _message) internal pure returns (uint8) {
31
+ return uint8(bytes1(_message[MSG_TYPE_OFFSET:SRC_EID_OFFSET]));
32
+ }
33
+
34
+ function srcEid(bytes calldata _message) internal pure returns (uint32) {
35
+ return uint32(bytes4(_message[SRC_EID_OFFSET:VALUE_OFFSET]));
36
+ }
37
+
38
+ function value(bytes calldata _message) internal pure returns (uint256) {
39
+ return uint256(bytes32(_message[VALUE_OFFSET:]));
40
+ }
41
+ }
42
+
43
+ // @dev declared as abstract to provide backwards compatibility with Oz5/Oz4
44
+ abstract contract OmniCounterAbstract is ILayerZeroComposer, OApp, OAppPreCrimeSimulator {
45
+ using MsgCodec for bytes;
46
+ using OptionsBuilder for bytes;
47
+
48
+ uint256 public count;
49
+ uint256 public composedCount;
50
+
51
+ address public admin;
52
+ uint32 public eid;
53
+
54
+ mapping(uint32 srcEid => mapping(bytes32 sender => uint64 nonce)) private maxReceivedNonce;
55
+ bool private orderedNonce;
56
+
57
+ // for global assertions
58
+ mapping(uint32 srcEid => uint256 count) public inboundCount;
59
+ mapping(uint32 dstEid => uint256 count) public outboundCount;
60
+
61
+ constructor(address _endpoint, address _delegate) OApp(_endpoint, _delegate) {
62
+ admin = msg.sender;
63
+ eid = ILayerZeroEndpointV2(_endpoint).eid();
64
+ }
65
+
66
+ modifier onlyAdmin() {
67
+ require(msg.sender == admin, "only admin");
68
+ _;
69
+ }
70
+
71
+ // -------------------------------
72
+ // Only Admin
73
+ function setAdmin(address _admin) external onlyAdmin {
74
+ admin = _admin;
75
+ }
76
+
77
+ function withdraw(address payable _to, uint256 _amount) external onlyAdmin {
78
+ (bool success, ) = _to.call{ value: _amount }("");
79
+ require(success, "OmniCounter: withdraw failed");
80
+ }
81
+
82
+ // -------------------------------
83
+ // Send
84
+ function increment(uint32 _eid, uint8 _type, bytes calldata _options) external payable {
85
+ // bytes memory options = combineOptions(_eid, _type, _options);
86
+ _lzSend(_eid, MsgCodec.encode(_type, eid), _options, MessagingFee(msg.value, 0), payable(msg.sender));
87
+ _incrementOutbound(_eid);
88
+ }
89
+
90
+ // this is a broken function to skip incrementing outbound count
91
+ // so that preCrime will fail
92
+ function brokenIncrement(uint32 _eid, uint8 _type, bytes calldata _options) external payable onlyAdmin {
93
+ // bytes memory options = combineOptions(_eid, _type, _options);
94
+ _lzSend(_eid, MsgCodec.encode(_type, eid), _options, MessagingFee(msg.value, 0), payable(msg.sender));
95
+ }
96
+
97
+ function batchIncrement(
98
+ uint32[] calldata _eids,
99
+ uint8[] calldata _types,
100
+ bytes[] calldata _options
101
+ ) external payable {
102
+ require(_eids.length == _options.length && _eids.length == _types.length, "OmniCounter: length mismatch");
103
+
104
+ MessagingReceipt memory receipt;
105
+ uint256 providedFee = msg.value;
106
+ for (uint256 i = 0; i < _eids.length; i++) {
107
+ address refundAddress = i == _eids.length - 1 ? msg.sender : address(this);
108
+ uint32 dstEid = _eids[i];
109
+ uint8 msgType = _types[i];
110
+ // bytes memory options = combineOptions(dstEid, msgType, _options[i]);
111
+ receipt = _lzSend(
112
+ dstEid,
113
+ MsgCodec.encode(msgType, eid),
114
+ _options[i],
115
+ MessagingFee(providedFee, 0),
116
+ payable(refundAddress)
117
+ );
118
+ _incrementOutbound(dstEid);
119
+ providedFee -= receipt.fee.nativeFee;
120
+ }
121
+ }
122
+
123
+ // -------------------------------
124
+ // View
125
+ function quote(
126
+ uint32 _eid,
127
+ uint8 _type,
128
+ bytes calldata _options
129
+ ) public view returns (uint256 nativeFee, uint256 lzTokenFee) {
130
+ // bytes memory options = combineOptions(_eid, _type, _options);
131
+ MessagingFee memory fee = _quote(_eid, MsgCodec.encode(_type, eid), _options, false);
132
+ return (fee.nativeFee, fee.lzTokenFee);
133
+ }
134
+
135
+ // @dev enables preCrime simulator
136
+ // @dev routes the call down from the OAppPreCrimeSimulator, and up to the OApp
137
+ function _lzReceiveSimulate(
138
+ Origin calldata _origin,
139
+ bytes32 _guid,
140
+ bytes calldata _message,
141
+ address _executor,
142
+ bytes calldata _extraData
143
+ ) internal virtual override {
144
+ _lzReceive(_origin, _guid, _message, _executor, _extraData);
145
+ }
146
+
147
+ // -------------------------------
148
+ function _lzReceive(
149
+ Origin calldata _origin,
150
+ bytes32 _guid,
151
+ bytes calldata _message,
152
+ address /*_executor*/,
153
+ bytes calldata /*_extraData*/
154
+ ) internal override {
155
+ _acceptNonce(_origin.srcEid, _origin.sender, _origin.nonce);
156
+ uint8 messageType = _message.msgType();
157
+
158
+ if (messageType == MsgCodec.VANILLA_TYPE) {
159
+ count++;
160
+
161
+ //////////////////////////////// IMPORTANT //////////////////////////////////
162
+ /// if you request for msg.value in the options, you should also encode it
163
+ /// into your message and check the value received at destination (example below).
164
+ /// if not, the executor could potentially provide less msg.value than you requested
165
+ /// leading to unintended behavior. Another option is to assert the executor to be
166
+ /// one that you trust.
167
+ /////////////////////////////////////////////////////////////////////////////
168
+ require(msg.value >= _message.value(), "OmniCounter: insufficient value");
169
+
170
+ _incrementInbound(_origin.srcEid);
171
+ } else if (messageType == MsgCodec.COMPOSED_TYPE || messageType == MsgCodec.COMPOSED_ABA_TYPE) {
172
+ count++;
173
+ _incrementInbound(_origin.srcEid);
174
+ endpoint.sendCompose(address(this), _guid, 0, _message);
175
+ } else if (messageType == MsgCodec.ABA_TYPE) {
176
+ count++;
177
+ _incrementInbound(_origin.srcEid);
178
+
179
+ // send back to the sender
180
+ _incrementOutbound(_origin.srcEid);
181
+ bytes memory options = OptionsBuilder.newOptions().addExecutorLzReceiveOption(200000, 10);
182
+ _lzSend(
183
+ _origin.srcEid,
184
+ MsgCodec.encode(MsgCodec.VANILLA_TYPE, eid, 10),
185
+ options,
186
+ MessagingFee(msg.value, 0),
187
+ payable(address(this))
188
+ );
189
+ } else {
190
+ revert("invalid message type");
191
+ }
192
+ }
193
+
194
+ function _incrementInbound(uint32 _srcEid) internal {
195
+ inboundCount[_srcEid]++;
196
+ }
197
+
198
+ function _incrementOutbound(uint32 _dstEid) internal {
199
+ outboundCount[_dstEid]++;
200
+ }
201
+
202
+ function lzCompose(
203
+ address _oApp,
204
+ bytes32 /*_guid*/,
205
+ bytes calldata _message,
206
+ address,
207
+ bytes calldata
208
+ ) external payable override {
209
+ require(_oApp == address(this), "!oApp");
210
+ require(msg.sender == address(endpoint), "!endpoint");
211
+
212
+ uint8 msgType = _message.msgType();
213
+ if (msgType == MsgCodec.COMPOSED_TYPE) {
214
+ composedCount += 1;
215
+ } else if (msgType == MsgCodec.COMPOSED_ABA_TYPE) {
216
+ composedCount += 1;
217
+
218
+ uint32 srcEid = _message.srcEid();
219
+ _incrementOutbound(srcEid);
220
+ bytes memory options = OptionsBuilder.newOptions().addExecutorLzReceiveOption(200000, 0);
221
+ _lzSend(
222
+ srcEid,
223
+ MsgCodec.encode(MsgCodec.VANILLA_TYPE, eid),
224
+ options,
225
+ MessagingFee(msg.value, 0),
226
+ payable(address(this))
227
+ );
228
+ } else {
229
+ revert("invalid message type");
230
+ }
231
+ }
232
+
233
+ // -------------------------------
234
+ // Ordered OApp
235
+ // this demonstrates how to build an app that requires execution nonce ordering
236
+ // normally an app should decide ordered or not on contract construction
237
+ // this is just a demo
238
+ function setOrderedNonce(bool _orderedNonce) external onlyOwner {
239
+ orderedNonce = _orderedNonce;
240
+ }
241
+
242
+ function _acceptNonce(uint32 _srcEid, bytes32 _sender, uint64 _nonce) internal virtual {
243
+ uint64 currentNonce = maxReceivedNonce[_srcEid][_sender];
244
+ if (orderedNonce) {
245
+ require(_nonce == currentNonce + 1, "OApp: invalid nonce");
246
+ }
247
+ // update the max nonce anyway. once the ordered mode is turned on, missing early nonces will be rejected
248
+ if (_nonce > currentNonce) {
249
+ maxReceivedNonce[_srcEid][_sender] = _nonce;
250
+ }
251
+ }
252
+
253
+ function nextNonce(uint32 _srcEid, bytes32 _sender) public view virtual override returns (uint64) {
254
+ if (orderedNonce) {
255
+ return maxReceivedNonce[_srcEid][_sender] + 1;
256
+ } else {
257
+ return 0; // path nonce starts from 1. if 0 it means that there is no specific nonce enforcement
258
+ }
259
+ }
260
+
261
+ // TODO should override oApp version with added ordered nonce increment
262
+ // a governance function to skip nonce
263
+ function skipInboundNonce(uint32 _srcEid, bytes32 _sender, uint64 _nonce) public virtual onlyOwner {
264
+ endpoint.skip(address(this), _srcEid, _sender, _nonce);
265
+ if (orderedNonce) {
266
+ maxReceivedNonce[_srcEid][_sender]++;
267
+ }
268
+ }
269
+
270
+ function isPeer(uint32 _eid, bytes32 _peer) public view override returns (bool) {
271
+ return peers[_eid] == _peer;
272
+ }
273
+
274
+ // @dev Batch send requires overriding this function from OAppSender because the msg.value contains multiple fees
275
+ function _payNative(uint256 _nativeFee) internal virtual override returns (uint256 nativeFee) {
276
+ if (msg.value < _nativeFee) revert NotEnoughNative(msg.value);
277
+ return _nativeFee;
278
+ }
279
+
280
+ // be able to receive ether
281
+ receive() external payable virtual {}
282
+
283
+ fallback() external payable {}
284
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@layerzerolabs/lz-evm-oapp-v2",
3
- "version": "2.1.1",
3
+ "version": "2.1.2",
4
4
  "license": "MIT",
5
5
  "files": [
6
6
  "artifacts/contracts/**/!(*.dbg).json",
@@ -11,9 +11,9 @@
11
11
  },
12
12
  "dependencies": {},
13
13
  "devDependencies": {
14
- "@layerzerolabs/lz-evm-messagelib-v2": "^2.1.1",
15
- "@layerzerolabs/lz-evm-protocol-v2": "^2.1.1",
16
- "@layerzerolabs/lz-evm-v1-0.7": "^2.1.1",
14
+ "@layerzerolabs/lz-evm-messagelib-v2": "^2.1.2",
15
+ "@layerzerolabs/lz-evm-protocol-v2": "^2.1.2",
16
+ "@layerzerolabs/lz-evm-v1-0.7": "^2.1.2",
17
17
  "@openzeppelin/contracts": "^4.8.1",
18
18
  "@openzeppelin/contracts-upgradeable": "^4.8.1",
19
19
  "hardhat-deploy": "^0.11.44",
@@ -21,9 +21,9 @@
21
21
  "solidity-bytes-utils": "^0.8.0"
22
22
  },
23
23
  "peerDependencies": {
24
- "@layerzerolabs/lz-evm-messagelib-v2": "^2.1.1",
25
- "@layerzerolabs/lz-evm-protocol-v2": "^2.1.1",
26
- "@layerzerolabs/lz-evm-v1-0.7": "^2.1.1",
24
+ "@layerzerolabs/lz-evm-messagelib-v2": "^2.1.2",
25
+ "@layerzerolabs/lz-evm-protocol-v2": "^2.1.2",
26
+ "@layerzerolabs/lz-evm-v1-0.7": "^2.1.2",
27
27
  "@openzeppelin/contracts": "^4.8.1 || ^5.0.0",
28
28
  "@openzeppelin/contracts-upgradeable": "^4.8.1 || ^5.0.0",
29
29
  "hardhat-deploy": "^0.11.44",