ButterRouterV31
0xee0319cf0bca5d09333f9f6277743e8de31bd69a
Verification
Verified
v0.8.25+commit.b61c2a91
Type
Contract
15,473 bytes
ABI entries
58
15 read · 13 write
License
none
Contract information
- Address
- 0xee0319cf0bca5d09333f9f6277743e8de31bd69a
- Chain
- Robinhood Chain (4663)
- Compiler
- v0.8.25+commit.b61c2a91
- Optimization
- Enabled
- Creator
- 0x472638E1F1…45A3FbEf8B
- Creation tx
- 0x4e3594a7e5…dff0d79261
Token
Not a token
This contract does not expose ERC-20 metadata.
Read contract (15)
approved(address) → bool
bridgeAddress() → address
feeManager() → address
feeReceiver() → address
funcBlackList(bytes4) → bool
getAmountBeforeFee(address, uint256, bytes) → address, uint256, uint256
getFee(address, uint256, bytes) → address, uint256, uint256, uint256
getFeeDetail(address, uint256, bytes) → tuple
getInputBeforeFee(address, uint256, bytes) → address, uint256, uint256
maxFeeRate() → uint256
maxNativeFee() → uint256
owner() → address
pendingOwner() → address
routerFeeRate() → uint256
routerFixedFee() → uint256
Events (14)
ApproveApproveTokenCollectFeeEditFuncBlackListOwnershipTransferStartedOwnershipTransferredRemoteSwapAndCallSetBridgeAddressSetFeeSetFeeManagerSetReferrerMaxFeeSetWrappedTokenSwapAndBridgeSwapAndCall
ABI
[
{
"inputs": [
{
"internalType": "address",
"name": "_bridgeAddress",
"type": "address"
},
{
"internalType": "address",
"name": "_owner",
"type": "address"
},
{
"internalType": "address",
"name": "_wToken",
"type": "address"
}
],
"stateMutability": "payable",
"type": "constructor"
},
{
"inputs": [],
"name": "CALL_BACK_FAIL",
"type": "error"
},
{
"inputs": [],
"name": "CALL_FUNC_BLACK_LIST",
"type": "error"
},
{
"inputs": [],
"name": "DATA_EMPTY",
"type": "error"
},
{
"inputs": [],
"name": "EMPTY",
"type": "error"
},
{
"inputs": [],
"name": "FEE_MISMATCH",
"type": "error"
},
{
"inputs": [],
"name": "NATIVE_VALUE_OVERSPEND",
"type": "error"
},
{
"inputs": [],
"name": "NOT_CONTRACT",
"type": "error"
},
{
"inputs": [],
"name": "NO_APPROVE",
"type": "error"
},
{
"inputs": [],
"name": "RECEIVE_LOW",
"type": "error"
},
{
"inputs": [],
"name": "SWAP_FAIL",
"type": "error"
},
{
"inputs": [],
"name": "SWAP_SAME_TOKEN",
"type": "error"
},
{
"inputs": [],
"name": "UNSUPPORT_DEX_TYPE",
"type": "error"
},
{
"inputs": [],
"name": "ZERO_ADDRESS",
"type": "error"
},
{
"inputs": [],
"name": "ZERO_IN",
"type": "error"
},
{
"anonymous": false,
"inputs": [
{
"indexed": true,
"internalType": "address",
"name": "executor",
"type": "address"
},
{
"indexed": true,
"internalType": "bool",
"name": "flag",
"type": "bool"
}
],
"name": "Approve",
"type": "event"
},
{
"anonymous": false,
"inputs": [
{
"indexed": false,
"internalType": "contract IERC20",
"name": "token",
"type": "address"
},
{
"indexed": false,
"internalType": "address",
"name": "spender",
"type": "address"
},
{
"indexed": false,
"internalType": "uint256",
"name": "amount",
"type": "uint256"
}
],
"name": "ApproveToken",
"type": "event"
},
{
"anonymous": false,
"inputs": [
{
"indexed": true,
"internalType": "address",
"name": "token",
"type": "address"
},
{
"indexed": true,
"internalType": "address",
"name": "receiver",
"type": "address"
},
{
"indexed": true,
"internalType": "address",
"name": "integrator",
"type": "address"
},
{
"indexed": false,
"internalType": "uint256",
"name": "routerAmount",
"type": "uint256"
},
{
"indexed": false,
"internalType": "uint256",
"name": "integratorAmount",
"type": "uint256"
},
{
"indexed": false,
"internalType": "uint256",
"name": "nativeAmount",
"type": "uint256"
},
{
"indexed": false,
"internalType": "uint256",
"name": "integratorNative",
"type": "uint256"
},
{
"indexed": false,
"internalType": "bytes32",
"name": "transferId",
"type": "bytes32"
}
],
"name": "CollectFee",
"type": "event"
},
{
"anonymous": false,
"inputs": [
{
"indexed": false,
"internalType": "bytes4",
"name": "_func",
"type": "bytes4"
},
{
"indexed": false,
"internalType": "bool",
"name": "flag",
"type": "bool"
}
],
"name": "EditFuncBlackList",
"type": "event"
},
{
"anonymous": false,
"inputs": [
{
"indexed": true,
"internalType": "address",
"name": "previousOwner",
"type": "address"
},
{
"indexed": true,
"internalType": "address",
"name": "newOwner",
"type": "address"
}
],
"name": "OwnershipTransferStarted",
"type": "event"
},
{
"anonymous": false,
"inputs": [
{
"indexed": true,
"internalType": "address",
"name": "previousOwner",
"type": "address"
},
{
"indexed": true,
"internalType": "address",
"name": "newOwner",
"type": "address"
}
],
"name": "OwnershipTransferred",
"type": "event"
},
{
"anonymous": false,
"inputs": [
{
"indexed": true,
"internalType": "bytes32",
"name": "orderId",
"type": "bytes32"
},
{
"indexed": true,
"internalType": "address",
"name": "receiver",
"type": "address"
},
{
"indexed": true,
"internalType": "address",
"name": "target",
"type": "address"
},
{
"indexed": false,
"internalType": "address",
"name": "originToken",
"type": "address"
},
{
"indexed": false,
"internalType": "address",
"name": "swapToken",
"type": "address"
},
{
"indexed": false,
"internalType": "uint256",
"name": "originAmount",
"type": "uint256"
},
{
"indexed": false,
"internalType": "uint256",
"name": "swapAmount",
"type": "uint256"
},
{
"indexed": false,
"internalType": "uint256",
"name": "callAmount",
"type": "uint256"
},
{
"indexed": false,
"internalType": "uint256",
"name": "fromChain",
"type": "uint256"
},
{
"indexed": false,
"internalType": "uint256",
"name": "toChain",
"type": "uint256"
},
{
"indexed": false,
"internalType": "bytes",
"name": "from",
"type": "bytes"
}
],
"name": "RemoteSwapAndCall",
"type": "event"
},
{
"anonymous": false,
"inputs": [
{
"indexed": true,
"internalType": "address",
"name": "_bridgeAddress",
"type": "address"
}
],
"name": "SetBridgeAddress",
"type": "event"
},
{
"anonymous": false,
"inputs": [
{
"indexed": true,
"internalType": "address",
"name": "receiver",
"type": "address"
},
{
"indexed": true,
"internalType": "uint256",
"name": "rate",
"type": "uint256"
},
{
"indexed": true,
"internalType": "uint256",
"name": "fixedf",
"type": "uint256"
}
],
"name": "SetFee",
"type": "event"
},
{
"anonymous": false,
"inputs": [
{
"indexed": true,
"internalType": "address",
"name": "_feeManager",
"type": "address"
}
],
"name": "SetFeeManager",
"type": "event"
},
{
"anonymous": false,
"inputs": [
{
"indexed": true,
"internalType": "uint256",
"name": "_maxFeeRate",
"type": "uint256"
},
{
"indexed": true,
"internalType": "uint256",
"name": "_maxNativeFee",
"type": "uint256"
}
],
"name": "SetReferrerMaxFee",
"type": "event"
},
{
"anonymous": false,
"inputs": [
{
"indexed": true,
"internalType": "address",
"name": "_wToken",
"type": "address"
}
],
"name": "SetWrappedToken",
"type": "event"
},
{
"anonymous": false,
"inputs": [
{
"indexed": true,
"internalType": "address",
"name": "referrer",
"type": "address"
},
{
"indexed": true,
"internalType": "address",
"name": "initiator",
"type": "address"
},
{
"indexed": true,
"internalType": "address",
"name": "from",
"type": "address"
},
{
"indexed": false,
"internalType": "bytes32",
"name": "transferId",
"type": "bytes32"
},
{
"indexed": false,
"internalType": "bytes32",
"name": "orderId",
"type": "bytes32"
},
{
"indexed": false,
"internalType": "address",
"name": "originToken",
"type": "address"
},
{
"indexed": false,
"internalType": "address",
"name": "bridgeToken",
"type": "address"
},
{
"indexed": false,
"internalType": "uint256",
"name": "originAmount",
"type": "uint256"
},
{
"indexed": false,
"internalType": "uint256",
"name": "bridgeAmount",
"type": "uint256"
},
{
"indexed": false,
"internalType": "uint256",
"name": "toChain",
"type": "uint256"
},
{
"indexed": false,
"internalType": "bytes",
"name": "to",
"type": "bytes"
}
],
"name": "SwapAndBridge",
"type": "event"
},
{
"anonymous": false,
"inputs": [
{
"indexed": true,
"internalType": "address",
"name": "referrer",
"type": "address"
},
{
"indexed": true,
"internalType": "address",
"name": "initiator",
"type": "address"
},
{
"indexed": true,
"internalType": "address",
"name": "from",
"type": "address"
},
{
"indexed": false,
"internalType": "bytes32",
"name": "transferId",
"type": "bytes32"
},
{
"indexed": false,
"internalType": "address",
"name": "originToken",
"type": "address"
},
{
"indexed": false,
"internalType": "address",
"name": "swapToken",
"type": "address"
},
{
"indexed": false,
"internalType": "uint256",
"name": "originAmount",
"type": "uint256"
},
{
"indexed": false,
"internalType": "uint256",
"name": "swapAmount",
"type": "uint256"
},
{
"indexed": false,
"internalType": "address",
"name": "receiver",
"type": "address"
},
{
"indexed": false,
"internalType": "address",
"name": "target",
"type": "address"
},
{
"indexed": false,
"internalType": "uint256",
"name": "callAmount",
"type": "uint256"
}
],
"name": "SwapAndCall",
"type": "event"
},
{
"inputs": [],
"name": "acceptOwnership",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [
{
"internalType": "contract IERC20",
"name": "token",
"type": "address"
},
{
"internalType": "address",
"name": "spender",
"type": "address"
},
{
"internalType": "uint256",
"name": "amount",
"type": "uint256"
}
],
"name": "approveToken",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [
{
"internalType": "address",
"name": "",
"type": "address"
}
],
"name": "approved",
"outputs": [
{
"internalType": "bool",
"name": "",
"type": "bool"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [],
"name": "bridgeAddress",
"outputs": [
{
"internalType": "address",
"name": "",
"type": "address"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"internalType": "bytes4",
"name": "_func",
"type": "bytes4"
},
{
"internalType": "bool",
"name": "_flag",
"type": "bool"
}
],
"name": "editFuncBlackList",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [],
"name": "feeManager",
"outputs": [
{
"internalType": "contract IFeeManager",
"name": "",
"type": "address"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [],
"name": "feeReceiver",
"outputs": [
{
"internalType": "address",
"name": "",
"type": "address"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"internalType": "bytes4",
"name": "",
"type": "bytes4"
}
],
"name": "funcBlackList",
"outputs": [
{
"internalType": "bool",
"name": "",
"type": "bool"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"internalType": "address",
"name": "_token",
"type": "address"
},
{
"internalType": "uint256",
"name": "_amountAfterFee",
"type": "uint256"
},
{
"internalType": "bytes",
"name": "_feeData",
"type": "bytes"
}
],
"name": "getAmountBeforeFee",
"outputs": [
{
"internalType": "address",
"name": "feeToken",
"type": "address"
},
{
"internalType": "uint256",
"name": "beforeAmount",
"type": "uint256"
},
{
"internalType": "uint256",
"name": "nativeFeeAmount",
"type": "uint256"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"internalType": "address",
"name": "_inputToken",
"type": "address"
},
{
"internalType": "uint256",
"name": "_inputAmount",
"type": "uint256"
},
{
"internalType": "bytes",
"name": "_feeData",
"type": "bytes"
}
],
"name": "getFee",
"outputs": [
{
"internalType": "address",
"name": "feeToken",
"type": "address"
},
{
"internalType": "uint256",
"name": "tokenFee",
"type": "uint256"
},
{
"internalType": "uint256",
"name": "nativeFee",
"type": "uint256"
},
{
"internalType": "uint256",
"name": "afterFeeAmount",
"type": "uint256"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"internalType": "address",
"name": "_inputToken",
"type": "address"
},
{
"internalType": "uint256",
"name": "_inputAmount",
"type": "uint256"
},
{
"internalType": "bytes",
"name": "_feeData",
"type": "bytes"
}
],
"name": "getFeeDetail",
"outputs": [
{
"components": [
{
"internalType": "address",
"name": "feeToken",
"type": "address"
},
{
"internalType": "address",
"name": "routerReceiver",
"type": "address"
},
{
"internalType": "address",
"name": "integrator",
"type": "address"
},
{
"internalType": "uint256",
"name": "routerNativeFee",
"type": "uint256"
},
{
"internalType": "uint256",
"name": "integratorNativeFee",
"type": "uint256"
},
{
"internalType": "uint256",
"name": "routerTokenFee",
"type": "uint256"
},
{
"internalType": "uint256",
"name": "integratorTokenFee",
"type": "uint256"
}
],
"internalType": "struct IFeeManager.FeeDetail",
"name": "feeDetail",
"type": "tuple"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"internalType": "address",
"name": "_token",
"type": "address"
},
{
"internalType": "uint256",
"name": "_amountAfterFee",
"type": "uint256"
},
{
"internalType": "bytes",
"name": "_feeData",
"type": "bytes"
}
],
"name": "getInputBeforeFee",
"outputs": [
{
"internalType": "address",
"name": "_feeToken",
"type": "address"
},
{
"internalType": "uint256",
"name": "_input",
"type": "uint256"
},
{
"internalType": "uint256",
"name": "_fee",
"type": "uint256"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [],
"name": "maxFeeRate",
"outputs": [
{
"internalType": "uint256",
"name": "",
"type": "uint256"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [],
"name": "maxNativeFee",
"outputs": [
{
"internalType": "uint256",
"name": "",
"type": "uint256"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [],
"name": "owner",
"outputs": [
{
"internalType": "address",
"name": "",
"type": "address"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [],
"name": "pendingOwner",
"outputs": [
{
"internalType": "address",
"name": "",
"type": "address"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [],
"name": "renounceOwnership",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [
{
"internalType": "address",
"name": "_token",
"type": "address"
},
{
"internalType": "uint256",
"name": "_amount",
"type": "uint256"
}
],
"name": "rescueFunds",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [],
"name": "routerFeeRate",
"outputs": [
{
"internalType": "uint256",
"name": "",
"type": "uint256"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [],
"name": "routerFixedFee",
"outputs": [
{
"internalType": "uint256",
"name": "",
"type": "uint256"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"internalType": "address[]",
"name": "_executors",
"type": "address[]"
},
{
"internalType": "bool",
"name": "_flag",
"type": "bool"
}
],
"name": "setAuthorization",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [
{
"internalType": "address",
"name": "_bridgeAddress",
"type": "address"
}
],
"name": "setBridgeAddress",
"outputs": [
{
"internalType": "bool",
"name": "",
"type": "bool"
}
],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [
{
"internalType": "address",
"name": "_feeReceiver",
"type": "address"
},
{
"internalType": "uint256",
"name": "_feeRate",
"type": "uint256"
},
{
"internalType": "uint256",
"name": "_fixedFee",
"type": "uint256"
}
],
"name": "setFee",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [
{
"internalType": "address",
"name": "_feeManager",
"type": "address"
}
],
"name": "setFeeManager",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [
{
"internalType": "uint256",
"name": "_maxFeeRate",
"type": "uint256"
},
{
"internalType": "uint256",
"name": "_maxNativeFee",
"type": "uint256"
}
],
"name": "setReferrerMaxFee",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [
{
"internalType": "bytes32",
"name": "_transferId",
"type": "bytes32"
},
{
"internalType": "address",
"name": "_initiator",
"type": "address"
},
{
"internalType": "address",
"name": "_srcToken",
"type": "address"
},
{
"internalType": "uint256",
"name": "_amount",
"type": "uint256"
},
{
"internalType": "bytes",
"name": "_swapData",
"type": "bytes"
},
{
"internalType": "bytes",
"name": "_bridgeData",
"type": "bytes"
},
{
"internalType": "bytes",
"name": "_permitData",
"type": "bytes"
},
{
"internalType": "bytes",
"name": "_feeData",
"type": "bytes"
}
],
"name": "swapAndBridge",
"outputs": [
{
"internalType": "bytes32",
"name": "orderId",
"type": "bytes32"
}
],
"stateMutability": "payable",
"type": "function"
},
{
"inputs": [
{
"internalType": "bytes32",
"name": "_transferId",
"type": "bytes32"
},
{
"internalType": "address",
"name": "_initiator",
"type": "address"
},
{
"internalType": "address",
"name": "_srcToken",
"type": "address"
},
{
"internalType": "uint256",
"name": "_amount",
"type": "uint256"
},
{
"internalType": "bytes",
"name": "_swapData",
"type": "bytes"
},
{
"internalType": "bytes",
"name": "_callbackData",
"type": "bytes"
},
{
"internalType": "bytes",
"name": "_permitData",
"type": "bytes"
},
{
"internalType": "bytes",
"name": "_feeData",
"type": "bytes"
}
],
"name": "swapAndCall",
"outputs": [],
"stateMutability": "payable",
"type": "function"
},
{
"inputs": [
{
"internalType": "address",
"name": "newOwner",
"type": "address"
}
],
"name": "transferOwnership",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
},
{
"stateMutability": "payable",
"type": "receive"
}
]Source code
// SPDX-License-Identifier: MIT
pragma solidity 0.8.25;
import "@openzeppelin/contracts/access/Ownable2Step.sol";
import "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
import "@openzeppelin/contracts/security/ReentrancyGuard.sol";
import "@openzeppelin/contracts/utils/Address.sol";
import "@butternetwork/bridge/contracts/interface/IButterBridgeV3.sol";
import "./interface/IFeeManager.sol";
import "./abstract/SwapCallV2.sol";
import "./interface/IButterRouterV3.sol";
import "./abstract/FeeManager.sol";
contract ButterRouterV31 is SwapCallV2, FeeManager, ReentrancyGuard, IButterRouterV3 {
using SafeERC20 for IERC20;
using Address for address;
address public bridgeAddress;
IFeeManager public feeManager;
// use to solve deep stack
struct SwapTemp {
address srcToken;
address swapToken;
uint256 srcAmount;
uint256 swapAmount;
bytes32 transferId;
address referrer;
address initiator;
address receiver;
address target;
uint256 callAmount;
uint256 toChain;
uint256 nativeBalance;
uint256 inputBalance;
}
event Approve(address indexed executor, bool indexed flag);
event SetFeeManager(address indexed _feeManager);
event ApproveToken(IERC20 token, address spender, uint256 amount);
event CollectFee(
address indexed token,
address indexed receiver,
address indexed integrator,
uint256 routerAmount,
uint256 integratorAmount,
uint256 nativeAmount,
uint256 integratorNative,
bytes32 transferId
);
event SetBridgeAddress(address indexed _bridgeAddress);
constructor(
address _bridgeAddress,
address _owner,
address _wToken
) payable SwapCallV2(_wToken) FeeManager(_owner) {
if (!_bridgeAddress.isContract()) revert Errors.NOT_CONTRACT();
// bridgeAddress = _bridgeAddress;
_setBridgeAddress(_bridgeAddress);
}
function setAuthorization(address[] calldata _executors, bool _flag) external onlyOwner {
if (_executors.length == 0) revert Errors.EMPTY();
for (uint i = 0; i < _executors.length; i++) {
if (!_executors[i].isContract()) revert Errors.NOT_CONTRACT();
approved[_executors[i]] = _flag;
emit Approve(_executors[i], _flag);
}
}
function approveToken(IERC20 token, address spender, uint256 amount) external onlyOwner {
token.forceApprove(spender, amount);
emit ApproveToken(token, spender, amount);
}
function setBridgeAddress(address _bridgeAddress) public onlyOwner returns (bool) {
_setBridgeAddress(_bridgeAddress);
return true;
}
function setFeeManager(address _feeManager) public onlyOwner {
if (!_feeManager.isContract()) revert Errors.NOT_CONTRACT();
feeManager = IFeeManager(_feeManager);
emit SetFeeManager(_feeManager);
}
function editFuncBlackList(bytes4 _func, bool _flag) external onlyOwner {
_editFuncBlackList(_func, _flag);
}
function swapAndBridge(
bytes32 _transferId,
address _initiator, // initiator address
address _srcToken,
uint256 _amount,
bytes calldata _swapData,
bytes calldata _bridgeData,
bytes calldata _permitData,
bytes calldata _feeData
) external payable override nonReentrant returns (bytes32 orderId) {
uint256 bridge_len = _bridgeData.length;
if (bridge_len == 0) revert Errors.DATA_EMPTY();
SwapTemp memory swapTemp;
swapTemp.initiator = _initiator;
swapTemp.srcToken = _srcToken;
swapTemp.srcAmount = _amount;
swapTemp.swapToken = _srcToken;
swapTemp.swapAmount = _amount;
swapTemp.transferId = _transferId;
(swapTemp.nativeBalance, swapTemp.inputBalance) = _transferIn(
swapTemp.srcToken,
swapTemp.srcAmount,
_permitData
);
if (_swapData.length != 0) {
(swapTemp.swapToken, swapTemp.swapAmount, ) = _swap(
swapTemp.srcToken,
swapTemp.swapAmount,
swapTemp.inputBalance,
_swapData
);
}
swapTemp.referrer = _getReferrerFromFeeData(_feeData);
bytes memory receiver;
(orderId, swapTemp.toChain, receiver) = _doBridge(
msg.sender,
swapTemp.swapToken,
swapTemp.swapAmount,
_bridgeData
);
emit SwapAndBridge(
swapTemp.referrer,
swapTemp.initiator,
msg.sender,
swapTemp.transferId,
orderId,
swapTemp.srcToken,
swapTemp.swapToken,
swapTemp.srcAmount,
swapTemp.swapAmount,
swapTemp.toChain,
receiver
);
_afterCheck(swapTemp.nativeBalance);
}
function swapAndCall(
bytes32 _transferId,
address _initiator, // initiator address
address _srcToken,
uint256 _amount,
bytes calldata _swapData,
bytes calldata _callbackData,
bytes calldata _permitData,
bytes calldata _feeData
) external payable override nonReentrant {
SwapTemp memory swapTemp;
swapTemp.initiator = _initiator;
swapTemp.srcToken = _srcToken;
swapTemp.srcAmount = _amount;
swapTemp.transferId = _transferId;
(swapTemp.nativeBalance, swapTemp.inputBalance) = _transferIn(
swapTemp.srcToken,
swapTemp.srcAmount,
_permitData
);
if ((_swapData.length + _callbackData.length) == 0) revert Errors.DATA_EMPTY();
FeeDetail memory fd;
(fd, swapTemp.swapAmount, swapTemp.referrer) = _collectFee(swapTemp.srcToken, swapTemp.srcAmount, _feeData);
if (fd.integratorNativeFee + fd.integratorTokenFee + fd.routerNativeFee + fd.routerTokenFee > 0) {
emit CollectFee(
swapTemp.srcToken,
fd.routerReceiver,
fd.integrator,
fd.routerTokenFee,
fd.integratorTokenFee,
fd.routerNativeFee,
fd.integratorNativeFee,
swapTemp.transferId
);
}
(
swapTemp.receiver,
swapTemp.target,
swapTemp.swapToken,
swapTemp.swapAmount,
swapTemp.callAmount
) = _doSwapAndCall(swapTemp.srcToken, swapTemp.swapAmount, swapTemp.inputBalance, _swapData, _callbackData);
if (swapTemp.swapAmount > swapTemp.callAmount) {
_transfer(swapTemp.swapToken, swapTemp.receiver, (swapTemp.swapAmount - swapTemp.callAmount));
}
emit SwapAndCall(
swapTemp.referrer,
swapTemp.initiator,
msg.sender,
swapTemp.transferId,
swapTemp.srcToken,
swapTemp.swapToken,
swapTemp.srcAmount,
swapTemp.swapAmount,
swapTemp.receiver,
swapTemp.target,
swapTemp.callAmount
);
_afterCheck(swapTemp.nativeBalance);
}
function getFee(
address _inputToken,
uint256 _inputAmount,
bytes calldata _feeData
) external view override returns (address feeToken, uint256 tokenFee, uint256 nativeFee, uint256 afterFeeAmount) {
IFeeManager.FeeDetail memory fd = _getFee(_inputToken, _inputAmount, _feeData);
feeToken = fd.feeToken;
(tokenFee, nativeFee, afterFeeAmount) = _calculateFee(_inputToken, _inputAmount, fd);
}
function _calculateFee(
address _inputToken,
uint256 _inputAmount,
IFeeManager.FeeDetail memory fd
) internal pure returns (uint256 tokenFee, uint256 nativeFee, uint256 afterFeeAmount) {
if (_isNative(_inputToken)) {
tokenFee = 0;
nativeFee = fd.routerNativeFee + fd.routerTokenFee + fd.integratorTokenFee + fd.integratorNativeFee;
afterFeeAmount = _inputAmount - nativeFee;
} else {
tokenFee = fd.routerTokenFee + fd.integratorTokenFee;
nativeFee = fd.routerNativeFee + fd.integratorNativeFee;
afterFeeAmount = _inputAmount - tokenFee;
}
}
function _getFee(
address _inputToken,
uint256 _inputAmount,
bytes calldata _feeData
) internal view returns (FeeDetail memory fd) {
if (address(feeManager) == ZERO_ADDRESS) {
fd = _getFeeDetailInternal(_inputToken, _inputAmount, _feeData);
} else {
fd = feeManager.getFeeDetail(_inputToken, _inputAmount, _feeData);
}
}
function getInputBeforeFee(
address _token,
uint256 _amountAfterFee,
bytes calldata _feeData
) external view override returns (address _feeToken, uint256 _input, uint256 _fee) {
if (address(feeManager) == ZERO_ADDRESS) {
return this.getAmountBeforeFee(_token, _amountAfterFee, _feeData);
}
return feeManager.getAmountBeforeFee(_token, _amountAfterFee, _feeData);
}
function _doSwapAndCall(
address _srcToken,
uint256 _amount,
uint256 _initBalance,
bytes calldata _swapData,
bytes calldata _callbackData
) internal returns (address receiver, address target, address dstToken, uint256 swapOutAmount, uint256 callAmount) {
swapOutAmount = _amount;
dstToken = _srcToken;
if (_swapData.length > 0) {
(dstToken, swapOutAmount, receiver) = _swap(_srcToken, _amount, _initBalance, _swapData);
}
if (_callbackData.length > 0) {
(callAmount, receiver, target) = _callBack(swapOutAmount, dstToken, _callbackData);
}
}
function _doBridge(
address _sender,
address _token,
uint256 _amount,
bytes calldata _bridgeData
) internal returns (bytes32 orderId, uint256 toChain, bytes memory receiver) {
BridgeParam memory _bridge = abi.decode(_bridgeData, (BridgeParam));
toChain = _bridge.toChain;
receiver = _bridge.receiver;
address bridge = bridgeAddress;
// not approve (approved by function approveToken)
//uint256 value = _bridge.nativeFee + _approveToken(_token, bridge, _amount);
uint256 value = _isNative(_token) ? (_bridge.nativeFee + _amount) : _bridge.nativeFee;
orderId = IButterBridgeV3(bridge).swapOutToken{value: value}(
_sender,
_token,
receiver,
_amount,
toChain,
_bridge.data
);
}
function _collectFee(
address _token,
uint256 _amount,
bytes calldata _feeData
) internal returns (FeeDetail memory fd, uint256 remain, address referrer) {
fd = _getFee(_token, _amount, _feeData);
referrer = fd.integrator;
if (_isNative(_token)) {
uint256 routerNative = fd.routerNativeFee + fd.routerTokenFee;
if (routerNative > 0) {
_transfer(_token, fd.routerReceiver, routerNative);
}
uint256 integratorNative = fd.integratorTokenFee + fd.integratorNativeFee;
if (integratorNative > 0) {
_transfer(_token, fd.integrator, integratorNative);
}
remain = _amount - routerNative - integratorNative;
} else {
if (fd.routerNativeFee > 0) {
_transfer(ZERO_ADDRESS, fd.routerReceiver, fd.routerNativeFee);
}
if (fd.routerTokenFee > 0) {
_transfer(_token, fd.routerReceiver, fd.routerTokenFee);
}
if (fd.integratorNativeFee > 0) {
_transfer(ZERO_ADDRESS, fd.integrator, fd.integratorNativeFee);
}
if (fd.integratorTokenFee > 0) {
_transfer(_token, fd.integrator, fd.integratorTokenFee);
}
remain = _amount - fd.routerTokenFee - fd.integratorTokenFee;
if (fd.routerNativeFee + fd.integratorNativeFee > msg.value) revert Errors.FEE_MISMATCH();
}
if (remain == 0) revert Errors.ZERO_IN();
}
function _setBridgeAddress(address _bridgeAddress) internal {
if (!_bridgeAddress.isContract()) revert Errors.NOT_CONTRACT();
bridgeAddress = _bridgeAddress;
emit SetBridgeAddress(_bridgeAddress);
}
function _transferIn(
address token,
uint256 amount,
bytes calldata permitData
) internal returns (uint256 nativeBalanceBeforeExec, uint256 initInputTokenBalance) {
if (amount == 0) revert Errors.ZERO_IN();
address self = address(this);
if (permitData.length != 0) {
_permit(permitData);
}
nativeBalanceBeforeExec = self.balance - msg.value;
if (_isNative(token)) {
if (msg.value < amount) revert Errors.FEE_MISMATCH();
//extra value maybe used for call native or bridge native fee
initInputTokenBalance = self.balance - amount;
} else {
initInputTokenBalance = _getBalance(token, self);
SafeERC20.safeTransferFrom(IERC20(token), msg.sender, self, amount);
}
}
function _getReferrerFromFeeData(bytes calldata feeData) internal pure returns (address referrer) {
if (feeData.length < 64) return referrer;
assembly {
referrer := calldataload(add(feeData.offset, 32))
}
}
function _permit(bytes calldata _data) internal {
(
address token,
address owner,
address spender,
uint256 value,
uint256 deadline,
uint8 v,
bytes32 r,
bytes32 s
) = abi.decode(_data, (address, address, address, uint256, uint256, uint8, bytes32, bytes32));
SafeERC20.safePermit(IERC20Permit(token), owner, spender, value, deadline, v, r, s);
}
function rescueFunds(address _token, uint256 _amount) external onlyOwner {
_transfer(_token, msg.sender, _amount);
}
receive() external payable {}
}
Chain explorer1961msChain node88ms