df8039f494
new file: Interchain-message/.eslintrc.js new file: Interchain-message/.gitignore new file: Interchain-message/.prettierrc new file: Interchain-message/.solhint.json new file: Interchain-message/.solhintignore new file: Interchain-message/contracts/interfaces/IBridge.sol new file: Interchain-message/contracts/interfaces/IMessageBus.sol new file: Interchain-message/contracts/interfaces/IMessageReceiverApp.sol new file: Interchain-message/contracts/interfaces/IUniswapRouterV3.sol new file: Interchain-message/contracts/interfaces/IWETH.sol new file: Interchain-message/contracts/message/apps/BridgeSwap.sol new file: Interchain-message/contracts/message/apps/RubicRouterV2.sol new file: Interchain-message/contracts/message/apps/RubicRouterV2ETH.sol new file: Interchain-message/contracts/message/apps/SwapBase.sol new file: Interchain-message/contracts/message/apps/TransferSwapInch.sol new file: Interchain-message/contracts/message/apps/TransferSwapV2.sol new file: Interchain-message/contracts/message/apps/TransferSwapV3.sol new file: Interchain-message/contracts/message/framework/MessageReceiverApp.sol new file: Interchain-message/contracts/message/framework/MessageSenderApp.sol new file: Interchain-message/contracts/message/libraries/MessageSenderLib.sol new file: Interchain-message/contracts/message/libraries/MsgDataTypes.sol new file: Interchain-message/contracts/test/MessageBusSender.sol new file: Interchain-message/contracts/test/TestERC20.sol new file: Interchain-message/contracts/test/TestMessages.sol new file: Interchain-message/contracts/test/WETH9.sol new file: Interchain-message/deployments/Readme.md new file: Interchain-message/executor/config/cbridge.toml new file: Interchain-message/executor/config/executor.toml new file: Interchain-message/executor/eth-ks/signer.json new file: Interchain-message/hardhat.config.ts new file: Interchain-message/package-lock.json new file: Interchain-message/package.json new file: Interchain-message/reports/contract_sizes.txt new file: Interchain-message/reports/gas_usage/summary.txt new file: Interchain-message/scripts/deploy/deploy.js new file: Interchain-message/scripts/deploy/deployAVAX.ts new file: Interchain-message/scripts/deploy/deployArbitrum.ts new file: Interchain-message/scripts/deploy/deployAurora.ts new file: Interchain-message/scripts/deploy/deployBSC.ts new file: Interchain-message/scripts/deploy/deployEth.ts new file: Interchain-message/scripts/deploy/deployFantom.ts new file: Interchain-message/scripts/deploy/deployPoly.ts new file: Interchain-message/scripts/privateKey.js new file: Interchain-message/scripts/sendTx/avaxToFantomBridge.js new file: Interchain-message/scripts/sendTx/avaxToFantomNativeV2.js new file: Interchain-message/test/RubicCrossChainBridge.spec.ts new file: Interchain-message/test/RubicCrossChainV2.spec.ts new file: Interchain-message/test/RubicCrossChainV3.spec.ts new file: Interchain-message/test/RubicFallback.spec.ts new file: Interchain-message/test/RubicSettings.spec.ts new file: Interchain-message/test/shared/consts.ts new file: Interchain-message/test/shared/fixtures.ts new file: Interchain-message/test/shared/utils.ts new file: Interchain-message/tsconfig.json deleted: Rubic-Inter-chain-Message-develop.zip deleted: proxy-instant-trades-master.zip deleted: rubic-app-master.zip deleted: rubic-sdk-master.zip
393 lines
12 KiB
Solidity
393 lines
12 KiB
Solidity
// SPDX-License-Identifier: MIT
|
|
|
|
pragma solidity >=0.8.9;
|
|
|
|
import "./TransferSwapV2.sol";
|
|
import "./TransferSwapV3.sol";
|
|
import "./TransferSwapInch.sol";
|
|
import "./BridgeSwap.sol";
|
|
|
|
contract RubicRouterV2 is
|
|
TransferSwapV2,
|
|
TransferSwapV3,
|
|
TransferSwapInch,
|
|
BridgeSwap
|
|
{
|
|
using SafeERC20Upgradeable for IERC20Upgradeable;
|
|
using EnumerableSetUpgradeable for EnumerableSetUpgradeable.AddressSet;
|
|
|
|
constructor(
|
|
uint256 _fixedCryptoFee,
|
|
uint256 _RubicPlatformFee,
|
|
address[] memory _routers,
|
|
address[] memory _tokens,
|
|
uint256[] memory _minTokenAmounts,
|
|
uint256[] memory _maxTokenAmounts,
|
|
uint256[] memory _blockchainIDs,
|
|
uint256[] memory _blockchainToGasFee,
|
|
address _relayer,
|
|
address _messageBus,
|
|
address _nativeWrap
|
|
) {
|
|
initialize(
|
|
_fixedCryptoFee,
|
|
_RubicPlatformFee,
|
|
_routers,
|
|
_tokens,
|
|
_minTokenAmounts,
|
|
_maxTokenAmounts,
|
|
_blockchainIDs,
|
|
_blockchainToGasFee
|
|
);
|
|
|
|
nativeWrap = _nativeWrap;
|
|
messageBus = _messageBus;
|
|
_setupRole(RELAYER_ROLE, _relayer);
|
|
}
|
|
|
|
function initialize(
|
|
uint256 _fixedCryptoFee,
|
|
uint256 _RubicPlatformFee,
|
|
address[] memory _routers,
|
|
address[] memory _tokens,
|
|
uint256[] memory _minTokenAmounts,
|
|
uint256[] memory _maxTokenAmounts,
|
|
uint256[] memory _blockchainIDs,
|
|
uint256[] memory _blockchainToGasFee
|
|
) private initializer {
|
|
__WithDestinationFunctionalityInit(
|
|
_fixedCryptoFee,
|
|
_RubicPlatformFee,
|
|
_routers,
|
|
_tokens,
|
|
_minTokenAmounts,
|
|
_maxTokenAmounts,
|
|
_blockchainIDs,
|
|
_blockchainToGasFee
|
|
);
|
|
}
|
|
|
|
/**
|
|
* @notice called by MessageBus when the tokens are checked to be arrived at this contract's address.
|
|
sends the amount received to the receiver. swaps beforehand if swap behavior is defined in message
|
|
* NOTE: if the swap fails, it sends the tokens received directly to the receiver as fallback behavior
|
|
* @param _token the address of the token sent through the bridge
|
|
* @param _amount the amount of tokens received at this contract through the cross-chain bridge
|
|
* @param _srcChainId source chain ID
|
|
* @param _message SwapRequestDst message that defines the swap behavior on this destination chain
|
|
*/
|
|
function executeMessageWithTransfer(
|
|
address,
|
|
address _token,
|
|
uint256 _amount,
|
|
uint64 _srcChainId,
|
|
bytes calldata _message,
|
|
address _relayer
|
|
)
|
|
external
|
|
payable
|
|
override
|
|
onlyMessageBus
|
|
nonReentrant
|
|
whenNotPaused
|
|
onlyRelayer(_relayer)
|
|
returns (ExecutionStatus)
|
|
{
|
|
SwapRequestDest memory m = abi.decode((_message), (SwapRequestDest));
|
|
bytes32 id = _computeSwapRequestId(
|
|
m.swap.receiverEOA,
|
|
_srcChainId,
|
|
uint64(block.chainid),
|
|
_message
|
|
);
|
|
|
|
_amount = accrueTokenFees(
|
|
m.swap.integrator,
|
|
integratorToFeeInfo[m.swap.integrator],
|
|
_amount,
|
|
0,
|
|
_token
|
|
);
|
|
|
|
address _outputToken = _retrieveDstTokenAddress(m.swap);
|
|
|
|
if (m.swap.version == SwapVersion.v3) {
|
|
_executeDstSwapV3(_token, _outputToken, _amount, id, m);
|
|
} else if (m.swap.version == SwapVersion.bridge) {
|
|
_executeDstBridge(_token, _amount, id, m);
|
|
} else {
|
|
_executeDstSwapV2(_token, _outputToken, _amount, id, m);
|
|
}
|
|
|
|
// always return true since swap failure is already handled in-place
|
|
return ExecutionStatus.Success;
|
|
}
|
|
|
|
/**
|
|
* @notice called by MessageBus when the executeMessageWithTransfer call fails. does nothing but emitting a "fail" event
|
|
* @param _srcChainId source chain ID
|
|
* @param _message SwapRequestDst message that defines the swap behavior on this destination chain
|
|
* execution on dst chain
|
|
*/
|
|
function executeMessageWithTransferFallback(
|
|
address, // _sender
|
|
address _token,
|
|
uint256 _amount,
|
|
uint64 _srcChainId,
|
|
bytes calldata _message,
|
|
address _relayer
|
|
)
|
|
external
|
|
payable
|
|
override
|
|
onlyMessageBus
|
|
nonReentrant
|
|
onlyRelayer(_relayer)
|
|
returns (ExecutionStatus)
|
|
{
|
|
SwapRequestDest memory m = abi.decode((_message), (SwapRequestDest));
|
|
|
|
bytes32 id = _computeSwapRequestId(
|
|
m.swap.receiverEOA,
|
|
_srcChainId,
|
|
uint64(block.chainid),
|
|
_message
|
|
);
|
|
|
|
// collect data about failed cross-chain for manual refund
|
|
refundDetails[id] = RefundData(
|
|
m.swap.integrator,
|
|
_token,
|
|
_amount,
|
|
m.swap.receiverEOA,
|
|
m.swap.nativeOut
|
|
);
|
|
|
|
// Failed status means user hasn't received funds
|
|
_afterTargetProcessing(id, _token, _amount, SwapStatus.Failed);
|
|
// always return Fail to mark this transfer as failed since if this function is called then there nothing more
|
|
// we can do in this app as the swap failures are already handled in executeMessageWithTransfer
|
|
return ExecutionStatus.Fail;
|
|
}
|
|
|
|
// called on source chain for handling of bridge failures (bad liquidity, bad slippage, etc...)
|
|
function executeMessageWithTransferRefund(
|
|
address _token,
|
|
uint256 _amount,
|
|
bytes calldata _message,
|
|
address _relayer
|
|
)
|
|
external
|
|
payable
|
|
override
|
|
onlyMessageBus
|
|
nonReentrant
|
|
whenNotPaused
|
|
onlyRelayer(_relayer)
|
|
returns (ExecutionStatus)
|
|
{
|
|
SwapRequestDest memory m = abi.decode((_message), (SwapRequestDest));
|
|
|
|
bytes32 id = _computeSwapRequestId(
|
|
m.swap.receiverEOA,
|
|
uint64(block.chainid),
|
|
m.dstChainId,
|
|
_message
|
|
);
|
|
|
|
_sendToken(_token, _amount, m.swap.receiverEOA, m.swap.nativeOut);
|
|
|
|
_afterTargetProcessing(id, _token, _amount, SwapStatus.Fallback);
|
|
|
|
return ExecutionStatus.Success;
|
|
}
|
|
|
|
// no need to swap, directly send the bridged token to user
|
|
function _executeDstBridge(
|
|
address _inputToken,
|
|
uint256 _amount,
|
|
bytes32 _id,
|
|
SwapRequestDest memory _msgDst
|
|
) private {
|
|
_sendToken(
|
|
_inputToken,
|
|
_amount,
|
|
_msgDst.swap.receiverEOA,
|
|
_msgDst.swap.nativeOut
|
|
);
|
|
|
|
_afterTargetProcessing(_id, _inputToken, _amount, SwapStatus.Succeeded);
|
|
}
|
|
|
|
function _executeDstSwapV2(
|
|
address _inputToken,
|
|
address _outputToken,
|
|
uint256 _amount,
|
|
bytes32 _id,
|
|
SwapRequestDest memory _msgDst
|
|
) private isTransit(_inputToken, _msgDst.swap.path[0]) {
|
|
SwapInfoV2 memory _dstSwap = SwapInfoV2({
|
|
dex: _msgDst.swap.dex,
|
|
path: _msgDst.swap.path,
|
|
deadline: _msgDst.swap.deadline,
|
|
amountOutMinimum: _msgDst.swap.amountOutMinimum
|
|
});
|
|
uint256 balanceBefore = IERC20Upgradeable(_outputToken).balanceOf(
|
|
address(this)
|
|
);
|
|
(bool success, ) = _trySwapV2(_dstSwap, _amount);
|
|
uint256 dstAmount = IERC20Upgradeable(_outputToken).balanceOf(
|
|
address(this)
|
|
) - balanceBefore;
|
|
if (success) {
|
|
_sendToken(
|
|
_outputToken,
|
|
dstAmount,
|
|
_msgDst.swap.receiverEOA,
|
|
_msgDst.swap.nativeOut
|
|
);
|
|
_afterTargetProcessing(
|
|
_id,
|
|
_outputToken,
|
|
dstAmount,
|
|
SwapStatus.Succeeded
|
|
);
|
|
} else {
|
|
// handle swap failure, send the received token directly to receiver
|
|
_sendToken(
|
|
_inputToken,
|
|
_amount,
|
|
_msgDst.swap.receiverEOA,
|
|
_msgDst.swap.nativeOut
|
|
);
|
|
_afterTargetProcessing(
|
|
_id,
|
|
_inputToken,
|
|
_amount,
|
|
SwapStatus.Fallback
|
|
);
|
|
}
|
|
}
|
|
|
|
function _executeDstSwapV3(
|
|
address _inputToken,
|
|
address _outputToken,
|
|
uint256 _amount,
|
|
bytes32 _id,
|
|
SwapRequestDest memory _msgDst
|
|
)
|
|
private
|
|
isTransit(_inputToken, address(_getFirstBytes20(_msgDst.swap.pathV3)))
|
|
{
|
|
SwapInfoV3 memory _dstSwap = SwapInfoV3({
|
|
dex: _msgDst.swap.dex,
|
|
path: _msgDst.swap.pathV3,
|
|
deadline: _msgDst.swap.deadline,
|
|
amountOutMinimum: _msgDst.swap.amountOutMinimum
|
|
});
|
|
|
|
uint256 balanceBefore = IERC20Upgradeable(_outputToken).balanceOf(
|
|
address(this)
|
|
);
|
|
(bool success, ) = _trySwapV3(_dstSwap, _amount);
|
|
uint256 dstAmount = IERC20Upgradeable(_outputToken).balanceOf(
|
|
address(this)
|
|
) - balanceBefore;
|
|
|
|
if (success) {
|
|
_sendToken(
|
|
_outputToken,
|
|
dstAmount,
|
|
_msgDst.swap.receiverEOA,
|
|
_msgDst.swap.nativeOut
|
|
);
|
|
_afterTargetProcessing(
|
|
_id,
|
|
_outputToken,
|
|
dstAmount,
|
|
SwapStatus.Succeeded
|
|
);
|
|
} else {
|
|
// handle swap failure, send the received token directly to receiver
|
|
_sendToken(
|
|
_inputToken,
|
|
_amount,
|
|
_msgDst.swap.receiverEOA,
|
|
_msgDst.swap.nativeOut
|
|
);
|
|
_afterTargetProcessing(
|
|
_id,
|
|
_inputToken,
|
|
_amount,
|
|
SwapStatus.Fallback
|
|
);
|
|
}
|
|
}
|
|
|
|
function _sendToken(
|
|
address _token,
|
|
uint256 _amount,
|
|
address _receiver,
|
|
bool _nativeOut
|
|
) private {
|
|
if (_token == nativeWrap && _nativeOut == true) {
|
|
IWETH(nativeWrap).withdraw(_amount);
|
|
sendToken(address(0), _amount, _receiver);
|
|
} else {
|
|
sendToken(_token, _amount, _receiver);
|
|
}
|
|
}
|
|
|
|
function _afterTargetProcessing(
|
|
bytes32 _id,
|
|
address _token,
|
|
uint256 _amount,
|
|
SwapStatus _status
|
|
) private {
|
|
processedTransactions[_id] = _status;
|
|
emit CrossChainProcessed(_id, _token, _amount, _status);
|
|
}
|
|
|
|
function sweepTokens(address _token, uint256 _amount) external onlyAdmin {
|
|
sendToken(_token, _amount, msg.sender);
|
|
}
|
|
|
|
function manualRefund(bytes32 _id)
|
|
external
|
|
nonReentrant
|
|
onlyManagerOrAdmin
|
|
{
|
|
SwapStatus _status = processedTransactions[_id];
|
|
require(
|
|
_status != SwapStatus.Succeeded && _status != SwapStatus.Fallback
|
|
);
|
|
|
|
RefundData memory refundParams = refundDetails[_id];
|
|
|
|
uint256 _amount = accrueTokenFees(
|
|
refundParams.integrator,
|
|
integratorToFeeInfo[refundParams.integrator],
|
|
refundParams.amount,
|
|
0,
|
|
refundParams.token
|
|
);
|
|
|
|
_sendToken(
|
|
refundParams.token,
|
|
_amount,
|
|
refundParams.to,
|
|
refundParams.nativeOut
|
|
);
|
|
processedTransactions[_id] = SwapStatus.Fallback;
|
|
}
|
|
|
|
function setNativeWrap(address _nativeWrap) external onlyManagerOrAdmin {
|
|
nativeWrap = _nativeWrap;
|
|
}
|
|
|
|
function setMessageBus(address _messageBus) external onlyManagerOrAdmin {
|
|
messageBus = _messageBus;
|
|
emit MessageBusUpdated(messageBus);
|
|
}
|
|
}
|