@hyperlane-xyz/core 1.0.0-beta8 → 1.0.0

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 (145) hide show
  1. package/contracts/InterchainGasPaymaster.sol +34 -5
  2. package/contracts/middleware/liquidity-layer/LiquidityLayerRouter.sol +13 -19
  3. package/contracts/middleware/liquidity-layer/adapters/CircleBridgeAdapter.sol +9 -11
  4. package/contracts/middleware/liquidity-layer/adapters/PortalAdapter.sol +216 -0
  5. package/contracts/middleware/liquidity-layer/interfaces/circle/{ICircleBridge.sol → ITokenMessenger.sol} +3 -3
  6. package/contracts/middleware/liquidity-layer/interfaces/portal/IPortalTokenBridge.sol +87 -0
  7. package/contracts/mock/MockCircleMessageTransmitter.sol +1 -1
  8. package/contracts/mock/{MockCircleBridge.sol → MockCircleTokenMessenger.sol} +2 -2
  9. package/contracts/mock/MockPortalBridge.sol +89 -0
  10. package/dist/contracts/InterchainGasPaymaster.d.ts +9 -1
  11. package/dist/contracts/InterchainGasPaymaster.d.ts.map +1 -1
  12. package/dist/contracts/middleware/liquidity-layer/LiquidityLayerRouter.d.ts +8 -8
  13. package/dist/contracts/middleware/liquidity-layer/LiquidityLayerRouter.d.ts.map +1 -1
  14. package/dist/contracts/middleware/liquidity-layer/adapters/CircleBridgeAdapter.d.ts +14 -14
  15. package/dist/contracts/middleware/liquidity-layer/adapters/CircleBridgeAdapter.d.ts.map +1 -1
  16. package/dist/contracts/middleware/liquidity-layer/adapters/PortalAdapter.d.ts +435 -0
  17. package/dist/contracts/middleware/liquidity-layer/adapters/PortalAdapter.d.ts.map +1 -0
  18. package/dist/contracts/middleware/liquidity-layer/{interfaces/circle/ICircleBridge.js → adapters/PortalAdapter.js} +1 -1
  19. package/dist/contracts/middleware/liquidity-layer/adapters/PortalAdapter.js.map +1 -0
  20. package/dist/contracts/middleware/liquidity-layer/adapters/index.d.ts +1 -0
  21. package/dist/contracts/middleware/liquidity-layer/adapters/index.d.ts.map +1 -1
  22. package/dist/contracts/middleware/liquidity-layer/interfaces/circle/{ICircleBridge.d.ts → ITokenMessenger.d.ts} +4 -4
  23. package/dist/contracts/middleware/liquidity-layer/interfaces/circle/ITokenMessenger.d.ts.map +1 -0
  24. package/dist/contracts/{mock/MockCircleBridge.js → middleware/liquidity-layer/interfaces/circle/ITokenMessenger.js} +1 -1
  25. package/dist/contracts/middleware/liquidity-layer/interfaces/circle/ITokenMessenger.js.map +1 -0
  26. package/dist/contracts/middleware/liquidity-layer/interfaces/circle/index.d.ts +1 -1
  27. package/dist/contracts/middleware/liquidity-layer/interfaces/circle/index.d.ts.map +1 -1
  28. package/dist/contracts/middleware/liquidity-layer/interfaces/index.d.ts +2 -0
  29. package/dist/contracts/middleware/liquidity-layer/interfaces/index.d.ts.map +1 -1
  30. package/dist/contracts/middleware/liquidity-layer/interfaces/portal/IPortalTokenBridge.d.ts +148 -0
  31. package/dist/contracts/middleware/liquidity-layer/interfaces/portal/IPortalTokenBridge.d.ts.map +1 -0
  32. package/dist/contracts/middleware/liquidity-layer/interfaces/portal/IPortalTokenBridge.js +4 -0
  33. package/dist/contracts/middleware/liquidity-layer/interfaces/portal/IPortalTokenBridge.js.map +1 -0
  34. package/dist/contracts/middleware/liquidity-layer/interfaces/portal/index.d.ts +2 -0
  35. package/dist/contracts/middleware/liquidity-layer/interfaces/portal/index.d.ts.map +1 -0
  36. package/dist/contracts/middleware/liquidity-layer/interfaces/portal/index.js +3 -0
  37. package/dist/contracts/middleware/liquidity-layer/interfaces/portal/index.js.map +1 -0
  38. package/dist/contracts/mock/MockCircleMessageTransmitter.d.ts +1 -1
  39. package/dist/contracts/mock/MockCircleMessageTransmitter.d.ts.map +1 -1
  40. package/dist/contracts/mock/{MockCircleBridge.d.ts → MockCircleTokenMessenger.d.ts} +4 -4
  41. package/dist/contracts/mock/MockCircleTokenMessenger.d.ts.map +1 -0
  42. package/dist/contracts/mock/MockCircleTokenMessenger.js +4 -0
  43. package/dist/contracts/mock/MockCircleTokenMessenger.js.map +1 -0
  44. package/dist/contracts/mock/MockPortalBridge.d.ts +164 -0
  45. package/dist/contracts/mock/MockPortalBridge.d.ts.map +1 -0
  46. package/dist/contracts/mock/MockPortalBridge.js +4 -0
  47. package/dist/contracts/mock/MockPortalBridge.js.map +1 -0
  48. package/dist/contracts/mock/index.d.ts +2 -1
  49. package/dist/contracts/mock/index.d.ts.map +1 -1
  50. package/dist/factories/contracts/InterchainGasPaymaster__factory.d.ts +4 -11
  51. package/dist/factories/contracts/InterchainGasPaymaster__factory.d.ts.map +1 -1
  52. package/dist/factories/contracts/InterchainGasPaymaster__factory.js +25 -1
  53. package/dist/factories/contracts/InterchainGasPaymaster__factory.js.map +1 -1
  54. package/dist/factories/contracts/middleware/InterchainAccountRouter__factory.d.ts +1 -1
  55. package/dist/factories/contracts/middleware/InterchainAccountRouter__factory.js +1 -1
  56. package/dist/factories/contracts/middleware/InterchainQueryRouter__factory.d.ts +1 -1
  57. package/dist/factories/contracts/middleware/InterchainQueryRouter__factory.js +1 -1
  58. package/dist/factories/contracts/middleware/liquidity-layer/LiquidityLayerRouter__factory.d.ts +1 -1
  59. package/dist/factories/contracts/middleware/liquidity-layer/LiquidityLayerRouter__factory.d.ts.map +1 -1
  60. package/dist/factories/contracts/middleware/liquidity-layer/LiquidityLayerRouter__factory.js +7 -7
  61. package/dist/factories/contracts/middleware/liquidity-layer/LiquidityLayerRouter__factory.js.map +1 -1
  62. package/dist/factories/contracts/middleware/liquidity-layer/adapters/CircleBridgeAdapter__factory.d.ts +1 -1
  63. package/dist/factories/contracts/middleware/liquidity-layer/adapters/CircleBridgeAdapter__factory.d.ts.map +1 -1
  64. package/dist/factories/contracts/middleware/liquidity-layer/adapters/CircleBridgeAdapter__factory.js +15 -15
  65. package/dist/factories/contracts/middleware/liquidity-layer/adapters/CircleBridgeAdapter__factory.js.map +1 -1
  66. package/dist/factories/contracts/middleware/liquidity-layer/adapters/PortalAdapter__factory.d.ts +48 -0
  67. package/dist/factories/contracts/middleware/liquidity-layer/adapters/PortalAdapter__factory.d.ts.map +1 -0
  68. package/dist/factories/contracts/middleware/liquidity-layer/adapters/PortalAdapter__factory.js +610 -0
  69. package/dist/factories/contracts/middleware/liquidity-layer/adapters/PortalAdapter__factory.js.map +1 -0
  70. package/dist/factories/contracts/middleware/liquidity-layer/adapters/index.d.ts +1 -0
  71. package/dist/factories/contracts/middleware/liquidity-layer/adapters/index.d.ts.map +1 -1
  72. package/dist/factories/contracts/middleware/liquidity-layer/adapters/index.js +3 -1
  73. package/dist/factories/contracts/middleware/liquidity-layer/adapters/index.js.map +1 -1
  74. package/dist/factories/contracts/middleware/liquidity-layer/interfaces/circle/{ICircleBridge__factory.d.ts → ITokenMessenger__factory.d.ts} +5 -5
  75. package/dist/factories/contracts/middleware/liquidity-layer/interfaces/circle/ITokenMessenger__factory.d.ts.map +1 -0
  76. package/dist/factories/contracts/middleware/liquidity-layer/interfaces/circle/{ICircleBridge__factory.js → ITokenMessenger__factory.js} +5 -5
  77. package/dist/factories/contracts/middleware/liquidity-layer/interfaces/circle/ITokenMessenger__factory.js.map +1 -0
  78. package/dist/factories/contracts/middleware/liquidity-layer/interfaces/circle/index.d.ts +1 -1
  79. package/dist/factories/contracts/middleware/liquidity-layer/interfaces/circle/index.d.ts.map +1 -1
  80. package/dist/factories/contracts/middleware/liquidity-layer/interfaces/circle/index.js +3 -3
  81. package/dist/factories/contracts/middleware/liquidity-layer/interfaces/circle/index.js.map +1 -1
  82. package/dist/factories/contracts/middleware/liquidity-layer/interfaces/index.d.ts +1 -0
  83. package/dist/factories/contracts/middleware/liquidity-layer/interfaces/index.d.ts.map +1 -1
  84. package/dist/factories/contracts/middleware/liquidity-layer/interfaces/index.js +2 -1
  85. package/dist/factories/contracts/middleware/liquidity-layer/interfaces/index.js.map +1 -1
  86. package/dist/factories/contracts/middleware/liquidity-layer/interfaces/portal/IPortalTokenBridge__factory.d.ts +56 -0
  87. package/dist/factories/contracts/middleware/liquidity-layer/interfaces/portal/IPortalTokenBridge__factory.d.ts.map +1 -0
  88. package/dist/factories/contracts/middleware/liquidity-layer/interfaces/portal/IPortalTokenBridge__factory.js +204 -0
  89. package/dist/factories/contracts/middleware/liquidity-layer/interfaces/portal/IPortalTokenBridge__factory.js.map +1 -0
  90. package/dist/factories/contracts/middleware/liquidity-layer/interfaces/portal/index.d.ts +2 -0
  91. package/dist/factories/contracts/middleware/liquidity-layer/interfaces/portal/index.d.ts.map +1 -0
  92. package/dist/factories/contracts/middleware/liquidity-layer/interfaces/portal/index.js +9 -0
  93. package/dist/factories/contracts/middleware/liquidity-layer/interfaces/portal/index.js.map +1 -0
  94. package/dist/factories/contracts/mock/MockCircleMessageTransmitter__factory.d.ts +1 -1
  95. package/dist/factories/contracts/mock/MockCircleMessageTransmitter__factory.d.ts.map +1 -1
  96. package/dist/factories/contracts/mock/MockCircleMessageTransmitter__factory.js +3 -3
  97. package/dist/factories/contracts/mock/MockCircleMessageTransmitter__factory.js.map +1 -1
  98. package/dist/factories/contracts/mock/{MockCircleBridge__factory.d.ts → MockCircleTokenMessenger__factory.d.ts} +11 -11
  99. package/dist/factories/contracts/mock/MockCircleTokenMessenger__factory.d.ts.map +1 -0
  100. package/dist/factories/contracts/mock/{MockCircleBridge__factory.js → MockCircleTokenMessenger__factory.js} +7 -7
  101. package/dist/factories/contracts/mock/MockCircleTokenMessenger__factory.js.map +1 -0
  102. package/dist/factories/contracts/mock/MockHyperlaneEnvironment__factory.d.ts +1 -1
  103. package/dist/factories/contracts/mock/MockHyperlaneEnvironment__factory.d.ts.map +1 -1
  104. package/dist/factories/contracts/mock/MockHyperlaneEnvironment__factory.js +1 -1
  105. package/dist/factories/contracts/mock/MockHyperlaneEnvironment__factory.js.map +1 -1
  106. package/dist/factories/contracts/mock/MockPortalBridge__factory.d.ts +79 -0
  107. package/dist/factories/contracts/mock/{MockCircleBridge__factory.d.ts.map → MockPortalBridge__factory.d.ts.map} +1 -1
  108. package/dist/factories/contracts/mock/MockPortalBridge__factory.js +296 -0
  109. package/dist/factories/contracts/mock/MockPortalBridge__factory.js.map +1 -0
  110. package/dist/factories/contracts/mock/index.d.ts +2 -1
  111. package/dist/factories/contracts/mock/index.d.ts.map +1 -1
  112. package/dist/factories/contracts/mock/index.js +5 -3
  113. package/dist/factories/contracts/mock/index.js.map +1 -1
  114. package/dist/factories/contracts/test/TestHyperlaneConnectionClient__factory.d.ts +1 -1
  115. package/dist/factories/contracts/test/TestHyperlaneConnectionClient__factory.js +1 -1
  116. package/dist/factories/contracts/test/TestQuery__factory.d.ts +1 -1
  117. package/dist/factories/contracts/test/TestQuery__factory.js +1 -1
  118. package/dist/factories/contracts/test/TestRouter__factory.d.ts +1 -1
  119. package/dist/factories/contracts/test/TestRouter__factory.js +1 -1
  120. package/dist/factories/contracts/test/TestSendReceiver__factory.d.ts +1 -1
  121. package/dist/factories/contracts/test/TestSendReceiver__factory.js +1 -1
  122. package/dist/factories/interfaces/IInterchainGasPaymaster__factory.d.ts +5 -1
  123. package/dist/factories/interfaces/IInterchainGasPaymaster__factory.d.ts.map +1 -1
  124. package/dist/factories/interfaces/IInterchainGasPaymaster__factory.js +25 -1
  125. package/dist/factories/interfaces/IInterchainGasPaymaster__factory.js.map +1 -1
  126. package/dist/factories/interfaces/ILiquidityLayerRouter__factory.js +6 -6
  127. package/dist/factories/interfaces/ILiquidityLayerRouter__factory.js.map +1 -1
  128. package/dist/index.d.ts +10 -4
  129. package/dist/index.d.ts.map +1 -1
  130. package/dist/index.js +12 -6
  131. package/dist/index.js.map +1 -1
  132. package/dist/interfaces/IInterchainGasPaymaster.d.ts +14 -6
  133. package/dist/interfaces/IInterchainGasPaymaster.d.ts.map +1 -1
  134. package/dist/interfaces/ILiquidityLayerRouter.d.ts +8 -8
  135. package/dist/interfaces/ILiquidityLayerRouter.d.ts.map +1 -1
  136. package/interfaces/IInterchainGasPaymaster.sol +6 -1
  137. package/interfaces/ILiquidityLayerRouter.sol +3 -3
  138. package/package.json +4 -5
  139. package/dist/contracts/middleware/liquidity-layer/interfaces/circle/ICircleBridge.d.ts.map +0 -1
  140. package/dist/contracts/middleware/liquidity-layer/interfaces/circle/ICircleBridge.js.map +0 -1
  141. package/dist/contracts/mock/MockCircleBridge.d.ts.map +0 -1
  142. package/dist/contracts/mock/MockCircleBridge.js.map +0 -1
  143. package/dist/factories/contracts/middleware/liquidity-layer/interfaces/circle/ICircleBridge__factory.d.ts.map +0 -1
  144. package/dist/factories/contracts/middleware/liquidity-layer/interfaces/circle/ICircleBridge__factory.js.map +0 -1
  145. package/dist/factories/contracts/mock/MockCircleBridge__factory.js.map +0 -1
