@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,10 @@
1
+ {
2
+ "_format": "hh-sol-artifact-1",
3
+ "contractName": "PacketDecoder",
4
+ "sourceName": "contracts/precrime/libs/Packet.sol",
5
+ "abi": [],
6
+ "bytecode": "0x60566037600b82828239805160001a607314602a57634e487b7160e01b600052600060045260246000fd5b30600052607381538281f3fe73000000000000000000000000000000000000000030146080604052600080fdfea264697066735822122029e3ce00edeb8557fe96561485377adb7ac0b821eb03a0e6790a9b82ee3eb46164736f6c63430008160033",
7
+ "deployedBytecode": "0x73000000000000000000000000000000000000000030146080604052600080fdfea264697066735822122029e3ce00edeb8557fe96561485377adb7ac0b821eb03a0e6790a9b82ee3eb46164736f6c63430008160033",
8
+ "linkReferences": {},
9
+ "deployedLinkReferences": {}
10
+ }
@@ -0,0 +1,39 @@
1
+ // SPDX-License-Identifier: MIT
2
+
3
+ pragma solidity ^0.8.22;
4
+
5
+ // @dev Import the 'MessagingFee' so it's exposed to OApp implementers
6
+ // solhint-disable-next-line no-unused-import
7
+ import { OAppSender, MessagingFee } from "./OAppSender.sol";
8
+ // @dev Import the 'Origin' so it's exposed to OApp implementers
9
+ // solhint-disable-next-line no-unused-import
10
+ import { OAppReceiver, Origin } from "./OAppReceiver.sol";
11
+ import { OAppCore } from "./OAppCore.sol";
12
+
13
+ /**
14
+ * @title OApp
15
+ * @dev Abstract contract serving as the base for OApp implementation, combining OAppSender and OAppReceiver functionality.
16
+ */
17
+ abstract contract OApp is OAppSender, OAppReceiver {
18
+ /**
19
+ * @dev Constructor to initialize the OApp with the provided endpoint and owner.
20
+ * @param _endpoint The address of the LOCAL LayerZero endpoint.
21
+ * @param _owner The address of the owner of the OApp.
22
+ */
23
+ constructor(address _endpoint, address _owner) OAppCore(_endpoint, _owner) {}
24
+
25
+ /**
26
+ * @notice Retrieves the OApp version information.
27
+ * @return senderVersion The version of the OAppSender.sol implementation.
28
+ * @return receiverVersion The version of the OAppReceiver.sol implementation.
29
+ */
30
+ function oAppVersion()
31
+ public
32
+ pure
33
+ virtual
34
+ override(OAppSender, OAppReceiver)
35
+ returns (uint64 senderVersion, uint64 receiverVersion)
36
+ {
37
+ return (SENDER_VERSION, RECEIVER_VERSION);
38
+ }
39
+ }
@@ -0,0 +1,68 @@
1
+ // SPDX-License-Identifier: MIT
2
+
3
+ pragma solidity ^0.8.22;
4
+
5
+ import { Ownable } from "@openzeppelin/contracts/access/Ownable.sol";
6
+ import { IOAppCore, ILayerZeroEndpointV2 } from "./interfaces/IOAppCore.sol";
7
+
8
+ /**
9
+ * @title OAppCore
10
+ * @dev Abstract contract implementing the IOAppCore interface with basic OApp configurations.
11
+ */
12
+ abstract contract OAppCore is IOAppCore, Ownable {
13
+ // The LayerZero endpoint associated with the given OApp
14
+ ILayerZeroEndpointV2 public immutable endpoint;
15
+
16
+ // Mapping to store peers associated with corresponding endpoints
17
+ mapping(uint32 eid => bytes32 peer) public peers;
18
+
19
+ /**
20
+ * @dev Constructor to initialize the OAppCore with the provided endpoint and owner.
21
+ * @param _endpoint The address of the LOCAL Layer Zero endpoint.
22
+ * @param _owner The address of the owner of the OAppCore.
23
+ */
24
+ constructor(address _endpoint, address _owner) {
25
+ _transferOwnership(_owner);
26
+ endpoint = ILayerZeroEndpointV2(_endpoint);
27
+ endpoint.setDelegate(_owner); // @dev By default, the owner is the delegate
28
+ }
29
+
30
+ /**
31
+ * @notice Sets the peer address (OApp instance) for a corresponding endpoint.
32
+ * @param _eid The endpoint ID.
33
+ * @param _peer The address of the peer to be associated with the corresponding endpoint.
34
+ *
35
+ * @dev Only the owner/admin of the OApp can call this function.
36
+ * @dev Indicates that the peer is trusted to send LayerZero messages to this OApp.
37
+ * @dev Set this to bytes32(0) to remove the peer address.
38
+ * @dev Peer is a bytes32 to accommodate non-evm chains.
39
+ */
40
+ function setPeer(uint32 _eid, bytes32 _peer) public virtual onlyOwner {
41
+ peers[_eid] = _peer;
42
+ emit PeerSet(_eid, _peer);
43
+ }
44
+
45
+ /**
46
+ * @notice Internal function to get the peer address associated with a specific endpoint; reverts if NOT set.
47
+ * ie. the peer is set to bytes32(0).
48
+ * @param _eid The endpoint ID.
49
+ * @return peer The address of the peer associated with the specified endpoint.
50
+ */
51
+ function _getPeerOrRevert(uint32 _eid) internal view virtual returns (bytes32) {
52
+ bytes32 peer = peers[_eid];
53
+ if (peer == bytes32(0)) revert NoPeer(_eid);
54
+ return peer;
55
+ }
56
+
57
+ /**
58
+ * @notice Sets the delegate address for the OApp.
59
+ * @param _delegate The address of the delegate to be set.
60
+ *
61
+ * @dev Only the owner/admin of the OApp can call this function.
62
+ * @dev Provides the ability for a delegate to set configs, on behalf of the OApp, directly on the Endpoint contract.
63
+ * @dev Defaults to the owner of the OApp.
64
+ */
65
+ function setDelegate(address _delegate) public onlyOwner {
66
+ endpoint.setDelegate(_delegate);
67
+ }
68
+ }
@@ -0,0 +1,101 @@
1
+ // SPDX-License-Identifier: MIT
2
+
3
+ pragma solidity ^0.8.22;
4
+
5
+ import { ILayerZeroReceiver, Origin } from "@layerzerolabs/lz-evm-protocol-v2/contracts/interfaces/ILayerZeroReceiver.sol";
6
+ import { OAppCore } from "./OAppCore.sol";
7
+
8
+ /**
9
+ * @title OAppReceiver
10
+ * @dev Abstract contract implementing the ILayerZeroReceiver interface and extending OAppCore for OApp receivers.
11
+ */
12
+ abstract contract OAppReceiver is ILayerZeroReceiver, OAppCore {
13
+ // Custom error message for when the caller is not the registered endpoint/
14
+ error OnlyEndpoint(address addr);
15
+
16
+ // @dev The version of the OAppReceiver implementation.
17
+ // @dev Version is bumped when changes are made to this contract.
18
+ uint64 internal constant RECEIVER_VERSION = 1;
19
+
20
+ /**
21
+ * @notice Retrieves the OApp version information.
22
+ * @return senderVersion The version of the OAppSender.sol contract.
23
+ * @return receiverVersion The version of the OAppReceiver.sol contract.
24
+ *
25
+ * @dev Providing 0 as the default for OAppSender version. Indicates that the OAppSender is not implemented.
26
+ * ie. this is a SEND only OApp.
27
+ * @dev If the OApp uses both OAppSender and OAppReceiver, then this needs to be override returning the correct versions.
28
+ */
29
+ function oAppVersion() public view virtual returns (uint64 senderVersion, uint64 receiverVersion) {
30
+ return (0, RECEIVER_VERSION);
31
+ }
32
+
33
+ /**
34
+ * @notice Checks if the path initialization is allowed based on the provided origin.
35
+ * @param origin The origin information containing the source endpoint and sender address.
36
+ * @return Whether the path has been initialized.
37
+ *
38
+ * @dev This indicates to the endpoint that the OApp has enabled msgs for this particular path to be received.
39
+ * @dev This defaults to assuming if a peer has been set, its initialized.
40
+ * Can be overridden by the OApp if there is other logic to determine this.
41
+ */
42
+ function allowInitializePath(Origin calldata origin) public view virtual returns (bool) {
43
+ return peers[origin.srcEid] == origin.sender;
44
+ }
45
+
46
+ /**
47
+ * @notice Retrieves the next nonce for a given source endpoint and sender address.
48
+ * @dev _srcEid The source endpoint ID.
49
+ * @dev _sender The sender address.
50
+ * @return nonce The next nonce.
51
+ *
52
+ * @dev The path nonce starts from 1. If 0 is returned it means that there is NO nonce ordered enforcement.
53
+ * @dev Is required by the off-chain executor to determine the OApp expects msg execution is ordered.
54
+ * @dev This is also enforced by the OApp.
55
+ * @dev By default this is NOT enabled. ie. nextNonce is hardcoded to return 0.
56
+ */
57
+ function nextNonce(uint32 /*_srcEid*/, bytes32 /*_sender*/) public view virtual returns (uint64 nonce) {
58
+ return 0;
59
+ }
60
+
61
+ /**
62
+ * @dev Entry point for receiving messages or packets from the endpoint.
63
+ * @param _origin The origin information containing the source endpoint and sender address.
64
+ * - srcEid: The source chain endpoint ID.
65
+ * - sender: The sender address on the src chain.
66
+ * - nonce: The nonce of the message.
67
+ * @param _guid The unique identifier for the received LayerZero message.
68
+ * @param _message The payload of the received message.
69
+ * @param _executor The address of the executor for the received message.
70
+ * @param _extraData Additional arbitrary data provided by the corresponding executor.
71
+ *
72
+ * @dev Entry point for receiving msg/packet from the LayerZero endpoint.
73
+ */
74
+ function lzReceive(
75
+ Origin calldata _origin,
76
+ bytes32 _guid,
77
+ bytes calldata _message,
78
+ address _executor,
79
+ bytes calldata _extraData
80
+ ) public payable virtual {
81
+ // Ensures that only the endpoint can attempt to lzReceive() messages to this OApp.
82
+ if (address(endpoint) != msg.sender) revert OnlyEndpoint(msg.sender);
83
+
84
+ // Ensure that the sender matches the expected peer for the source endpoint.
85
+ if (_getPeerOrRevert(_origin.srcEid) != _origin.sender) revert OnlyPeer(_origin.srcEid, _origin.sender);
86
+
87
+ // Call the internal OApp implementation of lzReceive.
88
+ _lzReceive(_origin, _guid, _message, _executor, _extraData);
89
+ }
90
+
91
+ /**
92
+ * @dev Internal function to implement lzReceive logic without needing to copy the basic parameter validation.
93
+ */
94
+ function _lzReceive(
95
+ Origin calldata _origin,
96
+ bytes32 _guid,
97
+ bytes calldata _message,
98
+ address _executor,
99
+ bytes calldata _extraData
100
+ ) internal virtual;
101
+ }
@@ -0,0 +1,124 @@
1
+ // SPDX-License-Identifier: MIT
2
+
3
+ pragma solidity ^0.8.22;
4
+
5
+ import { SafeERC20, IERC20 } from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
6
+ import { MessagingParams, MessagingFee, MessagingReceipt } from "@layerzerolabs/lz-evm-protocol-v2/contracts/interfaces/ILayerZeroEndpointV2.sol";
7
+ import { OAppCore } from "./OAppCore.sol";
8
+
9
+ /**
10
+ * @title OAppSender
11
+ * @dev Abstract contract implementing the OAppSender functionality for sending messages to a LayerZero endpoint.
12
+ */
13
+ abstract contract OAppSender is OAppCore {
14
+ using SafeERC20 for IERC20;
15
+
16
+ // Custom error messages
17
+ error NotEnoughNative(uint256 msgValue);
18
+ error LzTokenUnavailable();
19
+
20
+ // @dev The version of the OAppSender implementation.
21
+ // @dev Version is bumped when changes are made to this contract.
22
+ uint64 internal constant SENDER_VERSION = 1;
23
+
24
+ /**
25
+ * @notice Retrieves the OApp version information.
26
+ * @return senderVersion The version of the OAppSender.sol contract.
27
+ * @return receiverVersion The version of the OAppReceiver.sol contract.
28
+ *
29
+ * @dev Providing 0 as the default for OAppReceiver version. Indicates that the OAppReceiver is not implemented.
30
+ * ie. this is a RECEIVE only OApp.
31
+ * @dev If the OApp uses both OAppSender and OAppReceiver, then this needs to be override returning the correct versions
32
+ */
33
+ function oAppVersion() public view virtual returns (uint64 senderVersion, uint64 receiverVersion) {
34
+ return (SENDER_VERSION, 0);
35
+ }
36
+
37
+ /**
38
+ * @dev Internal function to interact with the LayerZero EndpointV2.quote() for fee calculation.
39
+ * @param _dstEid The destination endpoint ID.
40
+ * @param _message The message payload.
41
+ * @param _options Additional options for the message.
42
+ * @param _payInLzToken Flag indicating whether to pay the fee in LZ tokens.
43
+ * @return fee The calculated MessagingFee for the message.
44
+ * - nativeFee: The native fee for the message.
45
+ * - lzTokenFee: The LZ token fee for the message.
46
+ */
47
+ function _quote(
48
+ uint32 _dstEid,
49
+ bytes memory _message,
50
+ bytes memory _options,
51
+ bool _payInLzToken
52
+ ) internal view virtual returns (MessagingFee memory fee) {
53
+ return
54
+ endpoint.quote(
55
+ MessagingParams(_dstEid, _getPeerOrRevert(_dstEid), _message, _options, _payInLzToken),
56
+ address(this)
57
+ );
58
+ }
59
+
60
+ /**
61
+ * @dev Internal function to interact with the LayerZero EndpointV2.send() for sending a message.
62
+ * @param _dstEid The destination endpoint ID.
63
+ * @param _message The message payload.
64
+ * @param _options Additional options for the message.
65
+ * @param _fee The calculated LayerZero fee for the message.
66
+ * - nativeFee: The native fee.
67
+ * - lzTokenFee: The lzToken fee.
68
+ * @param _refundAddress The address to receive any excess fee values sent to the endpoint.
69
+ * @return receipt The receipt for the sent message.
70
+ * - guid: The unique identifier for the sent message.
71
+ * - nonce: The nonce of the sent message.
72
+ * - fee: The LayerZero fee incurred for the message.
73
+ */
74
+ function _lzSend(
75
+ uint32 _dstEid,
76
+ bytes memory _message,
77
+ bytes memory _options,
78
+ MessagingFee memory _fee,
79
+ address _refundAddress
80
+ ) internal virtual returns (MessagingReceipt memory receipt) {
81
+ // @dev Push corresponding fees to the endpoint, any excess is sent back to the _refundAddress from the endpoint.
82
+ uint256 messageValue = _payNative(_fee.nativeFee);
83
+ if (_fee.lzTokenFee > 0) _payLzToken(_fee.lzTokenFee);
84
+
85
+ return
86
+ // solhint-disable-next-line check-send-result
87
+ endpoint.send{ value: messageValue }(
88
+ MessagingParams(_dstEid, _getPeerOrRevert(_dstEid), _message, _options, _fee.lzTokenFee > 0),
89
+ _refundAddress
90
+ );
91
+ }
92
+
93
+ /**
94
+ * @dev Internal function to pay the native fee associated with the message.
95
+ * @param _nativeFee The native fee to be paid.
96
+ * @return nativeFee The amount of native currency paid.
97
+ *
98
+ * @dev If the OApp needs to initiate MULTIPLE LayerZero messages in a single transaction,
99
+ * this will need to be overridden because msg.value would contain multiple lzFees.
100
+ * @dev Should be overridden in the event the LayerZero endpoint requires a different native currency.
101
+ * @dev Some EVMs use an ERC20 as a method for paying transactions/gasFees.
102
+ * @dev The endpoint is EITHER/OR, ie. it will NOT support both types of native payment at a time.
103
+ */
104
+ function _payNative(uint256 _nativeFee) internal virtual returns (uint256 nativeFee) {
105
+ if (msg.value != _nativeFee) revert NotEnoughNative(msg.value);
106
+ return _nativeFee;
107
+ }
108
+
109
+ /**
110
+ * @dev Internal function to pay the LZ token fee associated with the message.
111
+ * @param _lzTokenFee The LZ token fee to be paid.
112
+ *
113
+ * @dev If the caller is trying to pay in the specified lzToken, then the lzTokenFee is passed to the endpoint.
114
+ * @dev Any excess sent, is passed back to the specified _refundAddress in the _lzSend().
115
+ */
116
+ function _payLzToken(uint256 _lzTokenFee) internal virtual {
117
+ // @dev Cannot cache the token because it is not immutable in the endpoint.
118
+ address lzToken = endpoint.lzToken();
119
+ if (lzToken == address(0)) revert LzTokenUnavailable();
120
+
121
+ // Pay LZ token fee by sending tokens to the endpoint.
122
+ IERC20(lzToken).safeTransferFrom(msg.sender, address(endpoint), _lzTokenFee);
123
+ }
124
+ }
@@ -0,0 +1,283 @@
1
+ // SPDX-License-Identifier: MIT
2
+
3
+ pragma solidity ^0.8.22;
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
+ contract OmniCounter is ILayerZeroComposer, OApp, OAppPreCrimeSimulator {
44
+ using MsgCodec for bytes;
45
+ using OptionsBuilder for bytes;
46
+
47
+ uint256 public count;
48
+ uint256 public composedCount;
49
+
50
+ address public admin;
51
+ uint32 public eid;
52
+
53
+ mapping(uint32 srcEid => mapping(bytes32 sender => uint64 nonce)) private maxReceivedNonce;
54
+ bool private orderedNonce;
55
+
56
+ // for global assertions
57
+ mapping(uint32 srcEid => uint256 count) public inboundCount;
58
+ mapping(uint32 dstEid => uint256 count) public outboundCount;
59
+
60
+ constructor(address _endpoint, address _owner) OApp(_endpoint, _owner) {
61
+ admin = msg.sender;
62
+ eid = ILayerZeroEndpointV2(_endpoint).eid();
63
+ }
64
+
65
+ modifier onlyAdmin() {
66
+ require(msg.sender == admin, "only admin");
67
+ _;
68
+ }
69
+
70
+ // -------------------------------
71
+ // Only Admin
72
+ function setAdmin(address _admin) external onlyAdmin {
73
+ admin = _admin;
74
+ }
75
+
76
+ function withdraw(address payable _to, uint256 _amount) external onlyAdmin {
77
+ (bool success, ) = _to.call{ value: _amount }("");
78
+ require(success, "OmniCounter: withdraw failed");
79
+ }
80
+
81
+ // -------------------------------
82
+ // Send
83
+ function increment(uint32 _eid, uint8 _type, bytes calldata _options) external payable {
84
+ // bytes memory options = combineOptions(_eid, _type, _options);
85
+ _lzSend(_eid, MsgCodec.encode(_type, eid), _options, MessagingFee(msg.value, 0), payable(msg.sender));
86
+ _incrementOutbound(_eid);
87
+ }
88
+
89
+ // this is a broken function to skip incrementing outbound count
90
+ // so that preCrime will fail
91
+ function brokenIncrement(uint32 _eid, uint8 _type, bytes calldata _options) external payable onlyAdmin {
92
+ // bytes memory options = combineOptions(_eid, _type, _options);
93
+ _lzSend(_eid, MsgCodec.encode(_type, eid), _options, MessagingFee(msg.value, 0), payable(msg.sender));
94
+ }
95
+
96
+ function batchIncrement(
97
+ uint32[] calldata _eids,
98
+ uint8[] calldata _types,
99
+ bytes[] calldata _options
100
+ ) external payable {
101
+ require(_eids.length == _options.length && _eids.length == _types.length, "OmniCounter: length mismatch");
102
+
103
+ MessagingReceipt memory receipt;
104
+ uint256 providedFee = msg.value;
105
+ for (uint256 i = 0; i < _eids.length; i++) {
106
+ address refundAddress = i == _eids.length - 1 ? msg.sender : address(this);
107
+ uint32 dstEid = _eids[i];
108
+ uint8 msgType = _types[i];
109
+ // bytes memory options = combineOptions(dstEid, msgType, _options[i]);
110
+ receipt = _lzSend(
111
+ dstEid,
112
+ MsgCodec.encode(msgType, eid),
113
+ _options[i],
114
+ MessagingFee(providedFee, 0),
115
+ payable(refundAddress)
116
+ );
117
+ _incrementOutbound(dstEid);
118
+ providedFee -= receipt.fee.nativeFee;
119
+ }
120
+ }
121
+
122
+ // -------------------------------
123
+ // View
124
+ function quote(
125
+ uint32 _eid,
126
+ uint8 _type,
127
+ bytes calldata _options
128
+ ) public view returns (uint256 nativeFee, uint256 lzTokenFee) {
129
+ // bytes memory options = combineOptions(_eid, _type, _options);
130
+ MessagingFee memory fee = _quote(_eid, MsgCodec.encode(_type, eid), _options, false);
131
+ return (fee.nativeFee, fee.lzTokenFee);
132
+ }
133
+
134
+ // @dev enables preCrime simulator
135
+ // @dev routes the call down from the OAppPreCrimeSimulator, and up to the OApp
136
+ function _lzReceiveSimulate(
137
+ Origin calldata _origin,
138
+ bytes32 _guid,
139
+ bytes calldata _message,
140
+ address _executor,
141
+ bytes calldata _extraData
142
+ ) internal virtual override {
143
+ _lzReceive(_origin, _guid, _message, _executor, _extraData);
144
+ }
145
+
146
+ // -------------------------------
147
+ function _lzReceive(
148
+ Origin calldata _origin,
149
+ bytes32 _guid,
150
+ bytes calldata _message,
151
+ address /*_executor*/,
152
+ bytes calldata /*_extraData*/
153
+ ) internal override {
154
+ _acceptNonce(_origin.srcEid, _origin.sender, _origin.nonce);
155
+ uint8 messageType = _message.msgType();
156
+
157
+ if (messageType == MsgCodec.VANILLA_TYPE) {
158
+ count++;
159
+
160
+ //////////////////////////////// IMPORTANT //////////////////////////////////
161
+ /// if you request for msg.value in the options, you should also encode it
162
+ /// into your message and check the value received at destination (example below).
163
+ /// if not, the executor could potentially provide less msg.value than you requested
164
+ /// leading to unintended behavior. Another option is to assert the executor to be
165
+ /// one that you trust.
166
+ /////////////////////////////////////////////////////////////////////////////
167
+ require(msg.value >= _message.value(), "OmniCounter: insufficient value");
168
+
169
+ _incrementInbound(_origin.srcEid);
170
+ } else if (messageType == MsgCodec.COMPOSED_TYPE || messageType == MsgCodec.COMPOSED_ABA_TYPE) {
171
+ count++;
172
+ _incrementInbound(_origin.srcEid);
173
+ endpoint.sendCompose(address(this), _guid, 0, _message);
174
+ } else if (messageType == MsgCodec.ABA_TYPE) {
175
+ count++;
176
+ _incrementInbound(_origin.srcEid);
177
+
178
+ // send back to the sender
179
+ _incrementOutbound(_origin.srcEid);
180
+ bytes memory options = OptionsBuilder.newOptions().addExecutorLzReceiveOption(200000, 10);
181
+ _lzSend(
182
+ _origin.srcEid,
183
+ MsgCodec.encode(MsgCodec.VANILLA_TYPE, eid, 10),
184
+ options,
185
+ MessagingFee(msg.value, 0),
186
+ payable(address(this))
187
+ );
188
+ } else {
189
+ revert("invalid message type");
190
+ }
191
+ }
192
+
193
+ function _incrementInbound(uint32 _srcEid) internal {
194
+ inboundCount[_srcEid]++;
195
+ }
196
+
197
+ function _incrementOutbound(uint32 _dstEid) internal {
198
+ outboundCount[_dstEid]++;
199
+ }
200
+
201
+ function lzCompose(
202
+ address _oApp,
203
+ bytes32 /*_guid*/,
204
+ bytes calldata _message,
205
+ address,
206
+ bytes calldata
207
+ ) external payable override {
208
+ require(_oApp == address(this), "!oApp");
209
+ require(msg.sender == address(endpoint), "!endpoint");
210
+
211
+ uint8 msgType = _message.msgType();
212
+ if (msgType == MsgCodec.COMPOSED_TYPE) {
213
+ composedCount += 1;
214
+ } else if (msgType == MsgCodec.COMPOSED_ABA_TYPE) {
215
+ composedCount += 1;
216
+
217
+ uint32 srcEid = _message.srcEid();
218
+ _incrementOutbound(srcEid);
219
+ bytes memory options = OptionsBuilder.newOptions().addExecutorLzReceiveOption(200000, 0);
220
+ _lzSend(
221
+ srcEid,
222
+ MsgCodec.encode(MsgCodec.VANILLA_TYPE, eid),
223
+ options,
224
+ MessagingFee(msg.value, 0),
225
+ payable(address(this))
226
+ );
227
+ } else {
228
+ revert("invalid message type");
229
+ }
230
+ }
231
+
232
+ // -------------------------------
233
+ // Ordered OApp
234
+ // this demonstrates how to build an app that requires execution nonce ordering
235
+ // normally an app should decide ordered or not on contract construction
236
+ // this is just a demo
237
+ function setOrderedNonce(bool _orderedNonce) external onlyOwner {
238
+ orderedNonce = _orderedNonce;
239
+ }
240
+
241
+ function _acceptNonce(uint32 _srcEid, bytes32 _sender, uint64 _nonce) internal virtual {
242
+ uint64 currentNonce = maxReceivedNonce[_srcEid][_sender];
243
+ if (orderedNonce) {
244
+ require(_nonce == currentNonce + 1, "OApp: invalid nonce");
245
+ }
246
+ // update the max nonce anyway. once the ordered mode is turned on, missing early nonces will be rejected
247
+ if (_nonce > currentNonce) {
248
+ maxReceivedNonce[_srcEid][_sender] = _nonce;
249
+ }
250
+ }
251
+
252
+ function nextNonce(uint32 _srcEid, bytes32 _sender) public view virtual override returns (uint64) {
253
+ if (orderedNonce) {
254
+ return maxReceivedNonce[_srcEid][_sender] + 1;
255
+ } else {
256
+ return 0; // path nonce starts from 1. if 0 it means that there is no specific nonce enforcement
257
+ }
258
+ }
259
+
260
+ // TODO should override oApp version with added ordered nonce increment
261
+ // a governance function to skip nonce
262
+ function skipInboundNonce(uint32 _srcEid, bytes32 _sender, uint64 _nonce) public virtual onlyOwner {
263
+ endpoint.skip(address(this), _srcEid, _sender, _nonce);
264
+ if (orderedNonce) {
265
+ maxReceivedNonce[_srcEid][_sender]++;
266
+ }
267
+ }
268
+
269
+ function isPeer(uint32 _eid, bytes32 _peer) public view override returns (bool) {
270
+ return peers[_eid] == _peer;
271
+ }
272
+
273
+ // @dev Batch send requires overriding this function from OAppSender because the msg.value contains multiple fees
274
+ function _payNative(uint256 _nativeFee) internal virtual override returns (uint256 nativeFee) {
275
+ if (msg.value < _nativeFee) revert NotEnoughNative(msg.value);
276
+ return _nativeFee;
277
+ }
278
+
279
+ // be able to receive ether
280
+ receive() external payable virtual {}
281
+
282
+ fallback() external payable {}
283
+ }