文件 1 的 7:Context.sol
pragma solidity ^0.8.0;
abstract contract Context {
function _msgSender() internal view virtual returns (address) {
return msg.sender;
}
function _msgData() internal view virtual returns (bytes calldata) {
return msg.data;
}
}
文件 2 的 7:IERC20.sol
pragma solidity ^0.8.0;
interface IERC20 {
function totalSupply() external view returns (uint256);
function balanceOf(address account) external view returns (uint256);
function transfer(address recipient, uint256 amount) external returns (bool);
function allowance(address owner, address spender) external view returns (uint256);
function approve(address spender, uint256 amount) external returns (bool);
function transferFrom(
address sender,
address recipient,
uint256 amount
) external returns (bool);
event Transfer(address indexed from, address indexed to, uint256 value);
event Approval(address indexed owner, address indexed spender, uint256 value);
}
文件 3 的 7:MetaRouteStructs.sol
pragma solidity ^0.8.0;
library MetaRouteStructs {
struct MetaBurnTransaction {
uint256 stableBridgingFee;
uint256 amount;
address syntCaller;
address finalReceiveSide;
address sToken;
bytes finalCallData;
uint256 finalOffset;
address chain2address;
address receiveSide;
address oppositeBridge;
address revertableAddress;
uint256 chainID;
bytes32 clientID;
}
struct MetaMintTransaction {
uint256 stableBridgingFee;
uint256 amount;
bytes32 externalID;
address tokenReal;
uint256 chainID;
address to;
address[] swapTokens;
address secondDexRouter;
bytes secondSwapCalldata;
address finalReceiveSide;
bytes finalCalldata;
uint256 finalOffset;
}
struct MetaRouteTransaction {
bytes firstSwapCalldata;
bytes secondSwapCalldata;
address[] approvedTokens;
address firstDexRouter;
address secondDexRouter;
uint256 amount;
bool nativeIn;
address relayRecipient;
bytes otherSideCalldata;
}
struct MetaSynthesizeTransaction {
uint256 stableBridgingFee;
uint256 amount;
address rtoken;
address chain2address;
address receiveSide;
address oppositeBridge;
address syntCaller;
uint256 chainID;
address[] swapTokens;
address secondDexRouter;
bytes secondSwapCalldata;
address finalReceiveSide;
bytes finalCalldata;
uint256 finalOffset;
address revertableAddress;
bytes32 clientID;
}
struct MetaRevertTransaction {
uint256 stableBridgingFee;
bytes32 internalID;
address receiveSide;
address managerChainBridge;
address sourceChainBridge;
uint256 managerChainId;
uint256 sourceChainId;
address router;
bytes swapCalldata;
address sourceChainSynthesis;
address burnToken;
bytes burnCalldata;
bytes32 clientID;
}
}
文件 4 的 7:MetaRouter.sol
pragma solidity ^0.8.0;
import "@openzeppelin/contracts/utils/Context.sol";
import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import "./MetaRouteStructs.sol";
import "./MetaRouterGateway.sol";
import "../../utils/RevertMessageParser.sol";
contract MetaRouter is Context {
MetaRouterGateway public immutable metaRouterGateway;
constructor() {
metaRouterGateway = new MetaRouterGateway(address(this));
}
function metaRoute(
MetaRouteStructs.MetaRouteTransaction calldata _metarouteTransaction
) external payable {
uint256 approvedTokensLength = _metarouteTransaction.approvedTokens.length;
if (!_metarouteTransaction.nativeIn) {
metaRouterGateway.claimTokens(
_metarouteTransaction.approvedTokens[0],
_msgSender(),
_metarouteTransaction.amount
);
}
uint256 secondSwapAmountIn = _metarouteTransaction.amount;
if (_metarouteTransaction.firstSwapCalldata.length != 0) {
if (!_metarouteTransaction.nativeIn) {
_lazyApprove(
_metarouteTransaction.approvedTokens[0],
_metarouteTransaction.firstDexRouter,
_metarouteTransaction.amount
);
}
require(
_metarouteTransaction.firstDexRouter != address(metaRouterGateway),
"MetaRouter: invalid first router"
);
{
uint256 size;
address toCheck = _metarouteTransaction.firstDexRouter;
assembly {
size := extcodesize(toCheck)
}
require(size != 0, "MetaRouter: call for a non-contract account");
}
(bool firstSwapSuccess, bytes memory swapData) = _metarouteTransaction.firstDexRouter.call{value: msg.value}(
_metarouteTransaction.firstSwapCalldata
);
if (!firstSwapSuccess) {
revert(RevertMessageParser.getRevertMessage(swapData, "MetaRouter: first swap failed"));
}
secondSwapAmountIn = IERC20(_metarouteTransaction.approvedTokens[1]).balanceOf(address(this));
}
uint256 finalSwapAmountIn = secondSwapAmountIn;
if (_metarouteTransaction.secondSwapCalldata.length != 0) {
bytes memory secondSwapCalldata = _metarouteTransaction.secondSwapCalldata;
assembly {
mstore(add(secondSwapCalldata, 36), secondSwapAmountIn)
}
_lazyApprove(
_metarouteTransaction.approvedTokens[approvedTokensLength - 2],
_metarouteTransaction.secondDexRouter,
secondSwapAmountIn
);
require(
_metarouteTransaction.secondDexRouter != address(metaRouterGateway),
"MetaRouter: invalid second router"
);
{
uint256 size;
address toCheck = _metarouteTransaction.secondDexRouter;
assembly {
size := extcodesize(toCheck)
}
require(size != 0, "MetaRouter: call for a non-contract account");
}
(bool secondSwapSuccess, bytes memory swapData) = _metarouteTransaction.secondDexRouter.call(secondSwapCalldata);
if (!secondSwapSuccess) {
revert(RevertMessageParser.getRevertMessage(swapData, "MetaRouter: second swap failed"));
}
finalSwapAmountIn = IERC20(
_metarouteTransaction.approvedTokens[approvedTokensLength - 1]
).balanceOf(address(this));
}
_lazyApprove(
_metarouteTransaction.approvedTokens[approvedTokensLength - 1],
_metarouteTransaction.relayRecipient,
finalSwapAmountIn
);
bytes memory otherSideCalldata = _metarouteTransaction.otherSideCalldata;
assembly {
mstore(add(otherSideCalldata, 100), finalSwapAmountIn)
}
require(
_metarouteTransaction.relayRecipient != address(metaRouterGateway),
"MetaRouter: invalid recipient"
);
{
uint256 size;
address toCheck = _metarouteTransaction.relayRecipient;
assembly {
size := extcodesize(toCheck)
}
require(size != 0, "MetaRouter: call for a non-contract account");
}
(bool otherSideCallSuccess, bytes memory data) = _metarouteTransaction.relayRecipient.call(otherSideCalldata);
if (!otherSideCallSuccess) {
revert(RevertMessageParser.getRevertMessage(data, "MetaRouter: other side call failed"));
}
}
function externalCall(
address _token,
uint256 _amount,
address _receiveSide,
bytes calldata _calldata,
uint256 _offset
) external {
(bool success, bytes memory data) = _externalCall(_token, _amount, _receiveSide, _calldata, _offset);
if (!success) {
revert(RevertMessageParser.getRevertMessage(data, "MetaRouter: external call failed"));
}
}
function returnSwap(
address _token,
uint256 _amount,
address _router,
bytes calldata _swapCalldata,
address _burnToken,
address _synthesis,
bytes calldata _burnCalldata
) external {
(bool success, bytes memory data) = _externalCall(_token, _amount, _router, _swapCalldata, 36);
if (!success) {
revert(RevertMessageParser.getRevertMessage(data, "MetaRouterV2: internal swap failed"));
}
uint256 internalSwapAmountOut = IERC20(_burnToken).balanceOf(address(this));
bytes memory burnCalldata = _burnCalldata;
assembly {
mstore(add(burnCalldata, 100), internalSwapAmountOut)
}
require(
_synthesis != address(metaRouterGateway),
"MetaRouterV2: invalid recipient"
);
{
uint256 size;
address toCheck = _synthesis;
assembly {
size := extcodesize(toCheck)
}
require(size != 0, "MetaRouter: call for a non-contract account");
}
(bool otherSideCallSuccess, bytes memory burnData) = _synthesis.call(burnCalldata);
if (!otherSideCallSuccess) {
revert(RevertMessageParser.getRevertMessage(burnData, "MetaRouterV2: revertSynthesizeRequest call failed"));
}
}
function metaMintSwap(
MetaRouteStructs.MetaMintTransaction calldata _metaMintTransaction
) external {
address finalCallToken = _metaMintTransaction.swapTokens[0];
if (_metaMintTransaction.secondSwapCalldata.length != 0) {
(bool internalSwapSuccess, bytes memory internalSwapData) = _externalCall(
_metaMintTransaction.swapTokens[0],
_metaMintTransaction.amount,
_metaMintTransaction.secondDexRouter,
_metaMintTransaction.secondSwapCalldata,
36
);
if (!internalSwapSuccess) {
revert(RevertMessageParser.getRevertMessage(internalSwapData, "MetaRouter: internal swap failed"));
}
finalCallToken = _metaMintTransaction.swapTokens[1];
}
if (_metaMintTransaction.finalCalldata.length != 0) {
uint256 finalAmountIn = IERC20(finalCallToken).balanceOf(address(this));
(bool finalSuccess, bytes memory finalData) = _externalCall(
finalCallToken,
finalAmountIn,
_metaMintTransaction.finalReceiveSide,
_metaMintTransaction.finalCalldata,
_metaMintTransaction.finalOffset
);
if (!finalSuccess) {
revert(RevertMessageParser.getRevertMessage(finalData, "MetaRouter: final call failed"));
}
}
uint256 amountOut = IERC20(_metaMintTransaction.swapTokens[_metaMintTransaction.swapTokens.length - 1]).balanceOf(address(this));
if (amountOut != 0) {
TransferHelper.safeTransfer(
_metaMintTransaction.swapTokens[_metaMintTransaction.swapTokens.length - 1],
_metaMintTransaction.to,
amountOut
);
}
}
function _externalCall(
address _token,
uint256 _amount,
address _receiveSide,
bytes memory _calldata,
uint256 _offset
) internal returns (bool success, bytes memory data) {
require(_receiveSide != address(metaRouterGateway), "MetaRouter: invalid receiveSide");
_lazyApprove(_token, _receiveSide, _amount);
assembly {
mstore(add(_calldata, _offset), _amount)
}
{
uint256 size;
address toCheck = _receiveSide;
assembly {
size := extcodesize(toCheck)
}
require(size != 0, "MetaRouter: call for a non-contract account");
}
(success, data) = _receiveSide.call(_calldata);
}
function _lazyApprove(address _token, address _to, uint256 _amount) internal {
if (IERC20(_token).allowance(address(this), _to) < _amount) {
TransferHelper.safeApprove(_token, _to, type(uint256).max);
}
}
}
文件 5 的 7:MetaRouterGateway.sol
pragma solidity ^0.8.0;
import "@uniswap/lib/contracts/libraries/TransferHelper.sol";
contract MetaRouterGateway {
address public immutable metaRouter;
modifier onlyMetarouter() {
require(metaRouter == msg.sender, "Symb: caller is not the metarouter");
_;
}
constructor(address _metaRouter) {
metaRouter = _metaRouter;
}
function claimTokens(
address _token,
address _from,
uint256 _amount
) external onlyMetarouter {
TransferHelper.safeTransferFrom(_token, _from, metaRouter, _amount);
}
}
文件 6 的 7:RevertMessageParser.sol
pragma solidity ^0.8.0;
library RevertMessageParser {
function getRevertMessage(bytes memory _data, string memory _defaultMessage) internal pure returns (string memory) {
if (_data.length < 68) return _defaultMessage;
assembly {
_data := add(_data, 0x04)
}
return abi.decode(_data, (string));
}
}
文件 7 的 7:TransferHelper.sol
pragma solidity >=0.6.0;
library TransferHelper {
function safeApprove(
address token,
address to,
uint256 value
) internal {
(bool success, bytes memory data) = token.call(abi.encodeWithSelector(0x095ea7b3, to, value));
require(
success && (data.length == 0 || abi.decode(data, (bool))),
'TransferHelper::safeApprove: approve failed'
);
}
function safeTransfer(
address token,
address to,
uint256 value
) internal {
(bool success, bytes memory data) = token.call(abi.encodeWithSelector(0xa9059cbb, to, value));
require(
success && (data.length == 0 || abi.decode(data, (bool))),
'TransferHelper::safeTransfer: transfer failed'
);
}
function safeTransferFrom(
address token,
address from,
address to,
uint256 value
) internal {
(bool success, bytes memory data) = token.call(abi.encodeWithSelector(0x23b872dd, from, to, value));
require(
success && (data.length == 0 || abi.decode(data, (bool))),
'TransferHelper::transferFrom: transferFrom failed'
);
}
function safeTransferETH(address to, uint256 value) internal {
(bool success, ) = to.call{value: value}(new bytes(0));
require(success, 'TransferHelper::safeTransferETH: ETH transfer failed');
}
}
{
"compilationTarget": {
"contracts/synth-core/metarouter/MetaRouter.sol": "MetaRouter"
},
"evmVersion": "london",
"libraries": {},
"metadata": {
"bytecodeHash": "ipfs"
},
"optimizer": {
"enabled": true,
"runs": 2000
},
"remappings": []
}
[{"inputs":[],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[{"internalType":"address","name":"_token","type":"address"},{"internalType":"uint256","name":"_amount","type":"uint256"},{"internalType":"address","name":"_receiveSide","type":"address"},{"internalType":"bytes","name":"_calldata","type":"bytes"},{"internalType":"uint256","name":"_offset","type":"uint256"}],"name":"externalCall","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"components":[{"internalType":"uint256","name":"stableBridgingFee","type":"uint256"},{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"bytes32","name":"externalID","type":"bytes32"},{"internalType":"address","name":"tokenReal","type":"address"},{"internalType":"uint256","name":"chainID","type":"uint256"},{"internalType":"address","name":"to","type":"address"},{"internalType":"address[]","name":"swapTokens","type":"address[]"},{"internalType":"address","name":"secondDexRouter","type":"address"},{"internalType":"bytes","name":"secondSwapCalldata","type":"bytes"},{"internalType":"address","name":"finalReceiveSide","type":"address"},{"internalType":"bytes","name":"finalCalldata","type":"bytes"},{"internalType":"uint256","name":"finalOffset","type":"uint256"}],"internalType":"struct MetaRouteStructs.MetaMintTransaction","name":"_metaMintTransaction","type":"tuple"}],"name":"metaMintSwap","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"components":[{"internalType":"bytes","name":"firstSwapCalldata","type":"bytes"},{"internalType":"bytes","name":"secondSwapCalldata","type":"bytes"},{"internalType":"address[]","name":"approvedTokens","type":"address[]"},{"internalType":"address","name":"firstDexRouter","type":"address"},{"internalType":"address","name":"secondDexRouter","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"bool","name":"nativeIn","type":"bool"},{"internalType":"address","name":"relayRecipient","type":"address"},{"internalType":"bytes","name":"otherSideCalldata","type":"bytes"}],"internalType":"struct MetaRouteStructs.MetaRouteTransaction","name":"_metarouteTransaction","type":"tuple"}],"name":"metaRoute","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"metaRouterGateway","outputs":[{"internalType":"contract MetaRouterGateway","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_token","type":"address"},{"internalType":"uint256","name":"_amount","type":"uint256"},{"internalType":"address","name":"_router","type":"address"},{"internalType":"bytes","name":"_swapCalldata","type":"bytes"},{"internalType":"address","name":"_burnToken","type":"address"},{"internalType":"address","name":"_synthesis","type":"address"},{"internalType":"bytes","name":"_burnCalldata","type":"bytes"}],"name":"returnSwap","outputs":[],"stateMutability":"nonpayable","type":"function"}]