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
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