@layerzerolabs/lz-evm-oapp-v2 2.0.23 → 2.0.25

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 (28) hide show
  1. package/artifacts/contracts/oapp/OApp.sol/OApp.json +18 -0
  2. package/artifacts/contracts/oapp/OAppCore.sol/OAppCore.json +5 -0
  3. package/artifacts/contracts/oapp/OAppReceiver.sol/OAppReceiver.json +18 -0
  4. package/artifacts/contracts/oapp/OAppSender.sol/OAppSender.json +5 -0
  5. package/artifacts/contracts/oapp/examples/OmniCounter.sol/MsgCodec.json +2 -2
  6. package/artifacts/contracts/oapp/examples/OmniCounter.sol/OmniCounter.json +21 -3
  7. package/artifacts/contracts/oapp/examples/OmniCounterPreCrime.sol/OmniCounterPreCrime.json +2 -7
  8. package/artifacts/contracts/oapp/interfaces/IOAppCore.sol/IOAppCore.json +5 -0
  9. package/artifacts/contracts/oapp/interfaces/IOAppReceiver.sol/IOAppReceiver.json +134 -0
  10. package/artifacts/contracts/oft/OFT.sol/OFT.json +108 -99
  11. package/artifacts/contracts/oft/OFTAdapter.sol/OFTAdapter.json +108 -107
  12. package/artifacts/contracts/oft/OFTCore.sol/OFTCore.json +108 -73
  13. package/artifacts/contracts/oft/interfaces/IOFT.sol/IOFT.json +80 -102
  14. package/contracts/oapp/OApp.sol +4 -4
  15. package/contracts/oapp/OAppCore.sol +8 -6
  16. package/contracts/oapp/OAppReceiver.sol +14 -3
  17. package/contracts/oapp/OAppSender.sol +1 -1
  18. package/contracts/oapp/examples/OmniCounter.sol +1 -1
  19. package/contracts/oapp/examples/OmniCounterPreCrime.sol +1 -1
  20. package/contracts/oapp/interfaces/IOAppCore.sol +1 -0
  21. package/contracts/oapp/interfaces/IOAppReceiver.sol +15 -0
  22. package/contracts/oft/OFT.sol +39 -55
  23. package/contracts/oft/OFTAdapter.sol +52 -65
  24. package/contracts/oft/OFTCore.sol +59 -133
  25. package/contracts/oft/interfaces/IOFT.sol +35 -55
  26. package/contracts/precrime/PreCrime.sol +1 -2
  27. package/contracts/precrime/extensions/PreCrimeE1.sol +1 -1
  28. package/package.json +9 -9
@@ -2,9 +2,9 @@
2
2
 
3
3
  pragma solidity ^0.8.20;
4
4
 
5
- // @dev Import the 'MessagingFee' so it's exposed to OApp implementers
5
+ // @dev Import the 'MessagingFee' and 'MessagingReceipt' so it's exposed to OApp implementers
6
6
  // solhint-disable-next-line no-unused-import
7
- import { OAppSender, MessagingFee } from "./OAppSender.sol";
7
+ import { OAppSender, MessagingFee, MessagingReceipt } from "./OAppSender.sol";
8
8
  // @dev Import the 'Origin' so it's exposed to OApp implementers
9
9
  // solhint-disable-next-line no-unused-import
10
10
  import { OAppReceiver, Origin } from "./OAppReceiver.sol";
