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
281 lines
7.7 KiB
Solidity
281 lines
7.7 KiB
Solidity
// SPDX-License-Identifier: MIT
|
|
|
|
pragma solidity >=0.8.9;
|
|
|
|
import "rubic-bridge-base/contracts/architecture/WithDestinationFunctionality.sol";
|
|
|
|
import "rubic-bridge-base/contracts/libraries/SmartApprove.sol";
|
|
|
|
import "../framework/MessageSenderApp.sol";
|
|
import "../../interfaces/IWETH.sol";
|
|
|
|
contract SwapBase is MessageSenderApp, WithDestinationFunctionality {
|
|
using SafeERC20Upgradeable for IERC20Upgradeable;
|
|
using EnumerableSetUpgradeable for EnumerableSetUpgradeable.AddressSet;
|
|
|
|
address public nativeWrap;
|
|
uint64 public nonce;
|
|
|
|
mapping(bytes32 => RefundData) public refundDetails;
|
|
|
|
modifier isTransit(address _transitToken, address _tokenInPath) {
|
|
checkIsTransit(_transitToken, _tokenInPath);
|
|
_;
|
|
}
|
|
|
|
// ============== struct for refunds ==============
|
|
|
|
struct RefundData {
|
|
address integrator; // integrator address in order to take commission
|
|
address token; // transit token
|
|
uint256 amount; // amount of transit token
|
|
address to; // recipient
|
|
bool nativeOut; // receive wrapped/native
|
|
}
|
|
|
|
// ============== struct for V2 like dexes ==============
|
|
|
|
struct SwapInfoV2 {
|
|
address dex; // the DEX to use for the swap
|
|
// if this array has only one element, it means no need to swap
|
|
address[] path;
|
|
// the following fields are only needed if path.length > 1
|
|
uint256 deadline; // deadline for the swap
|
|
uint256 amountOutMinimum; // minimum receive amount for the swap
|
|
}
|
|
|
|
// ============== struct for V3 like dexes ==============
|
|
|
|
struct SwapInfoV3 {
|
|
address dex; // the DEX to use for the swap
|
|
bytes path;
|
|
uint256 deadline;
|
|
uint256 amountOutMinimum;
|
|
}
|
|
|
|
// ============== struct for inch swap ==============
|
|
|
|
struct SwapInfoInch {
|
|
address dex;
|
|
// path is tokenIn, tokenOut
|
|
address[] path;
|
|
bytes data;
|
|
uint256 amountOutMinimum;
|
|
}
|
|
|
|
// ============== struct dstSwap ==============
|
|
// This is needed to make v2 -> SGN -> v3 swaps and etc.
|
|
|
|
struct SwapInfoDest {
|
|
address dex; // dex address
|
|
bool nativeOut;
|
|
address receiverEOA; // EOA recipient in dst chain
|
|
address integrator;
|
|
SwapVersion version; // identifies swap type
|
|
address[] path; // path address for v2 and inch
|
|
bytes pathV3; // path address for v3
|
|
uint256 deadline; // for v2 and v3
|
|
uint256 amountOutMinimum;
|
|
}
|
|
|
|
struct SwapRequestDest {
|
|
SwapInfoDest swap;
|
|
uint64 nonce;
|
|
uint64 dstChainId;
|
|
}
|
|
|
|
enum SwapVersion {
|
|
v2,
|
|
v3,
|
|
bridge
|
|
}
|
|
|
|
// ============== common checks for src swaps ==============
|
|
|
|
function _deriveFeeAndPerformChecksNative(
|
|
uint256 _amountIn,
|
|
uint64 _dstChainId,
|
|
address _integrator,
|
|
address srcInputToken
|
|
) internal onlyEOA whenNotPaused returns (uint256 _fee) {
|
|
require(srcInputToken == nativeWrap, "token mismatch");
|
|
require(msg.value >= _amountIn, "amount insufficient");
|
|
IWETH(nativeWrap).deposit{value: _amountIn}();
|
|
|
|
_fee =
|
|
accrueFixedAndGasFees(
|
|
_integrator,
|
|
integratorToFeeInfo[_integrator],
|
|
_dstChainId
|
|
) -
|
|
_amountIn;
|
|
}
|
|
|
|
function _deriveFeeAndPerformChecks(
|
|
uint256 _amountIn,
|
|
uint64 _dstChainId,
|
|
address _integrator,
|
|
address srcInputToken
|
|
) internal onlyEOA whenNotPaused returns (uint256 _fee) {
|
|
IERC20Upgradeable(srcInputToken).safeTransferFrom(
|
|
msg.sender,
|
|
address(this),
|
|
_amountIn
|
|
);
|
|
|
|
_fee = accrueFixedAndGasFees(
|
|
_integrator,
|
|
integratorToFeeInfo[_integrator],
|
|
_dstChainId
|
|
);
|
|
}
|
|
|
|
// ============== Celer call ==============
|
|
|
|
function _sendMessage(
|
|
address _receiver,
|
|
uint64 _dstChainId,
|
|
SwapInfoDest calldata _dstSwap,
|
|
uint32 _maxBridgeSlippage,
|
|
uint64 _nonce,
|
|
uint256 _fee,
|
|
address _srcOutputToken,
|
|
uint256 _srcAmtOut,
|
|
bool _success
|
|
) internal returns (bytes32 id) {
|
|
if (!_success) revert("src swap failed");
|
|
|
|
require(_srcAmtOut >= minTokenAmount[_srcOutputToken], "less than min");
|
|
if (maxTokenAmount[_srcOutputToken] > 0) {
|
|
require(
|
|
_srcAmtOut <= maxTokenAmount[_srcOutputToken],
|
|
"greater than max"
|
|
);
|
|
}
|
|
|
|
id = _crossChainTransferWithSwap(
|
|
_receiver,
|
|
_dstChainId,
|
|
_dstSwap,
|
|
_maxBridgeSlippage,
|
|
_nonce,
|
|
_fee,
|
|
_srcOutputToken,
|
|
_srcAmtOut
|
|
);
|
|
}
|
|
|
|
function _crossChainTransferWithSwap(
|
|
address _receiver,
|
|
uint64 _dstChainId,
|
|
SwapInfoDest calldata _dstSwap,
|
|
uint32 _maxBridgeSlippage,
|
|
uint64 _nonce,
|
|
uint256 _fee,
|
|
address srcOutputToken,
|
|
uint256 srcAmtOut
|
|
) private returns (bytes32 id) {
|
|
// todo increment nonce in compute ...
|
|
require(_dstSwap.path.length > 0, "empty dst swap path");
|
|
bytes memory message = abi.encode(
|
|
SwapRequestDest({
|
|
swap: _dstSwap,
|
|
nonce: nonce,
|
|
dstChainId: _dstChainId
|
|
})
|
|
);
|
|
id = _computeSwapRequestId(
|
|
_dstSwap.receiverEOA,
|
|
uint64(block.chainid),
|
|
_dstChainId,
|
|
message
|
|
);
|
|
|
|
sendMessageWithTransfer(
|
|
_receiver,
|
|
srcOutputToken,
|
|
srcAmtOut,
|
|
_dstChainId,
|
|
_nonce,
|
|
_maxBridgeSlippage,
|
|
message,
|
|
_fee
|
|
);
|
|
}
|
|
|
|
// ============== Utilities ==============
|
|
|
|
function _beforeSwapAndSendMessage() internal returns (uint64) {
|
|
return ++nonce;
|
|
}
|
|
|
|
function _retrieveDstTokenAddress(SwapInfoDest memory _swapInfo)
|
|
internal
|
|
pure
|
|
returns (address)
|
|
{
|
|
if (_swapInfo.version == SwapVersion.v3) {
|
|
require(_swapInfo.pathV3.length > 20, "dst swap expected");
|
|
|
|
return address(_getLastBytes20(_swapInfo.pathV3));
|
|
} else if (_swapInfo.version == SwapVersion.v2) {
|
|
require(_swapInfo.path.length > 1, "dst swap expected");
|
|
|
|
return _swapInfo.path[_swapInfo.path.length - 1];
|
|
} else {
|
|
require(_swapInfo.path.length == 1, "dst bridge expected");
|
|
return _swapInfo.path[0];
|
|
}
|
|
}
|
|
|
|
// returns address of first token for V3
|
|
function _getFirstBytes20(bytes memory input)
|
|
internal
|
|
pure
|
|
returns (bytes20 result)
|
|
{
|
|
assembly {
|
|
result := mload(add(input, 32))
|
|
}
|
|
}
|
|
|
|
// returns address of tokenOut for V3
|
|
function _getLastBytes20(bytes memory input)
|
|
internal
|
|
pure
|
|
returns (bytes20 result)
|
|
{
|
|
uint256 offset = input.length + 12;
|
|
assembly {
|
|
result := mload(add(input, offset))
|
|
}
|
|
}
|
|
|
|
function _computeSwapRequestId(
|
|
address _receiverEOA,
|
|
uint64 _srcChainId,
|
|
uint64 _dstChainId,
|
|
bytes memory _message
|
|
) internal pure returns (bytes32) {
|
|
return
|
|
keccak256(
|
|
abi.encodePacked(
|
|
_receiverEOA,
|
|
_srcChainId,
|
|
_dstChainId,
|
|
_message
|
|
)
|
|
);
|
|
}
|
|
|
|
/**
|
|
* @dev Function to check if the address in path is transit token received from Celer
|
|
*/
|
|
function checkIsTransit(address _transitToken, address _tokenInPath)
|
|
internal
|
|
pure
|
|
{
|
|
require(_transitToken == _tokenInPath, "first token must be transit");
|
|
}
|
|
}
|