You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
135 lines
4.7 KiB
135 lines
4.7 KiB
2 years ago
|
// SPDX-License-Identifier: Apache-2.0
|
||
|
pragma solidity ^0.8.13;
|
||
|
|
||
|
import {Router} from "../../Router.sol";
|
||
|
|
||
|
import {IMessageRecipient} from "../../../interfaces/IMessageRecipient.sol";
|
||
|
import {ICircleBridge} from "./interfaces/circle/ICircleBridge.sol";
|
||
|
import {ICircleMessageTransmitter} from "./interfaces/circle/ICircleMessageTransmitter.sol";
|
||
2 years ago
|
import {ILiquidityLayerAdapter} from "./interfaces/ILiquidityLayerAdapter.sol";
|
||
|
import {ILiquidityLayerMessageRecipient} from "./interfaces/ILiquidityLayerMessageRecipient.sol";
|
||
2 years ago
|
|
||
|
import {TypeCasts} from "../../libs/TypeCasts.sol";
|
||
|
|
||
|
import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol";
|
||
|
|
||
2 years ago
|
contract LiquidityLayerRouter is Router {
|
||
2 years ago
|
// Token bridge => adapter address
|
||
2 years ago
|
mapping(string => address) public liquidityLayerAdapters;
|
||
2 years ago
|
|
||
2 years ago
|
event LiquidityLayerAdapterSet(string indexed bridge, address adapter);
|
||
2 years ago
|
|
||
|
function initialize(
|
||
|
address _owner,
|
||
2 years ago
|
address _mailbox,
|
||
2 years ago
|
address _interchainGasPaymaster
|
||
|
) public initializer {
|
||
|
// Transfer ownership of the contract to deployer
|
||
|
_transferOwnership(_owner);
|
||
|
// Alternatively, this could be done later in an initialize method
|
||
2 years ago
|
_setMailbox(_mailbox);
|
||
2 years ago
|
_setInterchainGasPaymaster(_interchainGasPaymaster);
|
||
|
}
|
||
|
|
||
|
function dispatchWithTokens(
|
||
|
uint32 _destinationDomain,
|
||
|
bytes32 _recipientAddress,
|
||
|
bytes calldata _messageBody,
|
||
|
address _token,
|
||
|
uint256 _amount,
|
||
|
string calldata _bridge
|
||
|
) external payable {
|
||
2 years ago
|
ILiquidityLayerAdapter _adapter = _getAdapter(_bridge);
|
||
2 years ago
|
|
||
|
// Transfer the tokens to the adapter
|
||
|
// TODO: use safeTransferFrom
|
||
|
// TODO: Are there scenarios where a transferFrom fails and it doesn't revert?
|
||
|
require(
|
||
|
IERC20(_token).transferFrom(msg.sender, address(_adapter), _amount),
|
||
|
"!transfer in"
|
||
|
);
|
||
|
|
||
|
// Reverts if the bridge was unsuccessful.
|
||
|
// Gets adapter-specific data that is encoded into the message
|
||
|
// ultimately sent via Hyperlane.
|
||
|
bytes memory _adapterData = _adapter.sendTokens(
|
||
|
_destinationDomain,
|
||
|
_recipientAddress,
|
||
|
_token,
|
||
|
_amount
|
||
|
);
|
||
|
|
||
|
// The user's message "wrapped" with metadata required by this middleware
|
||
|
bytes memory _messageWithMetadata = abi.encode(
|
||
|
TypeCasts.addressToBytes32(msg.sender),
|
||
|
_recipientAddress, // The "user" recipient
|
||
|
_amount, // The amount of the tokens sent over the bridge
|
||
|
_bridge, // The destination token bridge ID
|
||
|
_adapterData, // The adapter-specific data
|
||
|
_messageBody // The "user" message
|
||
|
);
|
||
|
|
||
2 years ago
|
// Dispatch the _messageWithMetadata to the destination's LiquidityLayerRouter.
|
||
2 years ago
|
_dispatchWithGas(_destinationDomain, _messageWithMetadata, msg.value);
|
||
|
}
|
||
|
|
||
2 years ago
|
// Handles a message from an enrolled remote LiquidityLayerRouter
|
||
2 years ago
|
function _handle(
|
||
|
uint32 _origin,
|
||
|
bytes32, // _sender, unused
|
||
|
bytes calldata _message
|
||
|
) internal override {
|
||
|
// Decode the message with metadata, "unwrapping" the user's message body
|
||
|
(
|
||
|
bytes32 _originalSender,
|
||
|
bytes32 _userRecipientAddress,
|
||
|
uint256 _amount,
|
||
|
string memory _bridge,
|
||
|
bytes memory _adapterData,
|
||
|
bytes memory _userMessageBody
|
||
|
) = abi.decode(
|
||
|
_message,
|
||
|
(bytes32, bytes32, uint256, string, bytes, bytes)
|
||
|
);
|
||
|
|
||
2 years ago
|
ILiquidityLayerMessageRecipient _userRecipient = ILiquidityLayerMessageRecipient(
|
||
2 years ago
|
TypeCasts.bytes32ToAddress(_userRecipientAddress)
|
||
|
);
|
||
|
|
||
|
// Reverts if the adapter hasn't received the bridged tokens yet
|
||
|
(address _token, uint256 _receivedAmount) = _getAdapter(_bridge)
|
||
|
.receiveTokens(
|
||
|
_origin,
|
||
|
address(_userRecipient),
|
||
|
_amount,
|
||
|
_adapterData
|
||
|
);
|
||
|
|
||
|
_userRecipient.handleWithTokens(
|
||
|
_origin,
|
||
|
_originalSender,
|
||
|
_userMessageBody,
|
||
|
_token,
|
||
|
_receivedAmount
|
||
|
);
|
||
|
}
|
||
|
|
||
2 years ago
|
function setLiquidityLayerAdapter(string calldata _bridge, address _adapter)
|
||
2 years ago
|
external
|
||
|
onlyOwner
|
||
|
{
|
||
2 years ago
|
liquidityLayerAdapters[_bridge] = _adapter;
|
||
|
emit LiquidityLayerAdapterSet(_bridge, _adapter);
|
||
2 years ago
|
}
|
||
|
|
||
|
function _getAdapter(string memory _bridge)
|
||
|
internal
|
||
|
view
|
||
2 years ago
|
returns (ILiquidityLayerAdapter _adapter)
|
||
2 years ago
|
{
|
||
2 years ago
|
_adapter = ILiquidityLayerAdapter(liquidityLayerAdapters[_bridge]);
|
||
2 years ago
|
// Require the adapter to have been set
|
||
|
require(address(_adapter) != address(0), "No adapter found for bridge");
|
||
|
}
|
||
|
}
|