{"file_path":"contracts/transfer/TransferReference.sol","creation_status":"success","source_code":"// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport {IERC20} from \"../erc20/IERC20.sol\";\nimport {CCIPSender} from \"../bridge/CCIPSender.sol\";\nimport {Client} from \"@chainlink/contracts-ccip/src/v0.8/ccip/libraries/Client.sol\";\nimport {IRouterClient} from \"@chainlink/contracts-ccip/src/v0.8/ccip/interfaces/IRouterClient.sol\";\n\n/**\n * @dev A module for Frankencoin transfers with a reference number, incl. cross chain transfers\n */\ncontract TransferReference is CCIPSender {\n    IERC20 public immutable zchf;\n    uint256 internal constant INFINITY = (1 << 255); // @dev: copied from \"./ERC20.sol\"\n\n    event Transfer(address indexed from, address indexed to, uint256 amount, string ref);\n\n    // @dev: **to** is type bytes to support arbitrary destination chains without risk of unsafe conversion\n    event CrossTransfer(address indexed sender, address indexed from, uint64 toChain, bytes indexed to, uint256 amount, string ref);\n\n    error InfiniteAllowanceRequired(address owner, address spender);\n\n    constructor(address token, IRouterClient router, address link) CCIPSender(router, link) {\n        zchf = IERC20(token);\n    }\n\n    // erc20 transfer\n    function transfer(address recipient, uint256 amount, string calldata ref) public returns (bool) {\n        zchf.transferFrom(msg.sender, recipient, amount);\n        emit Transfer(msg.sender, recipient, amount, ref);\n        return true;\n    }\n\n    function transferFrom(address owner, address recipient, uint256 amount, string calldata ref) public returns (bool) {\n        if (zchf.allowance(owner, msg.sender) < INFINITY) revert InfiniteAllowanceRequired(owner, msg.sender);\n        zchf.transferFrom(owner, recipient, amount);\n        emit Transfer(owner, recipient, amount, ref);\n        return true;\n    }\n\n    // cross transfer\n    function crossTransfer(uint64 targetChain, address recipient, uint256 amount, string calldata ref) public payable returns (bool) {\n        _crossTransfer(targetChain, msg.sender, _toReceiver(recipient), amount, \"\", ref);\n        return true;\n    }\n\n    function crossTransfer(uint64 targetChain, address recipient, uint256 amount, Client.EVMExtraArgsV2 calldata extraArgs, string calldata ref) public payable returns (bool) {\n        _crossTransfer(targetChain, msg.sender, _toReceiver(recipient), amount, Client._argsToBytes(extraArgs), ref);\n        return true;\n    }\n\n    function crossTransfer(uint64 targetChain, bytes memory recipient, uint256 amount, bytes calldata extraArgs, string calldata ref) public payable returns (bool) {\n        _crossTransfer(targetChain, msg.sender, recipient, amount, extraArgs, ref);\n        return true;\n    }\n\n    // cross transfer from\n    function crossTransferFrom(uint64 targetChain, address owner, address recipient, uint256 amount, string calldata ref) public payable returns (bool) {\n        if (zchf.allowance(owner, msg.sender) < INFINITY) revert InfiniteAllowanceRequired(owner, msg.sender);\n        _crossTransfer(targetChain, owner, _toReceiver(recipient), amount, \"\", ref);\n        return true;\n    }\n\n    function crossTransferFrom(uint64 targetChain, address owner, address recipient, uint256 amount, Client.EVMExtraArgsV2 calldata extraArgs, string calldata ref) public payable returns (bool) {\n        if (zchf.allowance(owner, msg.sender) < INFINITY) revert InfiniteAllowanceRequired(owner, msg.sender);\n        _crossTransfer(targetChain, owner, _toReceiver(recipient), amount, Client._argsToBytes(extraArgs), ref);\n        return true;\n    }\n\n    function crossTransferFrom(uint64 targetChain, address owner, bytes memory recipient, uint256 amount, bytes calldata extraArgs, string calldata ref) public payable returns (bool) {\n        if (zchf.allowance(owner, msg.sender) < INFINITY) revert InfiniteAllowanceRequired(owner, msg.sender);\n        _crossTransfer(targetChain, owner, recipient, amount, extraArgs, ref);\n        return true;\n    }\n\n    function _crossTransfer(uint64 targetChain, address from, bytes memory target, uint256 amount, bytes memory extraArgs, string calldata ref) private {\n        zchf.transferFrom(from, address(this), amount);\n        zchf.approve(address(ROUTER), amount);\n        _send(targetChain, constructTransferMessage(target, amount, extraArgs));\n        emit CrossTransfer(msg.sender, from, targetChain, target, amount, ref); // @dev: target is type bytes\n    }\n\n    /// @notice Gets the CCIP fee for a transfer.\n    /// @param targetChain The chain selector of the destination chain.\n    /// @param target The address of the recipient on the destination chain.\n    /// @param amount The amount of tokens to transfer.\n    /// @param nativeToken Whether the token is a native token.\n    function getCCIPFee(uint64 targetChain, address target, uint256 amount, bool nativeToken) public view returns (uint256) {\n        return getCCIPFee(targetChain, _toReceiver(target), amount, nativeToken, \"\");\n    }\n\n    /// @notice Gets the CCIP fee for a transfer.\n    /// @param targetChain The chain selector of the destination chain.\n    /// @param target The address of the recipient on the destination chain.\n    /// @param amount The amount of tokens to transfer.\n    /// @param nativeToken Whether the token is a native token.\n    /// @param extraArgs Extra arguments for CCIP\n    function getCCIPFee(uint64 targetChain, address target, uint256 amount, bool nativeToken, bytes memory extraArgs) public view returns (uint256) {\n        return getCCIPFee(targetChain, _toReceiver(target), amount, nativeToken, extraArgs);\n    }\n\n    /// @notice Gets the CCIP fee for a transfer.\n    /// @param targetChain The chain selector of the destination chain.\n    /// @param target The address of the recipient on the destination chain.\n    /// @param amount The amount of tokens to transfer.\n    /// @param nativeToken Whether the token is a native token.\n    /// @param extraArgs Extra arguments for CCIP\n    function getCCIPFee(uint64 targetChain, bytes memory target, uint256 amount, bool nativeToken, bytes memory extraArgs) public view returns (uint256) {\n        Client.EVMTokenAmount[] memory tokenAmounts = new Client.EVMTokenAmount[](1);\n        tokenAmounts[0] = Client.EVMTokenAmount(address(zchf), amount);\n        return _calculateFee(targetChain, _constructMessage(target, \"\", tokenAmounts, nativeToken, extraArgs));\n    }\n\n    /// @notice Construct a CCIP message.\n    /// @dev This function will create an EVM2AnyMessage struct with all the necessary information for tokens transfer.\n    /// @param receiver The address of the receiver.\n    /// @param amount The amount of the token to be transferred.\n    /// @return Client.EVM2AnyMessage Returns an EVM2AnyMessage struct which contains information for sending a CCIP message.\n    function constructTransferMessage(bytes memory receiver, uint256 amount, bytes memory extraArgs) private view returns (Client.EVM2AnyMessage memory) {\n        Client.EVMTokenAmount[] memory tokenAmounts = new Client.EVMTokenAmount[](1);\n        tokenAmounts[0] = Client.EVMTokenAmount(address(zchf), amount);\n        return _constructMessage(receiver, \"\", tokenAmounts, extraArgs);\n    }\n}\n","deployed_bytecode":"0x6080604052600436106100dd5760003560e01c806332fe7b261161007f5780637ff37e73116100595780637ff37e7314610244578063912fa616146102575780639f3b3ea314610277578063c4d4803a1461029757600080fd5b806332fe7b26146101c257806353c521e6146101f657806356b8c7241461022457600080fd5b8063218d8df8116100bb578063218d8df8146101765780632bcba77a146101895780632e18e2b01461019c5780632fc2fcad146101af57600080fd5b80631af716ba146100e25780631b6b6d231461011757806320e0769614610163575b600080fd5b3480156100ee57600080fd5b506101026100fd36600461145b565b6102cb565b60405190151581526020015b60405180910390f35b34801561012357600080fd5b5061014b7f000000000000000000000000514910771af9ca656af840dff83e8264ecf986ca81565b6040516001600160a01b03909116815260200161010e565b610102610171366004611582565b61047c565b610102610184366004611648565b6104d3565b6101026101973660046116c7565b610554565b6101026101aa366004611727565b610633565b6101026101bd366004611748565b61064f565b3480156101ce57600080fd5b5061014b7f00000000000000000000000080226fc0ee2b096224eeac085bb9a8cba1146f7d81565b34801561020257600080fd5b506102166102113660046117d6565b610716565b60405190815260200161010e565b34801561023057600080fd5b5061010261023f366004611825565b610745565b61010261025236600461187e565b610836565b34801561026357600080fd5b5061021661027236600461193c565b610945565b34801561028357600080fd5b506102166102923660046119ce565b610a14565b3480156102a357600080fd5b5061014b7f000000000000000000000000b58e61c3098d85632df34eecfb899a1ed80921cb81565b6000600160ff1b7f000000000000000000000000b58e61c3098d85632df34eecfb899a1ed80921cb6001600160a01b031663dd62ed3e88336040518363ffffffff1660e01b8152600401610320929190611a3b565b602060405180830381865afa15801561033d573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906103619190611a55565b101561038d578533604051631787b42960e01b8152600401610384929190611a3b565b60405180910390fd5b6040516323b872dd60e01b81526001600160a01b037f000000000000000000000000b58e61c3098d85632df34eecfb899a1ed80921cb16906323b872dd906103dd90899089908990600401611a6e565b6020604051808303816000875af11580156103fc573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906104209190611a92565b50846001600160a01b0316866001600160a01b03167fcd6e659e4c2e75c3bfe47fecaccf39aeb368116a0ee52afb532e07f6cba6c0d186868660405161046893929190611adf565b60405180910390a350600195945050505050565b60006104c58833898989898080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152508b92508a9150610a359050565b506001979650505050505050565b600061054787336104e389610c03565b886105406104f6368b90038b018b611af9565b6040805182516024820152602092830151151560448083019190915282518083039091018152606490910190915290810180516001600160e01b0316630181dcf160e41b17905290565b8888610a35565b5060019695505050505050565b6000600160ff1b7f000000000000000000000000b58e61c3098d85632df34eecfb899a1ed80921cb6001600160a01b031663dd62ed3e88336040518363ffffffff1660e01b81526004016105a9929190611a3b565b602060405180830381865afa1580156105c6573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906105ea9190611a55565b101561060d578533604051631787b42960e01b8152600401610384929190611a3b565b610547878761061b88610c03565b87604051806020016040528060008152508888610a35565b6000610643863361061b88610c03565b50600195945050505050565b6000600160ff1b7f000000000000000000000000b58e61c3098d85632df34eecfb899a1ed80921cb6001600160a01b031663dd62ed3e89336040518363ffffffff1660e01b81526004016106a4929190611a3b565b602060405180830381865afa1580156106c1573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906106e59190611a55565b1015610708578633604051631787b42960e01b8152600401610384929190611a3b565b6104c588886104e389610c03565b600061073c8561072586610c03565b858560405180602001604052806000815250610945565b95945050505050565b6040516323b872dd60e01b81526000906001600160a01b037f000000000000000000000000b58e61c3098d85632df34eecfb899a1ed80921cb16906323b872dd9061079890339089908990600401611a6e565b6020604051808303816000875af11580156107b7573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906107db9190611a92565b50846001600160a01b0316336001600160a01b03167fcd6e659e4c2e75c3bfe47fecaccf39aeb368116a0ee52afb532e07f6cba6c0d186868660405161082393929190611adf565b60405180910390a3506001949350505050565b6000600160ff1b7f000000000000000000000000b58e61c3098d85632df34eecfb899a1ed80921cb6001600160a01b031663dd62ed3e8a336040518363ffffffff1660e01b815260040161088b929190611a3b565b602060405180830381865afa1580156108a8573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906108cc9190611a55565b10156108ef578733604051631787b42960e01b8152600401610384929190611a3b565b6109368989898989898080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152508b92508a9150610a359050565b50600198975050505050505050565b604080516001808252818301909252600091829190816020015b604080518082019091526000808252602082015281526020019060019003908161095f57905050905060405180604001604052807f000000000000000000000000b58e61c3098d85632df34eecfb899a1ed80921cb6001600160a01b0316815260200186815250816000815181106109d9576109d9611b4e565b6020026020010181905250610a0987610a048860405180602001604052806000815250858989610c30565b610c9e565b979650505050505050565b6000610a2b86610a2387610c03565b868686610945565b9695505050505050565b6040516323b872dd60e01b81526001600160a01b037f000000000000000000000000b58e61c3098d85632df34eecfb899a1ed80921cb16906323b872dd90610a8590899030908990600401611a6e565b6020604051808303816000875af1158015610aa4573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610ac89190611a92565b5060405163095ea7b360e01b81526001600160a01b037f00000000000000000000000080226fc0ee2b096224eeac085bb9a8cba1146f7d81166004830152602482018690527f000000000000000000000000b58e61c3098d85632df34eecfb899a1ed80921cb169063095ea7b3906044016020604051808303816000875af1158015610b58573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610b7c9190611a92565b50610b9187610b8c878787610d39565b610df8565b505084604051610ba19190611b88565b6040518091039020866001600160a01b0316336001600160a01b03167f06666856ab7ec8eca6666144744c8bdd710c19b0aba4a36495361c82a01099288a888787604051610bf29493929190611ba4565b60405180910390a450505050505050565b604080516001600160a01b0383166020820152606091016040516020818303038152906040529050919050565b610c386113c6565b6040518060a0016040528087815260200186815260200185815260200184610c80577f000000000000000000000000514910771af9ca656af840dff83e8264ecf986ca610c83565b60005b6001600160a01b031681526020019290925250949350505050565b6040516320487ded60e01b81526000906001600160a01b037f00000000000000000000000080226fc0ee2b096224eeac085bb9a8cba1146f7d16906320487ded90610cef9086908690600401611bf9565b602060405180830381865afa158015610d0c573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610d309190611a55565b90505b92915050565b610d416113c6565b604080516001808252818301909252600091816020015b6040805180820190915260008082526020820152815260200190600190039081610d5857905050905060405180604001604052807f000000000000000000000000b58e61c3098d85632df34eecfb899a1ed80921cb6001600160a01b031681526020018581525081600081518110610dd257610dd2611b4e565b602002602001018190525061073c8560405180602001604052806000815250838661134b565b6000806000610e078585610c9e565b60608501519091506000906001600160a01b03161561120f5760608501516040516370a0823160e01b815233600482015283916001600160a01b0316906370a0823190602401602060405180830381865afa158015610e6a573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610e8e9190611a55565b1015610ec55760608501516040516346d55cf960e01b81526001600160a01b03909116600482015260248101839052604401610384565b6060850151604051636eb1769f60e11b815283916001600160a01b03169063dd62ed3e90610ef99033903090600401611a3b565b602060405180830381865afa158015610f16573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610f3a9190611a55565b1015610f7157606085015160405163def222f760e01b81526001600160a01b03909116600482015260248101839052604401610384565b84606001516001600160a01b03166323b872dd3330856040518463ffffffff1660e01b8152600401610fa593929190611a6e565b6020604051808303816000875af1158015610fc4573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610fe89190611a92565b50606085015160405163095ea7b360e01b81526001600160a01b037f00000000000000000000000080226fc0ee2b096224eeac085bb9a8cba1146f7d81166004830152602482018590529091169063095ea7b3906044016020604051808303816000875af115801561105e573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906110829190611a92565b506040516396f4e9f960e01b81526001600160a01b037f00000000000000000000000080226fc0ee2b096224eeac085bb9a8cba1146f7d16906396f4e9f9906110d19089908990600401611bf9565b6020604051808303816000875af11580156110f0573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906111149190611a55565b60608601516040516370a0823160e01b81523060048201529192506000916001600160a01b03909116906370a0823190602401602060405180830381865afa158015611164573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906111889190611a55565b9050801561120957606086015160405163a9059cbb60e01b8152336004820152602481018390526001600160a01b039091169063a9059cbb906044016020604051808303816000875af11580156111e3573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906112079190611a92565b505b5061133f565b813410156112485760608501516040516346d55cf960e01b81526001600160a01b03909116600482015260248101839052604401610384565b6040516396f4e9f960e01b81526001600160a01b037f00000000000000000000000080226fc0ee2b096224eeac085bb9a8cba1146f7d16906396f4e9f9908490611298908a908a90600401611bf9565b60206040518083038185885af11580156112b6573d6000803e3d6000fd5b50505050506040513d601f19601f820116820180604052508101906112db9190611a55565b905060006112e98334611cd5565b111561133f57336112fa8334611cd5565b604051600081818185875af1925050503d8060008114611336576040519150601f19603f3d011682016040523d82523d6000602084013e61133b565b606091505b5050505b925090505b9250929050565b6113536113c6565b6040518060a00160405280868152602001858152602001848152602001611378611392565b6001600160a01b0316815260200192909252509392505050565b60008034116113c057507f000000000000000000000000514910771af9ca656af840dff83e8264ecf986ca90565b50600090565b6040518060a0016040528060608152602001606081526020016060815260200160006001600160a01b03168152602001606081525090565b80356001600160a01b038116811461141557600080fd5b919050565b60008083601f84011261142c57600080fd5b5081356001600160401b0381111561144357600080fd5b60208301915083602082850101111561134457600080fd5b60008060008060006080868803121561147357600080fd5b61147c866113fe565b945061148a602087016113fe565b93506040860135925060608601356001600160401b038111156114ac57600080fd5b6114b88882890161141a565b969995985093965092949392505050565b80356001600160401b038116811461141557600080fd5b634e487b7160e01b600052604160045260246000fd5b600082601f83011261150757600080fd5b81356001600160401b0380821115611521576115216114e0565b604051601f8301601f19908116603f01168101908282118183101715611549576115496114e0565b8160405283815286602085880101111561156257600080fd5b836020870160208301376000602085830101528094505050505092915050565b600080600080600080600060a0888a03121561159d57600080fd5b6115a6886114c9565b965060208801356001600160401b03808211156115c257600080fd5b6115ce8b838c016114f6565b975060408a0135965060608a01359150808211156115eb57600080fd5b6115f78b838c0161141a565b909650945060808a013591508082111561161057600080fd5b5061161d8a828b0161141a565b989b979a50959850939692959293505050565b60006040828403121561164257600080fd5b50919050565b60008060008060008060c0878903121561166157600080fd5b61166a876114c9565b9550611678602088016113fe565b94506040870135935061168e8860608901611630565b925060a08701356001600160401b038111156116a957600080fd5b6116b589828a0161141a565b979a9699509497509295939492505050565b60008060008060008060a087890312156116e057600080fd5b6116e9876114c9565b95506116f7602088016113fe565b9450611705604088016113fe565b93506060870135925060808701356001600160401b038111156116a957600080fd5b60008060008060006080868803121561173f57600080fd5b61147c866114c9565b600080600080600080600060e0888a03121561176357600080fd5b61176c886114c9565b965061177a602089016113fe565b9550611788604089016113fe565b94506060880135935061179e8960808a01611630565b925060c08801356001600160401b038111156117b957600080fd5b61161d8a828b0161141a565b80151581146117d357600080fd5b50565b600080600080608085870312156117ec57600080fd5b6117f5856114c9565b9350611803602086016113fe565b925060408501359150606085013561181a816117c5565b939692955090935050565b6000806000806060858703121561183b57600080fd5b611844856113fe565b93506020850135925060408501356001600160401b0381111561186657600080fd5b6118728782880161141a565b95989497509550505050565b60008060008060008060008060c0898b03121561189a57600080fd5b6118a3896114c9565b97506118b160208a016113fe565b965060408901356001600160401b03808211156118cd57600080fd5b6118d98c838d016114f6565b975060608b0135965060808b01359150808211156118f657600080fd5b6119028c838d0161141a565b909650945060a08b013591508082111561191b57600080fd5b506119288b828c0161141a565b999c989b5096995094979396929594505050565b600080600080600060a0868803121561195457600080fd5b61195d866114c9565b945060208601356001600160401b038082111561197957600080fd5b61198589838a016114f6565b9550604088013594506060880135915061199e826117c5565b909250608087013590808211156119b457600080fd5b506119c1888289016114f6565b9150509295509295909350565b600080600080600060a086880312156119e657600080fd5b6119ef866114c9565b94506119fd602087016113fe565b9350604086013592506060860135611a14816117c5565b915060808601356001600160401b03811115611a2f57600080fd5b6119c1888289016114f6565b6001600160a01b0392831681529116602082015260400190565b600060208284031215611a6757600080fd5b5051919050565b6001600160a01b039384168152919092166020820152604081019190915260600190565b600060208284031215611aa457600080fd5b8151611aaf816117c5565b9392505050565b81835281816020850137506000828201602090810191909152601f909101601f19169091010190565b83815260406020820152600061073c604083018486611ab6565b600060408284031215611b0b57600080fd5b604051604081018181106001600160401b0382111715611b2d57611b2d6114e0565b604052823581526020830135611b42816117c5565b60208201529392505050565b634e487b7160e01b600052603260045260246000fd5b60005b83811015611b7f578181015183820152602001611b67565b50506000910152565b60008251611b9a818460208701611b64565b9190910192915050565b6001600160401b0385168152836020820152606060408201526000610a2b606083018486611ab6565b60008151808452611be5816020860160208601611b64565b601f01601f19169290920160200192915050565b600060406001600160401b03851683526020604081850152845160a06040860152611c2760e0860182611bcd565b905081860151603f1980878403016060880152611c448383611bcd565b6040890151888203830160808a01528051808352908601945060009350908501905b80841015611c9857845180516001600160a01b0316835286015186830152938501936001939093019290860190611c66565b5060608901516001600160a01b031660a08901526080890151888203830160c08a01529550611cc78187611bcd565b9a9950505050505050505050565b81810381811115610d3357634e487b7160e01b600052601160045260246000fdfea26469706673582212203d1824d1704ad42a165a2a25ae8e3def99da87e1b0302f764dca2d178232558164736f6c63430008180033","optimization_enabled":true,"verified_twin_address_hash":null,"is_verified":true,"compiler_settings":{"evmVersion":"paris","libraries":{},"metadata":{"bytecodeHash":"ipfs","useLiteralContent":true},"optimizer":{"enabled":true,"runs":200},"remappings":[]},"optimization_runs":200,"sourcify_repo_url":"https://repo.sourcify.dev/contracts/full_match/1/0xf98c221661F51578f5E5236B189a493E2a8a1916/","decoded_constructor_args":[["0xB58E61C3098d85632Df34EecfB899A1Ed80921cB",{"internalType":"address","name":"token","type":"address"}],["0x80226fc0Ee2b096224EeAc085Bb9a8cba1146f7D",{"internalType":"contract IRouterClient","name":"router","type":"address"}],["0x514910771AF9Ca656af840dff83E8264EcF986CA",{"internalType":"address","name":"link","type":"address"}]],"compiler_version":"0.8.24+commit.e11b9ed9","is_verified_via_verifier_alliance":false,"verified_at":"2025-12-17T21:06:41.307927Z","implementations":[],"proxy_type":null,"external_libraries":[],"creation_bytecode":"0x60e06040523480156200001157600080fd5b5060405162001e9138038062001e9183398101604081905262000034916200006a565b6001600160a01b03918216608052811660a0521660c052620000be565b6001600160a01b03811681146200006757600080fd5b50565b6000806000606084860312156200008057600080fd5b83516200008d8162000051565b6020850151909350620000a08162000051565b6040850151909250620000b38162000051565b809150509250925092565b60805160a05160c051611d2c62000165600039600081816102a9015281816102d4015281816103a40152818161055d015281816106580152818161075f0152818161083f0152818161099501528181610a4c01528181610b0f0152610d8e01526000818161012901528181610c5c015261139e0152600081816101d401528181610ae001528181610cb8015281816110050152818161109a015261125f0152611d2c6000f3fe6080604052600436106100dd5760003560e01c806332fe7b261161007f5780637ff37e73116100595780637ff37e7314610244578063912fa616146102575780639f3b3ea314610277578063c4d4803a1461029757600080fd5b806332fe7b26146101c257806353c521e6146101f657806356b8c7241461022457600080fd5b8063218d8df8116100bb578063218d8df8146101765780632bcba77a146101895780632e18e2b01461019c5780632fc2fcad146101af57600080fd5b80631af716ba146100e25780631b6b6d231461011757806320e0769614610163575b600080fd5b3480156100ee57600080fd5b506101026100fd36600461145b565b6102cb565b60405190151581526020015b60405180910390f35b34801561012357600080fd5b5061014b7f000000000000000000000000000000000000000000000000000000000000000081565b6040516001600160a01b03909116815260200161010e565b610102610171366004611582565b61047c565b610102610184366004611648565b6104d3565b6101026101973660046116c7565b610554565b6101026101aa366004611727565b610633565b6101026101bd366004611748565b61064f565b3480156101ce57600080fd5b5061014b7f000000000000000000000000000000000000000000000000000000000000000081565b34801561020257600080fd5b506102166102113660046117d6565b610716565b60405190815260200161010e565b34801561023057600080fd5b5061010261023f366004611825565b610745565b61010261025236600461187e565b610836565b34801561026357600080fd5b5061021661027236600461193c565b610945565b34801561028357600080fd5b506102166102923660046119ce565b610a14565b3480156102a357600080fd5b5061014b7f000000000000000000000000000000000000000000000000000000000000000081565b6000600160ff1b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663dd62ed3e88336040518363ffffffff1660e01b8152600401610320929190611a3b565b602060405180830381865afa15801561033d573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906103619190611a55565b101561038d578533604051631787b42960e01b8152600401610384929190611a3b565b60405180910390fd5b6040516323b872dd60e01b81526001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016906323b872dd906103dd90899089908990600401611a6e565b6020604051808303816000875af11580156103fc573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906104209190611a92565b50846001600160a01b0316866001600160a01b03167fcd6e659e4c2e75c3bfe47fecaccf39aeb368116a0ee52afb532e07f6cba6c0d186868660405161046893929190611adf565b60405180910390a350600195945050505050565b60006104c58833898989898080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152508b92508a9150610a359050565b506001979650505050505050565b600061054787336104e389610c03565b886105406104f6368b90038b018b611af9565b6040805182516024820152602092830151151560448083019190915282518083039091018152606490910190915290810180516001600160e01b0316630181dcf160e41b17905290565b8888610a35565b5060019695505050505050565b6000600160ff1b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663dd62ed3e88336040518363ffffffff1660e01b81526004016105a9929190611a3b565b602060405180830381865afa1580156105c6573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906105ea9190611a55565b101561060d578533604051631787b42960e01b8152600401610384929190611a3b565b610547878761061b88610c03565b87604051806020016040528060008152508888610a35565b6000610643863361061b88610c03565b50600195945050505050565b6000600160ff1b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663dd62ed3e89336040518363ffffffff1660e01b81526004016106a4929190611a3b565b602060405180830381865afa1580156106c1573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906106e59190611a55565b1015610708578633604051631787b42960e01b8152600401610384929190611a3b565b6104c588886104e389610c03565b600061073c8561072586610c03565b858560405180602001604052806000815250610945565b95945050505050565b6040516323b872dd60e01b81526000906001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016906323b872dd9061079890339089908990600401611a6e565b6020604051808303816000875af11580156107b7573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906107db9190611a92565b50846001600160a01b0316336001600160a01b03167fcd6e659e4c2e75c3bfe47fecaccf39aeb368116a0ee52afb532e07f6cba6c0d186868660405161082393929190611adf565b60405180910390a3506001949350505050565b6000600160ff1b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663dd62ed3e8a336040518363ffffffff1660e01b815260040161088b929190611a3b565b602060405180830381865afa1580156108a8573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906108cc9190611a55565b10156108ef578733604051631787b42960e01b8152600401610384929190611a3b565b6109368989898989898080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152508b92508a9150610a359050565b50600198975050505050505050565b604080516001808252818301909252600091829190816020015b604080518082019091526000808252602082015281526020019060019003908161095f57905050905060405180604001604052807f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316815260200186815250816000815181106109d9576109d9611b4e565b6020026020010181905250610a0987610a048860405180602001604052806000815250858989610c30565b610c9e565b979650505050505050565b6000610a2b86610a2387610c03565b868686610945565b9695505050505050565b6040516323b872dd60e01b81526001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016906323b872dd90610a8590899030908990600401611a6e565b6020604051808303816000875af1158015610aa4573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610ac89190611a92565b5060405163095ea7b360e01b81526001600160a01b037f000000000000000000000000000000000000000000000000000000000000000081166004830152602482018690527f0000000000000000000000000000000000000000000000000000000000000000169063095ea7b3906044016020604051808303816000875af1158015610b58573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610b7c9190611a92565b50610b9187610b8c878787610d39565b610df8565b505084604051610ba19190611b88565b6040518091039020866001600160a01b0316336001600160a01b03167f06666856ab7ec8eca6666144744c8bdd710c19b0aba4a36495361c82a01099288a888787604051610bf29493929190611ba4565b60405180910390a450505050505050565b604080516001600160a01b0383166020820152606091016040516020818303038152906040529050919050565b610c386113c6565b6040518060a0016040528087815260200186815260200185815260200184610c80577f0000000000000000000000000000000000000000000000000000000000000000610c83565b60005b6001600160a01b031681526020019290925250949350505050565b6040516320487ded60e01b81526000906001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016906320487ded90610cef9086908690600401611bf9565b602060405180830381865afa158015610d0c573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610d309190611a55565b90505b92915050565b610d416113c6565b604080516001808252818301909252600091816020015b6040805180820190915260008082526020820152815260200190600190039081610d5857905050905060405180604001604052807f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031681526020018581525081600081518110610dd257610dd2611b4e565b602002602001018190525061073c8560405180602001604052806000815250838661134b565b6000806000610e078585610c9e565b60608501519091506000906001600160a01b03161561120f5760608501516040516370a0823160e01b815233600482015283916001600160a01b0316906370a0823190602401602060405180830381865afa158015610e6a573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610e8e9190611a55565b1015610ec55760608501516040516346d55cf960e01b81526001600160a01b03909116600482015260248101839052604401610384565b6060850151604051636eb1769f60e11b815283916001600160a01b03169063dd62ed3e90610ef99033903090600401611a3b565b602060405180830381865afa158015610f16573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610f3a9190611a55565b1015610f7157606085015160405163def222f760e01b81526001600160a01b03909116600482015260248101839052604401610384565b84606001516001600160a01b03166323b872dd3330856040518463ffffffff1660e01b8152600401610fa593929190611a6e565b6020604051808303816000875af1158015610fc4573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610fe89190611a92565b50606085015160405163095ea7b360e01b81526001600160a01b037f000000000000000000000000000000000000000000000000000000000000000081166004830152602482018590529091169063095ea7b3906044016020604051808303816000875af115801561105e573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906110829190611a92565b506040516396f4e9f960e01b81526001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016906396f4e9f9906110d19089908990600401611bf9565b6020604051808303816000875af11580156110f0573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906111149190611a55565b60608601516040516370a0823160e01b81523060048201529192506000916001600160a01b03909116906370a0823190602401602060405180830381865afa158015611164573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906111889190611a55565b9050801561120957606086015160405163a9059cbb60e01b8152336004820152602481018390526001600160a01b039091169063a9059cbb906044016020604051808303816000875af11580156111e3573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906112079190611a92565b505b5061133f565b813410156112485760608501516040516346d55cf960e01b81526001600160a01b03909116600482015260248101839052604401610384565b6040516396f4e9f960e01b81526001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016906396f4e9f9908490611298908a908a90600401611bf9565b60206040518083038185885af11580156112b6573d6000803e3d6000fd5b50505050506040513d601f19601f820116820180604052508101906112db9190611a55565b905060006112e98334611cd5565b111561133f57336112fa8334611cd5565b604051600081818185875af1925050503d8060008114611336576040519150601f19603f3d011682016040523d82523d6000602084013e61133b565b606091505b5050505b925090505b9250929050565b6113536113c6565b6040518060a00160405280868152602001858152602001848152602001611378611392565b6001600160a01b0316815260200192909252509392505050565b60008034116113c057507f000000000000000000000000000000000000000000000000000000000000000090565b50600090565b6040518060a0016040528060608152602001606081526020016060815260200160006001600160a01b03168152602001606081525090565b80356001600160a01b038116811461141557600080fd5b919050565b60008083601f84011261142c57600080fd5b5081356001600160401b0381111561144357600080fd5b60208301915083602082850101111561134457600080fd5b60008060008060006080868803121561147357600080fd5b61147c866113fe565b945061148a602087016113fe565b93506040860135925060608601356001600160401b038111156114ac57600080fd5b6114b88882890161141a565b969995985093965092949392505050565b80356001600160401b038116811461141557600080fd5b634e487b7160e01b600052604160045260246000fd5b600082601f83011261150757600080fd5b81356001600160401b0380821115611521576115216114e0565b604051601f8301601f19908116603f01168101908282118183101715611549576115496114e0565b8160405283815286602085880101111561156257600080fd5b836020870160208301376000602085830101528094505050505092915050565b600080600080600080600060a0888a03121561159d57600080fd5b6115a6886114c9565b965060208801356001600160401b03808211156115c257600080fd5b6115ce8b838c016114f6565b975060408a0135965060608a01359150808211156115eb57600080fd5b6115f78b838c0161141a565b909650945060808a013591508082111561161057600080fd5b5061161d8a828b0161141a565b989b979a50959850939692959293505050565b60006040828403121561164257600080fd5b50919050565b60008060008060008060c0878903121561166157600080fd5b61166a876114c9565b9550611678602088016113fe565b94506040870135935061168e8860608901611630565b925060a08701356001600160401b038111156116a957600080fd5b6116b589828a0161141a565b979a9699509497509295939492505050565b60008060008060008060a087890312156116e057600080fd5b6116e9876114c9565b95506116f7602088016113fe565b9450611705604088016113fe565b93506060870135925060808701356001600160401b038111156116a957600080fd5b60008060008060006080868803121561173f57600080fd5b61147c866114c9565b600080600080600080600060e0888a03121561176357600080fd5b61176c886114c9565b965061177a602089016113fe565b9550611788604089016113fe565b94506060880135935061179e8960808a01611630565b925060c08801356001600160401b038111156117b957600080fd5b61161d8a828b0161141a565b80151581146117d357600080fd5b50565b600080600080608085870312156117ec57600080fd5b6117f5856114c9565b9350611803602086016113fe565b925060408501359150606085013561181a816117c5565b939692955090935050565b6000806000806060858703121561183b57600080fd5b611844856113fe565b93506020850135925060408501356001600160401b0381111561186657600080fd5b6118728782880161141a565b95989497509550505050565b60008060008060008060008060c0898b03121561189a57600080fd5b6118a3896114c9565b97506118b160208a016113fe565b965060408901356001600160401b03808211156118cd57600080fd5b6118d98c838d016114f6565b975060608b0135965060808b01359150808211156118f657600080fd5b6119028c838d0161141a565b909650945060a08b013591508082111561191b57600080fd5b506119288b828c0161141a565b999c989b5096995094979396929594505050565b600080600080600060a0868803121561195457600080fd5b61195d866114c9565b945060208601356001600160401b038082111561197957600080fd5b61198589838a016114f6565b9550604088013594506060880135915061199e826117c5565b909250608087013590808211156119b457600080fd5b506119c1888289016114f6565b9150509295509295909350565b600080600080600060a086880312156119e657600080fd5b6119ef866114c9565b94506119fd602087016113fe565b9350604086013592506060860135611a14816117c5565b915060808601356001600160401b03811115611a2f57600080fd5b6119c1888289016114f6565b6001600160a01b0392831681529116602082015260400190565b600060208284031215611a6757600080fd5b5051919050565b6001600160a01b039384168152919092166020820152604081019190915260600190565b600060208284031215611aa457600080fd5b8151611aaf816117c5565b9392505050565b81835281816020850137506000828201602090810191909152601f909101601f19169091010190565b83815260406020820152600061073c604083018486611ab6565b600060408284031215611b0b57600080fd5b604051604081018181106001600160401b0382111715611b2d57611b2d6114e0565b604052823581526020830135611b42816117c5565b60208201529392505050565b634e487b7160e01b600052603260045260246000fd5b60005b83811015611b7f578181015183820152602001611b67565b50506000910152565b60008251611b9a818460208701611b64565b9190910192915050565b6001600160401b0385168152836020820152606060408201526000610a2b606083018486611ab6565b60008151808452611be5816020860160208601611b64565b601f01601f19169290920160200192915050565b600060406001600160401b03851683526020604081850152845160a06040860152611c2760e0860182611bcd565b905081860151603f1980878403016060880152611c448383611bcd565b6040890151888203830160808a01528051808352908601945060009350908501905b80841015611c9857845180516001600160a01b0316835286015186830152938501936001939093019290860190611c66565b5060608901516001600160a01b031660a08901526080890151888203830160c08a01529550611cc78187611bcd565b9a9950505050505050505050565b81810381811115610d3357634e487b7160e01b600052601160045260246000fdfea26469706673582212203d1824d1704ad42a165a2a25ae8e3def99da87e1b0302f764dca2d178232558164736f6c63430008180033000000000000000000000000b58e61c3098d85632df34eecfb899a1ed80921cb00000000000000000000000080226fc0ee2b096224eeac085bb9a8cba1146f7d000000000000000000000000514910771af9ca656af840dff83e8264ecf986ca","name":"TransferReference","is_blueprint":false,"license_type":"none","is_fully_verified":true,"is_verified_via_eth_bytecode_db":true,"language":"solidity","evm_version":"paris","can_be_visualized_via_sol2uml":true,"is_verified_via_sourcify":true,"additional_sources":[{"file_path":"@chainlink/contracts-ccip/src/v0.8/ccip/interfaces/IRouterClient.sol","source_code":"// SPDX-License-Identifier: MIT\npragma solidity ^0.8.4;\n\nimport {Client} from \"../libraries/Client.sol\";\n\ninterface IRouterClient {\n  error UnsupportedDestinationChain(uint64 destChainSelector);\n  error InsufficientFeeTokenAmount();\n  error InvalidMsgValue();\n\n  /// @notice Checks if the given chain ID is supported for sending/receiving.\n  /// @param destChainSelector The chain to check.\n  /// @return supported is true if it is supported, false if not.\n  function isChainSupported(\n    uint64 destChainSelector\n  ) external view returns (bool supported);\n\n  /// @param destinationChainSelector The destination chainSelector\n  /// @param message The cross-chain CCIP message including data and/or tokens\n  /// @return fee returns execution fee for the message\n  /// delivery to destination chain, denominated in the feeToken specified in the message.\n  /// @dev Reverts with appropriate reason upon invalid message.\n  function getFee(\n    uint64 destinationChainSelector,\n    Client.EVM2AnyMessage memory message\n  ) external view returns (uint256 fee);\n\n  /// @notice Request a message to be sent to the destination chain\n  /// @param destinationChainSelector The destination chain ID\n  /// @param message The cross-chain CCIP message including data and/or tokens\n  /// @return messageId The message ID\n  /// @dev Note if msg.value is larger than the required fee (from getFee) we accept\n  /// the overpayment with no refund.\n  /// @dev Reverts with appropriate reason upon invalid message.\n  function ccipSend(\n    uint64 destinationChainSelector,\n    Client.EVM2AnyMessage calldata message\n  ) external payable returns (bytes32);\n}\n"},{"file_path":"@chainlink/contracts-ccip/src/v0.8/ccip/libraries/Client.sol","source_code":"// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\n// End consumer library.\nlibrary Client {\n  /// @dev RMN depends on this struct, if changing, please notify the RMN maintainers.\n  struct EVMTokenAmount {\n    address token; // token address on the local chain.\n    uint256 amount; // Amount of tokens.\n  }\n\n  struct Any2EVMMessage {\n    bytes32 messageId; // MessageId corresponding to ccipSend on source.\n    uint64 sourceChainSelector; // Source chain selector.\n    bytes sender; // abi.decode(sender) if coming from an EVM chain.\n    bytes data; // payload sent in original message.\n    EVMTokenAmount[] destTokenAmounts; // Tokens and their amounts in their destination chain representation.\n  }\n\n  // If extraArgs is empty bytes, the default is 200k gas limit.\n  struct EVM2AnyMessage {\n    bytes receiver; // abi.encode(receiver address) for dest EVM chains\n    bytes data; // Data payload\n    EVMTokenAmount[] tokenAmounts; // Token transfers\n    address feeToken; // Address of feeToken. address(0) means you will send msg.value.\n    bytes extraArgs; // Populate this with _argsToBytes(EVMExtraArgsV2)\n  }\n\n  // bytes4(keccak256(\"CCIP EVMExtraArgsV1\"));\n  bytes4 public constant EVM_EXTRA_ARGS_V1_TAG = 0x97a657c9;\n\n  struct EVMExtraArgsV1 {\n    uint256 gasLimit;\n  }\n\n  function _argsToBytes(\n    EVMExtraArgsV1 memory extraArgs\n  ) internal pure returns (bytes memory bts) {\n    return abi.encodeWithSelector(EVM_EXTRA_ARGS_V1_TAG, extraArgs);\n  }\n\n  // bytes4(keccak256(\"CCIP EVMExtraArgsV2\"));\n  bytes4 public constant EVM_EXTRA_ARGS_V2_TAG = 0x181dcf10;\n\n  /// @param gasLimit: gas limit for the callback on the destination chain.\n  /// @param allowOutOfOrderExecution: if true, it indicates that the message can be executed in any order relative to other messages from the same sender.\n  /// This value's default varies by chain. On some chains, a particular value is enforced, meaning if the expected value\n  /// is not set, the message request will revert.\n  struct EVMExtraArgsV2 {\n    uint256 gasLimit;\n    bool allowOutOfOrderExecution;\n  }\n\n  function _argsToBytes(\n    EVMExtraArgsV2 memory extraArgs\n  ) internal pure returns (bytes memory bts) {\n    return abi.encodeWithSelector(EVM_EXTRA_ARGS_V2_TAG, extraArgs);\n  }\n}\n"},{"file_path":"contracts/bridge/CCIPSender.sol","source_code":"// SPDX-License-Identifier: MIT\n\npragma solidity ^0.8.0;\n\nimport {Client} from \"@chainlink/contracts-ccip/src/v0.8/ccip/libraries/Client.sol\";\nimport {IRouterClient} from \"@chainlink/contracts-ccip/src/v0.8/ccip/interfaces/IRouterClient.sol\";\nimport {IERC20} from \"../erc20/IERC20.sol\";\n\nabstract contract CCIPSender {\n    IRouterClient public immutable ROUTER;\n    address public immutable LINK;\n\n    error InsufficientFeeTokens(address token, uint256 fee);\n    error InsufficientFeeTokenAllowance(address token, uint256 fee);\n\n    constructor(IRouterClient router, address link) {\n        ROUTER = router;\n        LINK = link;\n    }\n\n    /// @notice Encodes the receiver correctly\n    /// @param target The target address\n    /// @return The encoded receiver\n    function _toReceiver(address target) internal pure returns (bytes memory) {\n        return abi.encode(target);\n    }\n\n    /// @notice Builds the message struct\n    /// @dev Guesses the fee token based on msg.value\n    /// @param receiver The receiver\n    /// @param payload The payload\n    /// @param tokenAmounts The token amounts\n    /// @param extraArgs The extra args such as gas limit and out-of-order execution\n    /// @return The message struct\n    function _constructMessage(bytes memory receiver, bytes memory payload, Client.EVMTokenAmount[] memory tokenAmounts, bytes memory extraArgs) internal view returns (Client.EVM2AnyMessage memory) {\n        return Client.EVM2AnyMessage(receiver, payload, tokenAmounts, _guessFeeToken(), extraArgs);\n    }\n\n    /// @notice Builds the message struct\n    /// @param receiver The receiver\n    /// @param payload The payload\n    /// @param tokenAmounts The token amounts\n    /// @param nativeToken Whether to use native token or LINK\n    /// @param extraArgs The extra args such as gas limit and out-of-order execution\n    /// @return The message struct\n    function _constructMessage(bytes memory receiver, bytes memory payload, Client.EVMTokenAmount[] memory tokenAmounts, bool nativeToken,  bytes memory extraArgs) internal view returns (Client.EVM2AnyMessage memory) {\n        return Client.EVM2AnyMessage(receiver, payload, tokenAmounts, nativeToken ? address(0) : LINK, extraArgs);\n    }\n\n    /// @notice Gets the fee from the router for the given message and chain combination\n    /// @param chain The chain\n    /// @param message The message\n    /// @return The fee\n    function _calculateFee(uint64 chain, Client.EVM2AnyMessage memory message) internal view returns (uint256) {\n        return ROUTER.getFee(chain, message);\n    }\n\n    /// @notice Sends the message to the router and handles fee payment\n    /// @dev External call to msg.sender if fees are paid in native token. This function can lead to a potential reentrancy.\n    /// @param chain The chain\n    /// @param message The message\n    /// @return The message id and fee\n    function _send(uint64 chain, Client.EVM2AnyMessage memory message) internal returns (bytes32, uint256) {\n        uint256 fee = _calculateFee(chain, message);\n        bytes32 messageId;\n        if (message.feeToken != address(0)) {\n            // We trust the feeToken to be not malicious.\n            // ROUTER.getFee() verifies that the feeToken is supported by CCIP and thus vetted.\n            if (IERC20(message.feeToken).balanceOf(msg.sender) < fee) revert InsufficientFeeTokens(message.feeToken, fee);\n            if (IERC20(message.feeToken).allowance(msg.sender, address(this)) < fee) revert InsufficientFeeTokenAllowance(message.feeToken, fee);\n            IERC20(message.feeToken).transferFrom(msg.sender, address(this), fee);\n            IERC20(message.feeToken).approve(address(ROUTER), fee);\n            messageId = ROUTER.ccipSend(chain, message);\n\n            // Send back any leftover fee tokens\n            uint256 leftover = IERC20(message.feeToken).balanceOf(address(this));\n            if (leftover > 0) IERC20(message.feeToken).transfer(msg.sender, leftover);\n        } else {\n            if (msg.value < fee) revert InsufficientFeeTokens(message.feeToken, fee);\n            messageId = ROUTER.ccipSend{value: fee}(chain, message);\n            // return overpaid fee to sender. We don't care about the success of this call.\n            if(msg.value - fee > 0) payable(msg.sender).call{value: msg.value - fee}(\"\");\n        }\n        return (messageId, fee);\n    }\n\n    /// @notice Guesses the fee token based on msg.value\n    /// @return The fee token\n    function _guessFeeToken() internal view returns (address) {\n        return (msg.value > 0) ? address(0) : LINK;\n    }\n}\n"},{"file_path":"contracts/erc20/IERC20.sol","source_code":"/**\n * SPDX-License-Identifier: MIT\n *\n * Copyright (c) 2016-2019 zOS Global Limited\n *\n */\npragma solidity ^0.8.0;\n\n/**\n * @dev Interface of the ERC20 standard as defined in the EIP. Does not include\n * the optional functions; to access them see `ERC20Detailed`.\n */\n\ninterface IERC20 {\n    function name() external view returns (string memory);\n\n    function symbol() external view returns (string memory);\n\n    function decimals() external view returns (uint8);\n\n    /**\n     * @dev Returns the amount of tokens in existence.\n     */\n    function totalSupply() external view returns (uint256);\n\n    /**\n     * @dev Returns the amount of tokens owned by `account`.\n     */\n    function balanceOf(address account) external view returns (uint256);\n\n    /**\n     * @dev Moves `amount` tokens from the caller's account to `recipient`.\n     *\n     * Returns always true. Throws error on failure.\n     *\n     * Emits a `Transfer` event.\n     */\n    function transfer(address recipient, uint256 amount) external returns (bool);\n\n    /**\n     * @dev Returns the remaining number of tokens that `spender` will be\n     * allowed to spend on behalf of `owner` through `transferFrom`. This is\n     * zero by default.\n     *\n     * This value can change when `approve` or `transferFrom` are called.\n     */\n    function allowance(address owner, address spender) external view returns (uint256);\n\n    /**\n     * @dev Sets `amount` as the allowance of `spender` over the caller's tokens.\n     *\n     * Returns a boolean value indicating whether the operation succeeded.\n     *\n     * > Beware that changing an allowance with this method brings the risk\n     * that someone may use both the old and the new allowance by unfortunate\n     * transaction ordering. One possible solution to mitigate this race\n     * condition is to first reduce the spender's allowance to 0 and set the\n     * desired value afterwards:\n     * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\n     *\n     * Emits an `Approval` event.\n     */\n    function approve(address spender, uint256 amount) external returns (bool);\n\n    /**\n     * @dev Moves `amount` tokens from `sender` to `recipient` using the\n     * allowance mechanism. `amount` is then deducted from the caller's\n     * allowance.\n     *\n     * Returns always true. Throws error on failure.\n     *\n     * Emits a `Transfer` event.\n     */\n    function transferFrom(address sender, address recipient, uint256 amount) external returns (bool);\n\n    /**\n     * @dev Emitted when `value` tokens are moved from one account (`from`) to\n     * another (`to`).\n     *\n     * Note that `value` may be zero.\n     */\n    event Transfer(address indexed from, address indexed to, uint256 value);\n\n    /**\n     * @dev Emitted when the allowance of a `spender` for an `owner` is set by\n     * a call to `approve`. `value` is the new allowance.\n     */\n    event Approval(address indexed owner, address indexed spender, uint256 value);\n}\n"}],"certified":false,"conflicting_implementations":null,"abi":[{"inputs":[{"internalType":"address","name":"token","type":"address"},{"internalType":"contract IRouterClient","name":"router","type":"address"},{"internalType":"address","name":"link","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[{"internalType":"address","name":"owner","type":"address"},{"internalType":"address","name":"spender","type":"address"}],"name":"InfiniteAllowanceRequired","type":"error"},{"inputs":[{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"fee","type":"uint256"}],"name":"InsufficientFeeTokenAllowance","type":"error"},{"inputs":[{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"fee","type":"uint256"}],"name":"InsufficientFeeTokens","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"sender","type":"address"},{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":false,"internalType":"uint64","name":"toChain","type":"uint64"},{"indexed":true,"internalType":"bytes","name":"to","type":"bytes"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"},{"indexed":false,"internalType":"string","name":"ref","type":"string"}],"name":"CrossTransfer","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"},{"indexed":false,"internalType":"string","name":"ref","type":"string"}],"name":"Transfer","type":"event"},{"inputs":[],"name":"LINK","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"ROUTER","outputs":[{"internalType":"contract IRouterClient","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint64","name":"targetChain","type":"uint64"},{"internalType":"bytes","name":"recipient","type":"bytes"},{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"bytes","name":"extraArgs","type":"bytes"},{"internalType":"string","name":"ref","type":"string"}],"name":"crossTransfer","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"uint64","name":"targetChain","type":"uint64"},{"internalType":"address","name":"recipient","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"},{"components":[{"internalType":"uint256","name":"gasLimit","type":"uint256"},{"internalType":"bool","name":"allowOutOfOrderExecution","type":"bool"}],"internalType":"struct Client.EVMExtraArgsV2","name":"extraArgs","type":"tuple"},{"internalType":"string","name":"ref","type":"string"}],"name":"crossTransfer","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"uint64","name":"targetChain","type":"uint64"},{"internalType":"address","name":"recipient","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"string","name":"ref","type":"string"}],"name":"crossTransfer","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"uint64","name":"targetChain","type":"uint64"},{"internalType":"address","name":"owner","type":"address"},{"internalType":"address","name":"recipient","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"string","name":"ref","type":"string"}],"name":"crossTransferFrom","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"uint64","name":"targetChain","type":"uint64"},{"internalType":"address","name":"owner","type":"address"},{"internalType":"address","name":"recipient","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"},{"components":[{"internalType":"uint256","name":"gasLimit","type":"uint256"},{"internalType":"bool","name":"allowOutOfOrderExecution","type":"bool"}],"internalType":"struct Client.EVMExtraArgsV2","name":"extraArgs","type":"tuple"},{"internalType":"string","name":"ref","type":"string"}],"name":"crossTransferFrom","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"uint64","name":"targetChain","type":"uint64"},{"internalType":"address","name":"owner","type":"address"},{"internalType":"bytes","name":"recipient","type":"bytes"},{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"bytes","name":"extraArgs","type":"bytes"},{"internalType":"string","name":"ref","type":"string"}],"name":"crossTransferFrom","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"uint64","name":"targetChain","type":"uint64"},{"internalType":"address","name":"target","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"bool","name":"nativeToken","type":"bool"}],"name":"getCCIPFee","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint64","name":"targetChain","type":"uint64"},{"internalType":"bytes","name":"target","type":"bytes"},{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"bool","name":"nativeToken","type":"bool"},{"internalType":"bytes","name":"extraArgs","type":"bytes"}],"name":"getCCIPFee","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint64","name":"targetChain","type":"uint64"},{"internalType":"address","name":"target","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"bool","name":"nativeToken","type":"bool"},{"internalType":"bytes","name":"extraArgs","type":"bytes"}],"name":"getCCIPFee","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"recipient","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"string","name":"ref","type":"string"}],"name":"transfer","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"},{"internalType":"address","name":"recipient","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"string","name":"ref","type":"string"}],"name":"transferFrom","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"zchf","outputs":[{"internalType":"contract IERC20","name":"","type":"address"}],"stateMutability":"view","type":"function"}],"is_changed_bytecode":false,"is_partially_verified":false,"constructor_args":"0x000000000000000000000000b58e61c3098d85632df34eecfb899a1ed80921cb00000000000000000000000080226fc0ee2b096224eeac085bb9a8cba1146f7d000000000000000000000000514910771af9ca656af840dff83e8264ecf986ca"}