@@ -53,15 +53,44 @@ contract InterchainGasPaymaster is IInterchainGasPaymaster, OwnableUpgradeable {
53
53
  uint256 _gasAmount,
54
54
  address _refundAddress
55
55
  ) external payable override {
56
- // Silence compiler warning. The NatSpec @param requires the parameter to be named.
57
- // While not used at the moment, future versions of the paymaster have behavior specific
58
- // to the destination domain and refund overpayments to the _refundAddress.
59
- _destinationDomain;
60
- _refundAddress;
56
+ uint256 _requiredPayment = quoteGasPayment(
57
+ _destinationDomain,
58
+ _gasAmount
59
+ );
60
+ require(
61
+ msg.value >= _requiredPayment,
62
+ "insufficient interchain gas payment"
63
+ );
64
+ uint256 _overpayment = msg.value - _requiredPayment;
65
+ if (_overpayment > 0) {
66
+ (bool _success, ) = _refundAddress.call{value: _overpayment}("");
67
+ // TODO reconsider this?
68
+ require(_success, "Interchain gas payment refund failed");
69
+ }
61
70
 
62
71
  emit GasPayment(_messageId, _gasAmount, msg.value);
63
72
  }
64
73
 
74
+ /**
75
+ * @notice Quotes the amount of native tokens to pay for interchain gas.
76
+ * @param _destinationDomain The domain of the message's destination chain.
77
+ * @param _gasAmount The amount of destination gas to pay for. Currently unused.
78
+ * @return The amount of native tokens required to pay for interchain gas.
79
+ */
80
+ function quoteGasPayment(uint32 _destinationDomain, uint256 _gasAmount)
81
+ public
82
+ pure
83
+ override
84
+ returns (uint256)
85
+ {
86
+ // Silence compiler warning.
87
+ _destinationDomain;
88
+ _gasAmount;
89
+ // Charge a flat 1 wei fee.
90
+ // This is an intermediate step toward fully on-chain accurate gas payment quoting.
91
+ return 1;
92
+ }
93
+
65
94
  /**
66
95
  * @notice Transfers the entire native token balance to the owner of the contract.
67
96
  * @dev The owner must be able to receive native tokens.
@@ -4,7 +4,6 @@ pragma solidity ^0.8.13;
4
4
  import {Router} from "../../Router.sol";
5
5
 
6
6
  import {ILiquidityLayerRouter} from "../../../interfaces/ILiquidityLayerRouter.sol";
7
- import {ICircleBridge} from "./interfaces/circle/ICircleBridge.sol";
8
7
  import {ICircleMessageTransmitter} from "./interfaces/circle/ICircleMessageTransmitter.sol";
9
8
  import {ILiquidityLayerAdapter} from "./interfaces/ILiquidityLayerAdapter.sol";
10
9
  import {ILiquidityLayerMessageRecipient} from "../../../interfaces/ILiquidityLayerMessageRecipient.sol";
@@ -43,11 +42,11 @@ contract LiquidityLayerRouter is Router, ILiquidityLayerRouter {
43
42
  function dispatchWithTokens(
44
43
  uint32 _destinationDomain,
45
44
  bytes32 _recipientAddress,
46
- bytes calldata _messageBody,
47
45
  address _token,
48
46
  uint256 _amount,
49
- string calldata _bridge
50
- ) external payable returns (bytes32) {
47
+ string calldata _bridge,
48
+ bytes calldata _messageBody
49
+ ) external returns (bytes32) {
51
50
  ILiquidityLayerAdapter _adapter = _getAdapter(_bridge);
52
51
 
53
52
  // Transfer the tokens to the adapter
@@ -79,14 +78,7 @@ contract LiquidityLayerRouter is Router, ILiquidityLayerRouter {
79
78
  );
80
79
 
81
80
  // Dispatch the _messageWithMetadata to the destination's LiquidityLayerRouter.
82
- return
83
- _dispatchWithGas(
84
- _destinationDomain,
85
- _messageWithMetadata,
86
- 0, // TODO eventually accommodate gas amounts
87
- msg.value,
88
- msg.sender
89
- );
81
+ return _dispatch(_destinationDomain, _messageWithMetadata);
90
82
  }
91
83
 
92
84
  // Handles a message from an enrolled remote LiquidityLayerRouter
@@ -121,13 +113,15 @@ contract LiquidityLayerRouter is Router, ILiquidityLayerRouter {
121
113
  _adapterData
122
114
  );
123
115
 
124
- _userRecipient.handleWithTokens(
125
- _origin,
126
- _originalSender,
127
- _userMessageBody,
128
- _token,
129
- _receivedAmount
130
- );
116
+ if (_userMessageBody.length > 0) {
117
+ _userRecipient.handleWithTokens(
118
+ _origin,
119
+ _originalSender,
120
+ _userMessageBody,
121
+ _token,
122
+ _receivedAmount
123
+ );
124
+ }
131
125
  }
132
126
 
133
127
  function setLiquidityLayerAdapter(string calldata _bridge, address _adapter)
@@ -3,15 +3,15 @@ pragma solidity ^0.8.13;
3
3
 
4
4
  import {Router} from "../../../Router.sol";
5
5
 
6
- import {ICircleBridge} from "../interfaces/circle/ICircleBridge.sol";
6
+ import {ITokenMessenger} from "../interfaces/circle/ITokenMessenger.sol";
7
7
  import {ICircleMessageTransmitter} from "../interfaces/circle/ICircleMessageTransmitter.sol";
8
8
  import {ILiquidityLayerAdapter} from "../interfaces/ILiquidityLayerAdapter.sol";
9
9
 
10
10
  import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol";
11
11
 
12
12
  contract CircleBridgeAdapter is ILiquidityLayerAdapter, Router {
13
- /// @notice The CircleBridge contract.
14
- ICircleBridge public circleBridge;
13
+ /// @notice The TokenMessenger contract.
14
+ ITokenMessenger public tokenMessenger;
15
15
 
16
16
  /// @notice The Circle MessageTransmitter contract.
17
17
  ICircleMessageTransmitter public circleMessageTransmitter;
@@ -61,20 +61,20 @@ contract CircleBridgeAdapter is ILiquidityLayerAdapter, Router {
61
61
 
62
62
  /**
63
63
  * @param _owner The new owner.
64
- * @param _circleBridge The CircleBridge contract.
64
+ * @param _tokenMessenger The TokenMessenger contract.
65
65
  * @param _circleMessageTransmitter The Circle MessageTransmitter contract.
66
66
  * @param _liquidityLayerRouter The LiquidityLayerRouter contract.
67
67
  */
