Overview
S Balance
S Value
$0.00More Info
Private Name Tags
ContractCreator
Loading...
Loading
Contract Name:
XBridge
Compiler Version
v0.8.19+commit.7dd6d404
Optimization Enabled:
Yes with 200 runs
Other Settings:
default evmVersion
Contract Source Code (Solidity Standard Json-Input format)
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; pragma abicoder v2; import "@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol"; import "@openzeppelin/contracts-upgradeable/security/PausableUpgradeable.sol"; import "@openzeppelin/contracts-upgradeable/security/ReentrancyGuardUpgradeable.sol"; import "@openzeppelin/contracts-upgradeable/token/ERC20/utils/SafeERC20Upgradeable.sol"; import "@openzeppelin/contracts-upgradeable/token/ERC20/IERC20Upgradeable.sol"; import "@openzeppelin/contracts/token/ERC20/extensions/draft-IERC20Permit.sol"; import "./adaptor/BridgeAdaptorBase.sol"; import "./helpers/Constants.sol"; import "./helpers/Errors.sol"; import "./interfaces/IDaiLikePermit.sol"; import "./interfaces/IApproveProxy.sol"; import "./interfaces/IWNativeRelayer.sol"; import "./interfaces/IWETH.sol"; import "./libraries/Bytes.sol"; import "./libraries/RevertReasonParser.sol"; import "./libraries/CommissionLib.sol"; /** * @title XBridge * @notice Entrance for Bridge * - Users can: * # Bridge: Initiate cross-chain asset transfers. * # Swap and bridge: Perform token swaps and initiate cross-chain transfers. * @dev XBridge is a smart contract that serves as the entrance for cross-chain operations, * allowing users to interact with various functionalities such as bridging assets, * swapping and bridging tokens, and claiming assets on the destination chain. */ contract XBridge is PausableUpgradeable, OwnableUpgradeable, ReentrancyGuardUpgradeable, CommissionLib { using SafeERC20Upgradeable for IERC20Upgradeable; // Struct representing the information needed for a bridge transaction struct BridgeRequestV2 { uint256 adaptorId; address to; address token; uint256 toChainId; // orderId[64bit] | gasFeeAmount[160] | target chainId[32bit] uint256 amount; bytes data; // router data bytes extData; } // Struct representing the information needed for a swap and bridge transaction struct SwapBridgeRequestV2 { address fromToken; // the source token address toToken; // the token to be bridged address to; // the address to be bridged to uint256 adaptorId; uint256 toChainId; // orderId[64bit] | gasFeeAmount[160] | target chainId[32bit] uint256 fromTokenAmount; // the source token amount uint256 toTokenMinAmount; uint256 toChainToTokenMinAmount; bytes data; // router data bytes dexData; // the call data for dexRouter bytes extData; } // Struct representing the information needed for a swap transaction struct SwapRequest { address fromToken; address toToken; address to; uint256 amount; // amount of swapped fromToken uint256 gasFeeAmount; // tx gas fee slash from fromToken uint256 srcChainId; bytes32 srcTxHash; bytes dexData; bytes extData; } // Struct representing the information needed for receiving gas tokens on another chain struct ReceiveGasRequest { address to; uint256 amount; uint256 srcChainId; bytes32 srcTxHash; bytes extData; } // Struct representing a threshold configuration for a specific address struct Threshold { bool opened; uint256 amount; } // Struct representing information related to an oracle, used for verifying certain transactions struct OracleInfo { uint256 srcChainId; bytes32 txHash; bytes32 to; bytes32 token; uint256 amount; uint256 actualAmount; } //------------------------------- //------- storage --------------- //------------------------------- mapping(uint256 => address) public adaptorInfo; /** * @dev This state variable is deprecated and should not be used anymore. */ address public approveProxy; address public dexRouter; address public payer; address public receiver; address public feeTo; address public admin; mapping(address => bool) public mpc; mapping(uint256 => mapping(bytes32 => bool)) public paidTx; mapping(uint256 => mapping(bytes32 => bool)) public receiveGasTx; /** * @dev Set by admin */ mapping(uint256 => uint256) public sysRatio; /** * @dev This state variable is deprecated and should not be used anymore. */ mapping(uint256 => address) public sysAddressConfig; mapping(address => Threshold) public thresholdConfig; mapping(address => bool) public proxies; // oracle proxy mapping(bytes4 => bool) public accessSelectorId; // for swap /** * @notice Initializes the XBridge contract. * @dev This function is part of the Upgradable pattern and is called once to initialize contract state. * It sets up the initial state by invoking the initializers of the inherited contracts. * The `admin` variable is set to the address of the account that deploys the contract. * Note: This function is meant to be called only once during the contract deployment. */ function initialize() public initializer { __Pausable_init(); __ReentrancyGuard_init(); __Ownable_init(); admin = msg.sender; } /// @custom:oz-upgrades-unsafe-allow constructor constructor() { _disableInitializers(); } //------------------------------- //------- Events ---------------- //------------------------------- event DexRouterChanged(address _dexRouter); /** * @notice Event emitted when a bridge transaction occurs */ event LogBridgeTo( uint256 indexed _adaptorId, address _from, address _to, address _token, uint256 _amount, uint256 _receiveFee, bytes32[] ext ); /** * @notice Event emitted when a swap and bridge transaction occurs */ event LogSwapAndBridgeTo( uint256 indexed _adaptorId, address _from, address _to, address _fromToken, uint256 _fromAmount, address _toToken, uint256 _toAmount, uint256 _receiveFee, bytes32[] ext ); event FeeToChanged(address _feeTo); event AdminChanged(address _newAdmin); event GasTokenReceived( address to, uint256 amount, uint256 srcChainId, bytes32[] ext ); /** * @notice Event emitted when a claim transaction occurs */ event Claimed( address to, address fromToken, address toToken, uint256 fromTokenAmount, uint256 toTokenAmount, uint256 gasFeeAmount, uint256 srcChainId, string errInfo, bytes32[] ext ); event AdaptorsChanged(uint256 indexed _adaptorId, address _adaptor); event MpcChanged(address _mpc, bool _enable); event SysRatioChanged(uint256 _index, uint256 _ratio); event ProxiesChanged(address _proxy, bool _enable); event AccessSelectorIdChanged(bytes4 _selectorId, bool _enable); //------------------------------- //------- Modifier -------------- //------------------------------- modifier onlyMPC() { require(mpc[msg.sender], XBridgeErrors.ONLY_MPC); _; } modifier onlyAdmin() { require(msg.sender == admin, XBridgeErrors.ONLY_ADMIN); _; } //------------------------------- //------- Internal Functions ---- //------------------------------- /** * @notice Internal pure function to extract information from a packed uint256 value representing gas receive details * @param toChainId Packed uint256 value containing order ID, gas fee amount, and chain ID */ function _getGasReceiveAmount(uint256 toChainId) internal pure returns ( uint256 orderId, uint256 gasFeeAmount, uint256 chainId ) { orderId = (toChainId & 0xffffffffffffffff000000000000000000000000000000000000000000000000) >> 192; gasFeeAmount = (toChainId & 0x0000000000000000ffffffffffffffffffffffffffffffffffffffff00000000) >> 32; chainId = toChainId & 0x00000000000000000000000000000000000000000000000000000000ffffffff; } /** * @notice Internal function to perform a token deposit operation. * @dev Ensures that the caller has sufficient allowance to deposit the specified amount of tokens. * @param from The address from which tokens are transferred. * @param to The recipient address to receive the deposited tokens. * @param token The address of the ERC20 token being deposited. * @param amount The amount of tokens to be deposited. */ function _deposit( address from, address to, address token, uint256 amount ) internal { IApproveProxy(XBridgeConstants.APPROVE_PROXY).claimTokens(token, from, to, amount); } function _getBalanceOf(address token) internal view returns (uint256) { return _getBalanceOf(token, address(this)); } function _getBalanceOf(address token, address who) internal view returns(uint256) { return token == XBridgeConstants.NATIVE_TOKEN ? who.balance : IERC20Upgradeable(token).balanceOf(who); } /** * @notice Internal function to transfer ERC20 tokens or native tokens (ETH) to a specified address. * @param to The address to which tokens are transferred. * @param token The address of the ERC20 token to be transferred. * @param amount The amount of tokens to be transferred. */ function _transferToken(address to, address token, uint256 amount) internal { if (amount > 0) { if (token == XBridgeConstants.NATIVE_TOKEN) { (bool success, ) = payable(to).call{value: amount}(""); require(success, XBridgeErrors.TRANSFER_ETH_FAILD); } else { IERC20Upgradeable(token).safeTransfer(to, amount); } } } /** * @notice Internal pure function to construct extension data for cross-chain transaction. * @param orderId The unique identifier for the cross-chain transaction. * @param toChainId The identifier of the target chain. * @param adaptorId The identifier of the cross-chain adaptor used. * @param to The destination address on the target chain. * @param data Additional data specific to the cross-chain adaptor. * @param extData Additional extension data containing user-specific information. * @return ext An array of bytes32 values representing the constructed extension data. */ function _constructExt(uint256 orderId, uint256 toChainId, uint256 adaptorId, address to, bytes memory data, bytes memory extData) internal pure returns(bytes32[] memory ext) { ext = new bytes32[](6); ext[0] = bytes32(orderId); ext[1] = bytes32(toChainId); if (adaptorId == XBridgeConstants.ADAPTER_ID_ANYSWAP || adaptorId == XBridgeConstants.ADAPTER_ID_CBRIDGE) { ext[2] = bytes32(abi.encodePacked(to)); ext[3] = bytes32(abi.encodePacked("")); } else if (adaptorId == XBridgeConstants.ADAPTER_ID_SWFT) { (,,string memory destination,) = abi.decode(data, (address, string, string, uint256)); bytes32[] memory destBytes32Arr = Bytes.bytesToBytes32Array(bytes(destination)); ext[2] = destBytes32Arr[0]; if (destBytes32Arr.length > 1) { ext[3] = destBytes32Arr[1]; } } if (extData.length > 0) { (string memory userAddress) = abi.decode(extData, (string)); bytes32[] memory userAddressBytes32Arr = Bytes.bytesToBytes32Array(bytes(userAddress)); ext[4] = userAddressBytes32Arr[0]; if (userAddressBytes32Arr.length > 1) { ext[5] = userAddressBytes32Arr[1]; } } else { ext[4] = ext[2]; ext[5] = ext[3]; } return ext; } /** * @notice Struct to represent the result of a commission operation. */ struct CommissionReturn { uint256 commissionAmount; // commission amount bytes extDataWithoutLast32; // extData without last 32 bytes } /** * @notice Internal function to initiate a cross-chain transaction using the specified BridgeRequestV2 parameters. * @param _request The BridgeRequestV2 struct containing transaction details. * @dev Performs necessary validations, token transfers, and calls the outboundBridgeTo function on the selected adaptor. */ function _bridgeToV2Internal(BridgeRequestV2 memory _request) internal { require(_request.adaptorId != 0, XBridgeErrors.INVALID_ADAPTOR_ID); address adaptor = adaptorInfo[_request.adaptorId]; require(adaptor != address(0), XBridgeErrors.INVALID_ADAPTOR_ADDRESS); require(_request.to != address(0), XBridgeErrors.ADDRESS_0); require(_request.token != address(0), XBridgeErrors.ADDRESS_0); require(_request.amount != 0, XBridgeErrors.AMOUNT_ZERO); // doCommission CommissionReturn memory vars; (vars.commissionAmount, vars.extDataWithoutLast32) = _doCommission(_request.amount, _request.token, _request.extData); _request.extData = vars.extDataWithoutLast32; uint256 ethValue = msg.value; // Extract gas fee details from toChainId (uint256 orderId, uint256 gasFeeAmount, uint256 toChainId) = _getGasReceiveAmount(_request.toChainId); if (_request.token == XBridgeConstants.NATIVE_TOKEN) { require(msg.value >= _request.amount + gasFeeAmount + vars.commissionAmount, XBridgeErrors.INVALID_MSG_VALUE); ethValue -= vars.commissionAmount; // after docommission if (gasFeeAmount > 0) { (bool success, ) = payable(feeTo).call{value: gasFeeAmount}(""); require(success, XBridgeErrors.TRANSFER_ETH_FAILD); ethValue -= gasFeeAmount; } } else { if (gasFeeAmount > 0) { _deposit(msg.sender, feeTo, _request.token, gasFeeAmount); } _deposit(msg.sender, adaptor, _request.token, _request.amount); } // Call the outboundBridgeTo function on the selected adaptor BridgeAdaptorBase(payable(adaptor)).outboundBridgeTo{value : ethValue}( msg.sender, _request.to, msg.sender, // refund to msg.sender _request.token, _request.amount, toChainId, _request.data ); // Construct extension data and emit the LogBridgeTo event bytes32[] memory ext = _constructExt( orderId, toChainId, _request.adaptorId, _request.to, _request.data, _request.extData ); emit LogBridgeTo( _request.adaptorId, msg.sender, _request.to, _request.token, _request.amount, gasFeeAmount, ext ); } /** * @notice Struct to represent the result of a cross-chain bridge operation. * @dev Holds information about the adaptor, token balances, gas fee, chain ID, order ID, success status, function selector, and result data. */ struct BridgeVariants { address adaptor; uint256 toTokenBalance; uint256 toTokenBalanceOrigin; uint256 gasFeeAmount; uint256 toChainId; uint256 orderId; bool success; bytes4 selectorId; bytes result; } /** * @notice Internal function to perform a token swap and bridge operation using the specified SwapBridgeRequestV2 parameters. * @param _request The SwapBridgeRequestV2 struct containing swap and bridge details. * @dev Performs necessary validations, token swaps, bridge calls, and balance checks. */ function _swapBridgeToInternal(SwapBridgeRequestV2 memory _request) internal { BridgeVariants memory vars; require(_request.adaptorId != 0, XBridgeErrors.INVALID_ADAPTOR_ID); vars.adaptor = adaptorInfo[_request.adaptorId]; require(vars.adaptor != address(0), XBridgeErrors.INVALID_ADAPTOR_ADDRESS); require(_request.fromToken != address(0), XBridgeErrors.ADDRESS_0); require(_request.toToken != address(0), XBridgeErrors.ADDRESS_0); require(_request.fromToken != _request.toToken, XBridgeErrors.ADDRESS_EQUAL); require(_request.to != address(0), XBridgeErrors.ADDRESS_0); require(dexRouter != address(0), XBridgeErrors.ADDRESS_0); require(_request.fromTokenAmount != 0, XBridgeErrors.AMOUNT_ZERO); require(_request.toTokenMinAmount != 0, XBridgeErrors.MIN_AMOUNT_ZERO); // Extract gas fee details from toChainId (vars.orderId, vars.gasFeeAmount, vars.toChainId) = _getGasReceiveAmount(_request.toChainId); vars.toTokenBalanceOrigin = _getBalanceOf(_request.toToken); // Validate the dexData function selector require(accessSelectorId[bytes4(_request.dexData)], XBridgeErrors.ERROR_SELECTOR_ID); // Set payer and receiver addresses for potential refund payer = msg.sender; receiver = address(this); // doCommission (uint256 commissionAmount, bytes memory extDataWithoutLast32) = _doCommission(_request.fromTokenAmount, _request.fromToken, _request.extData); _request.extData = extDataWithoutLast32; // 1. prepare and swap if (_request.fromToken == XBridgeConstants.NATIVE_TOKEN) { //FROM NATIVE require(msg.value - commissionAmount >= _request.fromTokenAmount, XBridgeErrors.INVALID_MSG_VALUE); if (_request.toToken == XBridgeConstants.WETH) { //ETH => WETH vars.success = _swapWrap(address(this), address(this), _request.fromTokenAmount, false); } else { // ETH => ERC20, use dexRouter (vars.success, vars.result) = dexRouter.call{value : _request.fromTokenAmount}(_request.dexData); } } else { // FROM ERC20 if (_request.fromToken == XBridgeConstants.WETH && _request.toToken == XBridgeConstants.NATIVE_TOKEN) { // WETH => ETH vars.success = _swapWrap(msg.sender, address(this), _request.fromTokenAmount, true); } else { // ERC20 => ERC20, use dexRouter (vars.success, vars.result) = dexRouter.call(_request.dexData); } } delete payer; delete receiver; // 2. check result and balance require(vars.success,vars.result.length == 0 ? XBridgeErrors.INTERNAL_WRAP_FAIL : RevertReasonParser.parse(vars.result, XBridgeErrors.DEX_ROUTER_ERR)); vars.toTokenBalance = _getBalanceOf(_request.toToken) - vars.toTokenBalanceOrigin; // toToken added require(vars.toTokenBalance >= vars.gasFeeAmount + _request.toTokenMinAmount, XBridgeErrors.MIN_AMOUNT_ERR); // 3. Receive to token for relay gas token on target chain to user _transferToken(feeTo, _request.toToken, vars.gasFeeAmount); // 4. Bridge the toToken to the target chain vars.toTokenBalance = vars.toTokenBalance - vars.gasFeeAmount; if (_request.toToken == XBridgeConstants.NATIVE_TOKEN) { // Internal with BridgeAdaptorBase, so it is safe to use payable BridgeAdaptorBase(payable(vars.adaptor)).outboundBridgeTo{ value: vars.toTokenBalance + msg.value }( msg.sender, _request.to, msg.sender, // refund to msg.sender _request.toToken, vars.toTokenBalance, vars.toChainId, _request.data ); } else { _transferToken(vars.adaptor, _request.toToken, vars.toTokenBalance); if (_request.fromToken == XBridgeConstants.NATIVE_TOKEN){ BridgeAdaptorBase(payable(vars.adaptor)).outboundBridgeTo{value : msg.value - commissionAmount - _request.fromTokenAmount }( msg.sender, _request.to, msg.sender, // refund to msg.sender _request.toToken, vars.toTokenBalance, vars.toChainId, _request.data ); } else { BridgeAdaptorBase(payable(vars.adaptor)).outboundBridgeTo{value : msg.value }( msg.sender, _request.to, msg.sender, // refund to msg.sender _request.toToken, vars.toTokenBalance, vars.toChainId, _request.data ); } } // Construct extension data and emit the LogBridgeTo event bytes32[] memory ext = _constructExt( vars.orderId, vars.toChainId, _request.adaptorId, _request.to, _request.data, _request.extData ); emit LogSwapAndBridgeTo( _request.adaptorId, msg.sender, _request.to, _request.fromToken, _request.fromTokenAmount, _request.toToken, vars.toTokenBalance, vars.gasFeeAmount, ext ); // 5. Check balance if (_request.toToken == XBridgeConstants.NATIVE_TOKEN){ // if toToken equal nativeToken, should add msg.value require(_getBalanceOf(_request.toToken) + msg.value >= vars.toTokenBalanceOrigin, XBridgeErrors.SLASH_MUCH_TOO_MONEY); } else { require(_getBalanceOf(_request.toToken) >= vars.toTokenBalanceOrigin, XBridgeErrors.SLASH_MUCH_TOO_MONEY); } } /** * @notice Internal function to execute a permit on an ERC20 token if a permit data is provided. * @param token Address of the ERC20 token. * @param permit Permit data containing the necessary parameters for the permit function. */ function _permit(address token, bytes calldata permit) internal { if (permit.length > 0) { bool success; bytes memory result; if (permit.length == 32 * 7) { // solhint-disable-next-line avoid-low-level-calls (success, result) = token.call(abi.encodePacked(IERC20Permit.permit.selector, permit)); } else if (permit.length == 32 * 8) { // solhint-disable-next-line avoid-low-level-calls (success, result) = token.call(abi.encodePacked(IDaiLikePermit.permit.selector, permit)); } else { revert("Wrong permit length"); } if (!success) { revert(RevertReasonParser.parse(result, "Permit failed: ")); } } } /** * @notice Internal function to receive gas tokens from the source chain and transfer them to the specified recipient. * @param _request The ReceiveGasRequest struct containing details about the gas token receipt. * @dev Performs necessary validations, updates state, and emits the GasTokenReceived event. */ function _receiveGasTokenInternal(ReceiveGasRequest memory _request) internal { require(_request.amount <= sysRatio[XBridgeConstants.GAS_TOKEN_RECEIVE_MAX_INDEX], XBridgeErrors.EXCEED_ALLOWED_GAS); require(!receiveGasTx[_request.srcChainId][_request.srcTxHash], XBridgeErrors.HAS_RECEIVE_GAS); receiveGasTx[_request.srcChainId][_request.srcTxHash] = true; _transferToken(_request.to, XBridgeConstants.NATIVE_TOKEN, _request.amount); bytes32[] memory ext = new bytes32[](1); ext[0] = _request.srcTxHash; emit GasTokenReceived(_request.to, _request.amount, _request.srcChainId, ext); } /** * @notice Internal function to decode a message and its signature to extract relevant information. * @param _message The encoded message containing information about the oracle request. * @param _signature The signature of the message for authentication. * @return source The address of the message sender recovered from the signature. * @return thisChainId The chain ID of this contract. * @return thisContractAddress The address of this contract. * @return oracleInfo An OracleInfo struct containing details of the oracle request. * @dev Decodes the message and signature to extract source address, chain ID, contract address, and oracle request details. */ function _decode(bytes memory _message, bytes memory _signature) internal pure returns ( address source, uint256 thisChainId, address thisContractAddress, OracleInfo memory oracleInfo ) { { // fix Stack too deep (bytes32 r, bytes32 s, uint8 v) = abi.decode(_signature, (bytes32, bytes32, uint8)); bytes32 hash = keccak256(abi.encodePacked("\x19Ethereum Signed Message:\n32", keccak256(_message))); source = ecrecover(hash, v, r, s); } ( thisChainId, thisContractAddress, oracleInfo.srcChainId, oracleInfo.txHash, oracleInfo.to, oracleInfo.token, oracleInfo.amount, oracleInfo.actualAmount ) = abi.decode(_message, (uint256, address, uint256, bytes32, bytes32, bytes32, uint256, uint256)); return (source, thisChainId, thisContractAddress, oracleInfo); } /** * @notice Internal function to verify the oracle signature and details for a swap request. * @param _request The SwapRequest struct containing swap details. * @param _amount The amount to be verified against the oracle threshold. * @dev Verifies the oracle signature, source address, and additional details for the swap request. */ function _verifyOracle( SwapRequest memory _request, uint256 _amount ) view internal { (bytes memory message, bytes memory signature) = abi.decode(_request.extData, (bytes, bytes)); ( address source, uint256 thisChainId, address thisContractAddress, OracleInfo memory oracleInfo ) = _decode(message, signature); // Validate the source address, oracle proxy status, chain ID, contract address, and request details require(source != address(0), XBridgeErrors.ZERO_SIGNER); require(proxies[source], XBridgeErrors.NOT_ORACLE_PROXY); require(thisChainId == sysRatio[XBridgeConstants.CHAIN_ID_INDEX], XBridgeErrors.ERR_CHAIN_ID); require(thisContractAddress == address(this), XBridgeErrors.CONTRACT_ADDRESS_ERROR); require(_request.srcTxHash == oracleInfo.txHash, XBridgeErrors.ORACLE_NO_INFO); require(_request.to == address(uint160(uint256(oracleInfo.to))), XBridgeErrors.ORACLE_TO_ADDRESS_ERR); require(_request.fromToken == address(uint160(uint256(oracleInfo.token))), XBridgeErrors.ORACLE_TOKEN_ADDRESS_ERR); // Calculate the high threshold based on the actualAmount and configured ratio uint256 ratio = sysRatio[XBridgeConstants.CLAIM_TOKEN_RATIO_MAX_INDEX]; uint256 high = oracleInfo.actualAmount * (ratio + XBridgeConstants.DEFAULT_RATIO_BASE) / XBridgeConstants.DEFAULT_RATIO_BASE; // Check if the requested amount is within the allowed high threshold require(_amount <= high, XBridgeErrors.ORACLE_TOKEN_AMOUNT_ERR); } /** * @notice Internal function to process the claim for a swap request, including gas fee handling and token transfer. * @param _request The SwapRequest struct containing swap details. * @dev Verifies the oracle, handles gas fees, performs token swap or transfer and emits the Claimed event. */ function _claimInternal(SwapRequest memory _request) internal { uint256 fromTokenOriginBalance = _getBalanceOf(_request.fromToken); // Calculate the total amount needed, including swap amount and gas fees uint256 fromTokenNeed = _request.amount + _request.gasFeeAmount; // Verify the oracle signature and threshold for the source token _verifyOracle(_request, fromTokenNeed); require(fromTokenOriginBalance >= fromTokenNeed, XBridgeErrors.NO_ENOUGH_MONEY); require(dexRouter != address(0), XBridgeErrors.ADDRESS_0); require(!paidTx[_request.srcChainId][_request.srcTxHash], XBridgeErrors.HAS_PAID); paidTx[_request.srcChainId][_request.srcTxHash] = true; // Initialize extension data for the Claimed event bytes32[] memory ext = new bytes32[](1); ext[0] = _request.srcTxHash; bool success; bytes memory result; string memory errInfo; // 1. Handle gas fee _transferToken(feeTo, _request.fromToken, _request.gasFeeAmount); // 2. Perform token swap or transfer to the user if (_request.dexData.length > 0) { // swap uint256 toTokenReceiverBalance = _getBalanceOf(_request.toToken, _request.to); // Exchange anypair using the dexRouter except WETH<=>ETH payer = address(this); receiver = _request.to; if (_request.fromToken == XBridgeConstants.NATIVE_TOKEN) { // FROM NATIVE if (_request.toToken == XBridgeConstants.WETH) { // ETH => WETH success = _swapWrap(address(this), _request.to, _request.amount, false); if (!success) { errInfo = XBridgeErrors.INTERNAL_WRAP_FAIL; } } else { // ETH => ERC20, use dexRouter (success, result) = dexRouter.call{value : _request.amount}(_request.dexData); } } else { // FROM ERC20 if (_request.fromToken == XBridgeConstants.WETH && _request.toToken == XBridgeConstants.NATIVE_TOKEN) { // WETH => ETH success =_swapWrap(address(this), _request.to, _request.amount, true); if (!success) { errInfo = XBridgeErrors.INTERNAL_WRAP_FAIL; } } else { // ERC20 => ERC20, use dexRouter address tokenApprove = IApproveProxy(XBridgeConstants.APPROVE_PROXY).tokenApprove(); IERC20Upgradeable(_request.fromToken).safeApprove(tokenApprove, _request.amount); (success, result) = dexRouter.call(_request.dexData); if (IERC20Upgradeable(_request.fromToken).allowance(address(this), tokenApprove) != 0){ IERC20Upgradeable(_request.fromToken).safeApprove(tokenApprove, 0); } } } if (!success && result.length > 0) { errInfo = RevertReasonParser.parse(result, XBridgeErrors.DEX_ROUTER_ERR); } delete payer; // payer = 0; delete receiver; if (!success) { // transfer fromToken if swap failed _transferToken(_request.to, _request.fromToken, _request.amount); emit Claimed(_request.to, _request.fromToken, _request.toToken, _request.amount, 0, _request.gasFeeAmount, _request.srcChainId, errInfo, ext); } else { toTokenReceiverBalance = _getBalanceOf(_request.toToken, _request.to) - toTokenReceiverBalance; emit Claimed(_request.to, _request.fromToken, _request.toToken, 0, toTokenReceiverBalance, _request.gasFeeAmount, _request.srcChainId, errInfo, ext); } } else { // transfer token errInfo = XBridgeConstants.__REFUND__; _transferToken(_request.to, _request.fromToken, _request.amount); emit Claimed(_request.to, _request.fromToken, _request.toToken, _request.amount, 0, _request.gasFeeAmount, _request.srcChainId, errInfo, ext); } // 3. Check the final balance of the source token require(fromTokenOriginBalance - _getBalanceOf(_request.fromToken) <= fromTokenNeed, XBridgeErrors.SLASH_MUCH_TOO_MONEY); } /** * @dev Internal function to swap and wrap tokens. * @param from The address to transfer the tokens from. * @param to The address to transfer the wrapped tokens to. * @param amount The amount of tokens to swap and wrap. * @param reversed Boolean indicating whether the swap is reversed (WETH => ETH). * @return A boolean indicating the success of the swap and wrap operation. */ function _swapWrap( address from, address to, uint256 amount, bool reversed ) internal returns (bool) { require(amount > 0, XBridgeErrors.WRAP_AMOUNT_ZERO); if (reversed) { // reversed == true: WETH => ETH if (from == address(this)){ IWETH(address(uint160(XBridgeConstants.WETH))).transfer(XBridgeConstants.WNATIVE_RELAY, amount); } else { _deposit(from, XBridgeConstants.WNATIVE_RELAY, XBridgeConstants.WETH, amount); } IWNativeRelayer(XBridgeConstants.WNATIVE_RELAY).withdraw(amount); if (to != address(this)){ (bool success, ) = payable(to).call{value: amount}(""); require(success, XBridgeErrors.TRANSFER_ETH_FAILD); } } else { // reversed == false: ETH => WETH IWETH(XBridgeConstants.WETH).deposit{value: amount}(); if (to != address(this)){ IERC20Upgradeable(XBridgeConstants.WETH).safeTransfer(to, amount); } } return true; } /** * @notice Internal function to handle commission logic * @param inputAmount The amount of tokens to be transferred. * @param commissionToken The address of the ERC20 token to be transferred. * @param extData Additional extension data containing user-specific information. * @return commissionAmount The amount of commission tokens to be transferred. * @return extDataWithoutLast32 Additional extension data containing user-specific information without last 32 bytes. */ function _doCommission( uint256 inputAmount, address commissionToken, bytes memory extData) internal returns (uint256 commissionAmount, bytes memory extDataWithoutLast32) { // Retrieve commission info from the last 32 bytes of extData uint256 commissionInfo; assembly { commissionInfo := calldataload(sub(calldatasize(),0x20)) } if ((commissionInfo & _COMMISSION_FLAG_MASK) == OKX_COMMISSION) { // 0. decode the commissionInfo address referrerAddress = address(uint160(commissionInfo & _REFERRER_MASK)); uint256 commissionRate = uint256((commissionInfo & _COMMISSION_FEE_MASK) >> 160); // 1. Check the commission ratio. CommissionFeeAmount = fromTokenAmount * Rate / (10000 - Rate) require(commissionRate <= commissionRateLimit, XBridgeErrors.COMMISSION_ERROR_RATE); commissionAmount = (inputAmount * commissionRate) / (10000 - commissionRate); // 2. Perform commission if (commissionToken == XBridgeConstants.NATIVE_TOKEN) { (bool success,) = payable(referrerAddress).call{value: commissionAmount}(""); require(success, XBridgeErrors.COMMISSION_ERROR_ETHER); } else { _deposit(msg.sender, referrerAddress, commissionToken, commissionAmount); } // 3. Restore extData uint256 extDataSize = extData.length; extDataWithoutLast32 = new bytes(extDataSize - 32); for (uint256 i = 0; i < extDataSize - 32; i++) { extDataWithoutLast32[i] = extData[i]; } emit CommissionRecord(commissionAmount, referrerAddress); } else { extDataWithoutLast32 = extData; } } //------------------------------- //------- Admin functions ------- //------------------------------- function setAdmin(address _newAdmin) external onlyOwner { require(_newAdmin != address(0), XBridgeErrors.ADDRESS_0); admin = _newAdmin; emit AdminChanged(_newAdmin); } function setDexRouter(address _newDexRouter) external onlyAdmin { require(_newDexRouter != address(0), XBridgeErrors.ADDRESS_0); dexRouter = _newDexRouter; emit DexRouterChanged(_newDexRouter); } function pause() external onlyAdmin { _pause(); } function unpause() external onlyAdmin { _unpause(); } function setAdaptors(uint256[] calldata _ids, address[] calldata _adaptors) external onlyAdmin { require(_ids.length == _adaptors.length, XBridgeErrors.LENGTH_NOT_EQUAL); for (uint256 i = 0; i < _ids.length; i++) { adaptorInfo[_ids[i]] = _adaptors[i]; emit AdaptorsChanged(_ids[i], _adaptors[i]); } } function setFeeTo(address _newFeeTo) external onlyAdmin { require(_newFeeTo != address(0), XBridgeErrors.ADDRESS_0); feeTo = _newFeeTo; emit FeeToChanged(_newFeeTo); } function setMpc(address[] memory _mpcList, bool[] memory _v) external onlyAdmin { require(_mpcList.length == _v.length, XBridgeErrors.LENGTH_NOT_EQUAL); for (uint256 i = 0; i < _mpcList.length; i++) { mpc[_mpcList[i]] = _v[i]; emit MpcChanged(_mpcList[i], _v[i]); } } function setSysRatio(uint256 _index, uint256 _v) external onlyAdmin { sysRatio[_index] = _v; emit SysRatioChanged(_index, _v); } function setProxies(address[] memory proxiesList, bool[] memory values) external onlyAdmin { require(proxiesList.length == values.length, XBridgeErrors.LENGTH_NOT_EQUAL); for (uint256 i = 0; i < proxiesList.length; i++) { proxies[proxiesList[i]] = values[i]; emit ProxiesChanged(proxiesList[i], values[i]); } } function setAccessSelectorId(bytes4[] memory selectorIds, bool[] memory values) external onlyAdmin{ require(selectorIds.length == values.length, XBridgeErrors.LENGTH_NOT_EQUAL); for (uint256 i = 0; i < selectorIds.length; i++) { accessSelectorId[selectorIds[i]] = values[i]; emit AccessSelectorIdChanged(selectorIds[i], values[i]); } } //------------------------------- //------- Users Functions ------- //------------------------------- /** * @notice Initiates the bridge operation to transfer assets to another chain using the bridge. * @param _request The BridgeRequestV2 struct containing the details of the bridge operation. */ function bridgeToV2(BridgeRequestV2 memory _request) external payable nonReentrant whenNotPaused { _bridgeToV2Internal(_request); } /** * @notice Initiates a swap and bridge operation using the bridge. * @param _request The SwapBridgeRequestV2 struct containing the details of the swap and bridge operation. */ function swapBridgeToV2(SwapBridgeRequestV2 memory _request) public payable nonReentrant whenNotPaused { _swapBridgeToInternal(_request); } /** * @notice Initiates a swap and bridge operation with permit using V2 of the bridge. * @param _request The SwapBridgeRequestV2 struct containing the details of the swap and bridge operation. * @param _signature The permit signature for the fromToken. */ function swapBridgeToWithPermit( SwapBridgeRequestV2 calldata _request, bytes calldata _signature ) external nonReentrant whenNotPaused { _permit(_request.fromToken, _signature); _swapBridgeToInternal(_request); } /** * @notice Completed receiving gas tokens from the source chain. * @param _request The ReceiveGasRequest struct containing the details of this operation. */ function receiveGasToken(ReceiveGasRequest memory _request) public payable nonReentrant whenNotPaused onlyMPC { require(msg.value == _request.amount, XBridgeErrors.INVALID_MSG_VALUE); _receiveGasTokenInternal(_request); } /** * @notice Claims the assets on the current chain as part of the cross-chain swap. * @param _request The SwapRequest struct containing details of the asset claiming operation. */ function claim(SwapRequest memory _request) public nonReentrant whenNotPaused onlyMPC { _claimInternal(_request); } /** * @notice Performs batch operations including Gas Token receiving and asset claiming. * @param _gasRequest Array of ReceiveGasRequest structs containing details of Gas Token receiving operations. * @param _claimRequest Array of SwapRequest structs containing details of asset claiming operations. */ function doBatch(ReceiveGasRequest[] memory _gasRequest, SwapRequest[] memory _claimRequest) public payable nonReentrant whenNotPaused onlyMPC { uint256 leftValue = msg.value; for (uint256 i = 0; i < _gasRequest.length; i++) { _receiveGasTokenInternal(_gasRequest[i]); // DOES NOT need check, because it will overflow if less than amount leftValue -= _gasRequest[i].amount; } for (uint256 i = 0; i < _claimRequest.length; i++) { _claimInternal(_claimRequest[i]); } require(leftValue == 0, XBridgeErrors.LEFT_VALUE_NOT_ZERO); } function payerReceiver() external view returns(address, address) { return (payer, receiver); } receive() external payable {} }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.9.0) (access/Ownable.sol) pragma solidity ^0.8.0; import "../utils/ContextUpgradeable.sol"; import "../proxy/utils/Initializable.sol"; /** * @dev Contract module which provides a basic access control mechanism, where * there is an account (an owner) that can be granted exclusive access to * specific functions. * * By default, the owner account will be the one that deploys the contract. This * can later be changed with {transferOwnership}. * * This module is used through inheritance. It will make available the modifier * `onlyOwner`, which can be applied to your functions to restrict their use to * the owner. */ abstract contract OwnableUpgradeable is Initializable, ContextUpgradeable { address private _owner; event OwnershipTransferred(address indexed previousOwner, address indexed newOwner); /** * @dev Initializes the contract setting the deployer as the initial owner. */ function __Ownable_init() internal onlyInitializing { __Ownable_init_unchained(); } function __Ownable_init_unchained() internal onlyInitializing { _transferOwnership(_msgSender()); } /** * @dev Throws if called by any account other than the owner. */ modifier onlyOwner() { _checkOwner(); _; } /** * @dev Returns the address of the current owner. */ function owner() public view virtual returns (address) { return _owner; } /** * @dev Throws if the sender is not the owner. */ function _checkOwner() internal view virtual { require(owner() == _msgSender(), "Ownable: caller is not the owner"); } /** * @dev Leaves the contract without owner. It will not be possible to call * `onlyOwner` functions. Can only be called by the current owner. * * NOTE: Renouncing ownership will leave the contract without an owner, * thereby disabling any functionality that is only available to the owner. */ function renounceOwnership() public virtual onlyOwner { _transferOwnership(address(0)); } /** * @dev Transfers ownership of the contract to a new account (`newOwner`). * Can only be called by the current owner. */ function transferOwnership(address newOwner) public virtual onlyOwner { require(newOwner != address(0), "Ownable: new owner is the zero address"); _transferOwnership(newOwner); } /** * @dev Transfers ownership of the contract to a new account (`newOwner`). * Internal function without access restriction. */ function _transferOwnership(address newOwner) internal virtual { address oldOwner = _owner; _owner = newOwner; emit OwnershipTransferred(oldOwner, newOwner); } /** * @dev This empty reserved space is put in place to allow future versions to add new * variables without shifting down storage in the inheritance chain. * See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps */ uint256[49] private __gap; }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.9.0) (proxy/utils/Initializable.sol) pragma solidity ^0.8.2; import "../../utils/AddressUpgradeable.sol"; /** * @dev This is a base contract to aid in writing upgradeable contracts, or any kind of contract that will be deployed * behind a proxy. Since proxied contracts do not make use of a constructor, it's common to move constructor logic to an * external initializer function, usually called `initialize`. It then becomes necessary to protect this initializer * function so it can only be called once. The {initializer} modifier provided by this contract will have this effect. * * The initialization functions use a version number. Once a version number is used, it is consumed and cannot be * reused. This mechanism prevents re-execution of each "step" but allows the creation of new initialization steps in * case an upgrade adds a module that needs to be initialized. * * For example: * * [.hljs-theme-light.nopadding] * ```solidity * contract MyToken is ERC20Upgradeable { * function initialize() initializer public { * __ERC20_init("MyToken", "MTK"); * } * } * * contract MyTokenV2 is MyToken, ERC20PermitUpgradeable { * function initializeV2() reinitializer(2) public { * __ERC20Permit_init("MyToken"); * } * } * ``` * * TIP: To avoid leaving the proxy in an uninitialized state, the initializer function should be called as early as * possible by providing the encoded function call as the `_data` argument to {ERC1967Proxy-constructor}. * * CAUTION: When used with inheritance, manual care must be taken to not invoke a parent initializer twice, or to ensure * that all initializers are idempotent. This is not verified automatically as constructors are by Solidity. * * [CAUTION] * ==== * Avoid leaving a contract uninitialized. * * An uninitialized contract can be taken over by an attacker. This applies to both a proxy and its implementation * contract, which may impact the proxy. To prevent the implementation contract from being used, you should invoke * the {_disableInitializers} function in the constructor to automatically lock it when it is deployed: * * [.hljs-theme-light.nopadding] * ``` * /// @custom:oz-upgrades-unsafe-allow constructor * constructor() { * _disableInitializers(); * } * ``` * ==== */ abstract contract Initializable { /** * @dev Indicates that the contract has been initialized. * @custom:oz-retyped-from bool */ uint8 private _initialized; /** * @dev Indicates that the contract is in the process of being initialized. */ bool private _initializing; /** * @dev Triggered when the contract has been initialized or reinitialized. */ event Initialized(uint8 version); /** * @dev A modifier that defines a protected initializer function that can be invoked at most once. In its scope, * `onlyInitializing` functions can be used to initialize parent contracts. * * Similar to `reinitializer(1)`, except that functions marked with `initializer` can be nested in the context of a * constructor. * * Emits an {Initialized} event. */ modifier initializer() { bool isTopLevelCall = !_initializing; require( (isTopLevelCall && _initialized < 1) || (!AddressUpgradeable.isContract(address(this)) && _initialized == 1), "Initializable: contract is already initialized" ); _initialized = 1; if (isTopLevelCall) { _initializing = true; } _; if (isTopLevelCall) { _initializing = false; emit Initialized(1); } } /** * @dev A modifier that defines a protected reinitializer function that can be invoked at most once, and only if the * contract hasn't been initialized to a greater version before. In its scope, `onlyInitializing` functions can be * used to initialize parent contracts. * * A reinitializer may be used after the original initialization step. This is essential to configure modules that * are added through upgrades and that require initialization. * * When `version` is 1, this modifier is similar to `initializer`, except that functions marked with `reinitializer` * cannot be nested. If one is invoked in the context of another, execution will revert. * * Note that versions can jump in increments greater than 1; this implies that if multiple reinitializers coexist in * a contract, executing them in the right order is up to the developer or operator. * * WARNING: setting the version to 255 will prevent any future reinitialization. * * Emits an {Initialized} event. */ modifier reinitializer(uint8 version) { require(!_initializing && _initialized < version, "Initializable: contract is already initialized"); _initialized = version; _initializing = true; _; _initializing = false; emit Initialized(version); } /** * @dev Modifier to protect an initialization function so that it can only be invoked by functions with the * {initializer} and {reinitializer} modifiers, directly or indirectly. */ modifier onlyInitializing() { require(_initializing, "Initializable: contract is not initializing"); _; } /** * @dev Locks the contract, preventing any future reinitialization. This cannot be part of an initializer call. * Calling this in the constructor of a contract will prevent that contract from being initialized or reinitialized * to any version. It is recommended to use this to lock implementation contracts that are designed to be called * through proxies. * * Emits an {Initialized} event the first time it is successfully executed. */ function _disableInitializers() internal virtual { require(!_initializing, "Initializable: contract is initializing"); if (_initialized != type(uint8).max) { _initialized = type(uint8).max; emit Initialized(type(uint8).max); } } /** * @dev Returns the highest version that has been initialized. See {reinitializer}. */ function _getInitializedVersion() internal view returns (uint8) { return _initialized; } /** * @dev Returns `true` if the contract is currently initializing. See {onlyInitializing}. */ function _isInitializing() internal view returns (bool) { return _initializing; } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.7.0) (security/Pausable.sol) pragma solidity ^0.8.0; import "../utils/ContextUpgradeable.sol"; import "../proxy/utils/Initializable.sol"; /** * @dev Contract module which allows children to implement an emergency stop * mechanism that can be triggered by an authorized account. * * This module is used through inheritance. It will make available the * modifiers `whenNotPaused` and `whenPaused`, which can be applied to * the functions of your contract. Note that they will not be pausable by * simply including this module, only once the modifiers are put in place. */ abstract contract PausableUpgradeable is Initializable, ContextUpgradeable { /** * @dev Emitted when the pause is triggered by `account`. */ event Paused(address account); /** * @dev Emitted when the pause is lifted by `account`. */ event Unpaused(address account); bool private _paused; /** * @dev Initializes the contract in unpaused state. */ function __Pausable_init() internal onlyInitializing { __Pausable_init_unchained(); } function __Pausable_init_unchained() internal onlyInitializing { _paused = false; } /** * @dev Modifier to make a function callable only when the contract is not paused. * * Requirements: * * - The contract must not be paused. */ modifier whenNotPaused() { _requireNotPaused(); _; } /** * @dev Modifier to make a function callable only when the contract is paused. * * Requirements: * * - The contract must be paused. */ modifier whenPaused() { _requirePaused(); _; } /** * @dev Returns true if the contract is paused, and false otherwise. */ function paused() public view virtual returns (bool) { return _paused; } /** * @dev Throws if the contract is paused. */ function _requireNotPaused() internal view virtual { require(!paused(), "Pausable: paused"); } /** * @dev Throws if the contract is not paused. */ function _requirePaused() internal view virtual { require(paused(), "Pausable: not paused"); } /** * @dev Triggers stopped state. * * Requirements: * * - The contract must not be paused. */ function _pause() internal virtual whenNotPaused { _paused = true; emit Paused(_msgSender()); } /** * @dev Returns to normal state. * * Requirements: * * - The contract must be paused. */ function _unpause() internal virtual whenPaused { _paused = false; emit Unpaused(_msgSender()); } /** * @dev This empty reserved space is put in place to allow future versions to add new * variables without shifting down storage in the inheritance chain. * See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps */ uint256[49] private __gap; }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.9.0) (security/ReentrancyGuard.sol) pragma solidity ^0.8.0; import "../proxy/utils/Initializable.sol"; /** * @dev Contract module that helps prevent reentrant calls to a function. * * Inheriting from `ReentrancyGuard` will make the {nonReentrant} modifier * available, which can be applied to functions to make sure there are no nested * (reentrant) calls to them. * * Note that because there is a single `nonReentrant` guard, functions marked as * `nonReentrant` may not call one another. This can be worked around by making * those functions `private`, and then adding `external` `nonReentrant` entry * points to them. * * TIP: If you would like to learn more about reentrancy and alternative ways * to protect against it, check out our blog post * https://blog.openzeppelin.com/reentrancy-after-istanbul/[Reentrancy After Istanbul]. */ abstract contract ReentrancyGuardUpgradeable is Initializable { // Booleans are more expensive than uint256 or any type that takes up a full // word because each write operation emits an extra SLOAD to first read the // slot's contents, replace the bits taken up by the boolean, and then write // back. This is the compiler's defense against contract upgrades and // pointer aliasing, and it cannot be disabled. // The values being non-zero value makes deployment a bit more expensive, // but in exchange the refund on every call to nonReentrant will be lower in // amount. Since refunds are capped to a percentage of the total // transaction's gas, it is best to keep them low in cases like this one, to // increase the likelihood of the full refund coming into effect. uint256 private constant _NOT_ENTERED = 1; uint256 private constant _ENTERED = 2; uint256 private _status; function __ReentrancyGuard_init() internal onlyInitializing { __ReentrancyGuard_init_unchained(); } function __ReentrancyGuard_init_unchained() internal onlyInitializing { _status = _NOT_ENTERED; } /** * @dev Prevents a contract from calling itself, directly or indirectly. * Calling a `nonReentrant` function from another `nonReentrant` * function is not supported. It is possible to prevent this from happening * by making the `nonReentrant` function external, and making it call a * `private` function that does the actual work. */ modifier nonReentrant() { _nonReentrantBefore(); _; _nonReentrantAfter(); } function _nonReentrantBefore() private { // On the first call to nonReentrant, _status will be _NOT_ENTERED require(_status != _ENTERED, "ReentrancyGuard: reentrant call"); // Any calls to nonReentrant after this point will fail _status = _ENTERED; } function _nonReentrantAfter() private { // By storing the original value once again, a refund is triggered (see // https://eips.ethereum.org/EIPS/eip-2200) _status = _NOT_ENTERED; } /** * @dev Returns true if the reentrancy guard is currently set to "entered", which indicates there is a * `nonReentrant` function in the call stack. */ function _reentrancyGuardEntered() internal view returns (bool) { return _status == _ENTERED; } /** * @dev This empty reserved space is put in place to allow future versions to add new * variables without shifting down storage in the inheritance chain. * See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps */ uint256[49] private __gap; }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.9.0) (token/ERC20/extensions/IERC20Permit.sol) pragma solidity ^0.8.0; /** * @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in * https://eips.ethereum.org/EIPS/eip-2612[EIP-2612]. * * Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by * presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't * need to send a transaction, and thus is not required to hold Ether at all. */ interface IERC20PermitUpgradeable { /** * @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens, * given ``owner``'s signed approval. * * IMPORTANT: The same issues {IERC20-approve} has related to transaction * ordering also apply here. * * Emits an {Approval} event. * * Requirements: * * - `spender` cannot be the zero address. * - `deadline` must be a timestamp in the future. * - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner` * over the EIP712-formatted function arguments. * - the signature must use ``owner``'s current nonce (see {nonces}). * * For more information on the signature format, see the * https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP * section]. */ function permit( address owner, address spender, uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s ) external; /** * @dev Returns the current nonce for `owner`. This value must be * included whenever a signature is generated for {permit}. * * Every successful call to {permit} increases ``owner``'s nonce by one. This * prevents a signature from being used multiple times. */ function nonces(address owner) external view returns (uint256); /** * @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}. */ // solhint-disable-next-line func-name-mixedcase function DOMAIN_SEPARATOR() external view returns (bytes32); }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.9.0) (token/ERC20/IERC20.sol) pragma solidity ^0.8.0; /** * @dev Interface of the ERC20 standard as defined in the EIP. */ interface IERC20Upgradeable { /** * @dev Emitted when `value` tokens are moved from one account (`from`) to * another (`to`). * * Note that `value` may be zero. */ event Transfer(address indexed from, address indexed to, uint256 value); /** * @dev Emitted when the allowance of a `spender` for an `owner` is set by * a call to {approve}. `value` is the new allowance. */ event Approval(address indexed owner, address indexed spender, uint256 value); /** * @dev Returns the amount of tokens in existence. */ function totalSupply() external view returns (uint256); /** * @dev Returns the amount of tokens owned by `account`. */ function balanceOf(address account) external view returns (uint256); /** * @dev Moves `amount` tokens from the caller's account to `to`. * * Returns a boolean value indicating whether the operation succeeded. * * Emits a {Transfer} event. */ function transfer(address to, uint256 amount) external returns (bool); /** * @dev Returns the remaining number of tokens that `spender` will be * allowed to spend on behalf of `owner` through {transferFrom}. This is * zero by default. * * This value changes when {approve} or {transferFrom} are called. */ function allowance(address owner, address spender) external view returns (uint256); /** * @dev Sets `amount` as the allowance of `spender` over the caller's tokens. * * Returns a boolean value indicating whether the operation succeeded. * * IMPORTANT: Beware that changing an allowance with this method brings the risk * that someone may use both the old and the new allowance by unfortunate * transaction ordering. One possible solution to mitigate this race * condition is to first reduce the spender's allowance to 0 and set the * desired value afterwards: * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729 * * Emits an {Approval} event. */ function approve(address spender, uint256 amount) external returns (bool); /** * @dev Moves `amount` tokens from `from` to `to` using the * allowance mechanism. `amount` is then deducted from the caller's * allowance. * * Returns a boolean value indicating whether the operation succeeded. * * Emits a {Transfer} event. */ function transferFrom(address from, address to, uint256 amount) external returns (bool); }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.9.3) (token/ERC20/utils/SafeERC20.sol) pragma solidity ^0.8.0; import "../IERC20Upgradeable.sol"; import "../extensions/IERC20PermitUpgradeable.sol"; import "../../../utils/AddressUpgradeable.sol"; /** * @title SafeERC20 * @dev Wrappers around ERC20 operations that throw on failure (when the token * contract returns false). Tokens that return no value (and instead revert or * throw on failure) are also supported, non-reverting calls are assumed to be * successful. * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract, * which allows you to call the safe operations as `token.safeTransfer(...)`, etc. */ library SafeERC20Upgradeable { using AddressUpgradeable for address; /** * @dev Transfer `value` amount of `token` from the calling contract to `to`. If `token` returns no value, * non-reverting calls are assumed to be successful. */ function safeTransfer(IERC20Upgradeable token, address to, uint256 value) internal { _callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value)); } /** * @dev Transfer `value` amount of `token` from `from` to `to`, spending the approval given by `from` to the * calling contract. If `token` returns no value, non-reverting calls are assumed to be successful. */ function safeTransferFrom(IERC20Upgradeable token, address from, address to, uint256 value) internal { _callOptionalReturn(token, abi.encodeWithSelector(token.transferFrom.selector, from, to, value)); } /** * @dev Deprecated. This function has issues similar to the ones found in * {IERC20-approve}, and its usage is discouraged. * * Whenever possible, use {safeIncreaseAllowance} and * {safeDecreaseAllowance} instead. */ function safeApprove(IERC20Upgradeable token, address spender, uint256 value) internal { // safeApprove should only be called when setting an initial allowance, // or when resetting it to zero. To increase and decrease it, use // 'safeIncreaseAllowance' and 'safeDecreaseAllowance' require( (value == 0) || (token.allowance(address(this), spender) == 0), "SafeERC20: approve from non-zero to non-zero allowance" ); _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, value)); } /** * @dev Increase the calling contract's allowance toward `spender` by `value`. If `token` returns no value, * non-reverting calls are assumed to be successful. */ function safeIncreaseAllowance(IERC20Upgradeable token, address spender, uint256 value) internal { uint256 oldAllowance = token.allowance(address(this), spender); _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, oldAllowance + value)); } /** * @dev Decrease the calling contract's allowance toward `spender` by `value`. If `token` returns no value, * non-reverting calls are assumed to be successful. */ function safeDecreaseAllowance(IERC20Upgradeable token, address spender, uint256 value) internal { unchecked { uint256 oldAllowance = token.allowance(address(this), spender); require(oldAllowance >= value, "SafeERC20: decreased allowance below zero"); _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, oldAllowance - value)); } } /** * @dev Set the calling contract's allowance toward `spender` to `value`. If `token` returns no value, * non-reverting calls are assumed to be successful. Meant to be used with tokens that require the approval * to be set to zero before setting it to a non-zero value, such as USDT. */ function forceApprove(IERC20Upgradeable token, address spender, uint256 value) internal { bytes memory approvalCall = abi.encodeWithSelector(token.approve.selector, spender, value); if (!_callOptionalReturnBool(token, approvalCall)) { _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, 0)); _callOptionalReturn(token, approvalCall); } } /** * @dev Use a ERC-2612 signature to set the `owner` approval toward `spender` on `token`. * Revert on invalid signature. */ function safePermit( IERC20PermitUpgradeable token, address owner, address spender, uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s ) internal { uint256 nonceBefore = token.nonces(owner); token.permit(owner, spender, value, deadline, v, r, s); uint256 nonceAfter = token.nonces(owner); require(nonceAfter == nonceBefore + 1, "SafeERC20: permit did not succeed"); } /** * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement * on the return value: the return value is optional (but if data is returned, it must not be false). * @param token The token targeted by the call. * @param data The call data (encoded using abi.encode or one of its variants). */ function _callOptionalReturn(IERC20Upgradeable token, bytes memory data) private { // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since // we're implementing it ourselves. We use {Address-functionCall} to perform this call, which verifies that // the target address contains contract code and also asserts for success in the low-level call. bytes memory returndata = address(token).functionCall(data, "SafeERC20: low-level call failed"); require(returndata.length == 0 || abi.decode(returndata, (bool)), "SafeERC20: ERC20 operation did not succeed"); } /** * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement * on the return value: the return value is optional (but if data is returned, it must not be false). * @param token The token targeted by the call. * @param data The call data (encoded using abi.encode or one of its variants). * * This is a variant of {_callOptionalReturn} that silents catches all reverts and returns a bool instead. */ function _callOptionalReturnBool(IERC20Upgradeable token, bytes memory data) private returns (bool) { // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since // we're implementing it ourselves. We cannot use {Address-functionCall} here since this should return false // and not revert is the subcall reverts. (bool success, bytes memory returndata) = address(token).call(data); return success && (returndata.length == 0 || abi.decode(returndata, (bool))) && AddressUpgradeable.isContract(address(token)); } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.9.0) (utils/Address.sol) pragma solidity ^0.8.1; /** * @dev Collection of functions related to the address type */ library AddressUpgradeable { /** * @dev Returns true if `account` is a contract. * * [IMPORTANT] * ==== * It is unsafe to assume that an address for which this function returns * false is an externally-owned account (EOA) and not a contract. * * Among others, `isContract` will return false for the following * types of addresses: * * - an externally-owned account * - a contract in construction * - an address where a contract will be created * - an address where a contract lived, but was destroyed * * Furthermore, `isContract` will also return true if the target contract within * the same transaction is already scheduled for destruction by `SELFDESTRUCT`, * which only has an effect at the end of a transaction. * ==== * * [IMPORTANT] * ==== * You shouldn't rely on `isContract` to protect against flash loan attacks! * * Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets * like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract * constructor. * ==== */ function isContract(address account) internal view returns (bool) { // This method relies on extcodesize/address.code.length, which returns 0 // for contracts in construction, since the code is only stored at the end // of the constructor execution. return account.code.length > 0; } /** * @dev Replacement for Solidity's `transfer`: sends `amount` wei to * `recipient`, forwarding all available gas and reverting on errors. * * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost * of certain opcodes, possibly making contracts go over the 2300 gas limit * imposed by `transfer`, making them unable to receive funds via * `transfer`. {sendValue} removes this limitation. * * https://consensys.net/diligence/blog/2019/09/stop-using-soliditys-transfer-now/[Learn more]. * * IMPORTANT: because control is transferred to `recipient`, care must be * taken to not create reentrancy vulnerabilities. Consider using * {ReentrancyGuard} or the * https://solidity.readthedocs.io/en/v0.8.0/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern]. */ function sendValue(address payable recipient, uint256 amount) internal { require(address(this).balance >= amount, "Address: insufficient balance"); (bool success, ) = recipient.call{value: amount}(""); require(success, "Address: unable to send value, recipient may have reverted"); } /** * @dev Performs a Solidity function call using a low level `call`. A * plain `call` is an unsafe replacement for a function call: use this * function instead. * * If `target` reverts with a revert reason, it is bubbled up by this * function (like regular Solidity function calls). * * Returns the raw returned data. To convert to the expected return value, * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`]. * * Requirements: * * - `target` must be a contract. * - calling `target` with `data` must not revert. * * _Available since v3.1._ */ function functionCall(address target, bytes memory data) internal returns (bytes memory) { return functionCallWithValue(target, data, 0, "Address: low-level call failed"); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with * `errorMessage` as a fallback revert reason when `target` reverts. * * _Available since v3.1._ */ function functionCall( address target, bytes memory data, string memory errorMessage ) internal returns (bytes memory) { return functionCallWithValue(target, data, 0, errorMessage); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], * but also transferring `value` wei to `target`. * * Requirements: * * - the calling contract must have an ETH balance of at least `value`. * - the called Solidity function must be `payable`. * * _Available since v3.1._ */ function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) { return functionCallWithValue(target, data, value, "Address: low-level call with value failed"); } /** * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but * with `errorMessage` as a fallback revert reason when `target` reverts. * * _Available since v3.1._ */ function functionCallWithValue( address target, bytes memory data, uint256 value, string memory errorMessage ) internal returns (bytes memory) { require(address(this).balance >= value, "Address: insufficient balance for call"); (bool success, bytes memory returndata) = target.call{value: value}(data); return verifyCallResultFromTarget(target, success, returndata, errorMessage); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], * but performing a static call. * * _Available since v3.3._ */ function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) { return functionStaticCall(target, data, "Address: low-level static call failed"); } /** * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`], * but performing a static call. * * _Available since v3.3._ */ function functionStaticCall( address target, bytes memory data, string memory errorMessage ) internal view returns (bytes memory) { (bool success, bytes memory returndata) = target.staticcall(data); return verifyCallResultFromTarget(target, success, returndata, errorMessage); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], * but performing a delegate call. * * _Available since v3.4._ */ function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) { return functionDelegateCall(target, data, "Address: low-level delegate call failed"); } /** * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`], * but performing a delegate call. * * _Available since v3.4._ */ function functionDelegateCall( address target, bytes memory data, string memory errorMessage ) internal returns (bytes memory) { (bool success, bytes memory returndata) = target.delegatecall(data); return verifyCallResultFromTarget(target, success, returndata, errorMessage); } /** * @dev Tool to verify that a low level call to smart-contract was successful, and revert (either by bubbling * the revert reason or using the provided one) in case of unsuccessful call or if target was not a contract. * * _Available since v4.8._ */ function verifyCallResultFromTarget( address target, bool success, bytes memory returndata, string memory errorMessage ) internal view returns (bytes memory) { if (success) { if (returndata.length == 0) { // only check isContract if the call was successful and the return data is empty // otherwise we already know that it was a contract require(isContract(target), "Address: call to non-contract"); } return returndata; } else { _revert(returndata, errorMessage); } } /** * @dev Tool to verify that a low level call was successful, and revert if it wasn't, either by bubbling the * revert reason or using the provided one. * * _Available since v4.3._ */ function verifyCallResult( bool success, bytes memory returndata, string memory errorMessage ) internal pure returns (bytes memory) { if (success) { return returndata; } else { _revert(returndata, errorMessage); } } function _revert(bytes memory returndata, string memory errorMessage) private pure { // Look for revert reason and bubble it up if present if (returndata.length > 0) { // The easiest way to bubble the revert reason is using memory via assembly /// @solidity memory-safe-assembly assembly { let returndata_size := mload(returndata) revert(add(32, returndata), returndata_size) } } else { revert(errorMessage); } } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts v4.4.1 (utils/Context.sol) pragma solidity ^0.8.0; import "../proxy/utils/Initializable.sol"; /** * @dev Provides information about the current execution context, including the * sender of the transaction and its data. While these are generally available * via msg.sender and msg.data, they should not be accessed in such a direct * manner, since when dealing with meta-transactions the account sending and * paying for execution may not be the actual sender (as far as an application * is concerned). * * This contract is only required for intermediate, library-like contracts. */ abstract contract ContextUpgradeable is Initializable { function __Context_init() internal onlyInitializing { } function __Context_init_unchained() internal onlyInitializing { } function _msgSender() internal view virtual returns (address) { return msg.sender; } function _msgData() internal view virtual returns (bytes calldata) { return msg.data; } /** * @dev This empty reserved space is put in place to allow future versions to add new * variables without shifting down storage in the inheritance chain. * See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps */ uint256[50] private __gap; }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.9.0) (access/Ownable.sol) pragma solidity ^0.8.0; import "../utils/Context.sol"; /** * @dev Contract module which provides a basic access control mechanism, where * there is an account (an owner) that can be granted exclusive access to * specific functions. * * By default, the owner account will be the one that deploys the contract. This * can later be changed with {transferOwnership}. * * This module is used through inheritance. It will make available the modifier * `onlyOwner`, which can be applied to your functions to restrict their use to * the owner. */ abstract contract Ownable is Context { address private _owner; event OwnershipTransferred(address indexed previousOwner, address indexed newOwner); /** * @dev Initializes the contract setting the deployer as the initial owner. */ constructor() { _transferOwnership(_msgSender()); } /** * @dev Throws if called by any account other than the owner. */ modifier onlyOwner() { _checkOwner(); _; } /** * @dev Returns the address of the current owner. */ function owner() public view virtual returns (address) { return _owner; } /** * @dev Throws if the sender is not the owner. */ function _checkOwner() internal view virtual { require(owner() == _msgSender(), "Ownable: caller is not the owner"); } /** * @dev Leaves the contract without owner. It will not be possible to call * `onlyOwner` functions. Can only be called by the current owner. * * NOTE: Renouncing ownership will leave the contract without an owner, * thereby disabling any functionality that is only available to the owner. */ function renounceOwnership() public virtual onlyOwner { _transferOwnership(address(0)); } /** * @dev Transfers ownership of the contract to a new account (`newOwner`). * Can only be called by the current owner. */ function transferOwnership(address newOwner) public virtual onlyOwner { require(newOwner != address(0), "Ownable: new owner is the zero address"); _transferOwnership(newOwner); } /** * @dev Transfers ownership of the contract to a new account (`newOwner`). * Internal function without access restriction. */ function _transferOwnership(address newOwner) internal virtual { address oldOwner = _owner; _owner = newOwner; emit OwnershipTransferred(oldOwner, newOwner); } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.9.0) (token/ERC20/extensions/draft-IERC20Permit.sol) pragma solidity ^0.8.0; // EIP-2612 is Final as of 2022-11-01. This file is deprecated. import "./IERC20Permit.sol";
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.9.0) (token/ERC20/extensions/IERC20Permit.sol) pragma solidity ^0.8.0; /** * @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in * https://eips.ethereum.org/EIPS/eip-2612[EIP-2612]. * * Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by * presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't * need to send a transaction, and thus is not required to hold Ether at all. */ interface IERC20Permit { /** * @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens, * given ``owner``'s signed approval. * * IMPORTANT: The same issues {IERC20-approve} has related to transaction * ordering also apply here. * * Emits an {Approval} event. * * Requirements: * * - `spender` cannot be the zero address. * - `deadline` must be a timestamp in the future. * - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner` * over the EIP712-formatted function arguments. * - the signature must use ``owner``'s current nonce (see {nonces}). * * For more information on the signature format, see the * https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP * section]. */ function permit( address owner, address spender, uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s ) external; /** * @dev Returns the current nonce for `owner`. This value must be * included whenever a signature is generated for {permit}. * * Every successful call to {permit} increases ``owner``'s nonce by one. This * prevents a signature from being used multiple times. */ function nonces(address owner) external view returns (uint256); /** * @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}. */ // solhint-disable-next-line func-name-mixedcase function DOMAIN_SEPARATOR() external view returns (bytes32); }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.9.0) (token/ERC20/IERC20.sol) pragma solidity ^0.8.0; /** * @dev Interface of the ERC20 standard as defined in the EIP. */ interface IERC20 { /** * @dev Emitted when `value` tokens are moved from one account (`from`) to * another (`to`). * * Note that `value` may be zero. */ event Transfer(address indexed from, address indexed to, uint256 value); /** * @dev Emitted when the allowance of a `spender` for an `owner` is set by * a call to {approve}. `value` is the new allowance. */ event Approval(address indexed owner, address indexed spender, uint256 value); /** * @dev Returns the amount of tokens in existence. */ function totalSupply() external view returns (uint256); /** * @dev Returns the amount of tokens owned by `account`. */ function balanceOf(address account) external view returns (uint256); /** * @dev Moves `amount` tokens from the caller's account to `to`. * * Returns a boolean value indicating whether the operation succeeded. * * Emits a {Transfer} event. */ function transfer(address to, uint256 amount) external returns (bool); /** * @dev Returns the remaining number of tokens that `spender` will be * allowed to spend on behalf of `owner` through {transferFrom}. This is * zero by default. * * This value changes when {approve} or {transferFrom} are called. */ function allowance(address owner, address spender) external view returns (uint256); /** * @dev Sets `amount` as the allowance of `spender` over the caller's tokens. * * Returns a boolean value indicating whether the operation succeeded. * * IMPORTANT: Beware that changing an allowance with this method brings the risk * that someone may use both the old and the new allowance by unfortunate * transaction ordering. One possible solution to mitigate this race * condition is to first reduce the spender's allowance to 0 and set the * desired value afterwards: * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729 * * Emits an {Approval} event. */ function approve(address spender, uint256 amount) external returns (bool); /** * @dev Moves `amount` tokens from `from` to `to` using the * allowance mechanism. `amount` is then deducted from the caller's * allowance. * * Returns a boolean value indicating whether the operation succeeded. * * Emits a {Transfer} event. */ function transferFrom(address from, address to, uint256 amount) external returns (bool); }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.9.3) (token/ERC20/utils/SafeERC20.sol) pragma solidity ^0.8.0; import "../IERC20.sol"; import "../extensions/IERC20Permit.sol"; import "../../../utils/Address.sol"; /** * @title SafeERC20 * @dev Wrappers around ERC20 operations that throw on failure (when the token * contract returns false). Tokens that return no value (and instead revert or * throw on failure) are also supported, non-reverting calls are assumed to be * successful. * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract, * which allows you to call the safe operations as `token.safeTransfer(...)`, etc. */ library SafeERC20 { using Address for address; /** * @dev Transfer `value` amount of `token` from the calling contract to `to`. If `token` returns no value, * non-reverting calls are assumed to be successful. */ function safeTransfer(IERC20 token, address to, uint256 value) internal { _callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value)); } /** * @dev Transfer `value` amount of `token` from `from` to `to`, spending the approval given by `from` to the * calling contract. If `token` returns no value, non-reverting calls are assumed to be successful. */ function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal { _callOptionalReturn(token, abi.encodeWithSelector(token.transferFrom.selector, from, to, value)); } /** * @dev Deprecated. This function has issues similar to the ones found in * {IERC20-approve}, and its usage is discouraged. * * Whenever possible, use {safeIncreaseAllowance} and * {safeDecreaseAllowance} instead. */ function safeApprove(IERC20 token, address spender, uint256 value) internal { // safeApprove should only be called when setting an initial allowance, // or when resetting it to zero. To increase and decrease it, use // 'safeIncreaseAllowance' and 'safeDecreaseAllowance' require( (value == 0) || (token.allowance(address(this), spender) == 0), "SafeERC20: approve from non-zero to non-zero allowance" ); _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, value)); } /** * @dev Increase the calling contract's allowance toward `spender` by `value`. If `token` returns no value, * non-reverting calls are assumed to be successful. */ function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal { uint256 oldAllowance = token.allowance(address(this), spender); _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, oldAllowance + value)); } /** * @dev Decrease the calling contract's allowance toward `spender` by `value`. If `token` returns no value, * non-reverting calls are assumed to be successful. */ function safeDecreaseAllowance(IERC20 token, address spender, uint256 value) internal { unchecked { uint256 oldAllowance = token.allowance(address(this), spender); require(oldAllowance >= value, "SafeERC20: decreased allowance below zero"); _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, oldAllowance - value)); } } /** * @dev Set the calling contract's allowance toward `spender` to `value`. If `token` returns no value, * non-reverting calls are assumed to be successful. Meant to be used with tokens that require the approval * to be set to zero before setting it to a non-zero value, such as USDT. */ function forceApprove(IERC20 token, address spender, uint256 value) internal { bytes memory approvalCall = abi.encodeWithSelector(token.approve.selector, spender, value); if (!_callOptionalReturnBool(token, approvalCall)) { _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, 0)); _callOptionalReturn(token, approvalCall); } } /** * @dev Use a ERC-2612 signature to set the `owner` approval toward `spender` on `token`. * Revert on invalid signature. */ function safePermit( IERC20Permit token, address owner, address spender, uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s ) internal { uint256 nonceBefore = token.nonces(owner); token.permit(owner, spender, value, deadline, v, r, s); uint256 nonceAfter = token.nonces(owner); require(nonceAfter == nonceBefore + 1, "SafeERC20: permit did not succeed"); } /** * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement * on the return value: the return value is optional (but if data is returned, it must not be false). * @param token The token targeted by the call. * @param data The call data (encoded using abi.encode or one of its variants). */ function _callOptionalReturn(IERC20 token, bytes memory data) private { // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since // we're implementing it ourselves. We use {Address-functionCall} to perform this call, which verifies that // the target address contains contract code and also asserts for success in the low-level call. bytes memory returndata = address(token).functionCall(data, "SafeERC20: low-level call failed"); require(returndata.length == 0 || abi.decode(returndata, (bool)), "SafeERC20: ERC20 operation did not succeed"); } /** * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement * on the return value: the return value is optional (but if data is returned, it must not be false). * @param token The token targeted by the call. * @param data The call data (encoded using abi.encode or one of its variants). * * This is a variant of {_callOptionalReturn} that silents catches all reverts and returns a bool instead. */ function _callOptionalReturnBool(IERC20 token, bytes memory data) private returns (bool) { // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since // we're implementing it ourselves. We cannot use {Address-functionCall} here since this should return false // and not revert is the subcall reverts. (bool success, bytes memory returndata) = address(token).call(data); return success && (returndata.length == 0 || abi.decode(returndata, (bool))) && Address.isContract(address(token)); } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.9.0) (utils/Address.sol) pragma solidity ^0.8.1; /** * @dev Collection of functions related to the address type */ library Address { /** * @dev Returns true if `account` is a contract. * * [IMPORTANT] * ==== * It is unsafe to assume that an address for which this function returns * false is an externally-owned account (EOA) and not a contract. * * Among others, `isContract` will return false for the following * types of addresses: * * - an externally-owned account * - a contract in construction * - an address where a contract will be created * - an address where a contract lived, but was destroyed * * Furthermore, `isContract` will also return true if the target contract within * the same transaction is already scheduled for destruction by `SELFDESTRUCT`, * which only has an effect at the end of a transaction. * ==== * * [IMPORTANT] * ==== * You shouldn't rely on `isContract` to protect against flash loan attacks! * * Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets * like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract * constructor. * ==== */ function isContract(address account) internal view returns (bool) { // This method relies on extcodesize/address.code.length, which returns 0 // for contracts in construction, since the code is only stored at the end // of the constructor execution. return account.code.length > 0; } /** * @dev Replacement for Solidity's `transfer`: sends `amount` wei to * `recipient`, forwarding all available gas and reverting on errors. * * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost * of certain opcodes, possibly making contracts go over the 2300 gas limit * imposed by `transfer`, making them unable to receive funds via * `transfer`. {sendValue} removes this limitation. * * https://consensys.net/diligence/blog/2019/09/stop-using-soliditys-transfer-now/[Learn more]. * * IMPORTANT: because control is transferred to `recipient`, care must be * taken to not create reentrancy vulnerabilities. Consider using * {ReentrancyGuard} or the * https://solidity.readthedocs.io/en/v0.8.0/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern]. */ function sendValue(address payable recipient, uint256 amount) internal { require(address(this).balance >= amount, "Address: insufficient balance"); (bool success, ) = recipient.call{value: amount}(""); require(success, "Address: unable to send value, recipient may have reverted"); } /** * @dev Performs a Solidity function call using a low level `call`. A * plain `call` is an unsafe replacement for a function call: use this * function instead. * * If `target` reverts with a revert reason, it is bubbled up by this * function (like regular Solidity function calls). * * Returns the raw returned data. To convert to the expected return value, * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`]. * * Requirements: * * - `target` must be a contract. * - calling `target` with `data` must not revert. * * _Available since v3.1._ */ function functionCall(address target, bytes memory data) internal returns (bytes memory) { return functionCallWithValue(target, data, 0, "Address: low-level call failed"); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with * `errorMessage` as a fallback revert reason when `target` reverts. * * _Available since v3.1._ */ function functionCall( address target, bytes memory data, string memory errorMessage ) internal returns (bytes memory) { return functionCallWithValue(target, data, 0, errorMessage); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], * but also transferring `value` wei to `target`. * * Requirements: * * - the calling contract must have an ETH balance of at least `value`. * - the called Solidity function must be `payable`. * * _Available since v3.1._ */ function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) { return functionCallWithValue(target, data, value, "Address: low-level call with value failed"); } /** * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but * with `errorMessage` as a fallback revert reason when `target` reverts. * * _Available since v3.1._ */ function functionCallWithValue( address target, bytes memory data, uint256 value, string memory errorMessage ) internal returns (bytes memory) { require(address(this).balance >= value, "Address: insufficient balance for call"); (bool success, bytes memory returndata) = target.call{value: value}(data); return verifyCallResultFromTarget(target, success, returndata, errorMessage); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], * but performing a static call. * * _Available since v3.3._ */ function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) { return functionStaticCall(target, data, "Address: low-level static call failed"); } /** * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`], * but performing a static call. * * _Available since v3.3._ */ function functionStaticCall( address target, bytes memory data, string memory errorMessage ) internal view returns (bytes memory) { (bool success, bytes memory returndata) = target.staticcall(data); return verifyCallResultFromTarget(target, success, returndata, errorMessage); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], * but performing a delegate call. * * _Available since v3.4._ */ function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) { return functionDelegateCall(target, data, "Address: low-level delegate call failed"); } /** * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`], * but performing a delegate call. * * _Available since v3.4._ */ function functionDelegateCall( address target, bytes memory data, string memory errorMessage ) internal returns (bytes memory) { (bool success, bytes memory returndata) = target.delegatecall(data); return verifyCallResultFromTarget(target, success, returndata, errorMessage); } /** * @dev Tool to verify that a low level call to smart-contract was successful, and revert (either by bubbling * the revert reason or using the provided one) in case of unsuccessful call or if target was not a contract. * * _Available since v4.8._ */ function verifyCallResultFromTarget( address target, bool success, bytes memory returndata, string memory errorMessage ) internal view returns (bytes memory) { if (success) { if (returndata.length == 0) { // only check isContract if the call was successful and the return data is empty // otherwise we already know that it was a contract require(isContract(target), "Address: call to non-contract"); } return returndata; } else { _revert(returndata, errorMessage); } } /** * @dev Tool to verify that a low level call was successful, and revert if it wasn't, either by bubbling the * revert reason or using the provided one. * * _Available since v4.3._ */ function verifyCallResult( bool success, bytes memory returndata, string memory errorMessage ) internal pure returns (bytes memory) { if (success) { return returndata; } else { _revert(returndata, errorMessage); } } function _revert(bytes memory returndata, string memory errorMessage) private pure { // Look for revert reason and bubble it up if present if (returndata.length > 0) { // The easiest way to bubble the revert reason is using memory via assembly /// @solidity memory-safe-assembly assembly { let returndata_size := mload(returndata) revert(add(32, returndata), returndata_size) } } else { revert(errorMessage); } } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts v4.4.1 (utils/Context.sol) pragma solidity ^0.8.0; /** * @dev Provides information about the current execution context, including the * sender of the transaction and its data. While these are generally available * via msg.sender and msg.data, they should not be accessed in such a direct * manner, since when dealing with meta-transactions the account sending and * paying for execution may not be the actual sender (as far as an application * is concerned). * * This contract is only required for intermediate, library-like contracts. */ abstract contract Context { function _msgSender() internal view virtual returns (address) { return msg.sender; } function _msgData() internal view virtual returns (bytes calldata) { return msg.data; } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; pragma abicoder v2; import "../helpers/Constants.sol"; import "../helpers/Errors.sol"; import "@openzeppelin/contracts/token/ERC20/IERC20.sol"; import "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol"; import "@openzeppelin/contracts/access/Ownable.sol"; /// @title BridgeAdaptorBase /// @notice All Bridge adaptor must implement it /// @dev All Bridge adaptor must implement it abstract contract BridgeAdaptorBase is Ownable { using SafeERC20 for IERC20; address public immutable xBridge; mapping(address => bool) public routers; constructor(address _xBridge, address[] memory _routersList) { require(_xBridge != address(0), XBridgeErrors.ADDRESS_0); xBridge = _xBridge; for (uint256 i = 0; i < _routersList.length; i++) { routers[_routersList[i]] = true; } } //------------------------------- //------- Events ---------------- //------------------------------- event LogOutboundBridgeTo(address _from, address _to, address _token, uint256 _amount, bytes32 _extraData); event EmergencyWithdraw(address indexed _to, address _token, uint amount); //------------------------------- //------- Modifier -------------- //------------------------------- modifier onlyXBridge() { require(msg.sender == xBridge, XBridgeErrors.ONLY_X_BRIDGE); _; } //------------------------------- //------- Internal Functions ---- //------------------------------- function _approve(address token, address spender, uint256 amount) internal { if (IERC20(token).allowance(address(this), spender) == 0) { IERC20(token).safeApprove(spender, amount); } else { IERC20(token).safeApprove(spender, 0); IERC20(token).safeApprove(spender, amount); } } function _approve2(address token, address spender, uint256 amount) internal { uint256 preAllowance = IERC20(token).allowance(address(this), spender); if (preAllowance == 0) { IERC20(token).safeApprove(spender, type(uint256).max); } else if (preAllowance < amount){ IERC20(token).safeApprove(spender, 0); IERC20(token).safeApprove(spender, type(uint256).max); } } //------------------------------- //------- Admin functions ------- //------------------------------- function setRouters(address[] calldata _routersList, bool[] calldata _v) public onlyOwner { for (uint256 i = 0; i < _routersList.length; i++) { routers[_routersList[i]] = _v[i]; } } // workaround for a possible solidity bug function withdrawEmergency(address _to, address _token, uint _amount) public onlyOwner { if (_token == XBridgeConstants.NATIVE_TOKEN) { payable(_to).transfer(_amount); } else { IERC20(_token).safeTransfer(_to, _amount); } emit EmergencyWithdraw(_to, _token, _amount); } //------------------------------- //------- Users Functions ------- //------------------------------- function outboundBridgeTo( address _from, address _to, address _refundAddress, address _token, uint256 _amount, uint256 _toChainId, bytes memory _data ) external payable virtual; receive() external payable {} }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; library XBridgeConstants { address public constant NATIVE_TOKEN = address(0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE); /// @dev WETH address is network-specific and needs to be changed before deployment. /// It can not be moved to immutable as immutables are not supported in assembly // ETH: C02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2 // BSC: bb4CdB9CBd36B01bD1cBaEBF2De08d9173bc095c // OEC: 8F8526dbfd6E38E3D8307702cA8469Bae6C56C15 // LOCAL: 5FbDB2315678afecb367f032d93F642f64180aa3 // LOCAL2: 02121128f1Ed0AdA5Df3a87f42752fcE4Ad63e59 // POLYGON: 0d500B1d8E8eF31E21C99d1Db9A6444d3ADf1270 // AVAX: B31f66AA3C1e785363F0875A1B74E27b85FD66c7 // FTM: 21be370D5312f44cB42ce377BC9b8a0cEF1A4C83 // ARB: 82aF49447D8a07e3bd95BD0d56f35241523fBab1 // OP: 4200000000000000000000000000000000000006 // CRO: 5C7F8A570d578ED84E63fdFA7b1eE72dEae1AE23 // CFX: 14b2D3bC65e74DAE1030EAFd8ac30c533c976A9b // POLYZK 4F9A0e7FD2Bf6067db6994CF12E4495Df938E6e9 // MANTA 0Dc808adcE2099A9F62AA87D9670745AbA741746 // METIS 75cb093E4D61d2A2e65D8e0BBb01DE8d89b53481 // MERLIN F6D226f9Dc15d9bB51182815b320D3fBE324e1bA // ZETA 5F0b1a82749cb4E2278EC87F8BF6B618dC71a8bf // MODE 4200000000000000000000000000000000000006 // XLAYER e538905cf8410324e03A5A23C1c177a474D59b2b // SONIC 039e2fB66102314Ce7b64Ce5Ce3E5183bc94aD38 address public constant WETH = 0x039e2fB66102314Ce7b64Ce5Ce3E5183bc94aD38; // ETH: 70cBb871E8f30Fc8Ce23609E9E0Ea87B6b222F58 // ETH-DEV:02D0131E5Cc86766e234EbF1eBe33444443b98a3 // BSC: d99cAE3FAC551f6b6Ba7B9f19bDD316951eeEE98 // OEC: E9BBD6eC0c9Ca71d3DcCD1282EE9de4F811E50aF // LOCAL: e7f1725E7734CE288F8367e1Bb143E90bb3F0512 // LOCAL2: 95D7fF1684a8F2e202097F28Dc2e56F773A55D02 // POLYGON: 40aA958dd87FC8305b97f2BA922CDdCa374bcD7f // AVAX: 70cBb871E8f30Fc8Ce23609E9E0Ea87B6b222F58 // FTM: E9BBD6eC0c9Ca71d3DcCD1282EE9de4F811E50aF // ARB: E9BBD6eC0c9Ca71d3DcCD1282EE9de4F811E50aF // ARB_DEV: eDC3a1C195591968488cA2E41E54d5Ac6c8016e2 // OP: 100F3f74125C8c724C7C0eE81E4dd5626830dD9a // CRO: E9BBD6eC0c9Ca71d3DcCD1282EE9de4F811E50aF // CFX: 100F3f74125C8c724C7C0eE81E4dd5626830dD9a // POLYZK 1b5d39419C268b76Db06DE49e38B010fbFB5e226 // MANTA 1b5d39419C268b76Db06DE49e38B010fbFB5e226 // METIS 1b5d39419C268b76Db06DE49e38B010fbFB5e226 // MERLIN fAd6a9eEe5b32E9B81bb217BaeF37742B2ca5B83 // ZETA 8009858707810928CCe2c3526B78A4Eb8043888c // MODE 6A4F2a37f188eC7079854cA7C9C0E1181f858A69 // XLAYER fAd6a9eEe5b32E9B81bb217BaeF37742B2ca5B83 // SONIC CFF09e645a627B8208ef67dA294d0eDC2d255517 address public constant APPROVE_PROXY = 0xCFF09e645a627B8208ef67dA294d0eDC2d255517; // ETH: 5703B683c7F928b721CA95Da988d73a3299d4757 // BSC: 0B5f474ad0e3f7ef629BD10dbf9e4a8Fd60d9A48 // OEC: d99cAE3FAC551f6b6Ba7B9f19bDD316951eeEE98 // LOCAL: D49a0e9A4CD5979aE36840f542D2d7f02C4817Be // LOCAL2: 11457D5b1025D162F3d9B7dBeab6E1fBca20e043 // POLYGON: f332761c673b59B21fF6dfa8adA44d78c12dEF09 // AVAX: 3B86917369B83a6892f553609F3c2F439C184e31 // FTM: 40aA958dd87FC8305b97f2BA922CDdCa374bcD7f // ARB: d99cAE3FAC551f6b6Ba7B9f19bDD316951eeEE98 // ARB_DEV: C183cFF4aC3B6D2b9405D856143C35a36E4C8710 // OP: 40aA958dd87FC8305b97f2BA922CDdCa374bcD7f // CRO: 40aA958dd87FC8305b97f2BA922CDdCa374bcD7f // CFX: 40aA958dd87FC8305b97f2BA922CDdCa374bcD7f // POLYZK d2F0aC2012C8433F235c8e5e97F2368197DD06C7 // MANTA d2F0aC2012C8433F235c8e5e97F2368197DD06C7 // METIS d2F0aC2012C8433F235c8e5e97F2368197DD06C7 // MERLIN 38a342664aBE254Fc2Ca4A98d85eaB7C5aE63c85 // ZETA 4CD5e737D1aD509573f6924465168e54417F013E // MODE 897a69668aDa305A7FB9FE3318e14f90dD76D070 // XLAYER 38a342664aBE254Fc2Ca4A98d85eaB7C5aE63c85 // SONIC 0007ef1Cde141326b0da51c83CBAc3F6fEaF507C address public constant WNATIVE_RELAY = 0x0007ef1Cde141326b0da51c83CBAc3F6fEaF507C; // sysRatio uint256 public constant GAS_TOKEN_RECEIVE_MAX_INDEX = 1; uint256 public constant CLAIM_TOKEN_RATIO_MAX_INDEX = 2; uint256 public constant CHAIN_ID_INDEX = 3; // sysAddressConfig // uint256 public constant ORACLE_ADDRESS_INDEX = 1; // deprecated uint256 public constant DEFAULT_RATIO_BASE = 100; uint256 public constant ADAPTER_ID_ANYSWAP = 1; uint256 public constant ADAPTER_ID_CBRIDGE = 2; uint256 public constant ADAPTER_ID_SWFT = 3; string public constant __REFUND__ = string("__refund__"); }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; library XBridgeErrors { string internal constant ONLY_X_BRIDGE = "only XBridge"; string internal constant ONLY_MPC = "only mpc"; string internal constant ONLY_ADMIN = "only admin"; string internal constant ADDRESS_0 = "address 0"; string internal constant LENGTH_NOT_EQUAL = "length not equal"; string internal constant DEX_ROUTER_ERR = "dex router err : "; string internal constant ADDRESS_EQUAL = "address equal"; string internal constant ADDRESS_NOT_EQUAL = "address not equal"; string internal constant MIN_AMOUNT_ERR = "min amount err"; string internal constant REFUND_ETH_ERROR = "refund eth err"; string internal constant REFUND_EXIST = "refund exist"; string internal constant CBRIDGE_HAS_WITHDRAW = "has withdraw"; string internal constant HAS_PAID = "has paid"; string internal constant HAS_RECEIVE_GAS = "has receive gas"; string internal constant NO_ENOUGH_MONEY = "no enough money"; string internal constant SLASH_MUCH_TOO_MONEY = "slash much too money"; string internal constant ERROR_SELECTOR_ID = "err selector id"; string internal constant EXCEED_ALLOWED_GAS = "exceed allowed gas"; string internal constant ALLOWANCE_NOT_ENOUGH = "allowance not enough"; string internal constant ORACLE_NO_INFO = "claim no oracle info"; string internal constant ORACLE_TO_ADDRESS_ERR = "claim to address err"; string internal constant ORACLE_TOKEN_ADDRESS_ERR = "claim token address err"; string internal constant ORACLE_TOKEN_AMOUNT_ERR = "claim token amount err"; string internal constant NOT_ORACLE_PROXY = "not oracle proxy"; string internal constant ERR_CHAIN_ID = "err chain id"; string internal constant ZERO_SIGNER = "zero signer"; string internal constant CONTRACT_ADDRESS_ERROR = "contract address error"; string internal constant INTERNAL_WRAP_FAIL = "internal wrap fail"; string internal constant WRAP_AMOUNT_ZERO = "wrap amount must be > 0"; string internal constant TRANSFER_ETH_FAILD = "ETH transfer failed"; string internal constant AMOUNT_ZERO = "amount must be > 0"; string internal constant MIN_AMOUNT_ZERO = "min amount must be > 0"; string internal constant LEFT_VALUE_NOT_ZERO = "left value must be 0"; string internal constant NOT_SUPPORT_CHAIN = "not support chain"; string internal constant NOT_SUPPORT_TOKEN = "not support token"; string internal constant AMOUNT_NOT_EQ_VALUE = "amount must == msg.value"; string internal constant VALUE_NOT_ENOUGH = "amount must <= msg.value"; string internal constant VALUE_MUST_ZERO = "msg.value == 0"; string internal constant INVALID_ADAPTOR_ID = "invalid adaptorID"; string internal constant INVALID_ADAPTOR_ADDRESS = "invalid adaptor address"; string internal constant INVALID_ROUTER = "invalid router"; string internal constant INVALID_MSG_VALUE = "invalid msg value"; string internal constant COMMISSION_ERROR_RATE = "error commission rate limit"; string internal constant COMMISSION_ERROR_ETHER = "commission with ether error"; }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; interface IApproveProxy { function owner() external view returns (address); function isAllowedProxy(address _proxy) external view returns (bool); function claimTokens( address token, address who, address dest, uint256 amount ) external; function tokenApprove() external view returns (address); function addProxy(address _newProxy) external; }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; /// @title Interface for DAI-style permits interface IDaiLikePermit { function permit( address holder, address spender, uint256 nonce, uint256 expiry, bool allowed, uint8 v, bytes32 r, bytes32 s ) external; }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; pragma abicoder v2; interface IWETH { function totalSupply() external view returns (uint256); function balanceOf(address account) external view returns (uint256); function transfer(address recipient, uint256 amount) external returns (bool); function allowance(address owner, address spender) external view returns (uint256); function approve(address spender, uint256 amount) external returns (bool); function transferFrom( address src, address dst, uint256 wad ) external returns (bool); function deposit() external payable; function withdraw(uint256 wad) external; }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; pragma abicoder v2; interface IWNativeRelayer { function owner() external view returns (address); function withdraw(uint256 _amount) external; function setCallerOk(address[] calldata whitelistedCallers, bool isOk) external; }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; library Bytes { function bytesToBytes32Array(bytes memory data) internal pure returns (bytes32[] memory dataList) { uint256 N = (data.length + 31) / 32; dataList = new bytes32[](N); for (uint256 index = 0; index < N; index++) { bytes32 element; uint256 start = 32 + index * 32; assembly { element := mload(add(data, start)) } dataList[index] = element; } } }
/// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; abstract contract CommissionLib { /** * commissionInfo uint256 * commissionInfo = flag + commissionRate + referrerAddress * [ 48 bits | 48 bits | 160 bits ] * [ flag | commissionRate | referrerAddress ] * [ MSB LSB ] */ uint256 internal constant _REFERRER_MASK = 0x000000000000000000000000ffffffffffffffffffffffffffffffffffffffff; uint256 internal constant _COMMISSION_FEE_MASK = 0x000000000000ffffffffffff0000000000000000000000000000000000000000; uint256 internal constant _COMMISSION_FLAG_MASK = 0xffffffffffff0000000000000000000000000000000000000000000000000000; uint256 internal constant OKX_COMMISSION = 0x3ca20afc2aaa0000000000000000000000000000000000000000000000000000; event CommissionRecord(uint256 commissionAmount, address referrerAddress); // set default vaule. can change when need. uint256 public constant commissionRateLimit = 300; }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; /// @title Library that allows to parse unsuccessful arbitrary calls revert reasons. /// See https://solidity.readthedocs.io/en/latest/control-structures.html#revert for details. /// Note that we assume revert reason being abi-encoded as Error(string) so it may fail to parse reason /// if structured reverts appear in the future. /// /// All unsuccessful parsings get encoded as Unknown(data) string library RevertReasonParser { bytes4 private constant _PANIC_SELECTOR = bytes4(keccak256("Panic(uint256)")); bytes4 private constant _ERROR_SELECTOR = bytes4(keccak256("Error(string)")); function parse(bytes memory data, string memory prefix) internal pure returns (string memory) { if (data.length >= 4) { bytes4 selector; assembly { // solhint-disable-line no-inline-assembly selector := mload(add(data, 0x20)) } // 68 = 4-byte selector + 32 bytes offset + 32 bytes length if (selector == _ERROR_SELECTOR && data.length >= 68) { uint256 offset; bytes memory reason; // solhint-disable no-inline-assembly assembly { // 36 = 32 bytes data length + 4-byte selector offset := mload(add(data, 36)) reason := add(data, add(36, offset)) } /* revert reason is padded up to 32 bytes with ABI encoder: Error(string) also sometimes there is extra 32 bytes of zeros padded in the end: https://github.com/ethereum/solidity/issues/10170 because of that we can't check for equality and instead check that offset + string length + extra 36 bytes is less than overall data length */ require( data.length >= 36 + offset + reason.length, "Invalid revert reason" ); return string(abi.encodePacked(prefix, "Error(", reason, ")")); } // 36 = 4-byte selector + 32 bytes integer else if (selector == _PANIC_SELECTOR && data.length == 36) { uint256 code; // solhint-disable no-inline-assembly assembly { // 36 = 32 bytes data length + 4-byte selector code := mload(add(data, 36)) } return string( abi.encodePacked(prefix, "Panic(", _toHex(code), ")") ); } } return string(abi.encodePacked(prefix, "Unknown(", _toHex(data), ")")); } function _toHex(uint256 value) private pure returns (string memory) { return _toHex(abi.encodePacked(value)); } function _toHex(bytes memory data) private pure returns (string memory) { bytes16 alphabet = 0x30313233343536373839616263646566; bytes memory str = new bytes(2 + data.length * 2); str[0] = "0"; str[1] = "x"; for (uint256 i = 0; i < data.length; i++) { str[2 * i + 2] = alphabet[uint8(data[i] >> 4)]; str[2 * i + 3] = alphabet[uint8(data[i] & 0x0f)]; } return string(str); } }
{ "optimizer": { "enabled": true, "runs": 200 }, "viaIR": true, "outputSelection": { "*": { "*": [ "evm.bytecode", "evm.deployedBytecode", "devdoc", "userdoc", "metadata", "abi" ] } }, "libraries": {} }
Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
[{"inputs":[],"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"bytes4","name":"_selectorId","type":"bytes4"},{"indexed":false,"internalType":"bool","name":"_enable","type":"bool"}],"name":"AccessSelectorIdChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"_adaptorId","type":"uint256"},{"indexed":false,"internalType":"address","name":"_adaptor","type":"address"}],"name":"AdaptorsChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"_newAdmin","type":"address"}],"name":"AdminChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"address","name":"fromToken","type":"address"},{"indexed":false,"internalType":"address","name":"toToken","type":"address"},{"indexed":false,"internalType":"uint256","name":"fromTokenAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"toTokenAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"gasFeeAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"srcChainId","type":"uint256"},{"indexed":false,"internalType":"string","name":"errInfo","type":"string"},{"indexed":false,"internalType":"bytes32[]","name":"ext","type":"bytes32[]"}],"name":"Claimed","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"commissionAmount","type":"uint256"},{"indexed":false,"internalType":"address","name":"referrerAddress","type":"address"}],"name":"CommissionRecord","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"_dexRouter","type":"address"}],"name":"DexRouterChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"_feeTo","type":"address"}],"name":"FeeToChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"srcChainId","type":"uint256"},{"indexed":false,"internalType":"bytes32[]","name":"ext","type":"bytes32[]"}],"name":"GasTokenReceived","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint8","name":"version","type":"uint8"}],"name":"Initialized","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"_adaptorId","type":"uint256"},{"indexed":false,"internalType":"address","name":"_from","type":"address"},{"indexed":false,"internalType":"address","name":"_to","type":"address"},{"indexed":false,"internalType":"address","name":"_token","type":"address"},{"indexed":false,"internalType":"uint256","name":"_amount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"_receiveFee","type":"uint256"},{"indexed":false,"internalType":"bytes32[]","name":"ext","type":"bytes32[]"}],"name":"LogBridgeTo","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"_adaptorId","type":"uint256"},{"indexed":false,"internalType":"address","name":"_from","type":"address"},{"indexed":false,"internalType":"address","name":"_to","type":"address"},{"indexed":false,"internalType":"address","name":"_fromToken","type":"address"},{"indexed":false,"internalType":"uint256","name":"_fromAmount","type":"uint256"},{"indexed":false,"internalType":"address","name":"_toToken","type":"address"},{"indexed":false,"internalType":"uint256","name":"_toAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"_receiveFee","type":"uint256"},{"indexed":false,"internalType":"bytes32[]","name":"ext","type":"bytes32[]"}],"name":"LogSwapAndBridgeTo","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"_mpc","type":"address"},{"indexed":false,"internalType":"bool","name":"_enable","type":"bool"}],"name":"MpcChanged","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":false,"internalType":"address","name":"account","type":"address"}],"name":"Paused","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"_proxy","type":"address"},{"indexed":false,"internalType":"bool","name":"_enable","type":"bool"}],"name":"ProxiesChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"_index","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"_ratio","type":"uint256"}],"name":"SysRatioChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"account","type":"address"}],"name":"Unpaused","type":"event"},{"inputs":[{"internalType":"bytes4","name":"","type":"bytes4"}],"name":"accessSelectorId","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"adaptorInfo","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"admin","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"approveProxy","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"components":[{"internalType":"uint256","name":"adaptorId","type":"uint256"},{"internalType":"address","name":"to","type":"address"},{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"toChainId","type":"uint256"},{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"bytes","name":"data","type":"bytes"},{"internalType":"bytes","name":"extData","type":"bytes"}],"internalType":"struct XBridge.BridgeRequestV2","name":"_request","type":"tuple"}],"name":"bridgeToV2","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"components":[{"internalType":"address","name":"fromToken","type":"address"},{"internalType":"address","name":"toToken","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"uint256","name":"gasFeeAmount","type":"uint256"},{"internalType":"uint256","name":"srcChainId","type":"uint256"},{"internalType":"bytes32","name":"srcTxHash","type":"bytes32"},{"internalType":"bytes","name":"dexData","type":"bytes"},{"internalType":"bytes","name":"extData","type":"bytes"}],"internalType":"struct XBridge.SwapRequest","name":"_request","type":"tuple"}],"name":"claim","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"commissionRateLimit","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"dexRouter","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"components":[{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"uint256","name":"srcChainId","type":"uint256"},{"internalType":"bytes32","name":"srcTxHash","type":"bytes32"},{"internalType":"bytes","name":"extData","type":"bytes"}],"internalType":"struct XBridge.ReceiveGasRequest[]","name":"_gasRequest","type":"tuple[]"},{"components":[{"internalType":"address","name":"fromToken","type":"address"},{"internalType":"address","name":"toToken","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"uint256","name":"gasFeeAmount","type":"uint256"},{"internalType":"uint256","name":"srcChainId","type":"uint256"},{"internalType":"bytes32","name":"srcTxHash","type":"bytes32"},{"internalType":"bytes","name":"dexData","type":"bytes"},{"internalType":"bytes","name":"extData","type":"bytes"}],"internalType":"struct XBridge.SwapRequest[]","name":"_claimRequest","type":"tuple[]"}],"name":"doBatch","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"feeTo","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"initialize","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"mpc","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"bytes32","name":"","type":"bytes32"}],"name":"paidTx","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"pause","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"paused","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"payer","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"payerReceiver","outputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"proxies","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"components":[{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"uint256","name":"srcChainId","type":"uint256"},{"internalType":"bytes32","name":"srcTxHash","type":"bytes32"},{"internalType":"bytes","name":"extData","type":"bytes"}],"internalType":"struct XBridge.ReceiveGasRequest","name":"_request","type":"tuple"}],"name":"receiveGasToken","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"bytes32","name":"","type":"bytes32"}],"name":"receiveGasTx","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"receiver","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"renounceOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes4[]","name":"selectorIds","type":"bytes4[]"},{"internalType":"bool[]","name":"values","type":"bool[]"}],"name":"setAccessSelectorId","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256[]","name":"_ids","type":"uint256[]"},{"internalType":"address[]","name":"_adaptors","type":"address[]"}],"name":"setAdaptors","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_newAdmin","type":"address"}],"name":"setAdmin","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_newDexRouter","type":"address"}],"name":"setDexRouter","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_newFeeTo","type":"address"}],"name":"setFeeTo","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address[]","name":"_mpcList","type":"address[]"},{"internalType":"bool[]","name":"_v","type":"bool[]"}],"name":"setMpc","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address[]","name":"proxiesList","type":"address[]"},{"internalType":"bool[]","name":"values","type":"bool[]"}],"name":"setProxies","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_index","type":"uint256"},{"internalType":"uint256","name":"_v","type":"uint256"}],"name":"setSysRatio","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"components":[{"internalType":"address","name":"fromToken","type":"address"},{"internalType":"address","name":"toToken","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"adaptorId","type":"uint256"},{"internalType":"uint256","name":"toChainId","type":"uint256"},{"internalType":"uint256","name":"fromTokenAmount","type":"uint256"},{"internalType":"uint256","name":"toTokenMinAmount","type":"uint256"},{"internalType":"uint256","name":"toChainToTokenMinAmount","type":"uint256"},{"internalType":"bytes","name":"data","type":"bytes"},{"internalType":"bytes","name":"dexData","type":"bytes"},{"internalType":"bytes","name":"extData","type":"bytes"}],"internalType":"struct XBridge.SwapBridgeRequestV2","name":"_request","type":"tuple"}],"name":"swapBridgeToV2","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"components":[{"internalType":"address","name":"fromToken","type":"address"},{"internalType":"address","name":"toToken","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"adaptorId","type":"uint256"},{"internalType":"uint256","name":"toChainId","type":"uint256"},{"internalType":"uint256","name":"fromTokenAmount","type":"uint256"},{"internalType":"uint256","name":"toTokenMinAmount","type":"uint256"},{"internalType":"uint256","name":"toChainToTokenMinAmount","type":"uint256"},{"internalType":"bytes","name":"data","type":"bytes"},{"internalType":"bytes","name":"dexData","type":"bytes"},{"internalType":"bytes","name":"extData","type":"bytes"}],"internalType":"struct XBridge.SwapBridgeRequestV2","name":"_request","type":"tuple"},{"internalType":"bytes","name":"_signature","type":"bytes"}],"name":"swapBridgeToWithPermit","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"sysAddressConfig","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"sysRatio","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"thresholdConfig","outputs":[{"internalType":"bool","name":"opened","type":"bool"},{"internalType":"uint256","name":"amount","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"unpause","outputs":[],"stateMutability":"nonpayable","type":"function"},{"stateMutability":"payable","type":"receive"}]
Contract Creation Code
60808060405234620000c6576000549060ff8260081c1662000074575060ff8082160362000038575b604051614dac9081620000cc8239f35b60ff90811916176000557f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb3847402498602060405160ff8152a13862000028565b62461bcd60e51b815260206004820152602760248201527f496e697469616c697a61626c653a20636f6e747261637420697320696e697469604482015266616c697a696e6760c81b6064820152608490fd5b600080fdfe6080604052600436101561001b575b361561001957600080fd5b005b60003560e01c80621a9f621461027a578063017e7e58146102755780630758d92414610270578063123119cd1461026b5780633d21e25a146102665780633eee9156146102615780633f4ba83a1461025c578063474707f014610257578063534015b314610252578063596056791461024d5780635c975abb14610248578063704b6c0214610243578063715018a61461023e5780637ae729ca146102395780638129fc1c1461023457806381a522221461022f5780638456cb591461022a578063861a8dcb146102255780638da5cb5b146102205780638e8920e31461021b578063972250fe14610216578063aa0bd4de14610211578063adc927af1461020c578063aeee23c414610207578063b796af1314610202578063bb8c17d3146101fd578063be75ddac146101f8578063c1a8e6fd146101f3578063c4552791146101ee578063ca68d8f6146101e9578063cea8ef5c146101e4578063e2587da1146101df578063f2fde38b146101da578063f3dced3c146101d5578063f46901ed146101d0578063f7260d3e146101cb578063f72f863b146101c65763f851a4400361000e576116f3565b61166f565b611646565b6115c2565b611599565b611508565b61145f565b61142b565b61140e565b6113cc565b611381565b611342565b6112d4565b6112a8565b611269565b6111ba565b611086565b610f99565b610f27565b610efe565b610e4b565b610cea565b610ca8565b610bc5565b610b91565b610b30565b610ab1565b610a8e565b610a4c565b610a03565b610992565b6108e6565b610881565b61078c565b610626565b6105fd565b6105d4565b6104bb565b634e487b7160e01b600052604160045260246000fd5b6001600160401b0381116102a857604052565b61027f565b60e081019081106001600160401b038211176102a857604052565b604081019081106001600160401b038211176102a857604052565b602081019081106001600160401b038211176102a857604052565b90601f801991011681019081106001600160401b038211176102a857604052565b6040519061016082018281106001600160401b038211176102a857604052565b6040519061012082018281106001600160401b038211176102a857604052565b6040519061036c826102ad565b565b6001600160401b0381116102a85760051b60200190565b6001600160a01b0381160361039657565b600080fd5b359061036c82610385565b8015150361039657565b81601f82011215610396578035916103c78361036e565b926103d560405194856102fe565b808452602092838086019260051b820101928311610396578301905b8282106103ff575050505090565b838091833561040d816103a6565b8152019101906103f1565b906040600319830112610396576001600160401b0360043581811161039657836023820112156103965780600401356104508161036e565b9161045e60405193846102fe565b81835260209160248385019160051b8301019187831161039657602401905b8282106104a25750505050926024359182116103965761049f916004016103b0565b90565b83809183356104b081610385565b81520191019061047d565b34610396576104c936610418565b60cf5490916001600160a01b03916104ed90831633146104e7611998565b90611968565b6104fd81518451146104e7611a02565b60005b815181101561001957807f0bf1a6b9bd400a8478e3082dd8932968c39600716acaf5dbf7553e798c1cd36a6105386105c49387611ae0565b511515856105468487611ae0565b511660005260d060205261056b604091826000209060ff801983541691151516179055565b6105856105788487611ae0565b516001600160a01b031690565b6105bc61059b610595868b611ae0565b51151590565b92516001600160a01b03909216825291151560208201529081906040820190565b0390a1611a44565b610500565b600091031261039657565b346103965760003660031901126103965760ce546040516001600160a01b039091168152602090f35b346103965760003660031901126103965760cb546040516001600160a01b039091168152602090f35b346103965760003660031901126103965760cc546040516001600160a01b039091168152602090f35b6001600160401b0381116102a857601f01601f191660200190565b81601f82011215610396578035906106818261064f565b9261068f60405194856102fe565b8284526020838301011161039657816000926020809301838601378301015290565b919061016083820312610396576106c661031f565b926106d08161039b565b84526106de6020820161039b565b60208501526106ef6040820161039b565b6040850152606081013560608501526080810135608085015260a081013560a085015260c081013560c085015260e081013560e08501526101009182820135926001600160401b0393848111610396578261074b91850161066a565b9086015261012080830135848111610396578261076991850161066a565b90860152610140928383013590811161039657610786920161066a565b90830152565b6020366003190112610396576004356001600160401b038111610396576107ba6107cf9136906004016106b1565b6107c2611f07565b6107ca6119be565b612a45565b6001609755005b919061012083820312610396576107eb61033f565b926107f58161039b565b84526108036020820161039b565b60208501526108146040820161039b565b6040850152606081013560608501526080810135608085015260a081013560a085015260c081013560c085015260e0810135916001600160401b0392838111610396578161086391840161066a565b60e0860152610100928383013590811161039657610786920161066a565b34610396576020366003190112610396576004356001600160401b038111610396576108b46107cf9136906004016107d6565b6108bc611f07565b6108c46119be565b3360005260d06020526108e160ff604060002054166104e761397a565b613c6d565b346103965760003660031901126103965760cf54610917906001600160a01b031661090f611998565b903314611968565b60335460ff8116156109565760ff19166033557f5db9ee0a495bf2e6ff9c91a7834c1ba4fdd244a5e8aa4e537bd38aeae4b073aa6020604051338152a1005b60405162461bcd60e51b815260206004820152601460248201527314185d5cd8589b194e881b9bdd081c185d5cd95960621b6044820152606490fd5b346103965760031960403682011261039657600435906001600160401b039081831161039657610160908336030112610396576024359181831161039657366023840112156103965782600401359182116103965736602483850101116103965760246100199301906004016137fc565b346103965760003660031901126103965760cc5460cd54604080516001600160a01b03938416815292909116602083015290f35b35906001600160e01b03198216820361039657565b346103965760203660031901126103965760043563ffffffff60e01b81168091036103965760005260d7602052602060ff604060002054166040519015158152f35b3461039657600036600319011261039657602060ff603354166040519015158152f35b34610396576020366003190112610396577f7ce7ec0b50378fb6c0186ffb5f48325f6593fcb4ca4386f21861af3129188f5c6020600435610af181610385565b610af961171c565b6001600160a01b0316610b15610b0d6118ea565b821515611968565b60cf80546001600160a01b03191682179055604051908152a1005b3461039657600080600319360112610b8e57610b4a61171c565b606580546001600160a01b0319811690915581906001600160a01b03167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e08280a380f35b80fd5b346103965760203660031901126103965760043560005260d4602052602060018060a01b0360406000205416604051908152f35b3461039657600080600319360112610b8e578054610bfa60ff8260081c161580928193610c9a575b8115610c7a575b506117bd565b80610c0d600160ff196000541617600055565b610c61575b610c1a611820565b610c215780f35b610c3161ff001960005416600055565b604051600181527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb384740249890602090a180f35b610c7561010061ff00196000541617600055565b610c12565b303b15915081610c8c575b5038610bf4565b6001915060ff161438610c85565b600160ff8216109150610bed565b3461039657602036600319011261039657600435610cc581610385565b60018060a01b031660005260d0602052602060ff604060002054166040519015158152f35b346103965760003660031901126103965760cf54610d13906001600160a01b031661090f611998565b610d1b6119be565b600160ff1960335416176033557f62e78cea01bee320cd4e420270b5ea74000d11b0c9f74754ebdbfc544b05a2586020604051338152a1005b91909160a08184031261039657604051906001600160401b039060a08301828111848210176102a85760405282948135610d8d81610385565b8452602082013560208501526040820135604085015260608201356060850152608082013592831161039657608092610dc6920161066a565b910152565b9080601f8301121561039657813590610de38261036e565b92610df160405194856102fe565b828452602092838086019160051b8301019280841161039657848301915b848310610e1f5750505050505090565b82356001600160401b038111610396578691610e40848480948901016107d6565b815201920191610e0f565b6040366003190112610396576001600160401b036004358181116103965736602382011215610396578060040135610e828161036e565b91610e9060405193846102fe565b8183526020908184016024809460051b8301019136831161039657848101915b838310610ed85785358789821161039657610ed2610019923690600401610dcb565b9061494b565b8235888111610396578591610ef38392893691870101610d54565b815201920191610eb0565b34610396576000366003190112610396576065546040516001600160a01b039091168152602090f35b6020366003190112610396576004356001600160401b03811161039657610f556107cf913690600401610d54565b610f5d611f07565b610f656119be565b3360005260d0602052610f8260ff604060002054166104e761397a565b610f94602082015134146104e761207c565b613a22565b60031960203682011261039657600435906001600160401b03908183116103965760e090833603011261039657610fce61035f565b9082600401358252610fe26024840161039b565b6020830152610ff36044840161039b565b6040830152606483013560608301526084830135608083015260a483013581811161039657611028906004369186010161066a565b60a083015260c48301359081116103965761001992600461104c923692010161066a565b60c0820152611bed565b9181601f84011215610396578235916001600160401b038311610396576020808501948460051b01011161039657565b3461039657604080600319360112610396576001600160401b0390600435828111610396576110b9903690600401611056565b92602435908111610396576110d2903690600401611056565b93909160018060a01b03936110ef8560cf541633146104e7611998565b6111026110fa611a02565b878514611968565b60005b83811061110e57005b8061111d6111b5928988611a6e565b3561112781610385565b611132828787611a6e565b3560005261116560209160c98352856000209060018060a01b03166bffffffffffffffffffffffff60a01b825416179055565b7f0f86ee2bbb4d6370cc5e337c548e9af76e112c16b1aa97877c11e1328fa8ca39611191838888611a6e565b359161119e848c8b611a6e565b356111a881610385565b8a875191168152a2611a44565b611105565b34610396576111c836610418565b60cf5490916001600160a01b03916111e690831633146104e7611998565b6111f681518451146104e7611a02565b60005b815181101561001957807f4519d4931af171182c3df6a6b61730c684f07903a4bd23a3edbff97685da43746112316112649387611ae0565b5115158561123f8487611ae0565b511660005260d660205261056b604091826000209060ff801983541691151516179055565b6111f9565b346103965760403660031901126103965760043560005260d16020526040600020602435600052602052602060ff604060002054166040519015158152f35b346103965760203660031901126103965760043560005260d36020526020604060002054604051908152f35b34610396576040366003190112610396577f7ef26aca67d68e814b326749559541e70261dc0bb13ec23b061cb4efae5bf10a604060043560243561132660018060a01b0360cf541633146104e7611998565b8160005260d360205280836000205582519182526020820152a1005b346103965760403660031901126103965760043560005260d26020526040600020602435600052602052602060ff604060002054166040519015158152f35b346103965760203660031901126103965760043561139e81610385565b60018060a01b031660005260d5602052604080600020600160ff825416910154825191151582526020820152f35b34610396576020366003190112610396576004356113e981610385565b60018060a01b031660005260d6602052602060ff604060002054166040519015158152f35b3461039657600036600319011261039657602060405161012c8152f35b346103965760203660031901126103965760043560005260c9602052602060018060a01b0360406000205416604051908152f35b34610396576040366003190112610396576001600160401b03600435818111610396573660238201121561039657806004013561149b8161036e565b916114a960405193846102fe565b81835260209160248385019160051b8301019136831161039657602401905b8282106114f15760243585878211610396576114eb6100199236906004016103b0565b90611af4565b8380916114fd84610a37565b8152019101906114c8565b346103965760203660031901126103965760043561152581610385565b61152d61171c565b6001600160a01b038116156115455761001990611774565b60405162461bcd60e51b815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201526564647265737360d01b6064820152608490fd5b346103965760003660031901126103965760ca546040516001600160a01b039091168152602090f35b34610396576020366003190112610396577f3dedba2a214b4fff9bf20fc473c114824654e0bc70512b4a92f6d5978763c28d602060043561160281610385565b60cf546001600160a01b03919061161f90831633146104e7611998565b1661162b610b0d6118ea565b60ce80546001600160a01b03191682179055604051908152a1005b346103965760003660031901126103965760cd546040516001600160a01b039091168152602090f35b34610396576020366003190112610396577f33f0bdb7050bc888ca819c34892844adff2a3109dc1810301e8fd6af0ac7edb960206004356116af81610385565b60cf546001600160a01b0391906116cc90831633146104e7611998565b166116d8610b0d6118ea565b60cb80546001600160a01b03191682179055604051908152a1005b346103965760003660031901126103965760cf546040516001600160a01b039091168152602090f35b6065546001600160a01b0316330361173057565b606460405162461bcd60e51b815260206004820152602060248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65726044820152fd5b606580546001600160a01b039283166001600160a01b0319821681179092559091167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0600080a3565b156117c457565b60405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201526d191e481a5b9a5d1a585b1a5e995960921b6064820152608490fd5b61186d60ff60005460081c166118358161188a565b61183e8161188a565b60ff19603354166033556118518161188a565b61185a8161188a565b60016097556118688161188a565b61188a565b61187633611774565b60cf80546001600160a01b03191633179055565b1561189157565b60405162461bcd60e51b815260206004820152602b60248201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960448201526a6e697469616c697a696e6760a81b6064820152608490fd5b604051906118f7826102c8565b600982526806164647265737320360bc1b6020830152565b60005b8381106119225750506000910152565b8181015183820152602001611912565b9060209161194b8151809281855285808601910161190f565b601f01601f1916010190565b90602061049f928181520190611932565b156119705750565b60405162461bcd60e51b815260206004820152908190611994906024830190611932565b0390fd5b604051906119a5826102c8565b600a82526937b7363c9030b236b4b760b11b6020830152565b60ff603354166119ca57565b60405162461bcd60e51b815260206004820152601060248201526f14185d5cd8589b194e881c185d5cd95960821b6044820152606490fd5b60405190611a0f826102c8565b601082526f1b195b99dd1a081b9bdd08195c5d585b60821b6020830152565b634e487b7160e01b600052601160045260246000fd5b6000198114611a535760010190565b611a2e565b634e487b7160e01b600052603260045260246000fd5b9190811015611a7e5760051b0190565b611a58565b805115611a7e5760200190565b805160011015611a7e5760400190565b805160021015611a7e5760600190565b805160031015611a7e5760800190565b805160041015611a7e5760a00190565b805160051015611a7e5760c00190565b8051821015611a7e5760209160051b010190565b9190611b0e60018060a01b0360cf541633146104e7611998565b611b1e83518251146104e7611a02565b600092835b8151811015611be657807f2fc5194644b0d028829e475d57cad5ccad073d27cef6d863b7bd7ed88ae9a2c1611b5b611be19386611ae0565b5115156001600160e01b0319611b718487611ae0565b5116885260d7602052611b94604091828a209060ff801983541691151516179055565b611baf611ba18487611ae0565b516001600160e01b03191690565b6105bc611bbf610595868a611ae0565b92516001600160e01b0319909216825291151560208201529081906040820190565b611b23565b5050509050565b611bf5611f07565b611bfd6119be565b611c0c815115156104e7611f5d565b611c31611c24825160005260c9602052604060002090565b546001600160a01b031690565b6001600160a01b0381811692611c50611c48611f8a565b851515611968565b602081018051909490611c8190611c77906001600160a01b03165b6001600160a01b031690565b15156104e76118ea565b604082018051909290611ca090611c77906001600160a01b0316611c6b565b6080810193611cb4855115156104e7611fc3565b611cbc611ff1565b8551855160c08501805190999392611cdd926001600160a01b0316906126bb565b908160208401528252885234611d0c60608601518060c01c9163ffffffff60018060a01b038360201c16921690565b939194909573eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee611d368b5160018060a01b031690565b91821603611ec257505090611d7091611d69611d5e611d56888d5161206f565b83519061206f565b8310156104e761207c565b51906120c8565b8380611e80575b505b89516001600160a01b031687519091906001600160a01b03169689519060a0880198895193823b15610396578695611dcd60009660405198899788968795636f82189d60e01b875233903360048901612134565b03925af1928315611e7b577ff6481cbc1da19356c5cb6b884be507da735b89f21dc4bbb7c9b7cc0968b03b7a99611e55978c611e3895611e2895611e4698611e62575b50895191516001600160a01b03169251935194612413565b935198516001600160a01b031690565b94516001600160a01b031690565b945160405195869533876121b8565b0390a261036c6001609755565b80611e6f611e7592610295565b806105c9565b38611e10565b612178565b611ebc91611eb7600080808086611ea4611c6b611c6b60ce5460018060a01b031690565b5af1611eae6120d5565b506104e7612105565b6120c8565b83611d77565b611ee492508680611ee9575b505088516001600160a01b03168a51913361228c565b611d79565b60ce54611f0092906001600160a01b03163361228c565b3886611ece565b600260975414611f18576002609755565b60405162461bcd60e51b815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c006044820152606490fd5b60405190611f6a826102c8565b60118252701a5b9d985b1a59081859185c1d1bdc9251607a1b6020830152565b60405190611f97826102c8565b601782527f696e76616c69642061646170746f7220616464726573730000000000000000006020830152565b60405190611fd0826102c8565b60128252710616d6f756e74206d757374206265203e20360741b6020830152565b60405190604082018281106001600160401b038211176102a8576040526060602083600081520152565b9060648201809211611a5357565b6020019081602011611a5357565b6024019081602411611a5357565b6002019081600211611a5357565b9060028201809211611a5357565b9060038201809211611a5357565b91908201809211611a5357565b60405190612089826102c8565b6011825270696e76616c6964206d73672076616c756560781b6020830152565b90612710918203918211611a5357565b601f19810191908211611a5357565b91908203918211611a5357565b3d15612100573d906120e68261064f565b916120f460405193846102fe565b82523d6000602084013e565b606090565b60405190612112826102c8565b6013825272115512081d1c985b9cd9995c8819985a5b1959606a1b6020830152565b9360e095929161049f98979460018060a01b038094818094168952166020880152166040860152166060840152608083015260a08201528160c08201520190611932565b6040513d6000823e3d90fd5b90815180825260208080930193019160005b8281106121a4575050505090565b835185529381019392810192600101612196565b929161049f96959260c0959260018060a01b0392838092168752166020860152166040840152606083015260808201528160a08201520190612184565b73cff09e645a627b8208ef67da294d0edc2d25551791823b156103965760405163052f523360e11b815273039e2fb66102314ce7b64ce5ce3e5183bc94ad3860048201526001600160a01b0390921660248301527207ef1cde141326b0da51c83cbac3f6feaf507c60448301526064820152906000908290608490829084905af18015611e7b576122835750565b61036c90610295565b929173cff09e645a627b8208ef67da294d0edc2d25551790813b156103965760405163052f523360e11b81526001600160a01b0391821660048201529481166024860152909116604484015260648301919091526000908290608490829084905af18015611e7b576122835750565b60405190612308826102ad565b6006825260c0366020840137565b60405190612323826102c8565b6001825260203681840137565b81601f820112156103965780516123468161064f565b9261235460405194856102fe565b818452602082840101116103965761049f916020808501910161190f565b60808183031261039657805161238781610385565b926020820151926001600160401b039384811161039657816123aa918501612330565b936040840151908111610396576060916123c5918501612330565b92015190565b6020815191015190602081106123df575090565b6000199060200360031b1b1690565b906020828203126103965781516001600160401b0381116103965761049f9201612330565b9493919061241f6122fb565b9561242987611a83565b5261243386611a90565b5260018114801561258b575b1561252357505060405160609190911b6bffffffffffffffffffffffff191660208201526124839061247e81603481015b03601f1981018352826102fe565b6123cb565b61248c83611aa0565b526124a06040516000815261247e816102e3565b6124a983611ab0565b525b805115612505576124c8816020806124cd945183010191016123ee565b614a32565b6124d681611a83565b516124e083611ac0565b5260018151116124ee575090565b6124f790611a90565b5161250182611ad0565b5290565b5061250f81611aa0565b5161251982611ac0565b526124f781611ab0565b600391925014612534575b506124ab565b61254a8160208061255394518301019101612372565b50915050614a32565b61255c81611a83565b5161256684611aa0565b5260018151111561252e5761257a90611a90565b5161258483611ab0565b523861252e565b506002811461243f565b604051906125a2826102c8565b601b82527f6572726f7220636f6d6d697373696f6e2072617465206c696d697400000000006020830152565b908160011b9180830460021490151715611a5357565b600181901b91906001600160ff1b03811603611a5357565b81810292918115918404141715611a5357565b8115612619570490565b634e487b7160e01b600052601260045260246000fd5b6040519061263c826102c8565b601b82527f636f6d6d697373696f6e2077697468206574686572206572726f7200000000006020830152565b906126728261064f565b61267f60405191826102fe565b8281528092612690601f199161064f565b0190602036910137565b805160011015611a7e5760210190565b908151811015611a7e570160200190565b6000939236601f190135929091856001600160d01b03198516651e51057e155560d11b0361282f57506001600160a01b038481169473eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee93926127489160a01c65ffffffffffff16906127429061273c90839061273761272c612595565b61012c841115611968565b6125fc565b916120a9565b9061260f565b92839183160361281f5761277091508680808093885af16127676120d5565b506104e761262f565b81519361278461277f866120b9565b612668565b93865b612790876120b9565b8110156127d2576127cb816127b96127ab61279094896126aa565b516001600160f81b03191690565b8a1a6127c5828a6126aa565b53611a44565b9050612787565b50604080518481526001600160a01b039092166020830152929650939450927fffc60ee157a42f4d8edbd1897e6581a96d9ed04e44fb2ab53a47ce1eb8f2775b925090819081015b0390a1565b61282a91853361228c565b612770565b95505050905090565b6040519061012082018281106001600160401b038211176102a857604052606061010083600080825280602083015280604083015280848301528060808301528060a08301528060c083015260e08201520152565b6040519061289a826102c8565b600d82526c1859191c995cdcc8195c5d585b609a1b6020830152565b604051906128c3826102c8565b601682527506d696e20616d6f756e74206d757374206265203e20360541b6020830152565b906020825192015163ffffffff60e01b90818116936004811061290a57505050565b60040360031b82901b16169150565b60405190612926826102c8565b600f82526e195c9c881cd95b1958dd1bdc881a59608a1b6020830152565b60405190612951826102c8565b601182527003232bc103937baba32b91032b939101d1607d1b6020830152565b6040519061297e826102c8565b60128252711a5b9d195c9b985b081ddc985c0819985a5b60721b6020830152565b604051906129ac826102c8565b600e82526d36b4b71030b6b7bab73a1032b93960911b6020830152565b95939061049f989795929360018060a01b038095818094168a52166020890152166040870152606086015216608084015260a083015260c0820152610100908160e08201520190612184565b60405190612a22826102c8565b6014825273736c617368206d75636820746f6f206d6f6e657960601b6020830152565b612a4d612838565b612a5f606083015115156104e7611f5d565b612a8a612a7d611c24606085015160005260c9602052604060002090565b6001600160a01b03168252565b8051612aa3906001600160a01b031615156104e7611f8a565b8151612abb90611c77906001600160a01b0316611c6b565b6020820151612ad690611c77906001600160a01b0316611c6b565b8151612b11906001600160a01b03166020840151612afc906001600160a01b0316611c6b565b6001600160a01b0390911614156104e761288d565b6040820151612b2c90611c77906001600160a01b0316611c6b565b60cb54612b4590611c77906001600160a01b0316611c6b565b612b5760a083015115156104e7611fc3565b612b6960c083015115156104e76128b6565b608082015160c081901c90602081901c6001600160a01b03169063ffffffff166080840152606083015260a08201526020820151612bb4906001600160a01b0316613210565b613210565b6040820152612bf8612bf0612be9612bd06101208601516128e8565b63ffffffff60e01b1660005260d7602052604060002090565b5460ff1690565b6104e7612919565b60cc80546001600160a01b0319163317905560cd80546001600160a01b0319163017905560a08201518251612c3d91906001600160a01b0316610140850151916126bb565b61014084015282516001600160a01b031673eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeed19810161317b5750612c87612c7882346120c8565b60a085015111156104e761207c565b60208301516001600160a01b031673039e2fb66102314ce7b64ce5ce3e5183bc94ad37190161313757612cca612cc160a0850151306136be565b151560c0840152565b60cc80546001600160a01b031916905560cd80546001600160a01b0319169055612d0f612cfa60c0840151151590565b610100840151805161312557506104e7612971565b6020830151612d5c90612d3990612d2e906001600160a01b0316613210565b6040850151906120c8565b806020850152612d52606085015160c08701519061206f565b11156104e761299f565b60ce54612d85906001600160a01b031660208501516001600160a01b03166060850151916132de565b612d9860208301516060840151906120c8565b60208381018290528401516001600160a01b03169073eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee829003612f995750508151612de49150611c6b9081906001600160a01b031681565b612df36020830151349061206f565b60408401519091906001600160a01b031660208501519091906001600160a01b03169060208501519160808601519461010088015194833b1561039657612e5660009660405198899788968795636f82189d60e01b875233903360048901612134565b03925af18015611e7b57612f86575b505b60a0810151608082015160608401516040850151612e9f939291906001600160a01b0316906101008701519261014088015194612413565b6060830151604084015190917fb9dae57db52a734b183c77227c96068231beb6a93a060ca7a9d3164f716714ea916001600160a01b03168551612f14906001600160a01b031660a088015160208901519194916001600160a01b031660208901519060608a01519260405197889733896129c9565b0390a260208201516001600160a01b031673eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee819003612f7457506040612f67612f60612baf602061036c96015160018060a01b031690565b349061206f565b91015111156104e7612a15565b61036c9250612f67604091309061322a565b80611e6f612f9392610295565b38612e65565b8351612fae92906001600160a01b03166132de565b825173eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee90612fd8906001600160a01b0316611c6b565b036130995761300e613003612ffc611c6b611c6b611c6b875160018060a01b031690565b92346120c8565b60a0850151906120c8565b60408401519091906001600160a01b031660208501519091906001600160a01b03169060208501519160808601519461010088015194833b156103965761307160009660405198899788968795636f82189d60e01b875233903360048901612134565b03925af18015611e7b57613086575b50612e67565b80611e6f61309392610295565b38613080565b5080516130b290611c6b9081906001600160a01b031681565b60408301516001600160a01b031660208401516001600160a01b03169160208401519060808501519361010087015193823b156103965761310f60009560405197889687958695636f82189d60e01b875233903360048901612134565b039134905af18015611e7b576130865750612e67565b6104e790613131612944565b90614b19565b60cb5460a08401516101208501518051613176936000938493602001916001600160a01b03165af16131676120d5565b610100850152151560c0840152565b612cca565b73039e2fb66102314ce7b64ce5ce3e5183bc94ad3814806131dc575b156131ae57613176612cc160a08501513033613577565b60cb546131769060009081906001600160a01b03166101208701519082602083519301915af16131676120d5565b50602083015173eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee9061320a906001600160a01b0316611c6b565b14613197565b61049f90309061322a565b90816020910312610396575190565b6000906001600160a01b039081169073eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee820361325b575050503190565b6024602092939460405194859384926370a0823160e01b84521660048301525afa918215611e7b579161328c575090565b61049f915060203d81116132ad575b6132a581836102fe565b81019061321b565b503d61329b565b90806132be575050565b61036c916000918291829182916001600160a01b03165af1611eae6120d5565b9190816132ea57505050565b6001600160a01b0390811673eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee810361332757506000808093819361036c96165af1611eae6120d5565b60405163a9059cbb60e01b60208201526001600160a01b03909416602485015260448401929092525061036c919061336c82606481015b03601f1981018452836102fe565b613386565b90816020910312610396575161049f816103a6565b6040516133e4916001600160a01b031661339f826102c8565b6000806020958685527f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c656487860152868151910182855af16133de6120d5565b9161350e565b805190828215928315613454575b505050156133fd5750565b6084906040519062461bcd60e51b82526004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e6044820152691bdd081cdd58d8d9595960b21b6064820152fd5b6134649350820181019101613371565b3882816133f2565b909190156134e2575080511561347f5790565b73039e2fb66102314ce7b64ce5ce3e5183bc94ad383b1561349d5790565b60405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000006044820152606490fd5b8151156134f25750805190602001fd5b60405162461bcd60e51b81529081906119949060048301611957565b9192901561352b5750815115613522575090565b3b1561349d5790565b8251909150156134f25750805190602001fd5b6040519061354b826102c8565b601782527f7772617020616d6f756e74206d757374206265203e20300000000000000000006020830152565b61358a61358261353e565b841515611968565b6001600160a01b03908381831630036136b057505060405163a9059cbb60e01b81527207ef1cde141326b0da51c83cbac3f6feaf507c600482015260248101849052602081604481600073039e2fb66102314ce7b64ce5ce3e5183bc94ad385af18015611e7b57613682575b505b7207ef1cde141326b0da51c83cbac3f6feaf507c91823b1561039657604051632e1a7d4d60e01b81526004810185905260009384908290602490829084905af18015611e7b5761366f575b5016308103613655575b505050600190565b81806136679481935af1611eae6120d5565b38808061364d565b80611e6f61367c92610295565b38613643565b6136a29060203d81116136a9575b61369a81836102fe565b810190613371565b50386135f6565b503d613690565b6136b9916121f5565b6135f8565b6136d16136c961353e565b831515611968565b73039e2fb66102314ce7b64ce5ce3e5183bc94ad3890813b1561039657604051630d0e30db60e41b815260008160048187875af18015611e7b576137ed575b50306001600160a01b0382160361372957505050600190565b60405163a9059cbb60e01b60208083019182526001600160a01b0393909316602483015260448083019590955293815290926137b8926000918291906137706064866102fe565b826040519561377e876102c8565b8887527f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c65648988015251925af16137b26120d5565b9061346c565b8051908282159283156137d5575b505050156133fd57808061364d565b6137e59350820181019101613371565b3882816137c6565b6137f690610295565b38613710565b91613805611f07565b61380d6119be565b82359061381982610385565b8061383a575b5050506107ca6138309136906106b1565b61036c6001609755565b60e081036138a15790600092836124706138608295604051928391602083019687613932565b51925af161386c6120d5565b905b1561387a57808061381f565b6138896119949161313161394f565b60405162461bcd60e51b815291829160048301611957565b9061010082036138da57600092836124706138c88295604051928391602083019687613915565b51925af16138d46120d5565b9061386e565b60405162461bcd60e51b81526020600482015260136024820152720aee4dedcce40e0cae4dad2e840d8cadccee8d606b1b6044820152606490fd5b6323f2ebc360e21b81526004929182908285013701016000815290565b63d505accf60e01b81526004929182908285013701016000815290565b6040519061395c826102c8565b600f82526e02832b936b4ba103330b4b632b21d1608d1b6020830152565b60405190613987826102c8565b60088252676f6e6c79206d706360c01b6020830152565b604051906139ab826102c8565b601282527165786365656420616c6c6f7765642067617360701b6020830152565b604051906139d9826102c8565b600f82526e68617320726563656976652067617360881b6020830152565b909260809261049f959460018060a01b03168352602083015260408201528160608201520190612184565b7fc9f1b98ce4fd29c9b2de9c4514957faa4bf8fbcad43c471530fb873726c3c2869060208101613a678151600160005260d360205260406000205410156104e761399e565b61281a6040830192613b24613a87855160005260d2602052604060002090565b91613ab5613aad613aa9612be960608501968751600052602052604060002090565b1590565b6104e76139cc565b613aed613ae0613ad0885160005260d2602052604060002090565b8551600052602052604060002090565b805460ff19166001179055565b80518551613b03916001600160a01b03166132b4565b613b0b612316565b9251613b1684611a83565b52516001600160a01b031690565b92519351604051948594856139f7565b60405190613b41826102c8565b600f82526e6e6f20656e6f756768206d6f6e657960881b6020830152565b60405190613b6c826102c8565b60088252671a185cc81c185a5960c21b6020830152565b60405190613b90826102c8565b600a8252695f5f726566756e645f5f60b01b6020830152565b9693909161049f989693613bf9969360018060a01b0392838092168b521660208a015216604088015260608701526000608087015260a086015260c08501526101208060e0860152840190611932565b91610100818403910152612184565b90816020910312610396575161049f81610385565b9693909161049f989693613bf9969360018060a01b0392838092168b521660208a015216604088015260006060880152608087015260a086015260c08501526101208060e0860152840190611932565b8051613c81906001600160a01b0316613210565b906060810191825191613c9a608082019384519061206f565b92613ca58483614623565b613cb9613cb0613b34565b85851015611968565b60cb546001600160a01b0390613cd590821615156104e76118ea565b60a0830191613cef835160005260d1602052604060002090565b613d18613d10613aa9612be960c08901948551600052602052604060002090565b6104e7613b5f565b613d43613ae0613d33865160005260d1602052604060002090565b8351600052602052604060002090565b613d4b612316565b9051613d5682611a83565b5260ce546060948591600090613d82906001600160a01b031689516001600160a01b03168751916132de565b60e088018051519097901561425b576020890180519098906001600160a01b031660408b018051909991613dc0916001600160a01b03165b9061322a565b60cc8054306001600160a01b0319918216179091558a5160cd80549092166001600160a01b03909116179055938b5173eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee9083166001600160a01b031673eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeed198101614021575050509c612baf9894613f4e9c9b989461036c9f948c989473039e2fb66102314ce7b64ce5ce3e5183bc94ad38600080516020614d578339815191529b97613f489f613e7e905160018060a01b031690565b1603613ff2575087518451613e9b916001600160a01b03166136be565b8015613fe2575b15908180613fd8575b613fc3575b5060cc80546001600160a01b031916905560cd80546001600160a01b031916905515613f58575085519495613f3895613f049190610578906001600160a01b03168c516001600160a01b03168651916132de565b8951909690613f25906001600160a01b03165b98516001600160a01b031690565b9251905191519260405198899889613ba9565b0390a1516001600160a01b031690565b906120c8565b11156104e7612a15565b8751613fbb969350613f9391613f8591611eb7906001600160a01b03168a516001600160a01b0316613dba565b96516001600160a01b031690565b8951909690613faa906001600160a01b0316613f17565b925191519260405198899889613c1d565b0390a1610578565b613fd1919550613131612944565b9338613eb0565b5080511515613eab565b9450613fec612971565b94613ea2565b60cb54600092508291906001600160a01b03168651915191602083519301915af161401b6120d5565b90613ea2565b73039e2fb66102314ce7b64ce5ce3e5183bc94ad389192935014908161423d575b501561409b57505093613f48979361036c9c8894613f4e9c9b9894600080516020614d578339815191529861408c614083612baf9d5160018060a01b031690565b85519030613577565b80613ea2579450613fec612971565b97939a999692959150979360405197631c6eced560e01b895260208960048173cff09e645a627b8208ef67da294d0edc2d2555175afa988915611e7b578e90829a6141fa575b50899a61410583928c6140fd611c6b8e5160018060a01b031690565b91519161439c565b60cb546001600160a01b031690519082602083519301915af19c6141276120d5565b9d9b6020614174614144611c6b611c6b8d5160018060a01b031690565b604051636eb1769f60e11b81523060048201526001600160a01b03909e1660248f01528d91829081906044820190565b03915afa978815611e7b5761036c9f613f4e9e8b612baf9d613f489f9c600080516020614d578339815191529d6000916141db575b506141b6575b5050613ea2565b90516141d491906141cf906001600160a01b0316611c6b565b61434b565b8b386141af565b6141f4915060203d6020116132ad576132a581836102fe565b386141a9565b611c6b9a509a61410583928b61422a6140fd9f60203d602011614236575b61422281836102fe565b810190613c08565b9d50509250509a6140e1565b503d614218565b8b51909150614254906001600160a01b0316611c6b565b1438614042565b5050613f489550612baf9450613f4e9796939150613fbb600080516020614d578339815191529361036c9b61428e613b83565b906142bc604089016105786142a9825160018060a01b031690565b8b516001600160a01b03168551916132de565b88519095906001600160a01b031660208a01519097906001600160a01b0316613f25565b156142e757565b60405162461bcd60e51b815260206004820152603660248201527f5361666545524332303a20617070726f76652066726f6d206e6f6e2d7a65726f60448201527520746f206e6f6e2d7a65726f20616c6c6f77616e636560501b6064820152608490fd5b60405163095ea7b360e01b60208201526001600160a01b039092166024830152600060448084019190915282526080820191906001600160401b038311828410176102a85761036c92604052613386565b919091811580156143ea575b61036c936143b861336c926142e0565b60405163095ea7b360e01b60208201526001600160a01b0390911660248201526044810193909352826064810161335e565b50604051636eb1769f60e11b81523060048201526001600160a01b038416602482015292602084806044810103816001600160a01b0386165afa908115611e7b576143b861336c9261036c9660009161444a575b501592505093506143a8565b614462915060203d81116132ad576132a581836102fe565b3861443e565b919091604081840312610396578051926001600160401b03938481116103965781614494918401612330565b9360208301519081116103965761049f9201612330565b604051906144b8826102c8565b600b82526a3d32b9379039b4b3b732b960a91b6020830152565b604051906144df826102c8565b601082526f6e6f74206f7261636c652070726f787960801b6020830152565b6040519061450b826102c8565b600c82526b195c9c8818da185a5b881a5960a21b6020830152565b60405190614533826102c8565b601682527531b7b73a3930b1ba1030b2323932b9b99032b93937b960511b6020830152565b60405190614565826102c8565b6014825273636c61696d206e6f206f7261636c6520696e666f60601b6020830152565b60405190614595826102c8565b601482527331b630b4b6903a379030b2323932b9b99032b93960611b6020830152565b604051906145c5826102c8565b601782527f636c61696d20746f6b656e2061646472657373206572720000000000000000006020830152565b604051906145fe826102c8565b601682527531b630b4b6903a37b5b2b71030b6b7bab73a1032b93960511b6020830152565b906147ae6147a76146f26147676146e061474061036c9761465b61465561010083015160208082518301019101614468565b90614863565b97929590916146ab6146a3612be96146716144ab565b6001600160a01b039a90614689908c83161515611968565b6001600160a01b0316600090815260d66020526040902090565b6104e76144d2565b600360005260d36020527f64de0974ce81404dc9f7f680a2e3b4cfc70679cd50192b307cda861d6e23b65054146104e76144fe565b6146e8614526565b9085163014611968565b61470860c08201516020870151146104e7614558565b6040810151610578906001600160a01b03166040870151859061473590611c6b906001600160a01b031681565b9116146104e7614588565b606084015190919061475c90611c6b906001600160a01b031681565b9116146104e76145b8565b600260005260d36020526147a160a07f8f145ec1981fda056bae73a9467bf215a78583d2d921572993bc5b1783a6fe0c549201519161201b565b906125fc565b6064900490565b10156104e76145f1565b6040519060c082018281106001600160401b038211176102a8576040528160a06000918281528260208201528260408201528260608201528260808201520152565b90816060910312610396578051916040602083015192015160ff811681036103965790565b91908261010091031261039657815191602081015161483d81610385565b9160408201519160608101519160808201519160a08101519160e060c083015192015190565b91906148879160006148736147b8565b9260209481868080945183010191016147fa565b9093916148fe895195858b019687206040516148d4816124708a82019485603c917f19457468657265756d205369676e6564204d6573736167653a0a3332000000008252601c8201520190565b51902092604051948594859094939260ff6060936080840197845216602083015260408201520152565b838052039060015afa15611e7b5761491f908460005196805101019061481f565b60a08a015260808901526060880152604087015295850195909552938352926001600160a01b03169190565b919091614956611f07565b61495e6119be565b3360005260209060d0825261497d60ff604060002054166104e761397a565b600093345b82518610156149c55761499e6149988785611ae0565b51613a22565b836149a98785611ae0565b5101518103908111611a53576149bf9095611a44565b94614982565b93929150935060005b84518110156149f857806149ee6149e86149f39388611ae0565b51613c6d565b611a44565b6149ce565b50909250613830917306c6566742076616c7565206d75737420626520360641b60405192614a25846102c8565b6014845283015215611968565b90815191601f8301809311611a5357600592831c614a4f8161036e565b614a5c60405191826102fe565b818152601f19614a6b8361036e565b01926020933685840137819560005b848110614a8957505050505050565b80821b90808204871481151715611a5357614aa6614ab992612029565b840151614ab38287611ae0565b52611a44565b614a7a565b90614ad16020928281519485920161190f565b0190565b15614adc57565b60405162461bcd60e51b815260206004820152601560248201527424b73b30b634b2103932bb32b93a103932b0b9b7b760591b6044820152606490fd5b80516004811015614b76575b50614b4f91612470614b69614b3c61049f94614c5f565b614b636040519687956020870190614abe565b670aadcd6dcdeeedc560c31b815260080190565b90614abe565b602960f81b815260010190565b60208201516001600160e01b03191662461bcd60e51b811480614c3a575b15614be6575050614bd491612470614b6983614b3c602461049f960151614bcd614bc5602483860101945192612037565b84519061206f565b1115614ad5565b6508ae4e4dee4560d31b815260060190565b634e487b7160e01b149081614c2f575b50614c0357614b4f614b25565b614c1d91612470614b69614b3c602461049f950151614c45565b650a0c2dcd2c6560d31b815260060190565b602491501438614bf6565b506044821015614b94565b61049f9060405190602082015260208152614c5f816102c8565b90614c7561277f614c7084516125ce565b612045565b6030614c8082611a83565b536078614c8c8261269a565b5360005b8351811015614d5157614cc7614cc1614cbb614caf6127ab85896126aa565b60041c600f60f81b1690565b60f81c90565b60ff1690565b9060109182811015611a7e576f181899199a1a9b1b9c1cb0b131b232b360811b9081901a614d05614cff614cfa856125e4565b612053565b866126aa565b53614d25614cc1600f60f81b614d1e6127ab868b6126aa565b1660f81c90565b92831015611a7e57614d4c921a6127c5614d46614d41846125e4565b612061565b856126aa565b614c90565b50915056fe6d1b775ce655ea3b568c59e0f161908781f216e4d9feb04fa524ca23a44f4b07a2646970667358221220e5265d56af53444cdb5b89cac8a9802478e974e7aed6dc611e318e12276e8e0b64736f6c63430008130033
Deployed Bytecode
0x6080604052600436101561001b575b361561001957600080fd5b005b60003560e01c80621a9f621461027a578063017e7e58146102755780630758d92414610270578063123119cd1461026b5780633d21e25a146102665780633eee9156146102615780633f4ba83a1461025c578063474707f014610257578063534015b314610252578063596056791461024d5780635c975abb14610248578063704b6c0214610243578063715018a61461023e5780637ae729ca146102395780638129fc1c1461023457806381a522221461022f5780638456cb591461022a578063861a8dcb146102255780638da5cb5b146102205780638e8920e31461021b578063972250fe14610216578063aa0bd4de14610211578063adc927af1461020c578063aeee23c414610207578063b796af1314610202578063bb8c17d3146101fd578063be75ddac146101f8578063c1a8e6fd146101f3578063c4552791146101ee578063ca68d8f6146101e9578063cea8ef5c146101e4578063e2587da1146101df578063f2fde38b146101da578063f3dced3c146101d5578063f46901ed146101d0578063f7260d3e146101cb578063f72f863b146101c65763f851a4400361000e576116f3565b61166f565b611646565b6115c2565b611599565b611508565b61145f565b61142b565b61140e565b6113cc565b611381565b611342565b6112d4565b6112a8565b611269565b6111ba565b611086565b610f99565b610f27565b610efe565b610e4b565b610cea565b610ca8565b610bc5565b610b91565b610b30565b610ab1565b610a8e565b610a4c565b610a03565b610992565b6108e6565b610881565b61078c565b610626565b6105fd565b6105d4565b6104bb565b634e487b7160e01b600052604160045260246000fd5b6001600160401b0381116102a857604052565b61027f565b60e081019081106001600160401b038211176102a857604052565b604081019081106001600160401b038211176102a857604052565b602081019081106001600160401b038211176102a857604052565b90601f801991011681019081106001600160401b038211176102a857604052565b6040519061016082018281106001600160401b038211176102a857604052565b6040519061012082018281106001600160401b038211176102a857604052565b6040519061036c826102ad565b565b6001600160401b0381116102a85760051b60200190565b6001600160a01b0381160361039657565b600080fd5b359061036c82610385565b8015150361039657565b81601f82011215610396578035916103c78361036e565b926103d560405194856102fe565b808452602092838086019260051b820101928311610396578301905b8282106103ff575050505090565b838091833561040d816103a6565b8152019101906103f1565b906040600319830112610396576001600160401b0360043581811161039657836023820112156103965780600401356104508161036e565b9161045e60405193846102fe565b81835260209160248385019160051b8301019187831161039657602401905b8282106104a25750505050926024359182116103965761049f916004016103b0565b90565b83809183356104b081610385565b81520191019061047d565b34610396576104c936610418565b60cf5490916001600160a01b03916104ed90831633146104e7611998565b90611968565b6104fd81518451146104e7611a02565b60005b815181101561001957807f0bf1a6b9bd400a8478e3082dd8932968c39600716acaf5dbf7553e798c1cd36a6105386105c49387611ae0565b511515856105468487611ae0565b511660005260d060205261056b604091826000209060ff801983541691151516179055565b6105856105788487611ae0565b516001600160a01b031690565b6105bc61059b610595868b611ae0565b51151590565b92516001600160a01b03909216825291151560208201529081906040820190565b0390a1611a44565b610500565b600091031261039657565b346103965760003660031901126103965760ce546040516001600160a01b039091168152602090f35b346103965760003660031901126103965760cb546040516001600160a01b039091168152602090f35b346103965760003660031901126103965760cc546040516001600160a01b039091168152602090f35b6001600160401b0381116102a857601f01601f191660200190565b81601f82011215610396578035906106818261064f565b9261068f60405194856102fe565b8284526020838301011161039657816000926020809301838601378301015290565b919061016083820312610396576106c661031f565b926106d08161039b565b84526106de6020820161039b565b60208501526106ef6040820161039b565b6040850152606081013560608501526080810135608085015260a081013560a085015260c081013560c085015260e081013560e08501526101009182820135926001600160401b0393848111610396578261074b91850161066a565b9086015261012080830135848111610396578261076991850161066a565b90860152610140928383013590811161039657610786920161066a565b90830152565b6020366003190112610396576004356001600160401b038111610396576107ba6107cf9136906004016106b1565b6107c2611f07565b6107ca6119be565b612a45565b6001609755005b919061012083820312610396576107eb61033f565b926107f58161039b565b84526108036020820161039b565b60208501526108146040820161039b565b6040850152606081013560608501526080810135608085015260a081013560a085015260c081013560c085015260e0810135916001600160401b0392838111610396578161086391840161066a565b60e0860152610100928383013590811161039657610786920161066a565b34610396576020366003190112610396576004356001600160401b038111610396576108b46107cf9136906004016107d6565b6108bc611f07565b6108c46119be565b3360005260d06020526108e160ff604060002054166104e761397a565b613c6d565b346103965760003660031901126103965760cf54610917906001600160a01b031661090f611998565b903314611968565b60335460ff8116156109565760ff19166033557f5db9ee0a495bf2e6ff9c91a7834c1ba4fdd244a5e8aa4e537bd38aeae4b073aa6020604051338152a1005b60405162461bcd60e51b815260206004820152601460248201527314185d5cd8589b194e881b9bdd081c185d5cd95960621b6044820152606490fd5b346103965760031960403682011261039657600435906001600160401b039081831161039657610160908336030112610396576024359181831161039657366023840112156103965782600401359182116103965736602483850101116103965760246100199301906004016137fc565b346103965760003660031901126103965760cc5460cd54604080516001600160a01b03938416815292909116602083015290f35b35906001600160e01b03198216820361039657565b346103965760203660031901126103965760043563ffffffff60e01b81168091036103965760005260d7602052602060ff604060002054166040519015158152f35b3461039657600036600319011261039657602060ff603354166040519015158152f35b34610396576020366003190112610396577f7ce7ec0b50378fb6c0186ffb5f48325f6593fcb4ca4386f21861af3129188f5c6020600435610af181610385565b610af961171c565b6001600160a01b0316610b15610b0d6118ea565b821515611968565b60cf80546001600160a01b03191682179055604051908152a1005b3461039657600080600319360112610b8e57610b4a61171c565b606580546001600160a01b0319811690915581906001600160a01b03167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e08280a380f35b80fd5b346103965760203660031901126103965760043560005260d4602052602060018060a01b0360406000205416604051908152f35b3461039657600080600319360112610b8e578054610bfa60ff8260081c161580928193610c9a575b8115610c7a575b506117bd565b80610c0d600160ff196000541617600055565b610c61575b610c1a611820565b610c215780f35b610c3161ff001960005416600055565b604051600181527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb384740249890602090a180f35b610c7561010061ff00196000541617600055565b610c12565b303b15915081610c8c575b5038610bf4565b6001915060ff161438610c85565b600160ff8216109150610bed565b3461039657602036600319011261039657600435610cc581610385565b60018060a01b031660005260d0602052602060ff604060002054166040519015158152f35b346103965760003660031901126103965760cf54610d13906001600160a01b031661090f611998565b610d1b6119be565b600160ff1960335416176033557f62e78cea01bee320cd4e420270b5ea74000d11b0c9f74754ebdbfc544b05a2586020604051338152a1005b91909160a08184031261039657604051906001600160401b039060a08301828111848210176102a85760405282948135610d8d81610385565b8452602082013560208501526040820135604085015260608201356060850152608082013592831161039657608092610dc6920161066a565b910152565b9080601f8301121561039657813590610de38261036e565b92610df160405194856102fe565b828452602092838086019160051b8301019280841161039657848301915b848310610e1f5750505050505090565b82356001600160401b038111610396578691610e40848480948901016107d6565b815201920191610e0f565b6040366003190112610396576001600160401b036004358181116103965736602382011215610396578060040135610e828161036e565b91610e9060405193846102fe565b8183526020908184016024809460051b8301019136831161039657848101915b838310610ed85785358789821161039657610ed2610019923690600401610dcb565b9061494b565b8235888111610396578591610ef38392893691870101610d54565b815201920191610eb0565b34610396576000366003190112610396576065546040516001600160a01b039091168152602090f35b6020366003190112610396576004356001600160401b03811161039657610f556107cf913690600401610d54565b610f5d611f07565b610f656119be565b3360005260d0602052610f8260ff604060002054166104e761397a565b610f94602082015134146104e761207c565b613a22565b60031960203682011261039657600435906001600160401b03908183116103965760e090833603011261039657610fce61035f565b9082600401358252610fe26024840161039b565b6020830152610ff36044840161039b565b6040830152606483013560608301526084830135608083015260a483013581811161039657611028906004369186010161066a565b60a083015260c48301359081116103965761001992600461104c923692010161066a565b60c0820152611bed565b9181601f84011215610396578235916001600160401b038311610396576020808501948460051b01011161039657565b3461039657604080600319360112610396576001600160401b0390600435828111610396576110b9903690600401611056565b92602435908111610396576110d2903690600401611056565b93909160018060a01b03936110ef8560cf541633146104e7611998565b6111026110fa611a02565b878514611968565b60005b83811061110e57005b8061111d6111b5928988611a6e565b3561112781610385565b611132828787611a6e565b3560005261116560209160c98352856000209060018060a01b03166bffffffffffffffffffffffff60a01b825416179055565b7f0f86ee2bbb4d6370cc5e337c548e9af76e112c16b1aa97877c11e1328fa8ca39611191838888611a6e565b359161119e848c8b611a6e565b356111a881610385565b8a875191168152a2611a44565b611105565b34610396576111c836610418565b60cf5490916001600160a01b03916111e690831633146104e7611998565b6111f681518451146104e7611a02565b60005b815181101561001957807f4519d4931af171182c3df6a6b61730c684f07903a4bd23a3edbff97685da43746112316112649387611ae0565b5115158561123f8487611ae0565b511660005260d660205261056b604091826000209060ff801983541691151516179055565b6111f9565b346103965760403660031901126103965760043560005260d16020526040600020602435600052602052602060ff604060002054166040519015158152f35b346103965760203660031901126103965760043560005260d36020526020604060002054604051908152f35b34610396576040366003190112610396577f7ef26aca67d68e814b326749559541e70261dc0bb13ec23b061cb4efae5bf10a604060043560243561132660018060a01b0360cf541633146104e7611998565b8160005260d360205280836000205582519182526020820152a1005b346103965760403660031901126103965760043560005260d26020526040600020602435600052602052602060ff604060002054166040519015158152f35b346103965760203660031901126103965760043561139e81610385565b60018060a01b031660005260d5602052604080600020600160ff825416910154825191151582526020820152f35b34610396576020366003190112610396576004356113e981610385565b60018060a01b031660005260d6602052602060ff604060002054166040519015158152f35b3461039657600036600319011261039657602060405161012c8152f35b346103965760203660031901126103965760043560005260c9602052602060018060a01b0360406000205416604051908152f35b34610396576040366003190112610396576001600160401b03600435818111610396573660238201121561039657806004013561149b8161036e565b916114a960405193846102fe565b81835260209160248385019160051b8301019136831161039657602401905b8282106114f15760243585878211610396576114eb6100199236906004016103b0565b90611af4565b8380916114fd84610a37565b8152019101906114c8565b346103965760203660031901126103965760043561152581610385565b61152d61171c565b6001600160a01b038116156115455761001990611774565b60405162461bcd60e51b815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201526564647265737360d01b6064820152608490fd5b346103965760003660031901126103965760ca546040516001600160a01b039091168152602090f35b34610396576020366003190112610396577f3dedba2a214b4fff9bf20fc473c114824654e0bc70512b4a92f6d5978763c28d602060043561160281610385565b60cf546001600160a01b03919061161f90831633146104e7611998565b1661162b610b0d6118ea565b60ce80546001600160a01b03191682179055604051908152a1005b346103965760003660031901126103965760cd546040516001600160a01b039091168152602090f35b34610396576020366003190112610396577f33f0bdb7050bc888ca819c34892844adff2a3109dc1810301e8fd6af0ac7edb960206004356116af81610385565b60cf546001600160a01b0391906116cc90831633146104e7611998565b166116d8610b0d6118ea565b60cb80546001600160a01b03191682179055604051908152a1005b346103965760003660031901126103965760cf546040516001600160a01b039091168152602090f35b6065546001600160a01b0316330361173057565b606460405162461bcd60e51b815260206004820152602060248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65726044820152fd5b606580546001600160a01b039283166001600160a01b0319821681179092559091167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0600080a3565b156117c457565b60405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201526d191e481a5b9a5d1a585b1a5e995960921b6064820152608490fd5b61186d60ff60005460081c166118358161188a565b61183e8161188a565b60ff19603354166033556118518161188a565b61185a8161188a565b60016097556118688161188a565b61188a565b61187633611774565b60cf80546001600160a01b03191633179055565b1561189157565b60405162461bcd60e51b815260206004820152602b60248201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960448201526a6e697469616c697a696e6760a81b6064820152608490fd5b604051906118f7826102c8565b600982526806164647265737320360bc1b6020830152565b60005b8381106119225750506000910152565b8181015183820152602001611912565b9060209161194b8151809281855285808601910161190f565b601f01601f1916010190565b90602061049f928181520190611932565b156119705750565b60405162461bcd60e51b815260206004820152908190611994906024830190611932565b0390fd5b604051906119a5826102c8565b600a82526937b7363c9030b236b4b760b11b6020830152565b60ff603354166119ca57565b60405162461bcd60e51b815260206004820152601060248201526f14185d5cd8589b194e881c185d5cd95960821b6044820152606490fd5b60405190611a0f826102c8565b601082526f1b195b99dd1a081b9bdd08195c5d585b60821b6020830152565b634e487b7160e01b600052601160045260246000fd5b6000198114611a535760010190565b611a2e565b634e487b7160e01b600052603260045260246000fd5b9190811015611a7e5760051b0190565b611a58565b805115611a7e5760200190565b805160011015611a7e5760400190565b805160021015611a7e5760600190565b805160031015611a7e5760800190565b805160041015611a7e5760a00190565b805160051015611a7e5760c00190565b8051821015611a7e5760209160051b010190565b9190611b0e60018060a01b0360cf541633146104e7611998565b611b1e83518251146104e7611a02565b600092835b8151811015611be657807f2fc5194644b0d028829e475d57cad5ccad073d27cef6d863b7bd7ed88ae9a2c1611b5b611be19386611ae0565b5115156001600160e01b0319611b718487611ae0565b5116885260d7602052611b94604091828a209060ff801983541691151516179055565b611baf611ba18487611ae0565b516001600160e01b03191690565b6105bc611bbf610595868a611ae0565b92516001600160e01b0319909216825291151560208201529081906040820190565b611b23565b5050509050565b611bf5611f07565b611bfd6119be565b611c0c815115156104e7611f5d565b611c31611c24825160005260c9602052604060002090565b546001600160a01b031690565b6001600160a01b0381811692611c50611c48611f8a565b851515611968565b602081018051909490611c8190611c77906001600160a01b03165b6001600160a01b031690565b15156104e76118ea565b604082018051909290611ca090611c77906001600160a01b0316611c6b565b6080810193611cb4855115156104e7611fc3565b611cbc611ff1565b8551855160c08501805190999392611cdd926001600160a01b0316906126bb565b908160208401528252885234611d0c60608601518060c01c9163ffffffff60018060a01b038360201c16921690565b939194909573eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee611d368b5160018060a01b031690565b91821603611ec257505090611d7091611d69611d5e611d56888d5161206f565b83519061206f565b8310156104e761207c565b51906120c8565b8380611e80575b505b89516001600160a01b031687519091906001600160a01b03169689519060a0880198895193823b15610396578695611dcd60009660405198899788968795636f82189d60e01b875233903360048901612134565b03925af1928315611e7b577ff6481cbc1da19356c5cb6b884be507da735b89f21dc4bbb7c9b7cc0968b03b7a99611e55978c611e3895611e2895611e4698611e62575b50895191516001600160a01b03169251935194612413565b935198516001600160a01b031690565b94516001600160a01b031690565b945160405195869533876121b8565b0390a261036c6001609755565b80611e6f611e7592610295565b806105c9565b38611e10565b612178565b611ebc91611eb7600080808086611ea4611c6b611c6b60ce5460018060a01b031690565b5af1611eae6120d5565b506104e7612105565b6120c8565b83611d77565b611ee492508680611ee9575b505088516001600160a01b03168a51913361228c565b611d79565b60ce54611f0092906001600160a01b03163361228c565b3886611ece565b600260975414611f18576002609755565b60405162461bcd60e51b815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c006044820152606490fd5b60405190611f6a826102c8565b60118252701a5b9d985b1a59081859185c1d1bdc9251607a1b6020830152565b60405190611f97826102c8565b601782527f696e76616c69642061646170746f7220616464726573730000000000000000006020830152565b60405190611fd0826102c8565b60128252710616d6f756e74206d757374206265203e20360741b6020830152565b60405190604082018281106001600160401b038211176102a8576040526060602083600081520152565b9060648201809211611a5357565b6020019081602011611a5357565b6024019081602411611a5357565b6002019081600211611a5357565b9060028201809211611a5357565b9060038201809211611a5357565b91908201809211611a5357565b60405190612089826102c8565b6011825270696e76616c6964206d73672076616c756560781b6020830152565b90612710918203918211611a5357565b601f19810191908211611a5357565b91908203918211611a5357565b3d15612100573d906120e68261064f565b916120f460405193846102fe565b82523d6000602084013e565b606090565b60405190612112826102c8565b6013825272115512081d1c985b9cd9995c8819985a5b1959606a1b6020830152565b9360e095929161049f98979460018060a01b038094818094168952166020880152166040860152166060840152608083015260a08201528160c08201520190611932565b6040513d6000823e3d90fd5b90815180825260208080930193019160005b8281106121a4575050505090565b835185529381019392810192600101612196565b929161049f96959260c0959260018060a01b0392838092168752166020860152166040840152606083015260808201528160a08201520190612184565b73cff09e645a627b8208ef67da294d0edc2d25551791823b156103965760405163052f523360e11b815273039e2fb66102314ce7b64ce5ce3e5183bc94ad3860048201526001600160a01b0390921660248301527207ef1cde141326b0da51c83cbac3f6feaf507c60448301526064820152906000908290608490829084905af18015611e7b576122835750565b61036c90610295565b929173cff09e645a627b8208ef67da294d0edc2d25551790813b156103965760405163052f523360e11b81526001600160a01b0391821660048201529481166024860152909116604484015260648301919091526000908290608490829084905af18015611e7b576122835750565b60405190612308826102ad565b6006825260c0366020840137565b60405190612323826102c8565b6001825260203681840137565b81601f820112156103965780516123468161064f565b9261235460405194856102fe565b818452602082840101116103965761049f916020808501910161190f565b60808183031261039657805161238781610385565b926020820151926001600160401b039384811161039657816123aa918501612330565b936040840151908111610396576060916123c5918501612330565b92015190565b6020815191015190602081106123df575090565b6000199060200360031b1b1690565b906020828203126103965781516001600160401b0381116103965761049f9201612330565b9493919061241f6122fb565b9561242987611a83565b5261243386611a90565b5260018114801561258b575b1561252357505060405160609190911b6bffffffffffffffffffffffff191660208201526124839061247e81603481015b03601f1981018352826102fe565b6123cb565b61248c83611aa0565b526124a06040516000815261247e816102e3565b6124a983611ab0565b525b805115612505576124c8816020806124cd945183010191016123ee565b614a32565b6124d681611a83565b516124e083611ac0565b5260018151116124ee575090565b6124f790611a90565b5161250182611ad0565b5290565b5061250f81611aa0565b5161251982611ac0565b526124f781611ab0565b600391925014612534575b506124ab565b61254a8160208061255394518301019101612372565b50915050614a32565b61255c81611a83565b5161256684611aa0565b5260018151111561252e5761257a90611a90565b5161258483611ab0565b523861252e565b506002811461243f565b604051906125a2826102c8565b601b82527f6572726f7220636f6d6d697373696f6e2072617465206c696d697400000000006020830152565b908160011b9180830460021490151715611a5357565b600181901b91906001600160ff1b03811603611a5357565b81810292918115918404141715611a5357565b8115612619570490565b634e487b7160e01b600052601260045260246000fd5b6040519061263c826102c8565b601b82527f636f6d6d697373696f6e2077697468206574686572206572726f7200000000006020830152565b906126728261064f565b61267f60405191826102fe565b8281528092612690601f199161064f565b0190602036910137565b805160011015611a7e5760210190565b908151811015611a7e570160200190565b6000939236601f190135929091856001600160d01b03198516651e51057e155560d11b0361282f57506001600160a01b038481169473eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee93926127489160a01c65ffffffffffff16906127429061273c90839061273761272c612595565b61012c841115611968565b6125fc565b916120a9565b9061260f565b92839183160361281f5761277091508680808093885af16127676120d5565b506104e761262f565b81519361278461277f866120b9565b612668565b93865b612790876120b9565b8110156127d2576127cb816127b96127ab61279094896126aa565b516001600160f81b03191690565b8a1a6127c5828a6126aa565b53611a44565b9050612787565b50604080518481526001600160a01b039092166020830152929650939450927fffc60ee157a42f4d8edbd1897e6581a96d9ed04e44fb2ab53a47ce1eb8f2775b925090819081015b0390a1565b61282a91853361228c565b612770565b95505050905090565b6040519061012082018281106001600160401b038211176102a857604052606061010083600080825280602083015280604083015280848301528060808301528060a08301528060c083015260e08201520152565b6040519061289a826102c8565b600d82526c1859191c995cdcc8195c5d585b609a1b6020830152565b604051906128c3826102c8565b601682527506d696e20616d6f756e74206d757374206265203e20360541b6020830152565b906020825192015163ffffffff60e01b90818116936004811061290a57505050565b60040360031b82901b16169150565b60405190612926826102c8565b600f82526e195c9c881cd95b1958dd1bdc881a59608a1b6020830152565b60405190612951826102c8565b601182527003232bc103937baba32b91032b939101d1607d1b6020830152565b6040519061297e826102c8565b60128252711a5b9d195c9b985b081ddc985c0819985a5b60721b6020830152565b604051906129ac826102c8565b600e82526d36b4b71030b6b7bab73a1032b93960911b6020830152565b95939061049f989795929360018060a01b038095818094168a52166020890152166040870152606086015216608084015260a083015260c0820152610100908160e08201520190612184565b60405190612a22826102c8565b6014825273736c617368206d75636820746f6f206d6f6e657960601b6020830152565b612a4d612838565b612a5f606083015115156104e7611f5d565b612a8a612a7d611c24606085015160005260c9602052604060002090565b6001600160a01b03168252565b8051612aa3906001600160a01b031615156104e7611f8a565b8151612abb90611c77906001600160a01b0316611c6b565b6020820151612ad690611c77906001600160a01b0316611c6b565b8151612b11906001600160a01b03166020840151612afc906001600160a01b0316611c6b565b6001600160a01b0390911614156104e761288d565b6040820151612b2c90611c77906001600160a01b0316611c6b565b60cb54612b4590611c77906001600160a01b0316611c6b565b612b5760a083015115156104e7611fc3565b612b6960c083015115156104e76128b6565b608082015160c081901c90602081901c6001600160a01b03169063ffffffff166080840152606083015260a08201526020820151612bb4906001600160a01b0316613210565b613210565b6040820152612bf8612bf0612be9612bd06101208601516128e8565b63ffffffff60e01b1660005260d7602052604060002090565b5460ff1690565b6104e7612919565b60cc80546001600160a01b0319163317905560cd80546001600160a01b0319163017905560a08201518251612c3d91906001600160a01b0316610140850151916126bb565b61014084015282516001600160a01b031673eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeed19810161317b5750612c87612c7882346120c8565b60a085015111156104e761207c565b60208301516001600160a01b031673039e2fb66102314ce7b64ce5ce3e5183bc94ad37190161313757612cca612cc160a0850151306136be565b151560c0840152565b60cc80546001600160a01b031916905560cd80546001600160a01b0319169055612d0f612cfa60c0840151151590565b610100840151805161312557506104e7612971565b6020830151612d5c90612d3990612d2e906001600160a01b0316613210565b6040850151906120c8565b806020850152612d52606085015160c08701519061206f565b11156104e761299f565b60ce54612d85906001600160a01b031660208501516001600160a01b03166060850151916132de565b612d9860208301516060840151906120c8565b60208381018290528401516001600160a01b03169073eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee829003612f995750508151612de49150611c6b9081906001600160a01b031681565b612df36020830151349061206f565b60408401519091906001600160a01b031660208501519091906001600160a01b03169060208501519160808601519461010088015194833b1561039657612e5660009660405198899788968795636f82189d60e01b875233903360048901612134565b03925af18015611e7b57612f86575b505b60a0810151608082015160608401516040850151612e9f939291906001600160a01b0316906101008701519261014088015194612413565b6060830151604084015190917fb9dae57db52a734b183c77227c96068231beb6a93a060ca7a9d3164f716714ea916001600160a01b03168551612f14906001600160a01b031660a088015160208901519194916001600160a01b031660208901519060608a01519260405197889733896129c9565b0390a260208201516001600160a01b031673eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee819003612f7457506040612f67612f60612baf602061036c96015160018060a01b031690565b349061206f565b91015111156104e7612a15565b61036c9250612f67604091309061322a565b80611e6f612f9392610295565b38612e65565b8351612fae92906001600160a01b03166132de565b825173eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee90612fd8906001600160a01b0316611c6b565b036130995761300e613003612ffc611c6b611c6b611c6b875160018060a01b031690565b92346120c8565b60a0850151906120c8565b60408401519091906001600160a01b031660208501519091906001600160a01b03169060208501519160808601519461010088015194833b156103965761307160009660405198899788968795636f82189d60e01b875233903360048901612134565b03925af18015611e7b57613086575b50612e67565b80611e6f61309392610295565b38613080565b5080516130b290611c6b9081906001600160a01b031681565b60408301516001600160a01b031660208401516001600160a01b03169160208401519060808501519361010087015193823b156103965761310f60009560405197889687958695636f82189d60e01b875233903360048901612134565b039134905af18015611e7b576130865750612e67565b6104e790613131612944565b90614b19565b60cb5460a08401516101208501518051613176936000938493602001916001600160a01b03165af16131676120d5565b610100850152151560c0840152565b612cca565b73039e2fb66102314ce7b64ce5ce3e5183bc94ad3814806131dc575b156131ae57613176612cc160a08501513033613577565b60cb546131769060009081906001600160a01b03166101208701519082602083519301915af16131676120d5565b50602083015173eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee9061320a906001600160a01b0316611c6b565b14613197565b61049f90309061322a565b90816020910312610396575190565b6000906001600160a01b039081169073eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee820361325b575050503190565b6024602092939460405194859384926370a0823160e01b84521660048301525afa918215611e7b579161328c575090565b61049f915060203d81116132ad575b6132a581836102fe565b81019061321b565b503d61329b565b90806132be575050565b61036c916000918291829182916001600160a01b03165af1611eae6120d5565b9190816132ea57505050565b6001600160a01b0390811673eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee810361332757506000808093819361036c96165af1611eae6120d5565b60405163a9059cbb60e01b60208201526001600160a01b03909416602485015260448401929092525061036c919061336c82606481015b03601f1981018452836102fe565b613386565b90816020910312610396575161049f816103a6565b6040516133e4916001600160a01b031661339f826102c8565b6000806020958685527f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c656487860152868151910182855af16133de6120d5565b9161350e565b805190828215928315613454575b505050156133fd5750565b6084906040519062461bcd60e51b82526004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e6044820152691bdd081cdd58d8d9595960b21b6064820152fd5b6134649350820181019101613371565b3882816133f2565b909190156134e2575080511561347f5790565b73039e2fb66102314ce7b64ce5ce3e5183bc94ad383b1561349d5790565b60405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000006044820152606490fd5b8151156134f25750805190602001fd5b60405162461bcd60e51b81529081906119949060048301611957565b9192901561352b5750815115613522575090565b3b1561349d5790565b8251909150156134f25750805190602001fd5b6040519061354b826102c8565b601782527f7772617020616d6f756e74206d757374206265203e20300000000000000000006020830152565b61358a61358261353e565b841515611968565b6001600160a01b03908381831630036136b057505060405163a9059cbb60e01b81527207ef1cde141326b0da51c83cbac3f6feaf507c600482015260248101849052602081604481600073039e2fb66102314ce7b64ce5ce3e5183bc94ad385af18015611e7b57613682575b505b7207ef1cde141326b0da51c83cbac3f6feaf507c91823b1561039657604051632e1a7d4d60e01b81526004810185905260009384908290602490829084905af18015611e7b5761366f575b5016308103613655575b505050600190565b81806136679481935af1611eae6120d5565b38808061364d565b80611e6f61367c92610295565b38613643565b6136a29060203d81116136a9575b61369a81836102fe565b810190613371565b50386135f6565b503d613690565b6136b9916121f5565b6135f8565b6136d16136c961353e565b831515611968565b73039e2fb66102314ce7b64ce5ce3e5183bc94ad3890813b1561039657604051630d0e30db60e41b815260008160048187875af18015611e7b576137ed575b50306001600160a01b0382160361372957505050600190565b60405163a9059cbb60e01b60208083019182526001600160a01b0393909316602483015260448083019590955293815290926137b8926000918291906137706064866102fe565b826040519561377e876102c8565b8887527f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c65648988015251925af16137b26120d5565b9061346c565b8051908282159283156137d5575b505050156133fd57808061364d565b6137e59350820181019101613371565b3882816137c6565b6137f690610295565b38613710565b91613805611f07565b61380d6119be565b82359061381982610385565b8061383a575b5050506107ca6138309136906106b1565b61036c6001609755565b60e081036138a15790600092836124706138608295604051928391602083019687613932565b51925af161386c6120d5565b905b1561387a57808061381f565b6138896119949161313161394f565b60405162461bcd60e51b815291829160048301611957565b9061010082036138da57600092836124706138c88295604051928391602083019687613915565b51925af16138d46120d5565b9061386e565b60405162461bcd60e51b81526020600482015260136024820152720aee4dedcce40e0cae4dad2e840d8cadccee8d606b1b6044820152606490fd5b6323f2ebc360e21b81526004929182908285013701016000815290565b63d505accf60e01b81526004929182908285013701016000815290565b6040519061395c826102c8565b600f82526e02832b936b4ba103330b4b632b21d1608d1b6020830152565b60405190613987826102c8565b60088252676f6e6c79206d706360c01b6020830152565b604051906139ab826102c8565b601282527165786365656420616c6c6f7765642067617360701b6020830152565b604051906139d9826102c8565b600f82526e68617320726563656976652067617360881b6020830152565b909260809261049f959460018060a01b03168352602083015260408201528160608201520190612184565b7fc9f1b98ce4fd29c9b2de9c4514957faa4bf8fbcad43c471530fb873726c3c2869060208101613a678151600160005260d360205260406000205410156104e761399e565b61281a6040830192613b24613a87855160005260d2602052604060002090565b91613ab5613aad613aa9612be960608501968751600052602052604060002090565b1590565b6104e76139cc565b613aed613ae0613ad0885160005260d2602052604060002090565b8551600052602052604060002090565b805460ff19166001179055565b80518551613b03916001600160a01b03166132b4565b613b0b612316565b9251613b1684611a83565b52516001600160a01b031690565b92519351604051948594856139f7565b60405190613b41826102c8565b600f82526e6e6f20656e6f756768206d6f6e657960881b6020830152565b60405190613b6c826102c8565b60088252671a185cc81c185a5960c21b6020830152565b60405190613b90826102c8565b600a8252695f5f726566756e645f5f60b01b6020830152565b9693909161049f989693613bf9969360018060a01b0392838092168b521660208a015216604088015260608701526000608087015260a086015260c08501526101208060e0860152840190611932565b91610100818403910152612184565b90816020910312610396575161049f81610385565b9693909161049f989693613bf9969360018060a01b0392838092168b521660208a015216604088015260006060880152608087015260a086015260c08501526101208060e0860152840190611932565b8051613c81906001600160a01b0316613210565b906060810191825191613c9a608082019384519061206f565b92613ca58483614623565b613cb9613cb0613b34565b85851015611968565b60cb546001600160a01b0390613cd590821615156104e76118ea565b60a0830191613cef835160005260d1602052604060002090565b613d18613d10613aa9612be960c08901948551600052602052604060002090565b6104e7613b5f565b613d43613ae0613d33865160005260d1602052604060002090565b8351600052602052604060002090565b613d4b612316565b9051613d5682611a83565b5260ce546060948591600090613d82906001600160a01b031689516001600160a01b03168751916132de565b60e088018051519097901561425b576020890180519098906001600160a01b031660408b018051909991613dc0916001600160a01b03165b9061322a565b60cc8054306001600160a01b0319918216179091558a5160cd80549092166001600160a01b03909116179055938b5173eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee9083166001600160a01b031673eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeed198101614021575050509c612baf9894613f4e9c9b989461036c9f948c989473039e2fb66102314ce7b64ce5ce3e5183bc94ad38600080516020614d578339815191529b97613f489f613e7e905160018060a01b031690565b1603613ff2575087518451613e9b916001600160a01b03166136be565b8015613fe2575b15908180613fd8575b613fc3575b5060cc80546001600160a01b031916905560cd80546001600160a01b031916905515613f58575085519495613f3895613f049190610578906001600160a01b03168c516001600160a01b03168651916132de565b8951909690613f25906001600160a01b03165b98516001600160a01b031690565b9251905191519260405198899889613ba9565b0390a1516001600160a01b031690565b906120c8565b11156104e7612a15565b8751613fbb969350613f9391613f8591611eb7906001600160a01b03168a516001600160a01b0316613dba565b96516001600160a01b031690565b8951909690613faa906001600160a01b0316613f17565b925191519260405198899889613c1d565b0390a1610578565b613fd1919550613131612944565b9338613eb0565b5080511515613eab565b9450613fec612971565b94613ea2565b60cb54600092508291906001600160a01b03168651915191602083519301915af161401b6120d5565b90613ea2565b73039e2fb66102314ce7b64ce5ce3e5183bc94ad389192935014908161423d575b501561409b57505093613f48979361036c9c8894613f4e9c9b9894600080516020614d578339815191529861408c614083612baf9d5160018060a01b031690565b85519030613577565b80613ea2579450613fec612971565b97939a999692959150979360405197631c6eced560e01b895260208960048173cff09e645a627b8208ef67da294d0edc2d2555175afa988915611e7b578e90829a6141fa575b50899a61410583928c6140fd611c6b8e5160018060a01b031690565b91519161439c565b60cb546001600160a01b031690519082602083519301915af19c6141276120d5565b9d9b6020614174614144611c6b611c6b8d5160018060a01b031690565b604051636eb1769f60e11b81523060048201526001600160a01b03909e1660248f01528d91829081906044820190565b03915afa978815611e7b5761036c9f613f4e9e8b612baf9d613f489f9c600080516020614d578339815191529d6000916141db575b506141b6575b5050613ea2565b90516141d491906141cf906001600160a01b0316611c6b565b61434b565b8b386141af565b6141f4915060203d6020116132ad576132a581836102fe565b386141a9565b611c6b9a509a61410583928b61422a6140fd9f60203d602011614236575b61422281836102fe565b810190613c08565b9d50509250509a6140e1565b503d614218565b8b51909150614254906001600160a01b0316611c6b565b1438614042565b5050613f489550612baf9450613f4e9796939150613fbb600080516020614d578339815191529361036c9b61428e613b83565b906142bc604089016105786142a9825160018060a01b031690565b8b516001600160a01b03168551916132de565b88519095906001600160a01b031660208a01519097906001600160a01b0316613f25565b156142e757565b60405162461bcd60e51b815260206004820152603660248201527f5361666545524332303a20617070726f76652066726f6d206e6f6e2d7a65726f60448201527520746f206e6f6e2d7a65726f20616c6c6f77616e636560501b6064820152608490fd5b60405163095ea7b360e01b60208201526001600160a01b039092166024830152600060448084019190915282526080820191906001600160401b038311828410176102a85761036c92604052613386565b919091811580156143ea575b61036c936143b861336c926142e0565b60405163095ea7b360e01b60208201526001600160a01b0390911660248201526044810193909352826064810161335e565b50604051636eb1769f60e11b81523060048201526001600160a01b038416602482015292602084806044810103816001600160a01b0386165afa908115611e7b576143b861336c9261036c9660009161444a575b501592505093506143a8565b614462915060203d81116132ad576132a581836102fe565b3861443e565b919091604081840312610396578051926001600160401b03938481116103965781614494918401612330565b9360208301519081116103965761049f9201612330565b604051906144b8826102c8565b600b82526a3d32b9379039b4b3b732b960a91b6020830152565b604051906144df826102c8565b601082526f6e6f74206f7261636c652070726f787960801b6020830152565b6040519061450b826102c8565b600c82526b195c9c8818da185a5b881a5960a21b6020830152565b60405190614533826102c8565b601682527531b7b73a3930b1ba1030b2323932b9b99032b93937b960511b6020830152565b60405190614565826102c8565b6014825273636c61696d206e6f206f7261636c6520696e666f60601b6020830152565b60405190614595826102c8565b601482527331b630b4b6903a379030b2323932b9b99032b93960611b6020830152565b604051906145c5826102c8565b601782527f636c61696d20746f6b656e2061646472657373206572720000000000000000006020830152565b604051906145fe826102c8565b601682527531b630b4b6903a37b5b2b71030b6b7bab73a1032b93960511b6020830152565b906147ae6147a76146f26147676146e061474061036c9761465b61465561010083015160208082518301019101614468565b90614863565b97929590916146ab6146a3612be96146716144ab565b6001600160a01b039a90614689908c83161515611968565b6001600160a01b0316600090815260d66020526040902090565b6104e76144d2565b600360005260d36020527f64de0974ce81404dc9f7f680a2e3b4cfc70679cd50192b307cda861d6e23b65054146104e76144fe565b6146e8614526565b9085163014611968565b61470860c08201516020870151146104e7614558565b6040810151610578906001600160a01b03166040870151859061473590611c6b906001600160a01b031681565b9116146104e7614588565b606084015190919061475c90611c6b906001600160a01b031681565b9116146104e76145b8565b600260005260d36020526147a160a07f8f145ec1981fda056bae73a9467bf215a78583d2d921572993bc5b1783a6fe0c549201519161201b565b906125fc565b6064900490565b10156104e76145f1565b6040519060c082018281106001600160401b038211176102a8576040528160a06000918281528260208201528260408201528260608201528260808201520152565b90816060910312610396578051916040602083015192015160ff811681036103965790565b91908261010091031261039657815191602081015161483d81610385565b9160408201519160608101519160808201519160a08101519160e060c083015192015190565b91906148879160006148736147b8565b9260209481868080945183010191016147fa565b9093916148fe895195858b019687206040516148d4816124708a82019485603c917f19457468657265756d205369676e6564204d6573736167653a0a3332000000008252601c8201520190565b51902092604051948594859094939260ff6060936080840197845216602083015260408201520152565b838052039060015afa15611e7b5761491f908460005196805101019061481f565b60a08a015260808901526060880152604087015295850195909552938352926001600160a01b03169190565b919091614956611f07565b61495e6119be565b3360005260209060d0825261497d60ff604060002054166104e761397a565b600093345b82518610156149c55761499e6149988785611ae0565b51613a22565b836149a98785611ae0565b5101518103908111611a53576149bf9095611a44565b94614982565b93929150935060005b84518110156149f857806149ee6149e86149f39388611ae0565b51613c6d565b611a44565b6149ce565b50909250613830917306c6566742076616c7565206d75737420626520360641b60405192614a25846102c8565b6014845283015215611968565b90815191601f8301809311611a5357600592831c614a4f8161036e565b614a5c60405191826102fe565b818152601f19614a6b8361036e565b01926020933685840137819560005b848110614a8957505050505050565b80821b90808204871481151715611a5357614aa6614ab992612029565b840151614ab38287611ae0565b52611a44565b614a7a565b90614ad16020928281519485920161190f565b0190565b15614adc57565b60405162461bcd60e51b815260206004820152601560248201527424b73b30b634b2103932bb32b93a103932b0b9b7b760591b6044820152606490fd5b80516004811015614b76575b50614b4f91612470614b69614b3c61049f94614c5f565b614b636040519687956020870190614abe565b670aadcd6dcdeeedc560c31b815260080190565b90614abe565b602960f81b815260010190565b60208201516001600160e01b03191662461bcd60e51b811480614c3a575b15614be6575050614bd491612470614b6983614b3c602461049f960151614bcd614bc5602483860101945192612037565b84519061206f565b1115614ad5565b6508ae4e4dee4560d31b815260060190565b634e487b7160e01b149081614c2f575b50614c0357614b4f614b25565b614c1d91612470614b69614b3c602461049f950151614c45565b650a0c2dcd2c6560d31b815260060190565b602491501438614bf6565b506044821015614b94565b61049f9060405190602082015260208152614c5f816102c8565b90614c7561277f614c7084516125ce565b612045565b6030614c8082611a83565b536078614c8c8261269a565b5360005b8351811015614d5157614cc7614cc1614cbb614caf6127ab85896126aa565b60041c600f60f81b1690565b60f81c90565b60ff1690565b9060109182811015611a7e576f181899199a1a9b1b9c1cb0b131b232b360811b9081901a614d05614cff614cfa856125e4565b612053565b866126aa565b53614d25614cc1600f60f81b614d1e6127ab868b6126aa565b1660f81c90565b92831015611a7e57614d4c921a6127c5614d46614d41846125e4565b612061565b856126aa565b614c90565b50915056fe6d1b775ce655ea3b568c59e0f161908781f216e4d9feb04fa524ca23a44f4b07a2646970667358221220e5265d56af53444cdb5b89cac8a9802478e974e7aed6dc611e318e12276e8e0b64736f6c63430008130033
Loading...
Loading
Loading...
Loading
Multichain Portfolio | 31 Chains
Chain | Token | Portfolio % | Price | Amount | Value |
---|---|---|---|---|---|
BASE | 100.00% | $2,280.01 | 0.00002675 | $0.06099 |
A contract address hosts a smart contract, which is a set of code stored on the blockchain that runs when predetermined conditions are met. Learn more about addresses in our Knowledge Base.