@@ -18,9 +18,9 @@ abstract contract OApp is OAppSender, OAppReceiver {
18
18
  /**
19
19
  * @dev Constructor to initialize the OApp with the provided endpoint and owner.
20
20
  * @param _endpoint The address of the LOCAL LayerZero endpoint.
21
- * @param _owner The address of the owner of the OApp.
21
+ * @param _delegate The delegate capable of making OApp configurations inside of the endpoint.
22
22
  */
23
- constructor(address _endpoint, address _owner) OAppCore(_endpoint, _owner) {}
23
+ constructor(address _endpoint, address _delegate) OAppCore(_endpoint, _delegate) {}
24
24
 
25
25
  /**
26
26
  * @notice Retrieves the OApp version information.
@@ -17,14 +17,17 @@ abstract contract OAppCore is IOAppCore, Ownable {
17
17
  mapping(uint32 eid => bytes32 peer) public peers;
18
18
 
19
19
  /**
20
- * @dev Constructor to initialize the OAppCore with the provided endpoint and owner.
20
+ * @dev Constructor to initialize the OAppCore with the provided endpoint and delegate.
21
21
  * @param _endpoint The address of the LOCAL Layer Zero endpoint.
22
- * @param _owner The address of the owner of the OAppCore.
22
+ * @param _delegate The delegate capable of making OApp configurations inside of the endpoint.
23
+ *
24
+ * @dev The delegate typically should be set as the owner of the contract.
23
25
  */
24
- constructor(address _endpoint, address _owner) {
25
- _transferOwnership(_owner);
26
+ constructor(address _endpoint, address _delegate) {
26
27
  endpoint = ILayerZeroEndpointV2(_endpoint);
27
- endpoint.setDelegate(_owner); // @dev By default, the owner is the delegate
28
+
29
+ if (_delegate == address(0)) revert InvalidDelegate();
30
+ endpoint.setDelegate(_delegate);
28
31
  }
29
32
 
30
33
  /**
@@ -60,7 +63,6 @@ abstract contract OAppCore is IOAppCore, Ownable {
60
63
  *
61
64
  * @dev Only the owner/admin of the OApp can call this function.
62
65
  * @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
66
  */
65
67
  function setDelegate(address _delegate) public onlyOwner {
66
68
  endpoint.setDelegate(_delegate);
@@ -2,14 +2,14 @@
2
2
 
3
3
  pragma solidity ^0.8.20;
4
4
 
5
- import { ILayerZeroReceiver, Origin } from "@layerzerolabs/lz-evm-protocol-v2/contracts/interfaces/ILayerZeroReceiver.sol";
5
+ import { IOAppReceiver, Origin } from "./interfaces/IOAppReceiver.sol";
6
6
  import { OAppCore } from "./OAppCore.sol";
7
7
 
8
8
  /**
9
9
  * @title OAppReceiver
10
10
  * @dev Abstract contract implementing the ILayerZeroReceiver interface and extending OAppCore for OApp receivers.
11
11
  */
12
- abstract contract OAppReceiver is ILayerZeroReceiver, OAppCore {
12
+ abstract contract OAppReceiver is IOAppReceiver, OAppCore {
13
13
  // Custom error message for when the caller is not the registered endpoint/
14
14
  error OnlyEndpoint(address addr);
15
15
 
@@ -23,13 +23,24 @@ abstract contract OAppReceiver is ILayerZeroReceiver, OAppCore {
23
23
  * @return receiverVersion The version of the OAppReceiver.sol contract.
24
24
  *
25
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.
26
+ * ie. this is a RECEIVE only OApp.
27
27
  * @dev If the OApp uses both OAppSender and OAppReceiver, then this needs to be override returning the correct versions.
28
28
  */
29
29
  function oAppVersion() public view virtual returns (uint64 senderVersion, uint64 receiverVersion) {
30
30
  return (0, RECEIVER_VERSION);
31
31
  }
32
32
 
33
+ /**
34
+ * @notice Retrieves the address responsible for 'sending' composeMsg's to the Endpoint.
35
+ * @return sender The address responsible for 'sending' composeMsg's to the Endpoint.
36
+ *
37
+ * @dev Applications can optionally choose to implement a separate composeMsg sender that is NOT the bridging layer.
38
+ * @dev The default sender IS the OApp implementer.
39
+ */
40
+ function composeMsgSender() public view virtual returns (address sender) {
41
+ return address(this);
42
+ }
43
+
33
44
  /**
34
45
  * @notice Checks if the path initialization is allowed based on the provided origin.
35
46
  * @param origin The origin information containing the source endpoint and sender address.
@@ -27,7 +27,7 @@ abstract contract OAppSender is OAppCore {
27
27
  * @return receiverVersion The version of the OAppReceiver.sol contract.
28
28
  *
29
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.
30
+ * ie. this is a SEND only OApp.
31
31
  * @dev If the OApp uses both OAppSender and OAppReceiver, then this needs to be override returning the correct versions
32
32
  */
33
33
  function oAppVersion() public view virtual returns (uint64 senderVersion, uint64 receiverVersion) {
@@ -57,7 +57,7 @@ contract OmniCounter is ILayerZeroComposer, OApp, OAppPreCrimeSimulator {
57
57
  mapping(uint32 srcEid => uint256 count) public inboundCount;
58
58
  mapping(uint32 dstEid => uint256 count) public outboundCount;
59
59
 
60
- constructor(address _endpoint, address _owner) OApp(_endpoint, _owner) {
60
+ constructor(address _endpoint, address _delegate) OApp(_endpoint, _delegate) {
61
61
  admin = msg.sender;
62
62
  eid = ILayerZeroEndpointV2(_endpoint).eid();
63
63
  }
@@ -13,7 +13,7 @@ contract OmniCounterPreCrime is PreCrime {
13
13
  uint256 outboundCount;
14
14
  }
15
15
 
16
- constructor(address _endpoint, address _counter, address _owner) PreCrime(_endpoint, _counter, _owner) {}
16
+ constructor(address _endpoint, address _counter) PreCrime(_endpoint, _counter) {}
17
17
 
18
18
  function buildSimulationResult() external view override returns (bytes memory) {
19
19
  address payable payableSimulator = payable(simulator);
@@ -12,6 +12,7 @@ interface IOAppCore {
12
12
  error OnlyPeer(uint32 eid, bytes32 sender);
13
13
  error NoPeer(uint32 eid);
14
14
  error InvalidEndpointCall();
15
+ error InvalidDelegate();
15
16
 
16
17
  // Event emitted when a peer (OApp) is set for a corresponding endpoint
17
18
  event PeerSet(uint32 eid, bytes32 peer);
@@ -0,0 +1,15 @@
1
+ // SPDX-License-Identifier: MIT
2
+ pragma solidity ^0.8.20;
3
+
4
+ import { ILayerZeroReceiver, Origin } from "@layerzerolabs/lz-evm-protocol-v2/contracts/interfaces/ILayerZeroReceiver.sol";
5
+
6
+ interface IOAppReceiver is ILayerZeroReceiver {
7
+ /**
8
+ * @notice Retrieves the address responsible for 'sending' composeMsg's to the Endpoint.
9
+ * @return sender The address responsible for 'sending' composeMsg's to the Endpoint.
10
+ *
11
+ * @dev Applications can optionally choose to implement a separate composeMsg sender that is NOT the bridging layer.
12
+ * @dev The default sender IS the OApp implementer.
13
+ */
14
+ function composeMsgSender() external view returns (address sender);
15
+ }
@@ -3,40 +3,39 @@
3
3
  pragma solidity ^0.8.20;
4
4
 
5
5
  import { ERC20 } from "@openzeppelin/contracts/token/ERC20/ERC20.sol";
6
- import { OFTCore } from "./OFTCore.sol";
6
+ import { IOFT, OFTCore } from "./OFTCore.sol";
7
7
 
8
8
  /**
9
9
  * @title OFT Contract
10
10
  * @dev OFT is an ERC-20 token that extends the functionality of the OFTCore contract.
11
11
  */
12
- contract OFT is OFTCore, ERC20 {
12
+ abstract contract OFT is OFTCore, ERC20 {
13
13
  /**
14
14
  * @dev Constructor for the OFT contract.
15
15
  * @param _name The name of the OFT.
16
16
  * @param _symbol The symbol of the OFT.
17
17
  * @param _lzEndpoint The LayerZero endpoint address.
18
- * @param _owner The owner of the contract.
18
+ * @param _delegate The delegate capable of making OApp configurations inside of the endpoint.
19
19
  */
20
20
  constructor(
21
21
  string memory _name,
22
22
  string memory _symbol,
23
23
  address _lzEndpoint,
24
- address _owner
25
- ) ERC20(_name, _symbol) OFTCore(decimals(), _lzEndpoint, _owner) {}
24
+ address _delegate
25
+ ) ERC20(_name, _symbol) OFTCore(decimals(), _lzEndpoint, _delegate) {}
26
26
 
27
27
  /**
28
- * @dev Retrieves the OFT contract version.
29
- * @return major The major version.
30
- * @return minor The minor version.
28
+ * @notice Retrieves interfaceID and the version of the OFT.
29
+ * @return interfaceId The interface ID.
30
+ * @return version The version.
31
31
  *
32
- * @dev major version: Indicates a cross-chain compatible msg encoding with other OFTs.
33
- * @dev minor version: Indicates a version within the local chains context. eg. OFTAdapter vs. OFT
34
- * @dev For example, if a new feature is added to the OFT contract, the minor version will be incremented.
35
- * @dev If a new feature is added to the OFT cross-chain msg encoding, the major version will be incremented.
36
- * ie. localOFT version(1,1) CAN send messages to remoteOFT version(1,2)
32
+ * @dev interfaceId: This specific interface ID is '0x02e49c2c'.
33
+ * @dev version: Indicates a cross-chain compatible msg encoding with other OFTs.
34
+ * @dev If a new feature is added to the OFT cross-chain msg encoding, the version will be incremented.
35
+ * ie. localOFT version(x,1) CAN send messages to remoteOFT version(x,1)
37
36
  */
38
- function oftVersion() external pure returns (uint64 major, uint64 minor) {
39
- return (1, 1);
37
+ function oftVersion() external pure virtual returns (bytes4 interfaceId, uint64 version) {
38
+ return (type(IOFT).interfaceId, 1);
40
39
  }
41
40
 
42
41
  /**
@@ -50,67 +49,52 @@ contract OFT is OFTCore, ERC20 {
50
49
  }
51
50
 
52
51
  /**
53
- * @dev Burns tokens from the sender's specified balance.
54
- * @param _amountToSendLD The amount of tokens to send in local decimals.
55
- * @param _minAmountToCreditLD The minimum amount to credit in local decimals.
56
- * @param _dstEid The destination chain ID.
57
- * @return amountDebitedLD The amount of tokens ACTUALLY debited in local decimals.
58
- * @return amountToCreditLD The amount of tokens to credit in local decimals.
52
+ * @notice Indicates whether the OFT contract requires approval of the 'token()' to send.
53
+ * @return requiresApproval Needs approval of the underlying token implementation.
54
+ *
55
+ * @dev In the case of OFT where the contract IS the token, approval is NOT required.
59
56
  */
60
- function _debitSender(
61
- uint256 _amountToSendLD,
62
- uint256 _minAmountToCreditLD,
63
- uint32 _dstEid
64
- ) internal virtual override returns (uint256 amountDebitedLD, uint256 amountToCreditLD) {
65
- (amountDebitedLD, amountToCreditLD) = _debitView(_amountToSendLD, _minAmountToCreditLD, _dstEid);
66
-
67
- // @dev In NON-default OFT, amountDebited could be 100, with a 10% fee, the credited amount is 90,
68
- // therefore amountDebited CAN differ from amountToCredit.
69
-
70
- // @dev Default OFT burns on src.
71
- _burn(msg.sender, amountDebitedLD);
57
+ function approvalRequired() external pure virtual returns (bool) {
58
+ return false;
72
59
  }
73
60
 
74
61
  /**
75
- * @dev Burns tokens that have been sent into this contract.
76
- * @param _minAmountToReceiveLD The minimum amount to receive in local decimals.
62
+ * @dev Burns tokens from the sender's specified balance.
63
+ * @param _amountLD The amount of tokens to send in local decimals.
64
+ * @param _minAmountLD The minimum amount to send in local decimals.
77
65
  * @param _dstEid The destination chain ID.
78
- * @return amountDebitedLD The amount of tokens ACTUALLY debited in local decimals.
79
- * @return amountToCreditLD The amount of tokens to credit in local decimals.
66
+ * @return amountSentLD The amount sent in local decimals.
67
+ * @return amountReceivedLD The amount received in local decimals on the remote.
80
68
  */
81
- function _debitThis(
82
- uint256 _minAmountToReceiveLD,
69
+ function _debit(
70
+ uint256 _amountLD,
71
+ uint256 _minAmountLD,
83
72
  uint32 _dstEid
84
- ) internal virtual override returns (uint256 amountDebitedLD, uint256 amountToCreditLD) {
85
- // @dev This is the push method, where at any point in the transaction, the OFT receives tokens and they can be sent by the caller.
86
- // @dev This SHOULD be done atomically, otherwise any caller can spend tokens that are owned by the contract.
87
- // @dev In the NON-default case where fees are stored in the contract, there should be a value reserved via a global state.
88
- // eg. balanceOf(address(this)) - accruedFees;
89
- (amountDebitedLD, amountToCreditLD) = _debitView(balanceOf(address(this)), _minAmountToReceiveLD, _dstEid);
73
+ ) internal virtual override returns (uint256 amountSentLD, uint256 amountReceivedLD) {
74
+ (amountSentLD, amountReceivedLD) = _debitView(_amountLD, _minAmountLD, _dstEid);
90
75
 
91
- // @dev Default OFT burns on src.
92
- _burn(address(this), amountDebitedLD);
76
+ // @dev In NON-default OFT, amountSentLD could be 100, with a 10% fee, the amountReceivedLD amount is 90,
77
+ // therefore amountSentLD CAN differ from amountReceivedLD.
93
78
 
94
- // @dev When sending tokens direct to the OFT contract,
95
- // there is NOT a default mechanism to capture the dust that MIGHT get left in the contract.
96
- // If you want to refund this dust, will need to add another function to return it.
79
+ // @dev Default OFT burns on src.
80
+ _burn(msg.sender, amountSentLD);
97
81
  }
98
82
 
99
83
  /**
100
84
  * @dev Credits tokens to the specified address.
101
85
  * @param _to The address to credit the tokens to.
102
- * @param _amountToCreditLD The amount of tokens to credit in local decimals.
86
+ * @param _amountLD The amount of tokens to credit in local decimals.
103
87
  * @dev _srcEid The source chain ID.
104
88
  * @return amountReceivedLD The amount of tokens ACTUALLY received in local decimals.
105
89
  */
106
90
  function _credit(
107
91
  address _to,
108
- uint256 _amountToCreditLD,
92
+ uint256 _amountLD,
109
93
  uint32 /*_srcEid*/
110
94
  ) internal virtual override returns (uint256 amountReceivedLD) {
111
95
  // @dev Default OFT mints on dst.
112
- _mint(_to, _amountToCreditLD);
113
- // @dev In the case of NON-default OFT, the amountToCreditLD MIGHT not == amountReceivedLD.
114
- return _amountToCreditLD;
96
+ _mint(_to, _amountLD);
97
+ // @dev In the case of NON-default OFT, the _amountLD MIGHT not be == amountReceivedLD.
98
+ return _amountLD;
115
99
  }
116
100
  }
@@ -4,7 +4,7 @@ pragma solidity ^0.8.20;
4
4
 
5
5
  import { IERC20Metadata, IERC20 } from "@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol";
6
6
  import { SafeERC20 } from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
7
- import { OFTCore } from "./OFTCore.sol";
7
+ import { IOFT, OFTCore } from "./OFTCore.sol";
8
8
 
9
9
  /**
10
10
  * @title OFTAdapter Contract
@@ -12,44 +12,42 @@ import { OFTCore } from "./OFTCore.sol";
12
12
  *
13
13
  * @dev For existing ERC20 tokens, this can be used to convert the token to crosschain compatibility.
14
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
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.
16
19
  */
17
- contract OFTAdapter is OFTCore {
20
+ abstract contract OFTAdapter is OFTCore {
18
21
  using SafeERC20 for IERC20;
19
22
 
20
23
  IERC20 internal immutable innerToken;
21
24
 
22
- // @dev The amount of tokens locked inside this contract.
23
- // @dev This SHOULD equal the total amount of OFTs in circulation on all the NON OFTAdapter chains
24
- uint256 public outboundAmount;
25
-
26
25
  /**
27
26
  * @dev Constructor for the OFTAdapter contract.
28
27
  * @param _token The address of the ERC-20 token to be adapted.
29
28
  * @param _lzEndpoint The LayerZero endpoint address.
30
- * @param _owner The owner of the contract.
29
+ * @param _delegate The delegate capable of making OApp configurations inside of the endpoint.
31
30
  */
32
31
  constructor(
33
32
  address _token,
34
33
  address _lzEndpoint,
35
- address _owner
36
- ) OFTCore(IERC20Metadata(_token).decimals(), _lzEndpoint, _owner) {
34
+ address _delegate
35
+ ) OFTCore(IERC20Metadata(_token).decimals(), _lzEndpoint, _delegate) {
37
36
  innerToken = IERC20(_token);
38
37
  }
39
38
 
40
39
  /**
41
- * @dev Retrieves the OFTAdapter contract version.
42
- * @return major The major version.
43
- * @return minor The minor version.
40
+ * @notice Retrieves interfaceID and the version of the OFT.
41
+ * @return interfaceId The interface ID.
42
+ * @return version The version.
44
43
  *
45
- * @dev major version: Indicates a cross-chain compatible msg encoding with other OFTs.
46
- * @dev minor version: Indicates a version within the local chains context. eg. OFTAdapter vs. OFT
47
- * @dev For example, if a new feature is added to the OFT contract, the minor version will be incremented.
48
- * @dev If a new feature is added to the OFT cross-chain msg encoding, the major version will be incremented.
49
- * ie. localOFT version(1,1) CAN send messages to remoteOFT version(1,2)
44
+ * @dev interfaceId: This specific interface ID is '0x02e49c2c'.
45
+ * @dev version: Indicates a cross-chain compatible msg encoding with other OFTs.
46
+ * @dev If a new feature is added to the OFT cross-chain msg encoding, the version will be incremented.
47
+ * ie. localOFT version(x,1) CAN send messages to remoteOFT version(x,1)
50
48
  */
51
- function oftVersion() external pure returns (uint64 major, uint64 minor) {
52
- return (1, 2);
49
+ function oftVersion() external pure virtual returns (bytes4 interfaceId, uint64 version) {
50
+ return (type(IOFT).interfaceId, 1);
53
51
  }
54
52
 
55
53
  /**
@@ -58,74 +56,63 @@ contract OFTAdapter is OFTCore {
58
56
  *
59
57
  * @dev In the case of OFTAdapter, address(this) and erc20 are NOT the same contract.
60
58
  */
61
- function token() public view virtual returns (address) {
59
+ function token() external view returns (address) {
62
60
  return address(innerToken);
63
61
  }
64
62
 
65
63
  /**
66
- * @dev Burns tokens from the sender's specified balance, ie. pull method.
67
- * @param _amountToSendLD The amount of tokens to send in local decimals.
68
- * @param _minAmountToCreditLD The minimum amount to credit in local decimals.
69
- * @param _dstEid The destination chain ID.
70
- * @return amountDebitedLD The amount of tokens ACTUALLY debited in local decimals.
71
- * @return amountToCreditLD The amount of tokens to credit in local decimals.
64
+ * @notice Indicates whether the OFT contract requires approval of the 'token()' to send.
65
+ * @return requiresApproval Needs approval of the underlying token implementation.
66
+ *
67
+ * @dev In the case of default OFTAdapter, approval is required.
68
+ * @dev In non-default OFTAdapter contracts with something like mint and burn privileges, it would NOT need approval.
72
69
  */
73
- function _debitSender(
74
- uint256 _amountToSendLD,
75
- uint256 _minAmountToCreditLD,
76
- uint32 _dstEid
77
- ) internal virtual override returns (uint256 amountDebitedLD, uint256 amountToCreditLD) {
78
- (amountDebitedLD, amountToCreditLD) = _debitView(_amountToSendLD, _minAmountToCreditLD, _dstEid);
79
- // @dev msg.sender will need to approve this amountLD of tokens to be locked inside of the contract.
80
- // @dev Move all of the debited tokens into this contract.
81
- innerToken.safeTransferFrom(msg.sender, address(this), amountDebitedLD);
82
-
83
- // @dev In NON-default OFTAdapter, amountDebited could be 100, with a 10% fee, the credited amount is 90,
84
- // so technically the amountToCredit would be locked as outboundAmount. Therefore amountDebited CAN differ from amountToCredit.
85
- // @dev Due to OFTs containing both push/pull methods, the reserved amount needs to be tracked so _debitThis() cant spend it.
86
- outboundAmount += amountToCreditLD;
70
+ function approvalRequired() external pure virtual returns (bool) {
71
+ return true;
87
72
  }
88
73
 
89
74
  /**
90
- * @dev Allows a sender to send tokens that are inside the contract but are NOT accounted for in outboundAmount, ie. push method.
91
- * @param _minAmountToCreditLD The minimum amount to credit in local decimals.
75
+ * @dev Burns tokens from the sender's specified balance, ie. pull method.
76
+ * @param _amountLD The amount of tokens to send in local decimals.
77
+ * @param _minAmountLD The minimum amount to send in local decimals.
92
78
  * @param _dstEid The destination chain ID.
93
- * @return amountDebitedLD The amount of tokens ACTUALLY debited in local decimals.
94
- * @return amountToCreditLD The amount of tokens to credit in local decimals.
79
+ * @return amountSentLD The amount sent in local decimals.
80
+ * @return amountReceivedLD The amount received in local decimals on the remote.
81
+ *
82
+ * @dev msg.sender will need to approve this _amountLD of tokens to be locked inside of the contract.
83
+ * @dev WARNING: The default OFTAdapter implementation assumes LOSSLESS transfers, ie. 1 token in, 1 token out.
84
+ * IF the 'innerToken' applies something like a transfer fee, the default will NOT work...
85
+ * a pre/post balance check will need to be done to calculate the amountReceivedLD.
95
86
  */
96
- function _debitThis(
97
- uint256 _minAmountToCreditLD,
87
+ function _debit(
88
+ uint256 _amountLD,
89
+ uint256 _minAmountLD,
98
90
  uint32 _dstEid
99
- ) internal virtual override returns (uint256 amountDebitedLD, uint256 amountToCreditLD) {
100
- // @dev This is the push method, where at any point in the transaction, the OFT receives tokens and they can be sent by the caller.
101
- // @dev This SHOULD be done atomically, otherwise any caller can spend tokens that are owned by the contract.
102
- uint256 availableToSend = innerToken.balanceOf(address(this)) - outboundAmount;
103
- (amountDebitedLD, amountToCreditLD) = _debitView(availableToSend, _minAmountToCreditLD, _dstEid);
104
-
105
- // @dev Due to OFTs containing both push/pull methods, the reserved amount needs to be tracked so _debitThis() cant spend it.
106
- outboundAmount += amountToCreditLD;
107
-
108
- // @dev When sending tokens direct to the OFTAdapter contract,
109
- // there is NOT a default mechanism to capture the dust that MIGHT get left in the contract.
110
- // If you want to refund this dust, will need to add another function to return it.
91
+ ) internal virtual override returns (uint256 amountSentLD, uint256 amountReceivedLD) {
92
+ (amountSentLD, amountReceivedLD) = _debitView(_amountLD, _minAmountLD, _dstEid);
93
+ // @dev Lock tokens by moving them into this contract from the caller.
94
+ innerToken.safeTransferFrom(msg.sender, address(this), amountSentLD);
111
95
  }
112
96
 
113
97
  /**
114
98
  * @dev Credits tokens to the specified address.
115
99
  * @param _to The address to credit the tokens to.
116
- * @param _amountToCreditLD The amount of tokens to credit in local decimals.
100
+ * @param _amountLD The amount of tokens to credit in local decimals.
117
101
  * @dev _srcEid The source chain ID.
118
102
  * @return amountReceivedLD The amount of tokens ACTUALLY received in local decimals.
103
+ *
104
+ * @dev WARNING: The default OFTAdapter implementation assumes LOSSLESS transfers, ie. 1 token in, 1 token out.
105
+ * IF the 'innerToken' applies something like a transfer fee, the default will NOT work...
106
+ * a pre/post balance check will need to be done to calculate the amountReceivedLD.
119
107
  */
120
108
  function _credit(
121
109
  address _to,
122
- uint256 _amountToCreditLD,
110
+ uint256 _amountLD,
123
111
  uint32 /*_srcEid*/
124
112
  ) internal virtual override returns (uint256 amountReceivedLD) {
125
- outboundAmount -= _amountToCreditLD;
126
113
  // @dev Unlock the tokens and transfer to the recipient.
127
- innerToken.safeTransfer(_to, _amountToCreditLD);
128
- // @dev In the case of NON-default OFTAdapter, the amountToCreditLD MIGHT not == amountReceivedLD.
129
- return _amountToCreditLD;
114
+ innerToken.safeTransfer(_to, _amountLD);
115
+ // @dev In the case of NON-default OFTAdapter, the amountLD MIGHT not be == amountReceivedLD.
116
+ return _amountLD;
130
117
  }
131
118
  }