68
68
  function initialize(
69
69
  address _owner,
70
- address _circleBridge,
70
+ address _tokenMessenger,
71
71
  address _circleMessageTransmitter,
72
72
  address _liquidityLayerRouter
73
73
  ) public initializer {
74
74
  // Transfer ownership of the contract to deployer
75
75
  _transferOwnership(_owner);
76
76
 
77
- circleBridge = ICircleBridge(_circleBridge);
77
+ tokenMessenger = ITokenMessenger(_tokenMessenger);
78
78
  circleMessageTransmitter = ICircleMessageTransmitter(
79
79
  _circleMessageTransmitter
80
80
  );
@@ -105,11 +105,11 @@ contract CircleBridgeAdapter is ILiquidityLayerAdapter, Router {
105
105
  // Approve the token to Circle. We assume that the LiquidityLayerRouter
106
106
  // has already transferred the token to this contract.
107
107
  require(
108
- IERC20(_token).approve(address(circleBridge), _amount),
108
+ IERC20(_token).approve(address(tokenMessenger), _amount),
109
109
  "!approval"
110
110
  );
111
111
 
112
- uint64 _nonce = circleBridge.depositForBurn(
112
+ uint64 _nonce = tokenMessenger.depositForBurn(
113
113
  _amount,
114
114
  _circleDomain,
115
115
  _remoteRouter, // Mint to the remote router
@@ -236,8 +236,6 @@ contract CircleBridgeAdapter is ILiquidityLayerAdapter, Router {
236
236
  pure
237
237
  returns (bytes32)
238
238
  {
239
- // The hash is of a uint256 nonce, not a uint64 one.
240
- return
241
- keccak256(abi.encodePacked(_originCircleDomain, uint256(_nonce)));
239
+ return keccak256(abi.encodePacked(_originCircleDomain, _nonce));
242
240
  }
243
241
  }
@@ -0,0 +1,216 @@
1
+ // SPDX-License-Identifier: Apache-2.0
2
+ pragma solidity ^0.8.13;
3
+
4
+ import {Router} from "../../../Router.sol";
5
+
6
+ import {IPortalTokenBridge} from "../interfaces/portal/IPortalTokenBridge.sol";
7
+ import {ILiquidityLayerAdapter} from "../interfaces/ILiquidityLayerAdapter.sol";
8
+ import {TypeCasts} from "../../../libs/TypeCasts.sol";
9
+
10
+ import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol";
11
+
12
+ contract PortalAdapter is ILiquidityLayerAdapter, Router {
13
+ /// @notice The Portal TokenBridge contract.
14
+ IPortalTokenBridge public portalTokenBridge;
15
+
16
+ /// @notice The LiquidityLayerRouter contract.
17
+ address public liquidityLayerRouter;
18
+
19
+ /// @notice Hyperlane domain => Wormhole domain.
20
+ mapping(uint32 => uint16) public hyperlaneDomainToWormholeDomain;
21
+ /// @notice transferId => token address
22
+ mapping(bytes32 => address) public portalTransfersProcessed;
23
+
24
+ uint32 localDomain;
25
+
26
+ // We could technically use Portal's sequence number here but it doesn't
27
+ // get passed through, so we would have to parse the VAA twice
28
+ // 224 bits should be large enough and allows us to pack into a single slot
29
+ // with a Hyperlane domain
30
+ uint224 public nonce = 0;
31
+
32
+ /**
33
+ * @notice Emits the nonce of the Portal message when a token is bridged.
34
+ * @param nonce The nonce of the Portal message.
35
+ * @param portalSequence The sequence of the Portal message.
36
+ * @param destination The hyperlane domain of the destination
37
+ */
38
+ event BridgedToken(
39
+ uint256 nonce,
40
+ uint64 portalSequence,
41
+ uint32 destination
42
+ );
43
+
44
+ /**
45
+ * @notice Emitted when the Hyperlane domain to Wormhole domain mapping is updated.
46
+ * @param hyperlaneDomain The Hyperlane domain.
47
+ * @param wormholeDomain The Wormhole domain.
48
+ */
49
+ event DomainAdded(uint32 indexed hyperlaneDomain, uint32 wormholeDomain);
50
+
51
+ modifier onlyLiquidityLayerRouter() {
52
+ require(msg.sender == liquidityLayerRouter, "!liquidityLayerRouter");
53
+ _;
54
+ }
55
+
56
+ /**
57
+ * @param _localDomain The local hyperlane domain
58
+ * @param _owner The new owner.
59
+ * @param _portalTokenBridge The Portal TokenBridge contract.
60
+ * @param _liquidityLayerRouter The LiquidityLayerRouter contract.
61
+ */
62
+ function initialize(
63
+ uint32 _localDomain,
64
+ address _owner,
65
+ address _portalTokenBridge,
66
+ address _liquidityLayerRouter
67
+ ) public initializer {
68
+ // Transfer ownership of the contract to deployer
69
+ _transferOwnership(_owner);
70
+
71
+ localDomain = _localDomain;
72
+ portalTokenBridge = IPortalTokenBridge(_portalTokenBridge);
73
+ liquidityLayerRouter = _liquidityLayerRouter;
74
+ }
75
+
76
+ /**
77
+ * Sends tokens as requested by the router
78
+ * @param _destinationDomain The hyperlane domain of the destination
79
+ * @param _token The token address
80
+ * @param _amount The amount of tokens to send
81
+ */
82
+ function sendTokens(
83
+ uint32 _destinationDomain,
84
+ bytes32, // _recipientAddress, unused
85
+ address _token,
86
+ uint256 _amount
87
+ ) external onlyLiquidityLayerRouter returns (bytes memory) {
88
+ nonce = nonce + 1;
89
+ uint16 _wormholeDomain = hyperlaneDomainToWormholeDomain[
90
+ _destinationDomain
91
+ ];
92
+
93
+ bytes32 _remoteRouter = _mustHaveRemoteRouter(_destinationDomain);
94
+
95
+ // Approve the token to Portal. We assume that the LiquidityLayerRouter
96
+ // has already transferred the token to this contract.
97
+ require(
98
+ IERC20(_token).approve(address(portalTokenBridge), _amount),
99
+ "!approval"
100
+ );
101
+
102
+ uint64 _portalSequence = portalTokenBridge.transferTokensWithPayload(
103
+ _token,
104
+ _amount,
105
+ _wormholeDomain,
106
+ _remoteRouter,
107
+ // Nonce for grouping Portal messages in the same tx, not relevant for us
108
+ // https://book.wormhole.com/technical/evm/coreLayer.html#emitting-a-vaa
109
+ 0,
110
+ // Portal Payload used in completeTransfer
111
+ abi.encode(localDomain, nonce)
112
+ );
113
+
114
+ emit BridgedToken(nonce, _portalSequence, _destinationDomain);
115
+ return abi.encode(nonce);
116
+ }
117
+
118
+ /**
119
+ * Sends the tokens to the recipient as requested by the router
120
+ * @param _originDomain The hyperlane domain of the origin
121
+ * @param _recipient The address of the recipient
122
+ * @param _amount The amount of tokens to send
123
+ * @param _adapterData The adapter data from the origin chain, containing the nonce
124
+ */
125
+ function receiveTokens(
126
+ uint32 _originDomain, // Hyperlane domain
127
+ address _recipient,
128
+ uint256 _amount,
129
+ bytes calldata _adapterData // The adapter data from the message
130
+ ) external onlyLiquidityLayerRouter returns (address, uint256) {
131
+ // Get the nonce information from the adapterData
132
+ uint224 _nonce = abi.decode(_adapterData, (uint224));
133
+
134
+ address _tokenAddress = portalTransfersProcessed[
135
+ transferId(_originDomain, _nonce)
136
+ ];
137
+
138
+ require(
139
+ _tokenAddress != address(0x0),
140
+ "Portal Transfer has not yet been completed"
141
+ );
142
+
143
+ IERC20 _token = IERC20(_tokenAddress);
144
+
145
+ // Transfer the token out to the recipient
146
+ // TODO: use safeTransfer
147
+ // Portal doesn't charge any fee, so we can safely transfer out the
148
+ // exact amount that was bridged over.
149
+ require(_token.transfer(_recipient, _amount), "!transfer out");
150
+ return (_tokenAddress, _amount);
151
+ }
152
+
153
+ /**
154
+ * Completes the Portal transfer which sends the funds to this adapter.
155
+ * The router can call receiveTokens to move those funds to the ultimate recipient.
156
+ * @param encodedVm The VAA from the Wormhole Guardians
157
+ */
158
+ function completeTransfer(bytes memory encodedVm) public {
159
+ bytes memory _tokenBridgeTransferWithPayload = portalTokenBridge
160
+ .completeTransferWithPayload(encodedVm);
161
+ IPortalTokenBridge.TransferWithPayload
162
+ memory _transfer = portalTokenBridge.parseTransferWithPayload(
163
+ _tokenBridgeTransferWithPayload
164
+ );
165
+
166
+ (uint32 _originDomain, uint224 _nonce) = abi.decode(
167
+ _transfer.payload,
168
+ (uint32, uint224)
169
+ );
170
+
171
+ // Logic taken from here https://github.com/wormhole-foundation/wormhole/blob/dev.v2/ethereum/contracts/bridge/Bridge.sol#L503
172
+ address tokenAddress = _transfer.tokenChain ==
173
+ hyperlaneDomainToWormholeDomain[localDomain]
174
+ ? TypeCasts.bytes32ToAddress(_transfer.tokenAddress)
175
+ : portalTokenBridge.wrappedAsset(
176
+ _transfer.tokenChain,
177
+ _transfer.tokenAddress
178
+ );
179
+
180
+ portalTransfersProcessed[
181
+ transferId(_originDomain, _nonce)
182
+ ] = tokenAddress;
183
+ }
184
+
185
+ // This contract is only a Router to be aware of remote router addresses,
186
+ // and doesn't actually send/handle Hyperlane messages directly
187
+ function _handle(
188
+ uint32, // origin
189
+ bytes32, // sender
190
+ bytes calldata // message
191
+ ) internal pure override {
192
+ revert("No messages expected");
193
+ }
194
+
195
+ function addDomain(uint32 _hyperlaneDomain, uint16 _wormholeDomain)
196
+ external
197
+ onlyOwner
198
+ {
199
+ hyperlaneDomainToWormholeDomain[_hyperlaneDomain] = _wormholeDomain;
200
+
201
+ emit DomainAdded(_hyperlaneDomain, _wormholeDomain);
202
+ }
203
+
204
+ /**
205
+ * The key that is used to track fulfilled Portal transfers
206
+ * @param _hyperlaneDomain The hyperlane of the origin
207
+ * @param _nonce The nonce of the adapter on the origin
208
+ */
209
+ function transferId(uint32 _hyperlaneDomain, uint224 _nonce)
210
+ public
211
+ pure
212
+ returns (bytes32)
213
+ {
214
+ return bytes32(abi.encodePacked(_hyperlaneDomain, _nonce));
215
+ }
216
+ }
@@ -1,7 +1,7 @@
1
1
  // SPDX-License-Identifier: Apache-2.0
2
2
  pragma solidity ^0.8.13;
3
3
 
4
- interface ICircleBridge {
4
+ interface ITokenMessenger {
5
5
  event MessageSent(bytes message);
6
6
 
7
7
  /**
@@ -9,7 +9,7 @@ interface ICircleBridge {
9
9
  * Emits a `DepositForBurn` event.
10
10
  * @dev reverts if:
11
11
  * - given burnToken is not supported
12
- * - given destinationDomain has no CircleBridge registered
12
+ * - given destinationDomain has no TokenMessenger registered
13
13
  * - transferFrom() reverts. For example, if sender's burnToken balance or approved allowance
14
14
  * to this contract is less than `amount`.
15
15
  * - burn() reverts. For example, if `amount` is 0.
@@ -37,7 +37,7 @@ interface ICircleBridge {
37
37
  * @dev reverts if:
38
38
  * - given destinationCaller is zero address
39
39
  * - given burnToken is not supported
40
- * - given destinationDomain has no CircleBridge registered
40
+ * - given destinationDomain has no TokenMessenger registered
41
41
  * - transferFrom() reverts. For example, if sender's burnToken balance or approved allowance
42
42
  * to this contract is less than `amount`.
43
43
  * - burn() reverts. For example, if `amount` is 0.
@@ -0,0 +1,87 @@
1
+ // SPDX-License-Identifier: Apache-2.0
2
+ pragma solidity ^0.8.13;
3
+
4
+ // Portal's interface from their docs
5
+ interface IPortalTokenBridge {
6
+ struct Transfer {
7
+ uint8 payloadID;
8
+ uint256 amount;
9
+ bytes32 tokenAddress;
10
+ uint16 tokenChain;
11
+ bytes32 to;
12
+ uint16 toChain;
13
+ uint256 fee;
14
+ }
15
+
16
+ struct TransferWithPayload {
17
+ uint8 payloadID;
18
+ uint256 amount;
19
+ bytes32 tokenAddress;
20
+ uint16 tokenChain;
21
+ bytes32 to;
22
+ uint16 toChain;
23
+ bytes32 fromAddress;
24
+ bytes payload;
25
+ }
26
+
27
+ struct AssetMeta {
28
+ uint8 payloadID;
29
+ bytes32 tokenAddress;
30
+ uint16 tokenChain;
31
+ uint8 decimals;
32
+ bytes32 symbol;
33
+ bytes32 name;
34
+ }
35
+
36
+ struct RegisterChain {
37
+ bytes32 module;
38
+ uint8 action;
39
+ uint16 chainId;
40
+ uint16 emitterChainID;
41
+ bytes32 emitterAddress;
42
+ }
43
+
44
+ struct UpgradeContract {
45
+ bytes32 module;
46
+ uint8 action;
47
+ uint16 chainId;
48
+ bytes32 newContract;
49
+ }
50
+
51
+ struct RecoverChainId {
52
+ bytes32 module;
53
+ uint8 action;
54
+ uint256 evmChainId;
55
+ uint16 newChainId;
56
+ }
57
+
58
+ event ContractUpgraded(
59
+ address indexed oldContract,
60
+ address indexed newContract
61
+ );
62
+
63
+ function transferTokensWithPayload(
64
+ address token,
65
+ uint256 amount,
66
+ uint16 recipientChain,
67
+ bytes32 recipient,
68
+ uint32 nonce,
69
+ bytes memory payload
70
+ ) external payable returns (uint64 sequence);
71
+
72
+ function completeTransferWithPayload(bytes memory encodedVm)
73
+ external
74
+ returns (bytes memory);
75
+
76
+ function parseTransferWithPayload(bytes memory encoded)
77
+ external
78
+ pure
79
+ returns (TransferWithPayload memory transfer);
80
+
81
+ function wrappedAsset(uint16 tokenChainId, bytes32 tokenAddress)
82
+ external
83
+ view
84
+ returns (address);
85
+
86
+ function isWrappedAsset(address token) external view returns (bool);
87
+ }
@@ -20,7 +20,7 @@ contract MockCircleMessageTransmitter is ICircleMessageTransmitter {
20
20
  success = true;
21
21
  }
22
22
 
23
- function hashSourceAndNonce(uint32 _source, uint256 _nonce)
23
+ function hashSourceAndNonce(uint32 _source, uint64 _nonce)
24
24
  public
25
25
  pure
26
26
  returns (bytes32)
@@ -1,10 +1,10 @@
1
1
  // SPDX-License-Identifier: Apache-2.0
2
2
  pragma solidity ^0.8.13;
3
3
 
4
- import {ICircleBridge} from "../middleware/liquidity-layer/interfaces/circle/ICircleBridge.sol";
4
+ import {ITokenMessenger} from "../middleware/liquidity-layer/interfaces/circle/ITokenMessenger.sol";
5
5
  import {MockToken} from "./MockToken.sol";
6
6
 
7
- contract MockCircleBridge is ICircleBridge {
7
+ contract MockCircleTokenMessenger is ITokenMessenger {
8
8
  uint64 public nextNonce = 0;
9
9
  MockToken token;
10
10
 
@@ -0,0 +1,89 @@
1
+ // SPDX-License-Identifier: Apache-2.0
2
+ pragma solidity ^0.8.13;
3
+
4
+ import {IPortalTokenBridge} from "../middleware/liquidity-layer/interfaces/portal/IPortalTokenBridge.sol";
5
+ import {MockToken} from "./MockToken.sol";
6
+ import {TypeCasts} from "../libs/TypeCasts.sol";
7
+
8
+ contract MockPortalBridge is IPortalTokenBridge {
9
+ uint256 nextNonce = 0;
10
+ MockToken token;
11
+
12
+ constructor(MockToken _token) {
13
+ token = _token;
14
+ }
15
+
16
+ function transferTokensWithPayload(
17
+ address,
18
+ uint256 amount,
19
+ uint16,
20
+ bytes32,
21
+ uint32,
22
+ bytes memory
23
+ ) external payable returns (uint64 sequence) {
24
+ nextNonce = nextNonce + 1;
25
+ token.transferFrom(msg.sender, address(this), amount);
26
+ token.burn(amount);
27
+ return uint64(nextNonce);
28
+ }
29
+
30
+ function wrappedAsset(uint16, bytes32) external view returns (address) {
31
+ return address(token);
32
+ }
33
+
34
+ function isWrappedAsset(address) external pure returns (bool) {
35
+ return true;
36
+ }
37
+
38
+ function completeTransferWithPayload(bytes memory encodedVm)
39
+ external
40
+ returns (bytes memory)
41
+ {
42
+ (uint32 _originDomain, uint224 _nonce, uint256 _amount) = abi.decode(
43
+ encodedVm,
44
+ (uint32, uint224, uint256)
45
+ );
46
+
47
+ token.mint(msg.sender, _amount);
48
+ // Format it so that parseTransferWithPayload returns the desired payload
49
+ return
50
+ abi.encode(
51
+ TypeCasts.addressToBytes32(address(token)),
52
+ adapterData(_originDomain, _nonce, address(token))
53
+ );
54
+ }
55
+
56
+ function parseTransferWithPayload(bytes memory encoded)
57
+ external
58
+ pure
59
+ returns (TransferWithPayload memory transfer)
60
+ {
61
+ (bytes32 tokenAddress, bytes memory payload) = abi.decode(
62
+ encoded,
63
+ (bytes32, bytes)
64
+ );
65
+ transfer.payload = payload;
66
+ transfer.tokenAddress = tokenAddress;
67
+ }
68
+
69
+ function adapterData(
70
+ uint32 _originDomain,
71
+ uint224 _nonce,
72
+ address _token
73
+ ) public pure returns (bytes memory) {
74
+ return
75
+ abi.encode(
76
+ _originDomain,
77
+ _nonce,
78
+ TypeCasts.addressToBytes32(_token)
79
+ );
80
+ }
81
+
82
+ function mockPortalVaa(
83
+ uint32 _originDomain,
84
+ uint224 _nonce,
85
+ uint256 _amount
86
+ ) public pure returns (bytes memory) {
87
+ return abi.encode(_originDomain, _nonce, _amount);
88
+ }
89
+ }