Pnuttaste/Interchain-message/contracts/message/apps/RubicRouterV2.sol

393 lines
12 KiB
Solidity
Raw Normal View History

new file: Interchain-message/.env.example 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
2024-07-09 21:32:00 +00:00
// 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);
}
}