More Info
Private Name Tags
ContractCreator
Latest 1 from a total of 1 transactions
Transaction Hash |
Method
|
Block
|
From
|
To
|
|||||
---|---|---|---|---|---|---|---|---|---|
0x60a06040 | 30008428 | 719 days ago | IN | 0 ETH | 0.005653678192 |
Loading...
Loading
Similar Match Source Code This contract matches the deployed Bytecode of the Source Code for Contract 0xF762C3fC...55e44305e The constructor portion of the code might be different and could alter the actual behaviour of the contract
Contract Name:
TransferSwapper
Compiler Version
v0.8.15+commit.e14f2714
Contract Source Code (Solidity Standard Json-Input format)
// SPDX-License-Identifier: GPL-3.0-only pragma solidity >=0.8.15; import "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol"; import "@openzeppelin/contracts/token/ERC20/IERC20.sol"; import "@openzeppelin/contracts/utils/cryptography/ECDSA.sol"; import "@openzeppelin/contracts/security/ReentrancyGuard.sol"; import "./lib/Types.sol"; import "./lib/MessageSenderLib.sol"; import "./lib/MessageReceiverApp.sol"; import "./lib/Pauser.sol"; import "./BridgeRegistry.sol"; import "./FeeOperator.sol"; import "./SigVerifier.sol"; import "./Swapper.sol"; import "./interfaces/IBridgeAdapter.sol"; import "./interfaces/ICodec.sol"; /** * @author Chainhop Dex Team * @author Padoriku * @title An app that enables swapping on a chain, transferring to another chain and swapping * another time on the destination chain before sending the result tokens to a user */ contract TransferSwapper is MessageReceiverApp, Swapper, SigVerifier, FeeOperator, ReentrancyGuard, BridgeRegistry, Pauser { using SafeERC20 for IERC20; using ECDSA for bytes32; bytes32 public immutable CBRIDGE_PROVIDER_HASH; /// @notice erc20 wrap of the gas token of this chain, e.g. WETH address public nativeWrap; constructor( address _messageBus, address _nativeWrap, address _signer, address _feeCollector, string[] memory _funcSigs, address[] memory _codecs, address[] memory _supportedDexList, string[] memory _supportedDexFuncs, bool _testMode ) Swapper(_funcSigs, _codecs, _supportedDexList, _supportedDexFuncs) FeeOperator(_feeCollector) SigVerifier(_signer) { messageBus = _messageBus; nativeWrap = _nativeWrap; testMode = _testMode; CBRIDGE_PROVIDER_HASH = keccak256(bytes("cbridge")); } event NativeWrapUpdated(address nativeWrap); /** * @notice Emitted when requested dstChainId == srcChainId, no bridging * @param id see _computeId() * @param amountIn the input amount approved by the sender * @param tokenIn the input token approved by the sender * @param amountOut the output amount gained after swapping using the input tokens * @param tokenOut the output token gained after swapping using the input tokens */ event DirectSwap(bytes32 id, uint256 amountIn, address tokenIn, uint256 amountOut, address tokenOut); /** * @notice Emitted when operations on src chain is done, the transfer is sent through the bridge * @param id see _computeId() * @param bridgeResp arbitrary response data returned by bridge * @param dstChainId destination chain id * @param srcAmount input amount approved by the sender * @param srcToken the input token approved by the sender * @param dstToken the final output token (after bridging and swapping) desired by the sender * @param bridgeOutReceiver the receiver (user or dst TransferSwapper) of the bridge token * @param bridgeToken the token used for bridging * @param bridgeAmount the amount of the bridgeToken to bridge * @param bridgeProvider the bridge provider */ event RequestSent( bytes32 id, bytes bridgeResp, uint64 dstChainId, uint256 srcAmount, address srcToken, address dstToken, address bridgeOutReceiver, address bridgeToken, uint256 bridgeAmount, string bridgeProvider ); // emitted when operations on dst chain is done. // dstAmount is denominated by dstToken, refundAmount is denominated by bridge out token. // if refundAmount is a non-zero number, it means the "allow partial fill" option is turned on. /** * @notice Emitted when operations on dst chain is done. * @param id see _computeId() * @param dstAmount the final output token (after bridging and swapping) desired by the sender * @param refundAmount the amount refunded to the receiver in bridge token * @dev refundAmount may be fill by either a complete refund or when allowPartialFill is on and * some swaps fails in the swap routes * @param refundToken bridge out token * @param feeCollected the fee chainhop deducts from bridge out token * @param status see RequestStatus */ event RequestDone( bytes32 id, uint256 dstAmount, uint256 refundAmount, address refundToken, uint256 feeCollected, Types.RequestStatus status, bytes forwardResp ); /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * Source chain functions * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ /** * @notice swaps if needed, then transfer the token to another chain along with an instruction on how to swap * on that chain */ function transferWithSwap( Types.TransferDescription calldata _desc, ICodec.SwapDescription[] calldata _srcSwaps, ICodec.SwapDescription[] calldata _dstSwaps ) external payable nonReentrant whenNotPaused { // a request needs to incur a swap, a transfer, or both. otherwise it's a nop and we revert early to save gas require(_srcSwaps.length != 0 || _desc.dstChainId != uint64(block.chainid), "nop"); require(_srcSwaps.length != 0 || (_desc.amountIn != 0 && _desc.tokenIn != address(0)), "nop"); // swapping on the dst chain requires message passing. only integrated with cbridge for now bytes32 bridgeProviderHash = keccak256(bytes(_desc.bridgeProvider)); require( (_dstSwaps.length == 0 && _desc.forward.length == 0) || bridgeProviderHash == CBRIDGE_PROVIDER_HASH, "bridge does not support msg" ); IBridgeAdapter bridge = bridges[bridgeProviderHash]; // if not DirectSwap, the bridge provider should be a valid one require(_desc.dstChainId == uint64(block.chainid) || address(bridge) != address(0), "unsupported bridge"); uint256 amountIn = _desc.amountIn; ICodec[] memory codecs; address srcToken = _desc.tokenIn; address bridgeToken = _desc.tokenIn; if (_srcSwaps.length != 0) { (amountIn, srcToken, bridgeToken, codecs) = sanitizeSwaps(_srcSwaps); } if (_desc.nativeIn) { require(srcToken == nativeWrap, "tkin no nativeWrap"); require(msg.value >= amountIn, "insfcnt amt"); // insufficient amount IWETH(nativeWrap).deposit{value: amountIn}(); } else { IERC20(srcToken).safeTransferFrom(msg.sender, address(this), amountIn); } _swapAndSend(srcToken, bridgeToken, amountIn, _desc, _srcSwaps, _dstSwaps, codecs); } function _swapAndSend( address srcToken, address bridgeToken, uint256 _amountIn, Types.TransferDescription memory _desc, ICodec.SwapDescription[] memory _srcSwaps, ICodec.SwapDescription[] memory _dstSwaps, ICodec[] memory _codecs ) private { // swap if needed uint256 amountOut = _amountIn; if (_srcSwaps.length != 0) { bool ok; (ok, amountOut) = executeSwaps(_srcSwaps, _codecs); require(ok, "swap fail"); } bytes32 id = _computeId(_desc.receiver, _desc.nonce); // direct send if needed if (_desc.dstChainId == uint64(block.chainid)) { emit DirectSwap(id, _amountIn, srcToken, amountOut, bridgeToken); _sendToken(bridgeToken, amountOut, _desc.receiver, _desc.nativeOut); return; } _transfer(id, srcToken, bridgeToken, _desc, _dstSwaps, _amountIn, amountOut); } function _transfer( bytes32 _id, address srcToken, address bridgeToken, Types.TransferDescription memory _desc, ICodec.SwapDescription[] memory _dstSwaps, uint256 _amountIn, uint256 _amountOut ) private { // fund is directly to user if there is no swaps needed on the destination chain address bridgeOutReceiver = (_dstSwaps.length > 0 || _desc.forward.length > 0) ? _desc.dstTransferSwapper : _desc.receiver; bytes memory bridgeResp; { _verifyFee(_desc, _amountIn, srcToken); uint256 msgFee = msg.value; if (_desc.nativeIn) { msgFee = msg.value - _amountIn; } IBridgeAdapter bridge = bridges[keccak256(bytes(_desc.bridgeProvider))]; IERC20(bridgeToken).safeIncreaseAllowance(address(bridge), _amountOut); bytes memory requestMessage = _encodeRequestMessage(_id, _desc, _dstSwaps); bridgeResp = bridge.bridge{value: msgFee}( _desc.dstChainId, bridgeOutReceiver, _amountOut, bridgeToken, _desc.bridgeParams, requestMessage ); } emit RequestSent( _id, bridgeResp, _desc.dstChainId, _amountIn, srcToken, _desc.dstTokenOut, bridgeOutReceiver, bridgeToken, _amountOut, _desc.bridgeProvider ); } /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * Destination chain functions * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ /** * @notice Executes a swap if needed, then sends the output token to the receiver * @dev If allowPartialFill is off, this function reverts as soon as one swap in swap routes fails * @dev This function is called and is only callable by MessageBus. The transaction of such call is triggered by executor. * @dev Bridge contract *always* sends native token to its receiver (this contract) even though the _token field is always an ERC20 token * @param _token the token received by this contract * @param _amount the amount of token received by this contract * @return ok whether the processing is successful */ function executeMessageWithTransfer( address, // _sender address _token, uint256 _amount, uint64, // _srcChainId bytes memory _message, address _executor ) external payable override onlyMessageBus nonReentrant returns (ExecutionStatus) { if (paused()) { return ExecutionStatus.Retry; } Types.Request memory m = abi.decode((_message), (Types.Request)); // handle the case where amount received is not enough to pay fee if (_amount < m.fee) { m.fee = _amount; emit RequestDone(m.id, 0, 0, _token, m.fee, Types.RequestStatus.Succeeded, bytes("")); return ExecutionStatus.Success; } else { _amount = _amount - m.fee; } uint256 sumAmtOut = _amount; uint256 sumAmtFailed; bytes memory forwardResp; { // Note if to wrap, the NATIVE used to convert is from the ones sent by upstream in advance, but not part of the `msg.value` // `msg.value` here is only used to pay for msg fee _wrapBridgeOutToken(_token, _amount); address tokenOut = _token; if (m.swaps.length != 0) { ICodec[] memory codecs; address tokenIn; // swap first before sending the token out to user (, tokenIn, tokenOut, codecs) = sanitizeSwaps(m.swaps); require(tokenIn == _token, "tkin mm"); // tokenIn mismatch (sumAmtOut, sumAmtFailed) = executeSwapsWithOverride(m.swaps, codecs, _amount, m.allowPartialFill); // if at this stage the tx is not reverted, it means at least 1 swap in routes succeeded if (sumAmtFailed > 0) { _sendToken(_token, sumAmtFailed, m.receiver, false); } } if (m.forward.length > 0) { Types.Forward memory f = abi.decode(m.forward, (Types.Forward)); IBridgeAdapter cBridge = bridges[CBRIDGE_PROVIDER_HASH]; require(address(cBridge) != address(0), "cbridge not set"); IERC20(tokenOut).safeIncreaseAllowance(address(cBridge), sumAmtOut); bytes memory requestMessage = _encodeRequestMessage(m.id, m.receiver); forwardResp = cBridge.bridge{value: msg.value}( f.dstChain, m.receiver, sumAmtOut, tokenOut, f.params, requestMessage ); } else { // msg.value is not used in this code branch, pay back to sender if (msg.value > 0) { (bool sent, ) = _executor.call{value: msg.value}(""); require(sent, "send fail"); } _sendToken(tokenOut, sumAmtOut, m.receiver, m.nativeOut); } } // status is always success as long as this function call doesn't revert. partial fill is also considered success emit RequestDone(m.id, sumAmtOut, sumAmtFailed, _token, m.fee, Types.RequestStatus.Succeeded, forwardResp); return ExecutionStatus.Success; } /** * @notice Sends the received token to the receiver * @dev Only called if executeMessageWithTransfer reverts * @dev Bridge contract *always* sends native token to its receiver (this contract) even though the _token field is always an ERC20 token * @param _token the token received by this contract * @param _amount the amount of token received by this contract * @return ok whether the processing is successful */ function executeMessageWithTransferFallback( address, // _sender address _token, uint256 _amount, uint64, // _srcChainId bytes memory _message, address // _executor ) external payable override onlyMessageBus nonReentrant returns (ExecutionStatus) { if (paused()) { return ExecutionStatus.Retry; } Types.Request memory m = abi.decode((_message), (Types.Request)); _wrapBridgeOutToken(_token, _amount); uint256 refundAmount = _amount - m.fee; // no need to check amount >= fee as it's already checked before _sendToken(_token, refundAmount, m.receiver, false); emit RequestDone(m.id, 0, refundAmount, _token, m.fee, Types.RequestStatus.Fallback, bytes("")); return ExecutionStatus.Success; } /** * @notice Used to trigger refund when bridging fails due to large slippage * @dev only MessageBus can call this function, this requires the user to get sigs of the message from SGN * @dev Bridge contract *always* sends native token to its receiver (this contract) even though the _token field is always an ERC20 token * @param _token the token received by this contract * @param _amount the amount of token received by this contract * @return ok whether the processing is successful */ function executeMessageWithTransferRefundFromAdapter( address _token, uint256 _amount, bytes calldata _message, address // _executor ) external payable nonReentrant returns (ExecutionStatus) { if (paused()) { return ExecutionStatus.Retry; } if (_token != nativeWrap) { IERC20(_token).safeTransferFrom(msg.sender, address(this), _amount); } else { require(msg.value >= _amount, "no native transferred in"); } Types.Request memory m = abi.decode((_message), (Types.Request)); _wrapBridgeOutToken(_token, _amount); _sendToken(_token, _amount, m.receiver, false); emit RequestDone(m.id, 0, _amount, _token, m.fee, Types.RequestStatus.Fallback, bytes("")); return ExecutionStatus.Success; } /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * Misc * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ function _computeId(address _receiver, uint64 _nonce) private view returns (bytes32) { return keccak256(abi.encodePacked(msg.sender, _receiver, uint64(block.chainid), _nonce)); } function _encodeRequestMessage( bytes32 _id, Types.TransferDescription memory _desc, ICodec.SwapDescription[] memory _swaps ) internal pure returns (bytes memory message) { message = abi.encode( Types.Request({ id: _id, swaps: _swaps, receiver: _desc.receiver, nativeOut: _desc.nativeOut, fee: _desc.fee, allowPartialFill: _desc.allowPartialFill, forward: _desc.forward }) ); } function _encodeRequestMessage(bytes32 _id, address _receiver) internal pure returns (bytes memory message) { ICodec.SwapDescription[] memory emptySwaps; bytes memory empty; message = abi.encode( Types.Request({ id: _id, swaps: emptySwaps, receiver: _receiver, nativeOut: false, fee: 0, allowPartialFill: false, forward: empty }) ); } function _wrapBridgeOutToken(address _token, uint256 _amount) private { // Wrapping the bridge token before doing anything. There is inefficiency in this function and _sendToken() only if the received the token // is native and the user wants native out. The wrapping then unwrapping process could be skipped. This inefficiency is tolerated for logic tidiness if (_token == nativeWrap) { // If the bridge out token is a native wrap, we need to check whether the actual received token is native token // Note Assumption: only the liquidity bridge is capable of sending a native wrap address bridge = IMessageBus(messageBus).liquidityBridge(); // If bridge's nativeWrap is set, then bridge automatically unwraps the token and send it to this contract // Otherwise the received token in this contract is ERC20 if (IBridgeCeler(bridge).nativeWrap() == nativeWrap) { IWETH(nativeWrap).deposit{value: _amount}(); } } } function _sendToken( address _token, uint256 _amount, address _receiver, bool _nativeOut ) private { if (_nativeOut) { require(_token == nativeWrap, "tk no native"); IWETH(nativeWrap).withdraw(_amount); (bool sent, ) = _receiver.call{value: _amount, gas: 50000}(""); require(sent, "send fail"); } else { IERC20(_token).safeTransfer(_receiver, _amount); } } function _verifyFee( Types.TransferDescription memory _desc, uint256 _amountIn, address _tokenIn ) private view { bytes32 hash = keccak256( abi.encodePacked( "executor fee", uint64(block.chainid), _desc.dstChainId, _amountIn, _tokenIn, _desc.feeDeadline, _desc.fee ) ); bytes32 signHash = hash.toEthSignedMessageHash(); verifySig(signHash, _desc.feeSig); require(_desc.feeDeadline > block.timestamp, "deadline exceeded"); } function setNativeWrap(address _nativeWrap) external onlyOwner { nativeWrap = _nativeWrap; emit NativeWrapUpdated(_nativeWrap); } // This is needed to receive ETH when calling `IWETH.withdraw` receive() external payable {} }
// SPDX-License-Identifier: GPL-3.0-only pragma solidity >=0.8.15; import "./interfaces/IBridgeAdapter.sol"; import "@openzeppelin/contracts/access/Ownable.sol"; /** * @title Manages a list of supported bridges * @author lionelhoho */ abstract contract BridgeRegistry is Ownable { event SupportedBridgesUpdated(string[] _bridgeProviders, address[] _bridgeAdapters); mapping(bytes32 => IBridgeAdapter) public bridges; // to disable a bridge, set the bridge addr of the corresponding provider to address(0) function setSupportedBridges( string[] calldata _bridgeProviders, address[] calldata _bridgeAdapters ) external onlyOwner { require(_bridgeProviders.length == _bridgeAdapters.length, "params size mismatch"); for (uint256 i = 0; i < _bridgeProviders.length; i++) { bridges[keccak256(bytes(_bridgeProviders[i]))] = IBridgeAdapter(_bridgeAdapters[i]); } emit SupportedBridgesUpdated(_bridgeProviders, _bridgeAdapters); } }
// SPDX-License-Identifier: GPL-3.0-only pragma solidity >=0.8.15; interface IBridgeAdapter { function bridge( uint64 _dstChainId, // the address that the fund is transfered to on the destination chain address _receiver, uint256 _amount, address _token, // Bridge transfers quoted and abi encoded by chainhop backend server. // Bridge adapter implementations need to decode this themselves. bytes memory _bridgeParams, // The message to be bridged alongside the transfer. // Note if the bridge adapter doesn't support message passing, the call should revert when // this field is set. bytes memory _requestMessage ) external payable returns (bytes memory bridgeResp); }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.7.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 anymore. Can only be called by the current owner. * * NOTE: Renouncing ownership will leave the contract without an owner, * thereby removing 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 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 // OpenZeppelin Contracts (last updated v4.7.0) (token/ERC20/utils/SafeERC20.sol) pragma solidity ^0.8.0; import "../IERC20.sol"; import "../extensions/draft-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; function safeTransfer( IERC20 token, address to, uint256 value ) internal { _callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value)); } 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)); } function safeIncreaseAllowance( IERC20 token, address spender, uint256 value ) internal { uint256 newAllowance = token.allowance(address(this), spender) + value; _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance)); } 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"); uint256 newAllowance = oldAllowance - value; _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance)); } } 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"); if (returndata.length > 0) { // Return data is optional require(abi.decode(returndata, (bool)), "SafeERC20: ERC20 operation did not succeed"); } } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.6.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.7.3) (utils/cryptography/ECDSA.sol) pragma solidity ^0.8.0; import "../Strings.sol"; /** * @dev Elliptic Curve Digital Signature Algorithm (ECDSA) operations. * * These functions can be used to verify that a message was signed by the holder * of the private keys of a given address. */ library ECDSA { enum RecoverError { NoError, InvalidSignature, InvalidSignatureLength, InvalidSignatureS, InvalidSignatureV } function _throwError(RecoverError error) private pure { if (error == RecoverError.NoError) { return; // no error: do nothing } else if (error == RecoverError.InvalidSignature) { revert("ECDSA: invalid signature"); } else if (error == RecoverError.InvalidSignatureLength) { revert("ECDSA: invalid signature length"); } else if (error == RecoverError.InvalidSignatureS) { revert("ECDSA: invalid signature 's' value"); } else if (error == RecoverError.InvalidSignatureV) { revert("ECDSA: invalid signature 'v' value"); } } /** * @dev Returns the address that signed a hashed message (`hash`) with * `signature` or error string. This address can then be used for verification purposes. * * The `ecrecover` EVM opcode allows for malleable (non-unique) signatures: * this function rejects them by requiring the `s` value to be in the lower * half order, and the `v` value to be either 27 or 28. * * IMPORTANT: `hash` _must_ be the result of a hash operation for the * verification to be secure: it is possible to craft signatures that * recover to arbitrary addresses for non-hashed data. A safe way to ensure * this is by receiving a hash of the original message (which may otherwise * be too long), and then calling {toEthSignedMessageHash} on it. * * Documentation for signature generation: * - with https://web3js.readthedocs.io/en/v1.3.4/web3-eth-accounts.html#sign[Web3.js] * - with https://docs.ethers.io/v5/api/signer/#Signer-signMessage[ethers] * * _Available since v4.3._ */ function tryRecover(bytes32 hash, bytes memory signature) internal pure returns (address, RecoverError) { if (signature.length == 65) { bytes32 r; bytes32 s; uint8 v; // ecrecover takes the signature parameters, and the only way to get them // currently is to use assembly. /// @solidity memory-safe-assembly assembly { r := mload(add(signature, 0x20)) s := mload(add(signature, 0x40)) v := byte(0, mload(add(signature, 0x60))) } return tryRecover(hash, v, r, s); } else { return (address(0), RecoverError.InvalidSignatureLength); } } /** * @dev Returns the address that signed a hashed message (`hash`) with * `signature`. This address can then be used for verification purposes. * * The `ecrecover` EVM opcode allows for malleable (non-unique) signatures: * this function rejects them by requiring the `s` value to be in the lower * half order, and the `v` value to be either 27 or 28. * * IMPORTANT: `hash` _must_ be the result of a hash operation for the * verification to be secure: it is possible to craft signatures that * recover to arbitrary addresses for non-hashed data. A safe way to ensure * this is by receiving a hash of the original message (which may otherwise * be too long), and then calling {toEthSignedMessageHash} on it. */ function recover(bytes32 hash, bytes memory signature) internal pure returns (address) { (address recovered, RecoverError error) = tryRecover(hash, signature); _throwError(error); return recovered; } /** * @dev Overload of {ECDSA-tryRecover} that receives the `r` and `vs` short-signature fields separately. * * See https://eips.ethereum.org/EIPS/eip-2098[EIP-2098 short signatures] * * _Available since v4.3._ */ function tryRecover( bytes32 hash, bytes32 r, bytes32 vs ) internal pure returns (address, RecoverError) { bytes32 s = vs & bytes32(0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff); uint8 v = uint8((uint256(vs) >> 255) + 27); return tryRecover(hash, v, r, s); } /** * @dev Overload of {ECDSA-recover} that receives the `r and `vs` short-signature fields separately. * * _Available since v4.2._ */ function recover( bytes32 hash, bytes32 r, bytes32 vs ) internal pure returns (address) { (address recovered, RecoverError error) = tryRecover(hash, r, vs); _throwError(error); return recovered; } /** * @dev Overload of {ECDSA-tryRecover} that receives the `v`, * `r` and `s` signature fields separately. * * _Available since v4.3._ */ function tryRecover( bytes32 hash, uint8 v, bytes32 r, bytes32 s ) internal pure returns (address, RecoverError) { // EIP-2 still allows signature malleability for ecrecover(). Remove this possibility and make the signature // unique. Appendix F in the Ethereum Yellow paper (https://ethereum.github.io/yellowpaper/paper.pdf), defines // the valid range for s in (301): 0 < s < secp256k1n ÷ 2 + 1, and for v in (302): v ∈ {27, 28}. Most // signatures from current libraries generate a unique signature with an s-value in the lower half order. // // If your library generates malleable signatures, such as s-values in the upper range, calculate a new s-value // with 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141 - s1 and flip v from 27 to 28 or // vice versa. If your library also generates signatures with 0/1 for v instead 27/28, add 27 to v to accept // these malleable signatures as well. if (uint256(s) > 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5D576E7357A4501DDFE92F46681B20A0) { return (address(0), RecoverError.InvalidSignatureS); } if (v != 27 && v != 28) { return (address(0), RecoverError.InvalidSignatureV); } // If the signature is valid (and not malleable), return the signer address address signer = ecrecover(hash, v, r, s); if (signer == address(0)) { return (address(0), RecoverError.InvalidSignature); } return (signer, RecoverError.NoError); } /** * @dev Overload of {ECDSA-recover} that receives the `v`, * `r` and `s` signature fields separately. */ function recover( bytes32 hash, uint8 v, bytes32 r, bytes32 s ) internal pure returns (address) { (address recovered, RecoverError error) = tryRecover(hash, v, r, s); _throwError(error); return recovered; } /** * @dev Returns an Ethereum Signed Message, created from a `hash`. This * produces hash corresponding to the one signed with the * https://eth.wiki/json-rpc/API#eth_sign[`eth_sign`] * JSON-RPC method as part of EIP-191. * * See {recover}. */ function toEthSignedMessageHash(bytes32 hash) internal pure returns (bytes32) { // 32 is the length in bytes of hash, // enforced by the type signature above return keccak256(abi.encodePacked("\x19Ethereum Signed Message:\n32", hash)); } /** * @dev Returns an Ethereum Signed Message, created from `s`. This * produces hash corresponding to the one signed with the * https://eth.wiki/json-rpc/API#eth_sign[`eth_sign`] * JSON-RPC method as part of EIP-191. * * See {recover}. */ function toEthSignedMessageHash(bytes memory s) internal pure returns (bytes32) { return keccak256(abi.encodePacked("\x19Ethereum Signed Message:\n", Strings.toString(s.length), s)); } /** * @dev Returns an Ethereum Signed Typed Data, created from a * `domainSeparator` and a `structHash`. This produces hash corresponding * to the one signed with the * https://eips.ethereum.org/EIPS/eip-712[`eth_signTypedData`] * JSON-RPC method as part of EIP-712. * * See {recover}. */ function toTypedDataHash(bytes32 domainSeparator, bytes32 structHash) internal pure returns (bytes32) { return keccak256(abi.encodePacked("\x19\x01", domainSeparator, structHash)); } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts v4.4.1 (security/ReentrancyGuard.sol) pragma solidity ^0.8.0; /** * @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 ReentrancyGuard { // 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; constructor() { _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() { // On the first call to nonReentrant, _notEntered will be true require(_status != _ENTERED, "ReentrancyGuard: reentrant call"); // Any calls to nonReentrant after this point will fail _status = _ENTERED; _; // By storing the original value once again, a refund is triggered (see // https://eips.ethereum.org/EIPS/eip-2200) _status = _NOT_ENTERED; } }
// SPDX-License-Identifier: GPL-3.0-only pragma solidity 0.8.15; import "./MsgDataTypes.sol"; import "../interfaces/ICodec.sol"; library Types { /** * @notice Denotes the status of a cross-chain transfer/swap request * @dev Partially filled requests are considered 'Succeeded'. There is no 'Failed' state as * it's only possible if everything reverts and there is no successful transaction * @param Null An empty status that should never be reached * @param Succeeded Transfer/swap has succeeded and funds are received by the receiver * @param Fallback Swaps have failed on the dst chain, and bridge tokens are refunded to receiver */ enum RequestStatus { Null, Succeeded, Fallback } struct Request { bytes32 id; // see _computeId() ICodec.SwapDescription[] swaps; // the swaps need to happen on the destination chain address receiver; // see TransferDescription.receiver bool nativeOut; // see TransferDescription.nativeOut uint256 fee; // see TransferDescription.fee bool allowPartialFill; // see TransferDescription.allowPartialFill // sets if another cbridge hop is required on the chain, abi.encode(Forward) bytes forward; } struct Forward { uint64 dstChain; // abi encoded cbridge params bytes params; } struct TransferDescription { address receiver; // The receiving party (the user) of the final output token uint64 dstChainId; // Destination chain id // The address of the TransferSwapper on the destination chain. // Ignored if there is no swaps on the destination chain. address dstTransferSwapper; // A number unique enough to be used in request ID generation. uint64 nonce; // bridge provider identifier string bridgeProvider; // Bridge transfers quoted and abi encoded by chainhop backend server. // Bridge adapter implementations need to decode this themselves. bytes bridgeParams; bool nativeIn; // whether to check msg.value and wrap token before swapping/sending bool nativeOut; // whether to unwrap before sending the final token to user uint256 fee; // this fee is only executor fee. it does not include msg bridge fee uint256 feeDeadline; // the unix timestamp before which the fee is valid // sig of sha3("executor fee", srcChainId, dstChainId, amountIn, tokenIn, feeDeadline, fee) // see _verifyFee() bytes feeSig; // IMPORTANT: amountIn & tokenIn is completely ignored if src chain has a swap uint256 amountIn; address tokenIn; address dstTokenOut; // the final output token, emitted in event for display purpose only // in case of multi route swaps, whether to allow the successful swaps to go through // and sending the amountIn of the failed swaps back to user bool allowPartialFill; // sets if another cbridge hop is required on the dst chain, abi.encode(Forward) bytes forward; } }
// SPDX-License-Identifier: GPL-3.0-only pragma solidity 0.8.15; import "@openzeppelin/contracts/token/ERC20/IERC20.sol"; import "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol"; import "../interfaces/IBridgeCeler.sol"; import "../interfaces/IOriginalTokenVault.sol"; import "../interfaces/IOriginalTokenVaultV2.sol"; import "../interfaces/IPeggedTokenBridge.sol"; import "../interfaces/IPeggedTokenBridgeV2.sol"; import "../interfaces/IMessageBus.sol"; import "./MsgDataTypes.sol"; library MessageSenderLib { using SafeERC20 for IERC20; // ============== Internal library functions called by apps ============== /** * @notice Sends a message to an app on another chain via MessageBus without an associated transfer. * @param _receiver The address of the destination app contract. * @param _dstChainId The destination chain ID. * @param _message Arbitrary message bytes to be decoded by the destination app contract. * @param _messageBus The address of the MessageBus on this chain. * @param _fee The fee amount to pay to MessageBus. */ function sendMessage( address _receiver, uint64 _dstChainId, bytes memory _message, address _messageBus, uint256 _fee ) internal { IMessageBus(_messageBus).sendMessage{value: _fee}(_receiver, _dstChainId, _message); } /** * @notice Sends a message to an app on another chain via MessageBus with an associated transfer. * @param _receiver The address of the destination app contract. * @param _token The address of the token to be sent. * @param _amount The amount of tokens to be sent. * @param _dstChainId The destination chain ID. * @param _nonce A number input to guarantee uniqueness of transferId. Can be timestamp in practice. * @param _maxSlippage The max slippage accepted, given as percentage in point (pip). Eg. 5000 means 0.5%. * Must be greater than minimalMaxSlippage. Receiver is guaranteed to receive at least (100% - max slippage percentage) * amount or the * transfer can be refunded. Only applicable to the {MsgDataTypes.BridgeSendType.Liquidity}. * @param _message Arbitrary message bytes to be decoded by the destination app contract. * @param _bridgeSendType One of the {MsgDataTypes.BridgeSendType} enum. * @param _messageBus The address of the MessageBus on this chain. * @param _fee The fee amount to pay to MessageBus. * @return The transfer ID. */ function sendMessageWithTransfer( address _receiver, address _token, uint256 _amount, uint64 _dstChainId, uint64 _nonce, uint32 _maxSlippage, bytes memory _message, MsgDataTypes.BridgeSendType _bridgeSendType, address _messageBus, uint256 _fee ) internal returns (bytes32) { (bytes32 transferId, address bridge) = sendTokenTransfer( _receiver, _token, _amount, _dstChainId, _nonce, _maxSlippage, _bridgeSendType, _messageBus ); if (_message.length > 0) { IMessageBus(_messageBus).sendMessageWithTransfer{value: _fee}( _receiver, _dstChainId, bridge, transferId, _message ); } return transferId; } /** * @notice Sends a token transfer via a bridge. * @param _receiver The address of the destination app contract. * @param _token The address of the token to be sent. * @param _amount The amount of tokens to be sent. * @param _dstChainId The destination chain ID. * @param _nonce A number input to guarantee uniqueness of transferId. Can be timestamp in practice. * @param _maxSlippage The max slippage accepted, given as percentage in point (pip). Eg. 5000 means 0.5%. * Must be greater than minimalMaxSlippage. Receiver is guaranteed to receive at least (100% - max slippage percentage) * amount or the * transfer can be refunded. * @param _bridgeSendType One of the {MsgDataTypes.BridgeSendType} enum. */ function sendTokenTransfer( address _receiver, address _token, uint256 _amount, uint64 _dstChainId, uint64 _nonce, uint32 _maxSlippage, MsgDataTypes.BridgeSendType _bridgeSendType, address _messageBus ) internal returns (bytes32 transferId, address bridge) { if (_bridgeSendType == MsgDataTypes.BridgeSendType.Liquidity) { bridge = IMessageBus(_messageBus).liquidityBridge(); IERC20(_token).safeIncreaseAllowance(bridge, _amount); IBridgeCeler(bridge).send(_receiver, _token, _amount, _dstChainId, _nonce, _maxSlippage); transferId = computeLiqBridgeTransferId(_receiver, _token, _amount, _dstChainId, _nonce); } else if (_bridgeSendType == MsgDataTypes.BridgeSendType.PegDeposit) { bridge = IMessageBus(_messageBus).pegVault(); IERC20(_token).safeIncreaseAllowance(bridge, _amount); IOriginalTokenVault(bridge).deposit(_token, _amount, _dstChainId, _receiver, _nonce); transferId = computePegV1DepositId(_receiver, _token, _amount, _dstChainId, _nonce); } else if (_bridgeSendType == MsgDataTypes.BridgeSendType.PegBurn) { bridge = IMessageBus(_messageBus).pegBridge(); IERC20(_token).safeIncreaseAllowance(bridge, _amount); IPeggedTokenBridge(bridge).burn(_token, _amount, _receiver, _nonce); // handle cases where certain tokens do not spend allowance for role-based burn IERC20(_token).safeApprove(bridge, 0); transferId = computePegV1BurnId(_receiver, _token, _amount, _nonce); } else if (_bridgeSendType == MsgDataTypes.BridgeSendType.PegV2Deposit) { bridge = IMessageBus(_messageBus).pegVaultV2(); IERC20(_token).safeIncreaseAllowance(bridge, _amount); transferId = IOriginalTokenVaultV2(bridge).deposit(_token, _amount, _dstChainId, _receiver, _nonce); } else if (_bridgeSendType == MsgDataTypes.BridgeSendType.PegV2Burn) { bridge = IMessageBus(_messageBus).pegBridgeV2(); IERC20(_token).safeIncreaseAllowance(bridge, _amount); transferId = IPeggedTokenBridgeV2(bridge).burn(_token, _amount, _dstChainId, _receiver, _nonce); // handle cases where certain tokens do not spend allowance for role-based burn IERC20(_token).safeApprove(bridge, 0); } else if (_bridgeSendType == MsgDataTypes.BridgeSendType.PegV2BurnFrom) { bridge = IMessageBus(_messageBus).pegBridgeV2(); IERC20(_token).safeIncreaseAllowance(bridge, _amount); transferId = IPeggedTokenBridgeV2(bridge).burnFrom(_token, _amount, _dstChainId, _receiver, _nonce); // handle cases where certain tokens do not spend allowance for role-based burn IERC20(_token).safeApprove(bridge, 0); } else { revert("bridge type not supported"); } } function computeLiqBridgeTransferId( address _receiver, address _token, uint256 _amount, uint64 _dstChainId, uint64 _nonce ) internal view returns (bytes32) { return keccak256( abi.encodePacked(address(this), _receiver, _token, _amount, _dstChainId, _nonce, uint64(block.chainid)) ); } function computePegV1DepositId( address _receiver, address _token, uint256 _amount, uint64 _dstChainId, uint64 _nonce ) internal view returns (bytes32) { return keccak256( abi.encodePacked(address(this), _token, _amount, _dstChainId, _receiver, _nonce, uint64(block.chainid)) ); } function computePegV1BurnId( address _receiver, address _token, uint256 _amount, uint64 _nonce ) internal view returns (bytes32) { return keccak256(abi.encodePacked(address(this), _token, _amount, _receiver, _nonce, uint64(block.chainid))); } }
// SPDX-License-Identifier: GPL-3.0-only pragma solidity 0.8.15; import "../interfaces/IMessageReceiverApp.sol"; import "./MessageBusAddress.sol"; abstract contract MessageReceiverApp is IMessageReceiverApp, MessageBusAddress { // testMode is used for the ease of testing functions with the "onlyMessageBus" modifier. // WARNING: when testMode is true, ANYONE can call executeMessageXXX functions // this variable can only be set during contract construction and is always not set on mainnets bool public testMode; modifier onlyMessageBus() { if (!testMode) { require(msg.sender == messageBus, "caller is not message bus"); } _; } /** * @notice Called by MessageBus (MessageBusReceiver) if the process is originated from MessageBus (MessageBusSender)'s * sendMessageWithTransfer it is only called when the tokens are checked to be arrived at this contract's address. * @param _sender The address of the source app contract * @param _token The address of the token that comes out of the bridge * @param _amount The amount of tokens received at this contract through the cross-chain bridge. * the contract that implements this contract can safely assume that the tokens will arrive before this * function is called. * @param _srcChainId The source chain ID where the transfer is originated from * @param _message Arbitrary message bytes originated from and encoded by the source app contract * @param _executor Address who called the MessageBus execution function */ function executeMessageWithTransfer( address _sender, address _token, uint256 _amount, uint64 _srcChainId, bytes calldata _message, address _executor ) external payable virtual override onlyMessageBus returns (ExecutionStatus) {} /** * @notice Only called by MessageBus (MessageBusReceiver) if * 1. executeMessageWithTransfer reverts, or * 2. executeMessageWithTransfer returns ExecutionStatus.Fail * @param _sender The address of the source app contract * @param _token The address of the token that comes out of the bridge * @param _amount The amount of tokens received at this contract through the cross-chain bridge. * the contract that implements this contract can safely assume that the tokens will arrive before this * function is called. * @param _srcChainId The source chain ID where the transfer is originated from * @param _message Arbitrary message bytes originated from and encoded by the source app contract * @param _executor Address who called the MessageBus execution function */ function executeMessageWithTransferFallback( address _sender, address _token, uint256 _amount, uint64 _srcChainId, bytes calldata _message, address _executor ) external payable virtual override onlyMessageBus returns (ExecutionStatus) {} /** * @notice Called by MessageBus (MessageBusReceiver) to process refund of the original transfer from this contract * @param _token The token address of the original transfer * @param _amount The amount of the original transfer * @param _message The same message associated with the original transfer * @param _executor Address who called the MessageBus execution function */ function executeMessageWithTransferRefund( address _token, uint256 _amount, bytes calldata _message, address _executor ) external payable virtual override onlyMessageBus returns (ExecutionStatus) {} /** * @notice Called by MessageBus (MessageBusReceiver) * @param _sender The address of the source app contract * @param _srcChainId The source chain ID where the transfer is originated from * @param _message Arbitrary message bytes originated from and encoded by the source app contract * @param _executor Address who called the MessageBus execution function */ function executeMessage( address _sender, uint64 _srcChainId, bytes calldata _message, address _executor ) external payable virtual override onlyMessageBus returns (ExecutionStatus) {} }
// SPDX-License-Identifier: GPL-3.0-only pragma solidity >=0.8.15; import "@openzeppelin/contracts/security/Pausable.sol"; import "@openzeppelin/contracts/access/Ownable.sol"; abstract contract Pauser is Ownable, Pausable { mapping(address => bool) public pausers; event PauserAdded(address account); event PauserRemoved(address account); constructor() { _addPauser(msg.sender); } modifier onlyPauser() { require(isPauser(msg.sender), "Caller is not pauser"); _; } function pause() public onlyPauser { _pause(); } function unpause() public onlyPauser { _unpause(); } function isPauser(address account) public view returns (bool) { return pausers[account]; } function addPauser(address account) public onlyOwner { _addPauser(account); } function removePauser(address account) public onlyOwner { _removePauser(account); } function renouncePauser() public { _removePauser(msg.sender); } function _addPauser(address account) private { require(!isPauser(account), "Account is already pauser"); pausers[account] = true; emit PauserAdded(account); } function _removePauser(address account) private { require(isPauser(account), "Account is not pauser"); pausers[account] = false; emit PauserRemoved(account); } }
// SPDX-License-Identifier: GPL-3.0-only pragma solidity >=0.8.15; import "@openzeppelin/contracts/token/ERC20/IERC20.sol"; import "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol"; import "@openzeppelin/contracts/access/Ownable.sol"; /** * @title Allows the owner to set fee collector and allows fee collectors to collect fees * @author Padoriku */ abstract contract FeeOperator is Ownable { using SafeERC20 for IERC20; address public feeCollector; event FeeCollectorUpdated(address from, address to); modifier onlyFeeCollector() { require(msg.sender == feeCollector, "not fee collector"); _; } constructor(address _feeCollector) { feeCollector = _feeCollector; } function collectFee(address[] calldata _tokens, address _to) external onlyFeeCollector { for (uint256 i = 0; i < _tokens.length; i++) { // use zero address to denote native token if (_tokens[i] == address(0)) { uint256 bal = address(this).balance; (bool sent, ) = _to.call{value: bal, gas: 50000}(""); require(sent, "send native failed"); } else { uint256 balance = IERC20(_tokens[i]).balanceOf(address(this)); IERC20(_tokens[i]).safeTransfer(_to, balance); } } } function setFeeCollector(address _feeCollector) external onlyOwner { address oldFeeCollector = feeCollector; feeCollector = _feeCollector; emit FeeCollectorUpdated(oldFeeCollector, _feeCollector); } }
// SPDX-License-Identifier: GPL-3.0-only pragma solidity >=0.8.15; import "@openzeppelin/contracts/utils/cryptography/ECDSA.sol"; import "@openzeppelin/contracts/access/Ownable.sol"; /** * @title Allows owner to set signer, and verifies signatures * @author Padoriku */ contract SigVerifier is Ownable { using ECDSA for bytes32; address public signer; event SignerUpdated(address from, address to); constructor(address _signer) { signer = _signer; } function setSigner(address _signer) public onlyOwner { address oldSigner = signer; signer = _signer; emit SignerUpdated(oldSigner, _signer); } function verifySig(bytes32 _hash, bytes memory _feeSig) internal view { address _signer = _hash.recover(_feeSig); require(_signer == signer, "invalid signer"); } }
// SPDX-License-Identifier: GPL-3.0-only pragma solidity >=0.8.15; import "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol"; import "@openzeppelin/contracts/token/ERC20/IERC20.sol"; import "@openzeppelin/contracts/access/Ownable.sol"; import "./CodecRegistry.sol"; import "./interfaces/ICodec.sol"; import "./interfaces/IWETH.sol"; import "./DexRegistry.sol"; /** * @title Loads codecs for the swaps and performs swap actions * @author Padoriku */ contract Swapper is CodecRegistry, DexRegistry { using SafeERC20 for IERC20; constructor( string[] memory _funcSigs, address[] memory _codecs, address[] memory _supportedDexList, string[] memory _supportedDexFuncs ) DexRegistry(_supportedDexList, _supportedDexFuncs) CodecRegistry(_funcSigs, _codecs) {} /** * @dev Checks the input swaps for that tokenIn and tokenOut for every swap should be the same * @param _swaps the swaps the check * @return sumAmtIn the sum of all amountIns in the swaps * @return tokenIn the input token of the swaps * @return tokenOut the desired output token of the swaps * @return codecs a list of codecs which each of them corresponds to a swap */ function sanitizeSwaps(ICodec.SwapDescription[] memory _swaps) internal view returns ( uint256 sumAmtIn, address tokenIn, address tokenOut, ICodec[] memory codecs // _codecs[i] is for _swaps[i] ) { address prevTokenIn; address prevTokenOut; codecs = loadCodecs(_swaps); for (uint256 i = 0; i < _swaps.length; i++) { require(dexRegistry[_swaps[i].dex][bytes4(_swaps[i].data)], "unsupported dex"); (uint256 _amountIn, address _tokenIn, address _tokenOut) = codecs[i].decodeCalldata(_swaps[i]); require(prevTokenIn == address(0) || prevTokenIn == _tokenIn, "tkin mismatch"); prevTokenIn = _tokenIn; require(prevTokenOut == address(0) || prevTokenOut == _tokenOut, "tko mismatch"); prevTokenOut = _tokenOut; sumAmtIn += _amountIn; tokenIn = _tokenIn; tokenOut = _tokenOut; } } /** * @notice Executes the swaps, decode their return values and sums the returned amount * @dev This function is intended to be used on src chain only * @dev This function immediately fails (return false) if any swaps fail. There is no "partial fill" on src chain * @param _swaps swaps. this function assumes that the swaps are already sanitized * @param _codecs the codecs for each swap * @return ok whether the operation is successful * @return sumAmtOut the sum of all amounts gained from swapping */ function executeSwaps( ICodec.SwapDescription[] memory _swaps, ICodec[] memory _codecs // _codecs[i] is for _swaps[i] ) internal returns (bool ok, uint256 sumAmtOut) { for (uint256 i = 0; i < _swaps.length; i++) { (uint256 amountIn, address tokenIn, address tokenOut) = _codecs[i].decodeCalldata(_swaps[i]); bytes memory data = _codecs[i].encodeCalldataWithOverride(_swaps[i].data, amountIn, address(this)); IERC20(tokenIn).safeIncreaseAllowance(_swaps[i].dex, amountIn); uint256 balBefore = IERC20(tokenOut).balanceOf(address(this)); (ok, ) = _swaps[i].dex.call(data); if (!ok) { return (false, 0); } uint256 balAfter = IERC20(tokenOut).balanceOf(address(this)); sumAmtOut += balAfter - balBefore; } } /** * @notice Executes the swaps with override, redistributes amountIns for each swap route, * decode their return values and sums the returned amount * @dev This function is intended to be used on dst chain only * @param _swaps swaps to execute. this function assumes that the swaps are already sanitized * @param _codecs the codecs for each swap * @param _amountInOverride the amountIn to substitute the amountIns in swaps for * @dev _amountInOverride serves the purpose of correcting the estimated amountIns to actual bridge outs * @dev _amountInOverride is also distributed according to the weight of each original amountIn * @return sumAmtOut the sum of all amounts gained from swapping * @return sumAmtFailed the sum of all amounts that fails to swap */ function executeSwapsWithOverride( ICodec.SwapDescription[] memory _swaps, ICodec[] memory _codecs, // _codecs[i] is for _swaps[i] uint256 _amountInOverride, bool _allowPartialFill ) internal returns (uint256 sumAmtOut, uint256 sumAmtFailed) { (uint256[] memory amountIns, address tokenIn, address tokenOut) = _redistributeAmountIn( _swaps, _amountInOverride, _codecs ); uint256 balBefore = IERC20(tokenOut).balanceOf(address(this)); // execute the swaps with adjusted amountIns for (uint256 i = 0; i < _swaps.length; i++) { bytes memory swapCalldata = _codecs[i].encodeCalldataWithOverride( _swaps[i].data, amountIns[i], address(this) ); IERC20(tokenIn).safeIncreaseAllowance(_swaps[i].dex, amountIns[i]); (bool ok, ) = _swaps[i].dex.call(swapCalldata); require(ok || _allowPartialFill, "swap failed"); if (!ok) { sumAmtFailed += amountIns[i]; } } uint256 balAfter = IERC20(tokenOut).balanceOf(address(this)); sumAmtOut = balAfter - balBefore; require(sumAmtOut > 0, "all swaps failed"); } /// @notice distributes the _amountInOverride to the swaps base on how much each original amountIns weight function _redistributeAmountIn( ICodec.SwapDescription[] memory _swaps, uint256 _amountInOverride, ICodec[] memory _codecs ) private view returns ( uint256[] memory amountIns, address tokenIn, address tokenOut ) { uint256 sumAmtIn; amountIns = new uint256[](_swaps.length); // compute sumAmtIn and collect amountIns for (uint256 i = 0; i < _swaps.length; i++) { uint256 amountIn; (amountIn, tokenIn, tokenOut) = _codecs[i].decodeCalldata(_swaps[i]); sumAmtIn += amountIn; amountIns[i] = amountIn; } // compute adjusted amountIns with regard to the weight of each amountIns in total amountIn for (uint256 i = 0; i < amountIns.length; i++) { amountIns[i] = (_amountInOverride * amountIns[i]) / sumAmtIn; } } }
// SPDX-License-Identifier: GPL-3.0-only pragma solidity >=0.8.0; interface ICodec { struct SwapDescription { address dex; // the DEX to use for the swap, zero address implies no swap needed bytes data; // the data to call the dex with } function decodeCalldata(SwapDescription calldata swap) external view returns ( uint256 amountIn, address tokenIn, address tokenOut ); function encodeCalldataWithOverride( bytes calldata data, uint256 amountInOverride, address receiverOverride ) external pure returns (bytes memory swapCalldata); }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts v4.4.1 (token/ERC20/extensions/draft-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.7.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 * ==== * * [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://diligence.consensys.net/posts/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.5.11/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 functionCall(target, data, "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"); require(isContract(target), "Address: call to non-contract"); (bool success, bytes memory returndata) = target.call{value: value}(data); return verifyCallResult(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) { require(isContract(target), "Address: static call to non-contract"); (bool success, bytes memory returndata) = target.staticcall(data); return verifyCallResult(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) { require(isContract(target), "Address: delegate call to non-contract"); (bool success, bytes memory returndata) = target.delegatecall(data); return verifyCallResult(success, returndata, errorMessage); } /** * @dev Tool to verifies that a low level call was successful, and revert if it wasn't, either by bubbling the * revert reason 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 { // 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 (last updated v4.7.0) (utils/Strings.sol) pragma solidity ^0.8.0; /** * @dev String operations. */ library Strings { bytes16 private constant _HEX_SYMBOLS = "0123456789abcdef"; uint8 private constant _ADDRESS_LENGTH = 20; /** * @dev Converts a `uint256` to its ASCII `string` decimal representation. */ function toString(uint256 value) internal pure returns (string memory) { // Inspired by OraclizeAPI's implementation - MIT licence // https://github.com/oraclize/ethereum-api/blob/b42146b063c7d6ee1358846c198246239e9360e8/oraclizeAPI_0.4.25.sol if (value == 0) { return "0"; } uint256 temp = value; uint256 digits; while (temp != 0) { digits++; temp /= 10; } bytes memory buffer = new bytes(digits); while (value != 0) { digits -= 1; buffer[digits] = bytes1(uint8(48 + uint256(value % 10))); value /= 10; } return string(buffer); } /** * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation. */ function toHexString(uint256 value) internal pure returns (string memory) { if (value == 0) { return "0x00"; } uint256 temp = value; uint256 length = 0; while (temp != 0) { length++; temp >>= 8; } return toHexString(value, length); } /** * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation with fixed length. */ function toHexString(uint256 value, uint256 length) internal pure returns (string memory) { bytes memory buffer = new bytes(2 * length + 2); buffer[0] = "0"; buffer[1] = "x"; for (uint256 i = 2 * length + 1; i > 1; --i) { buffer[i] = _HEX_SYMBOLS[value & 0xf]; value >>= 4; } require(value == 0, "Strings: hex length insufficient"); return string(buffer); } /** * @dev Converts an `address` with fixed length of 20 bytes to its not checksummed ASCII `string` hexadecimal representation. */ function toHexString(address addr) internal pure returns (string memory) { return toHexString(uint256(uint160(addr)), _ADDRESS_LENGTH); } }
// SPDX-License-Identifier: GPL-3.0-only pragma solidity 0.8.15; library MsgDataTypes { // bridge operation type at the sender side (src chain) enum BridgeSendType { Null, Liquidity, PegDeposit, PegBurn, PegV2Deposit, PegV2Burn, PegV2BurnFrom } // bridge operation type at the receiver side (dst chain) enum TransferType { Null, LqRelay, // relay through liquidity bridge LqWithdraw, // withdraw from liquidity bridge PegMint, // mint through pegged token bridge PegWithdraw, // withdraw from original token vault PegV2Mint, // mint through pegged token bridge v2 PegV2Withdraw // withdraw from original token vault v2 } enum MsgType { MessageWithTransfer, MessageOnly } enum TxStatus { Null, Success, Fail, Fallback, Pending // transient state within a transaction } struct TransferInfo { TransferType t; address sender; address receiver; address token; uint256 amount; uint64 wdseq; // only needed for LqWithdraw (refund) uint64 srcChainId; bytes32 refId; bytes32 srcTxHash; // src chain msg tx hash } struct RouteInfo { address sender; address receiver; uint64 srcChainId; bytes32 srcTxHash; // src chain msg tx hash } struct MsgWithTransferExecutionParams { bytes message; TransferInfo transfer; bytes[] sigs; address[] signers; uint256[] powers; } struct BridgeTransferParams { bytes request; bytes[] sigs; address[] signers; uint256[] powers; } }
// SPDX-License-Identifier: GPL-3.0-only pragma solidity >=0.8.15; interface IBridgeCeler { // common function delayThresholds(address token) external view returns (uint256); function delayPeriod() external view returns (uint256); function epochVolumes(address token) external view returns (uint256); function epochVolumeCaps(address token) external view returns (uint256); // liquidity bridge function minSend(address token) external view returns (uint256); function maxSend(address token) external view returns (uint256); // peg vault v0/v2 function minDeposit(address token) external view returns (uint256); function maxDeposit(address token) external view returns (uint256); // peg bridge v0/v2 function minBurn(address token) external view returns (uint256); function maxBurn(address token) external view returns (uint256); function nativeWrap() external view returns (address); function send( address _receiver, address _token, uint256 _amount, uint64 _dstChainId, uint64 _nonce, uint32 _maxSlippage ) external; function relay( bytes calldata _relayRequest, bytes[] calldata _sigs, address[] calldata _signers, uint256[] calldata _powers ) external; function transfers(bytes32 transferId) external view returns (bool); function withdraws(bytes32 withdrawId) external view returns (bool); function withdraw( bytes calldata _wdmsg, bytes[] calldata _sigs, address[] calldata _signers, uint256[] calldata _powers ) external; /** * @notice Verifies that a message is signed by a quorum among the signers. * @param _msg signed message * @param _sigs list of signatures sorted by signer addresses in ascending order * @param _signers sorted list of current signers * @param _powers powers of current signers */ function verifySigs( bytes memory _msg, bytes[] calldata _sigs, address[] calldata _signers, uint256[] calldata _powers ) external view; }
// SPDX-License-Identifier: GPL-3.0-only pragma solidity >=0.8.0; interface IOriginalTokenVault { /** * @notice Lock original tokens to trigger mint at a remote chain's PeggedTokenBridge * @param _token local token address * @param _amount locked token amount * @param _mintChainId destination chainId to mint tokens * @param _mintAccount destination account to receive minted tokens * @param _nonce user input to guarantee unique depositId */ function deposit( address _token, uint256 _amount, uint64 _mintChainId, address _mintAccount, uint64 _nonce ) external; function records(bytes32 recordId) external view returns (bool); }
// SPDX-License-Identifier: GPL-3.0-only pragma solidity >=0.8.0; interface IOriginalTokenVaultV2 { /** * @notice Lock original tokens to trigger mint at a remote chain's PeggedTokenBridge * @param _token local token address * @param _amount locked token amount * @param _mintChainId destination chainId to mint tokens * @param _mintAccount destination account to receive minted tokens * @param _nonce user input to guarantee unique depositId */ function deposit( address _token, uint256 _amount, uint64 _mintChainId, address _mintAccount, uint64 _nonce ) external returns (bytes32); function records(bytes32 recordId) external view returns (bool); }
// SPDX-License-Identifier: GPL-3.0-only pragma solidity >=0.8.0; interface IPeggedTokenBridge { /** * @notice Burn tokens to trigger withdrawal at a remote chain's OriginalTokenVault * @param _token local token address * @param _amount locked token amount * @param _withdrawAccount account who withdraw original tokens on the remote chain * @param _nonce user input to guarantee unique depositId */ function burn( address _token, uint256 _amount, address _withdrawAccount, uint64 _nonce ) external; function records(bytes32 recordId) external view returns (bool); }
// SPDX-License-Identifier: GPL-3.0-only pragma solidity >=0.8.0; interface IPeggedTokenBridgeV2 { /** * @notice Burn pegged tokens to trigger a cross-chain withdrawal of the original tokens at a remote chain's * OriginalTokenVault, or mint at another remote chain * @param _token The pegged token address. * @param _amount The amount to burn. * @param _toChainId If zero, withdraw from original vault; otherwise, the remote chain to mint tokens. * @param _toAccount The account to receive tokens on the remote chain * @param _nonce A number to guarantee unique depositId. Can be timestamp in practice. */ function burn( address _token, uint256 _amount, uint64 _toChainId, address _toAccount, uint64 _nonce ) external returns (bytes32); // same with `burn` above, use openzeppelin ERC20Burnable interface function burnFrom( address _token, uint256 _amount, uint64 _toChainId, address _toAccount, uint64 _nonce ) external returns (bytes32); /** * @notice Mint tokens triggered by deposit at a remote chain's OriginalTokenVault. * @param _request The serialized Mint protobuf. * @param _sigs The list of signatures sorted by signing addresses in ascending order. A relay must be signed-off by * +2/3 of the sigsVerifier's current signing power to be delivered. * @param _signers The sorted list of signers. * @param _powers The signing powers of the signers. */ function mint( bytes calldata _request, bytes[] calldata _sigs, address[] calldata _signers, uint256[] calldata _powers ) external returns (bytes32); function records(bytes32 recordId) external view returns (bool); }
// SPDX-License-Identifier: GPL-3.0-only pragma solidity >=0.8.0; import "../lib/MsgDataTypes.sol"; interface IMessageBus { function liquidityBridge() external view returns (address); function pegBridge() external view returns (address); function pegBridgeV2() external view returns (address); function pegVault() external view returns (address); function pegVaultV2() external view returns (address); function feeBase() external view returns (uint256); function feePerByte() external view returns (uint256); /** * @notice Calculates the required fee for the message. * @param _message Arbitrary message bytes to be decoded by the destination app contract. @ @return The required fee. */ function calcFee(bytes calldata _message) external view returns (uint256); /** * @notice Sends a message to an app on another chain via MessageBus without an associated transfer. * A fee is charged in the native gas token. * @param _receiver The address of the destination app contract. * @param _dstChainId The destination chain ID. * @param _message Arbitrary message bytes to be decoded by the destination app contract. */ function sendMessage( address _receiver, uint256 _dstChainId, bytes calldata _message ) external payable; /** * @notice Sends a message associated with a transfer to an app on another chain via MessageBus without an associated transfer. * A fee is charged in the native token. * @param _receiver The address of the destination app contract. * @param _dstChainId The destination chain ID. * @param _srcBridge The bridge contract to send the transfer with. * @param _srcTransferId The transfer ID. * @param _dstChainId The destination chain ID. * @param _message Arbitrary message bytes to be decoded by the destination app contract. */ function sendMessageWithTransfer( address _receiver, uint256 _dstChainId, address _srcBridge, bytes32 _srcTransferId, bytes calldata _message ) external payable; /** * @notice Withdraws message fee in the form of native gas token. * @param _account The address receiving the fee. * @param _cumulativeFee The cumulative fee credited to the account. Tracked by SGN. * @param _sigs The list of signatures sorted by signing addresses in ascending order. A withdrawal must be * signed-off by +2/3 of the sigsVerifier's current signing power to be delivered. * @param _signers The sorted list of signers. * @param _powers The signing powers of the signers. */ function withdrawFee( address _account, uint256 _cumulativeFee, bytes[] calldata _sigs, address[] calldata _signers, uint256[] calldata _powers ) external; /** * @notice Execute a message with a successful transfer. * @param _message Arbitrary message bytes originated from and encoded by the source app contract * @param _transfer The transfer info. * @param _sigs The list of signatures sorted by signing addresses in ascending order. A relay must be signed-off by * +2/3 of the sigsVerifier's current signing power to be delivered. * @param _signers The sorted list of signers. * @param _powers The signing powers of the signers. */ function executeMessageWithTransfer( bytes calldata _message, MsgDataTypes.TransferInfo calldata _transfer, bytes[] calldata _sigs, address[] calldata _signers, uint256[] calldata _powers ) external payable; /** * @notice Execute a message with a refunded transfer. * @param _message Arbitrary message bytes originated from and encoded by the source app contract * @param _transfer The transfer info. * @param _sigs The list of signatures sorted by signing addresses in ascending order. A relay must be signed-off by * +2/3 of the sigsVerifier's current signing power to be delivered. * @param _signers The sorted list of signers. * @param _powers The signing powers of the signers. */ function executeMessageWithTransferRefund( bytes calldata _message, // the same message associated with the original transfer MsgDataTypes.TransferInfo calldata _transfer, bytes[] calldata _sigs, address[] calldata _signers, uint256[] calldata _powers ) external payable; /** * @notice Execute a message not associated with a transfer. * @param _message Arbitrary message bytes originated from and encoded by the source app contract * @param _sigs The list of signatures sorted by signing addresses in ascending order. A relay must be signed-off by * +2/3 of the sigsVerifier's current signing power to be delivered. * @param _signers The sorted list of signers. * @param _powers The signing powers of the signers. */ function executeMessage( bytes calldata _message, MsgDataTypes.RouteInfo calldata _route, bytes[] calldata _sigs, address[] calldata _signers, uint256[] calldata _powers ) external payable; }
// SPDX-License-Identifier: GPL-3.0-only pragma solidity >=0.8.0; interface IMessageReceiverApp { enum ExecutionStatus { Fail, // execution failed, finalized Success, // execution succeeded, finalized Retry // execution rejected, can retry later } /** * @notice Called by MessageBus (MessageBusReceiver) if the process is originated from MessageBus (MessageBusSender)'s * sendMessageWithTransfer it is only called when the tokens are checked to be arrived at this contract's address. * @param _sender The address of the source app contract * @param _token The address of the token that comes out of the bridge * @param _amount The amount of tokens received at this contract through the cross-chain bridge. * the contract that implements this contract can safely assume that the tokens will arrive before this * function is called. * @param _srcChainId The source chain ID where the transfer is originated from * @param _message Arbitrary message bytes originated from and encoded by the source app contract * @param _executor Address who called the MessageBus execution function */ function executeMessageWithTransfer( address _sender, address _token, uint256 _amount, uint64 _srcChainId, bytes calldata _message, address _executor ) external payable returns (ExecutionStatus); /** * @notice Only called by MessageBus (MessageBusReceiver) if * 1. executeMessageWithTransfer reverts, or * 2. executeMessageWithTransfer returns ExecutionStatus.Fail * @param _sender The address of the source app contract * @param _token The address of the token that comes out of the bridge * @param _amount The amount of tokens received at this contract through the cross-chain bridge. * the contract that implements this contract can safely assume that the tokens will arrive before this * function is called. * @param _srcChainId The source chain ID where the transfer is originated from * @param _message Arbitrary message bytes originated from and encoded by the source app contract * @param _executor Address who called the MessageBus execution function */ function executeMessageWithTransferFallback( address _sender, address _token, uint256 _amount, uint64 _srcChainId, bytes calldata _message, address _executor ) external payable returns (ExecutionStatus); /** * @notice Called by MessageBus (MessageBusReceiver) to process refund of the original transfer from this contract * @param _token The token address of the original transfer * @param _amount The amount of the original transfer * @param _message The same message associated with the original transfer * @param _executor Address who called the MessageBus execution function */ function executeMessageWithTransferRefund( address _token, uint256 _amount, bytes calldata _message, address _executor ) external payable returns (ExecutionStatus); /** * @notice Called by MessageBus (MessageBusReceiver) * @param _sender The address of the source app contract * @param _srcChainId The source chain ID where the transfer is originated from * @param _message Arbitrary message bytes originated from and encoded by the source app contract * @param _executor Address who called the MessageBus execution function */ function executeMessage( address _sender, uint64 _srcChainId, bytes calldata _message, address _executor ) external payable returns (ExecutionStatus); }
// SPDX-License-Identifier: GPL-3.0-only pragma solidity 0.8.15; import "@openzeppelin/contracts/access/Ownable.sol"; abstract contract MessageBusAddress is Ownable { event MessageBusUpdated(address messageBus); address public messageBus; function setMessageBus(address _messageBus) public onlyOwner { messageBus = _messageBus; emit MessageBusUpdated(messageBus); } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.7.0) (security/Pausable.sol) pragma solidity ^0.8.0; import "../utils/Context.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 Pausable is Context { /** * @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. */ constructor() { _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()); } }
// SPDX-License-Identifier: GPL-3.0-only pragma solidity >=0.8.15; import "@openzeppelin/contracts/access/Ownable.sol"; import "./interfaces/ICodec.sol"; /** * @title A codec registry that maps swap function selectors to corresponding codec addresses * @author Padoriku */ abstract contract CodecRegistry is Ownable { mapping(bytes4 => ICodec) public selector2codec; // not used programmatically, but added for contract transparency address[] public codecs; event CodecUpdated(bytes4 selector, address codec); constructor(string[] memory _funcSigs, address[] memory _codecs) { require(_funcSigs.length == _codecs.length, "len mm"); for (uint256 i = 0; i < _funcSigs.length; i++) { bytes4 selector = bytes4(keccak256(bytes(_funcSigs[i]))); _setCodec(selector, _codecs[i]); } } function setCodec(string calldata _funcSig, address _codec) public onlyOwner { bytes4 selector = bytes4(keccak256(bytes(_funcSig))); _setCodec(selector, _codec); emit CodecUpdated(selector, _codec); } function _setCodec(bytes4 _selector, address _codec) private { selector2codec[_selector] = ICodec(_codec); codecs.push(_codec); } function loadCodecs(ICodec.SwapDescription[] memory _swaps) internal view returns (ICodec[] memory) { ICodec[] memory _codecs = new ICodec[](_swaps.length); for (uint256 i = 0; i < _swaps.length; i++) { bytes4 selector = bytes4(_swaps[i].data); _codecs[i] = selector2codec[selector]; require(address(_codecs[i]) != address(0), "cdc no found"); } return (_codecs); } function getCodec( bytes4[] memory _selectors, ICodec[] memory _codecs, bytes4 _selector ) internal pure returns (ICodec) { for (uint256 i = 0; i < _codecs.length; i++) { if (_selector == _selectors[i]) { return _codecs[i]; } } revert("cdc no found"); } }
// SPDX-License-Identifier: GPL-3.0-only pragma solidity >=0.8.15; import "@openzeppelin/contracts/token/ERC20/IERC20.sol"; interface IWETH is IERC20 { function deposit() external payable; function withdraw(uint256) external; }
// SPDX-License-Identifier: GPL-3.0-only pragma solidity >=0.8.15; import "@openzeppelin/contracts/access/Ownable.sol"; /** * @title Manages a list supported dex * @author Padoriku */ abstract contract DexRegistry is Ownable { event SupportedDexUpdated(address dex, bytes4 selector, bool enabled); // supported swap functions // 0x3df02124 exchange(int128,int128,uint256,uint256) // 0xa6417ed6 exchange_underlying(int128,int128,uint256,uint256) // 0x44ee1986 exchange_underlying(int128,int128,uint256,uint256,address) // 0x38ed1739 swapExactTokensForTokens(uint256,uint256,address[],address,uint256) // 0xc04b8d59 exactInput((bytes,address,uint256,uint256,uint256)) // 0xb0431182 clipperSwap(address,address,uint256,uint256) // 0xe449022e uniswapV3Swap(uint256,uint256,uint256[]) // 0x2e95b6c8 unoswap(address,uint256,uint256,bytes32[]) // 0x7c025200 swap(address,(address,address,address,address,uint256,uint256,uint256,bytes),bytes) // 0xd0a3b665 fillOrderRFQ((uint256,address,address,address,address,uint256,uint256),bytes,uint256,uint256) mapping(address => mapping(bytes4 => bool)) public dexRegistry; constructor(address[] memory _supportedDexList, string[] memory _supportedFuncs) { for (uint256 i = 0; i < _supportedDexList.length; i++) { bytes4 selector = bytes4(keccak256(bytes(_supportedFuncs[i]))); _setSupportedDex(_supportedDexList[i], selector, true); } } function setSupportedDex( address _dex, bytes4 _selector, bool _enabled ) external onlyOwner { _setSupportedDex(_dex, _selector, _enabled); emit SupportedDexUpdated(_dex, _selector, _enabled); } function _setSupportedDex( address _dex, bytes4 _selector, bool _enabled ) private { bool enabled = dexRegistry[_dex][_selector]; require(enabled != _enabled, "nop"); dexRegistry[_dex][_selector] = _enabled; } }
// SPDX-License-Identifier: GPL-3.0-only pragma solidity >=0.8.15; import "@openzeppelin/contracts/token/ERC20/ERC20.sol"; import "@openzeppelin/contracts/token/ERC20/IERC20.sol"; import "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol"; import "@openzeppelin/contracts/access/Ownable.sol"; /** * @title Intermediary token that automatically transfers the canonical token when interacting with approved bridges. */ contract IntermediaryOriginalToken is ERC20, Ownable { using SafeERC20 for IERC20; mapping(address => bool) public bridges; address public immutable canonical; // canonical token event BridgeUpdated(address bridge, bool enable); constructor( string memory name_, string memory symbol_, address[] memory bridges_, address canonical_ ) ERC20(name_, symbol_) { for (uint256 i = 0; i < bridges_.length; i++) { bridges[bridges_[i]] = true; } canonical = canonical_; } function transfer(address _to, uint256 _amount) public virtual override returns (bool) { bool success = super.transfer(_to, _amount); if (bridges[msg.sender]) { _burn(_to, _amount); IERC20(canonical).safeTransfer(_to, _amount); } return success; } function transferFrom( address _from, address _to, uint256 _amount ) public virtual override returns (bool) { if (bridges[msg.sender]) { _mint(_from, _amount); IERC20(canonical).safeTransferFrom(_from, address(this), _amount); } return super.transferFrom(_from, _to, _amount); } function updateBridge(address _bridge, bool _enable) external onlyOwner { bridges[_bridge] = _enable; emit BridgeUpdated(_bridge, _enable); } // to make compatible with BEP20 function getOwner() external view returns (address) { return owner(); } function decimals() public view virtual override returns (uint8) { return ERC20(canonical).decimals(); } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.7.0) (token/ERC20/ERC20.sol) pragma solidity ^0.8.0; import "./IERC20.sol"; import "./extensions/IERC20Metadata.sol"; import "../../utils/Context.sol"; /** * @dev Implementation of the {IERC20} interface. * * This implementation is agnostic to the way tokens are created. This means * that a supply mechanism has to be added in a derived contract using {_mint}. * For a generic mechanism see {ERC20PresetMinterPauser}. * * TIP: For a detailed writeup see our guide * https://forum.zeppelin.solutions/t/how-to-implement-erc20-supply-mechanisms/226[How * to implement supply mechanisms]. * * We have followed general OpenZeppelin Contracts guidelines: functions revert * instead returning `false` on failure. This behavior is nonetheless * conventional and does not conflict with the expectations of ERC20 * applications. * * Additionally, an {Approval} event is emitted on calls to {transferFrom}. * This allows applications to reconstruct the allowance for all accounts just * by listening to said events. Other implementations of the EIP may not emit * these events, as it isn't required by the specification. * * Finally, the non-standard {decreaseAllowance} and {increaseAllowance} * functions have been added to mitigate the well-known issues around setting * allowances. See {IERC20-approve}. */ contract ERC20 is Context, IERC20, IERC20Metadata { mapping(address => uint256) private _balances; mapping(address => mapping(address => uint256)) private _allowances; uint256 private _totalSupply; string private _name; string private _symbol; /** * @dev Sets the values for {name} and {symbol}. * * The default value of {decimals} is 18. To select a different value for * {decimals} you should overload it. * * All two of these values are immutable: they can only be set once during * construction. */ constructor(string memory name_, string memory symbol_) { _name = name_; _symbol = symbol_; } /** * @dev Returns the name of the token. */ function name() public view virtual override returns (string memory) { return _name; } /** * @dev Returns the symbol of the token, usually a shorter version of the * name. */ function symbol() public view virtual override returns (string memory) { return _symbol; } /** * @dev Returns the number of decimals used to get its user representation. * For example, if `decimals` equals `2`, a balance of `505` tokens should * be displayed to a user as `5.05` (`505 / 10 ** 2`). * * Tokens usually opt for a value of 18, imitating the relationship between * Ether and Wei. This is the value {ERC20} uses, unless this function is * overridden; * * NOTE: This information is only used for _display_ purposes: it in * no way affects any of the arithmetic of the contract, including * {IERC20-balanceOf} and {IERC20-transfer}. */ function decimals() public view virtual override returns (uint8) { return 18; } /** * @dev See {IERC20-totalSupply}. */ function totalSupply() public view virtual override returns (uint256) { return _totalSupply; } /** * @dev See {IERC20-balanceOf}. */ function balanceOf(address account) public view virtual override returns (uint256) { return _balances[account]; } /** * @dev See {IERC20-transfer}. * * Requirements: * * - `to` cannot be the zero address. * - the caller must have a balance of at least `amount`. */ function transfer(address to, uint256 amount) public virtual override returns (bool) { address owner = _msgSender(); _transfer(owner, to, amount); return true; } /** * @dev See {IERC20-allowance}. */ function allowance(address owner, address spender) public view virtual override returns (uint256) { return _allowances[owner][spender]; } /** * @dev See {IERC20-approve}. * * NOTE: If `amount` is the maximum `uint256`, the allowance is not updated on * `transferFrom`. This is semantically equivalent to an infinite approval. * * Requirements: * * - `spender` cannot be the zero address. */ function approve(address spender, uint256 amount) public virtual override returns (bool) { address owner = _msgSender(); _approve(owner, spender, amount); return true; } /** * @dev See {IERC20-transferFrom}. * * Emits an {Approval} event indicating the updated allowance. This is not * required by the EIP. See the note at the beginning of {ERC20}. * * NOTE: Does not update the allowance if the current allowance * is the maximum `uint256`. * * Requirements: * * - `from` and `to` cannot be the zero address. * - `from` must have a balance of at least `amount`. * - the caller must have allowance for ``from``'s tokens of at least * `amount`. */ function transferFrom( address from, address to, uint256 amount ) public virtual override returns (bool) { address spender = _msgSender(); _spendAllowance(from, spender, amount); _transfer(from, to, amount); return true; } /** * @dev Atomically increases the allowance granted to `spender` by the caller. * * This is an alternative to {approve} that can be used as a mitigation for * problems described in {IERC20-approve}. * * Emits an {Approval} event indicating the updated allowance. * * Requirements: * * - `spender` cannot be the zero address. */ function increaseAllowance(address spender, uint256 addedValue) public virtual returns (bool) { address owner = _msgSender(); _approve(owner, spender, allowance(owner, spender) + addedValue); return true; } /** * @dev Atomically decreases the allowance granted to `spender` by the caller. * * This is an alternative to {approve} that can be used as a mitigation for * problems described in {IERC20-approve}. * * Emits an {Approval} event indicating the updated allowance. * * Requirements: * * - `spender` cannot be the zero address. * - `spender` must have allowance for the caller of at least * `subtractedValue`. */ function decreaseAllowance(address spender, uint256 subtractedValue) public virtual returns (bool) { address owner = _msgSender(); uint256 currentAllowance = allowance(owner, spender); require(currentAllowance >= subtractedValue, "ERC20: decreased allowance below zero"); unchecked { _approve(owner, spender, currentAllowance - subtractedValue); } return true; } /** * @dev Moves `amount` of tokens from `from` to `to`. * * This internal function is equivalent to {transfer}, and can be used to * e.g. implement automatic token fees, slashing mechanisms, etc. * * Emits a {Transfer} event. * * Requirements: * * - `from` cannot be the zero address. * - `to` cannot be the zero address. * - `from` must have a balance of at least `amount`. */ function _transfer( address from, address to, uint256 amount ) internal virtual { require(from != address(0), "ERC20: transfer from the zero address"); require(to != address(0), "ERC20: transfer to the zero address"); _beforeTokenTransfer(from, to, amount); uint256 fromBalance = _balances[from]; require(fromBalance >= amount, "ERC20: transfer amount exceeds balance"); unchecked { _balances[from] = fromBalance - amount; } _balances[to] += amount; emit Transfer(from, to, amount); _afterTokenTransfer(from, to, amount); } /** @dev Creates `amount` tokens and assigns them to `account`, increasing * the total supply. * * Emits a {Transfer} event with `from` set to the zero address. * * Requirements: * * - `account` cannot be the zero address. */ function _mint(address account, uint256 amount) internal virtual { require(account != address(0), "ERC20: mint to the zero address"); _beforeTokenTransfer(address(0), account, amount); _totalSupply += amount; _balances[account] += amount; emit Transfer(address(0), account, amount); _afterTokenTransfer(address(0), account, amount); } /** * @dev Destroys `amount` tokens from `account`, reducing the * total supply. * * Emits a {Transfer} event with `to` set to the zero address. * * Requirements: * * - `account` cannot be the zero address. * - `account` must have at least `amount` tokens. */ function _burn(address account, uint256 amount) internal virtual { require(account != address(0), "ERC20: burn from the zero address"); _beforeTokenTransfer(account, address(0), amount); uint256 accountBalance = _balances[account]; require(accountBalance >= amount, "ERC20: burn amount exceeds balance"); unchecked { _balances[account] = accountBalance - amount; } _totalSupply -= amount; emit Transfer(account, address(0), amount); _afterTokenTransfer(account, address(0), amount); } /** * @dev Sets `amount` as the allowance of `spender` over the `owner` s tokens. * * This internal function is equivalent to `approve`, and can be used to * e.g. set automatic allowances for certain subsystems, etc. * * Emits an {Approval} event. * * Requirements: * * - `owner` cannot be the zero address. * - `spender` cannot be the zero address. */ function _approve( address owner, address spender, uint256 amount ) internal virtual { require(owner != address(0), "ERC20: approve from the zero address"); require(spender != address(0), "ERC20: approve to the zero address"); _allowances[owner][spender] = amount; emit Approval(owner, spender, amount); } /** * @dev Updates `owner` s allowance for `spender` based on spent `amount`. * * Does not update the allowance amount in case of infinite allowance. * Revert if not enough allowance is available. * * Might emit an {Approval} event. */ function _spendAllowance( address owner, address spender, uint256 amount ) internal virtual { uint256 currentAllowance = allowance(owner, spender); if (currentAllowance != type(uint256).max) { require(currentAllowance >= amount, "ERC20: insufficient allowance"); unchecked { _approve(owner, spender, currentAllowance - amount); } } } /** * @dev Hook that is called before any transfer of tokens. This includes * minting and burning. * * Calling conditions: * * - when `from` and `to` are both non-zero, `amount` of ``from``'s tokens * will be transferred to `to`. * - when `from` is zero, `amount` tokens will be minted for `to`. * - when `to` is zero, `amount` of ``from``'s tokens will be burned. * - `from` and `to` are never both zero. * * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks]. */ function _beforeTokenTransfer( address from, address to, uint256 amount ) internal virtual {} /** * @dev Hook that is called after any transfer of tokens. This includes * minting and burning. * * Calling conditions: * * - when `from` and `to` are both non-zero, `amount` of ``from``'s tokens * has been transferred to `to`. * - when `from` is zero, `amount` tokens have been minted for `to`. * - when `to` is zero, `amount` of ``from``'s tokens have been burned. * - `from` and `to` are never both zero. * * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks]. */ function _afterTokenTransfer( address from, address to, uint256 amount ) internal virtual {} }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts v4.4.1 (token/ERC20/extensions/IERC20Metadata.sol) pragma solidity ^0.8.0; import "../IERC20.sol"; /** * @dev Interface for the optional metadata functions from the ERC20 standard. * * _Available since v4.1._ */ interface IERC20Metadata is IERC20 { /** * @dev Returns the name of the token. */ function name() external view returns (string memory); /** * @dev Returns the symbol of the token. */ function symbol() external view returns (string memory); /** * @dev Returns the decimals places of the token. */ function decimals() external view returns (uint8); }
// SPDX-License-Identifier: GPL-3.0-only pragma solidity >=0.8.15; import "@openzeppelin/contracts/token/ERC20/IERC20.sol"; import "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol"; contract MockUniswapV2 { using SafeERC20 for IERC20; uint256 fakeSlippage; // 100% = 100 * 1e4 uint256 constant HUNDRED_PERC = 100 * 1e4; constructor(uint256 _fakeSlippage) { fakeSlippage = _fakeSlippage; } function swapExactTokensForTokens( uint256 amountIn, uint256 amountOutMin, address[] calldata path, address to, uint256 deadline ) external returns (uint256[] memory amounts) { require(deadline != 0 && deadline > block.timestamp, "deadline exceeded"); require(path.length > 1, "path must have more than 1 token in it"); // fake simulate slippage uint256 amountAfterSlippage = (amountIn * (HUNDRED_PERC - fakeSlippage)) / HUNDRED_PERC; require(amountAfterSlippage >= amountOutMin, "bad slippage"); IERC20(path[0]).safeTransferFrom(msg.sender, address(this), amountIn); IERC20(path[path.length - 1]).safeTransfer(to, amountAfterSlippage); uint256[] memory ret = new uint256[](2); ret[0] = amountIn; ret[1] = amountAfterSlippage; return ret; } function setFakeSlippage(uint256 _fakeSlippage) public { fakeSlippage = _fakeSlippage; } }
// SPDX-License-Identifier: GPL-3.0-only pragma solidity >=0.8.15; import "@openzeppelin/contracts/token/ERC20/IERC20.sol"; import "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol"; import "../interfaces/ICurvePool.sol"; import "hardhat/console.sol"; contract MockCurvePool { using SafeERC20 for IERC20; address[] public coins; uint8[] public decimals; uint256 fakeSlippage; // 100% = 100 * 1e4 uint256 constant HUNDRED_PERC = 100 * 1e4; constructor( address[] memory _coins, uint8[] memory _decimals, uint256 _fakeSlippage ) { coins = _coins; fakeSlippage = _fakeSlippage; decimals = _decimals; } function exchange( int128 _i, int128 _j, uint256 _dx, uint256 _min_dy ) external { address coini = coins[uint256(int256(_i))]; address coinj = coins[uint256(int256(_j))]; uint8 decimali = decimals[uint256(int256(_i))]; uint8 decimalj = decimals[uint256(int256(_j))]; require(coini != address(0), "coin i not found"); require(coinj != address(0), "coin j not found"); IERC20(coini).safeTransferFrom(msg.sender, address(this), _dx); uint256 amountOut = (((_dx * decimali) / decimalj) * (HUNDRED_PERC - fakeSlippage)) / HUNDRED_PERC; require(amountOut >= _min_dy, "slippage too large"); IERC20(coinj).safeTransfer(msg.sender, amountOut); } function get_dy( int128 _i, int128 _j, uint256 _dx ) external view returns (uint256) { address coini = coins[uint256(int256(_i))]; address coinj = coins[uint256(int256(_j))]; require(coini != address(0), "coin i not found"); require(coinj != address(0), "coin j not found"); return (_dx * (HUNDRED_PERC - fakeSlippage)) / HUNDRED_PERC; } }
// SPDX-License-Identifier: GPL-3.0-only pragma solidity >=0.8.15; interface ICurvePool { function coins(uint256 i) external view returns (address); function underlying_coins(uint256 i) external view returns (address); // plain & meta pool function get_dy( int128 i, int128 j, uint256 dx ) external view returns (uint256); // meta pool function get_dy_underlying( int128 i, int128 j, uint256 dx ) external view returns (uint256); // plain & meta pool function exchange( int128 i, int128 j, uint256 dx, uint256 min_dy ) external; // meta pool function exchange_underlying( int128 i, int128 j, uint256 dx, uint256 min_dy, address _receiver ) external returns (uint256); // special function signature that is only used by the sUSD pool on Ethereum 0xA5407eAE9Ba41422680e2e00537571bcC53efBfD function exchange_underlying( int128 i, int128 j, uint256 dx, uint256 min_dy ) external; }
// SPDX-License-Identifier: MIT pragma solidity >= 0.4.22 <0.9.0; library console { address constant CONSOLE_ADDRESS = address(0x000000000000000000636F6e736F6c652e6c6f67); function _sendLogPayload(bytes memory payload) private view { uint256 payloadLength = payload.length; address consoleAddress = CONSOLE_ADDRESS; assembly { let payloadStart := add(payload, 32) let r := staticcall(gas(), consoleAddress, payloadStart, payloadLength, 0, 0) } } function log() internal view { _sendLogPayload(abi.encodeWithSignature("log()")); } function logInt(int p0) internal view { _sendLogPayload(abi.encodeWithSignature("log(int)", p0)); } function logUint(uint p0) internal view { _sendLogPayload(abi.encodeWithSignature("log(uint)", p0)); } function logString(string memory p0) internal view { _sendLogPayload(abi.encodeWithSignature("log(string)", p0)); } function logBool(bool p0) internal view { _sendLogPayload(abi.encodeWithSignature("log(bool)", p0)); } function logAddress(address p0) internal view { _sendLogPayload(abi.encodeWithSignature("log(address)", p0)); } function logBytes(bytes memory p0) internal view { _sendLogPayload(abi.encodeWithSignature("log(bytes)", p0)); } function logBytes1(bytes1 p0) internal view { _sendLogPayload(abi.encodeWithSignature("log(bytes1)", p0)); } function logBytes2(bytes2 p0) internal view { _sendLogPayload(abi.encodeWithSignature("log(bytes2)", p0)); } function logBytes3(bytes3 p0) internal view { _sendLogPayload(abi.encodeWithSignature("log(bytes3)", p0)); } function logBytes4(bytes4 p0) internal view { _sendLogPayload(abi.encodeWithSignature("log(bytes4)", p0)); } function logBytes5(bytes5 p0) internal view { _sendLogPayload(abi.encodeWithSignature("log(bytes5)", p0)); } function logBytes6(bytes6 p0) internal view { _sendLogPayload(abi.encodeWithSignature("log(bytes6)", p0)); } function logBytes7(bytes7 p0) internal view { _sendLogPayload(abi.encodeWithSignature("log(bytes7)", p0)); } function logBytes8(bytes8 p0) internal view { _sendLogPayload(abi.encodeWithSignature("log(bytes8)", p0)); } function logBytes9(bytes9 p0) internal view { _sendLogPayload(abi.encodeWithSignature("log(bytes9)", p0)); } function logBytes10(bytes10 p0) internal view { _sendLogPayload(abi.encodeWithSignature("log(bytes10)", p0)); } function logBytes11(bytes11 p0) internal view { _sendLogPayload(abi.encodeWithSignature("log(bytes11)", p0)); } function logBytes12(bytes12 p0) internal view { _sendLogPayload(abi.encodeWithSignature("log(bytes12)", p0)); } function logBytes13(bytes13 p0) internal view { _sendLogPayload(abi.encodeWithSignature("log(bytes13)", p0)); } function logBytes14(bytes14 p0) internal view { _sendLogPayload(abi.encodeWithSignature("log(bytes14)", p0)); } function logBytes15(bytes15 p0) internal view { _sendLogPayload(abi.encodeWithSignature("log(bytes15)", p0)); } function logBytes16(bytes16 p0) internal view { _sendLogPayload(abi.encodeWithSignature("log(bytes16)", p0)); } function logBytes17(bytes17 p0) internal view { _sendLogPayload(abi.encodeWithSignature("log(bytes17)", p0)); } function logBytes18(bytes18 p0) internal view { _sendLogPayload(abi.encodeWithSignature("log(bytes18)", p0)); } function logBytes19(bytes19 p0) internal view { _sendLogPayload(abi.encodeWithSignature("log(bytes19)", p0)); } function logBytes20(bytes20 p0) internal view { _sendLogPayload(abi.encodeWithSignature("log(bytes20)", p0)); } function logBytes21(bytes21 p0) internal view { _sendLogPayload(abi.encodeWithSignature("log(bytes21)", p0)); } function logBytes22(bytes22 p0) internal view { _sendLogPayload(abi.encodeWithSignature("log(bytes22)", p0)); } function logBytes23(bytes23 p0) internal view { _sendLogPayload(abi.encodeWithSignature("log(bytes23)", p0)); } function logBytes24(bytes24 p0) internal view { _sendLogPayload(abi.encodeWithSignature("log(bytes24)", p0)); } function logBytes25(bytes25 p0) internal view { _sendLogPayload(abi.encodeWithSignature("log(bytes25)", p0)); } function logBytes26(bytes26 p0) internal view { _sendLogPayload(abi.encodeWithSignature("log(bytes26)", p0)); } function logBytes27(bytes27 p0) internal view { _sendLogPayload(abi.encodeWithSignature("log(bytes27)", p0)); } function logBytes28(bytes28 p0) internal view { _sendLogPayload(abi.encodeWithSignature("log(bytes28)", p0)); } function logBytes29(bytes29 p0) internal view { _sendLogPayload(abi.encodeWithSignature("log(bytes29)", p0)); } function logBytes30(bytes30 p0) internal view { _sendLogPayload(abi.encodeWithSignature("log(bytes30)", p0)); } function logBytes31(bytes31 p0) internal view { _sendLogPayload(abi.encodeWithSignature("log(bytes31)", p0)); } function logBytes32(bytes32 p0) internal view { _sendLogPayload(abi.encodeWithSignature("log(bytes32)", p0)); } function log(uint p0) internal view { _sendLogPayload(abi.encodeWithSignature("log(uint)", p0)); } function log(string memory p0) internal view { _sendLogPayload(abi.encodeWithSignature("log(string)", p0)); } function log(bool p0) internal view { _sendLogPayload(abi.encodeWithSignature("log(bool)", p0)); } function log(address p0) internal view { _sendLogPayload(abi.encodeWithSignature("log(address)", p0)); } function log(uint p0, uint p1) internal view { _sendLogPayload(abi.encodeWithSignature("log(uint,uint)", p0, p1)); } function log(uint p0, string memory p1) internal view { _sendLogPayload(abi.encodeWithSignature("log(uint,string)", p0, p1)); } function log(uint p0, bool p1) internal view { _sendLogPayload(abi.encodeWithSignature("log(uint,bool)", p0, p1)); } function log(uint p0, address p1) internal view { _sendLogPayload(abi.encodeWithSignature("log(uint,address)", p0, p1)); } function log(string memory p0, uint p1) internal view { _sendLogPayload(abi.encodeWithSignature("log(string,uint)", p0, p1)); } function log(string memory p0, string memory p1) internal view { _sendLogPayload(abi.encodeWithSignature("log(string,string)", p0, p1)); } function log(string memory p0, bool p1) internal view { _sendLogPayload(abi.encodeWithSignature("log(string,bool)", p0, p1)); } function log(string memory p0, address p1) internal view { _sendLogPayload(abi.encodeWithSignature("log(string,address)", p0, p1)); } function log(bool p0, uint p1) internal view { _sendLogPayload(abi.encodeWithSignature("log(bool,uint)", p0, p1)); } function log(bool p0, string memory p1) internal view { _sendLogPayload(abi.encodeWithSignature("log(bool,string)", p0, p1)); } function log(bool p0, bool p1) internal view { _sendLogPayload(abi.encodeWithSignature("log(bool,bool)", p0, p1)); } function log(bool p0, address p1) internal view { _sendLogPayload(abi.encodeWithSignature("log(bool,address)", p0, p1)); } function log(address p0, uint p1) internal view { _sendLogPayload(abi.encodeWithSignature("log(address,uint)", p0, p1)); } function log(address p0, string memory p1) internal view { _sendLogPayload(abi.encodeWithSignature("log(address,string)", p0, p1)); } function log(address p0, bool p1) internal view { _sendLogPayload(abi.encodeWithSignature("log(address,bool)", p0, p1)); } function log(address p0, address p1) internal view { _sendLogPayload(abi.encodeWithSignature("log(address,address)", p0, p1)); } function log(uint p0, uint p1, uint p2) internal view { _sendLogPayload(abi.encodeWithSignature("log(uint,uint,uint)", p0, p1, p2)); } function log(uint p0, uint p1, string memory p2) internal view { _sendLogPayload(abi.encodeWithSignature("log(uint,uint,string)", p0, p1, p2)); } function log(uint p0, uint p1, bool p2) internal view { _sendLogPayload(abi.encodeWithSignature("log(uint,uint,bool)", p0, p1, p2)); } function log(uint p0, uint p1, address p2) internal view { _sendLogPayload(abi.encodeWithSignature("log(uint,uint,address)", p0, p1, p2)); } function log(uint p0, string memory p1, uint p2) internal view { _sendLogPayload(abi.encodeWithSignature("log(uint,string,uint)", p0, p1, p2)); } function log(uint p0, string memory p1, string memory p2) internal view { _sendLogPayload(abi.encodeWithSignature("log(uint,string,string)", p0, p1, p2)); } function log(uint p0, string memory p1, bool p2) internal view { _sendLogPayload(abi.encodeWithSignature("log(uint,string,bool)", p0, p1, p2)); } function log(uint p0, string memory p1, address p2) internal view { _sendLogPayload(abi.encodeWithSignature("log(uint,string,address)", p0, p1, p2)); } function log(uint p0, bool p1, uint p2) internal view { _sendLogPayload(abi.encodeWithSignature("log(uint,bool,uint)", p0, p1, p2)); } function log(uint p0, bool p1, string memory p2) internal view { _sendLogPayload(abi.encodeWithSignature("log(uint,bool,string)", p0, p1, p2)); } function log(uint p0, bool p1, bool p2) internal view { _sendLogPayload(abi.encodeWithSignature("log(uint,bool,bool)", p0, p1, p2)); } function log(uint p0, bool p1, address p2) internal view { _sendLogPayload(abi.encodeWithSignature("log(uint,bool,address)", p0, p1, p2)); } function log(uint p0, address p1, uint p2) internal view { _sendLogPayload(abi.encodeWithSignature("log(uint,address,uint)", p0, p1, p2)); } function log(uint p0, address p1, string memory p2) internal view { _sendLogPayload(abi.encodeWithSignature("log(uint,address,string)", p0, p1, p2)); } function log(uint p0, address p1, bool p2) internal view { _sendLogPayload(abi.encodeWithSignature("log(uint,address,bool)", p0, p1, p2)); } function log(uint p0, address p1, address p2) internal view { _sendLogPayload(abi.encodeWithSignature("log(uint,address,address)", p0, p1, p2)); } function log(string memory p0, uint p1, uint p2) internal view { _sendLogPayload(abi.encodeWithSignature("log(string,uint,uint)", p0, p1, p2)); } function log(string memory p0, uint p1, string memory p2) internal view { _sendLogPayload(abi.encodeWithSignature("log(string,uint,string)", p0, p1, p2)); } function log(string memory p0, uint p1, bool p2) internal view { _sendLogPayload(abi.encodeWithSignature("log(string,uint,bool)", p0, p1, p2)); } function log(string memory p0, uint p1, address p2) internal view { _sendLogPayload(abi.encodeWithSignature("log(string,uint,address)", p0, p1, p2)); } function log(string memory p0, string memory p1, uint p2) internal view { _sendLogPayload(abi.encodeWithSignature("log(string,string,uint)", p0, p1, p2)); } function log(string memory p0, string memory p1, string memory p2) internal view { _sendLogPayload(abi.encodeWithSignature("log(string,string,string)", p0, p1, p2)); } function log(string memory p0, string memory p1, bool p2) internal view { _sendLogPayload(abi.encodeWithSignature("log(string,string,bool)", p0, p1, p2)); } function log(string memory p0, string memory p1, address p2) internal view { _sendLogPayload(abi.encodeWithSignature("log(string,string,address)", p0, p1, p2)); } function log(string memory p0, bool p1, uint p2) internal view { _sendLogPayload(abi.encodeWithSignature("log(string,bool,uint)", p0, p1, p2)); } function log(string memory p0, bool p1, string memory p2) internal view { _sendLogPayload(abi.encodeWithSignature("log(string,bool,string)", p0, p1, p2)); } function log(string memory p0, bool p1, bool p2) internal view { _sendLogPayload(abi.encodeWithSignature("log(string,bool,bool)", p0, p1, p2)); } function log(string memory p0, bool p1, address p2) internal view { _sendLogPayload(abi.encodeWithSignature("log(string,bool,address)", p0, p1, p2)); } function log(string memory p0, address p1, uint p2) internal view { _sendLogPayload(abi.encodeWithSignature("log(string,address,uint)", p0, p1, p2)); } function log(string memory p0, address p1, string memory p2) internal view { _sendLogPayload(abi.encodeWithSignature("log(string,address,string)", p0, p1, p2)); } function log(string memory p0, address p1, bool p2) internal view { _sendLogPayload(abi.encodeWithSignature("log(string,address,bool)", p0, p1, p2)); } function log(string memory p0, address p1, address p2) internal view { _sendLogPayload(abi.encodeWithSignature("log(string,address,address)", p0, p1, p2)); } function log(bool p0, uint p1, uint p2) internal view { _sendLogPayload(abi.encodeWithSignature("log(bool,uint,uint)", p0, p1, p2)); } function log(bool p0, uint p1, string memory p2) internal view { _sendLogPayload(abi.encodeWithSignature("log(bool,uint,string)", p0, p1, p2)); } function log(bool p0, uint p1, bool p2) internal view { _sendLogPayload(abi.encodeWithSignature("log(bool,uint,bool)", p0, p1, p2)); } function log(bool p0, uint p1, address p2) internal view { _sendLogPayload(abi.encodeWithSignature("log(bool,uint,address)", p0, p1, p2)); } function log(bool p0, string memory p1, uint p2) internal view { _sendLogPayload(abi.encodeWithSignature("log(bool,string,uint)", p0, p1, p2)); } function log(bool p0, string memory p1, string memory p2) internal view { _sendLogPayload(abi.encodeWithSignature("log(bool,string,string)", p0, p1, p2)); } function log(bool p0, string memory p1, bool p2) internal view { _sendLogPayload(abi.encodeWithSignature("log(bool,string,bool)", p0, p1, p2)); } function log(bool p0, string memory p1, address p2) internal view { _sendLogPayload(abi.encodeWithSignature("log(bool,string,address)", p0, p1, p2)); } function log(bool p0, bool p1, uint p2) internal view { _sendLogPayload(abi.encodeWithSignature("log(bool,bool,uint)", p0, p1, p2)); } function log(bool p0, bool p1, string memory p2) internal view { _sendLogPayload(abi.encodeWithSignature("log(bool,bool,string)", p0, p1, p2)); } function log(bool p0, bool p1, bool p2) internal view { _sendLogPayload(abi.encodeWithSignature("log(bool,bool,bool)", p0, p1, p2)); } function log(bool p0, bool p1, address p2) internal view { _sendLogPayload(abi.encodeWithSignature("log(bool,bool,address)", p0, p1, p2)); } function log(bool p0, address p1, uint p2) internal view { _sendLogPayload(abi.encodeWithSignature("log(bool,address,uint)", p0, p1, p2)); } function log(bool p0, address p1, string memory p2) internal view { _sendLogPayload(abi.encodeWithSignature("log(bool,address,string)", p0, p1, p2)); } function log(bool p0, address p1, bool p2) internal view { _sendLogPayload(abi.encodeWithSignature("log(bool,address,bool)", p0, p1, p2)); } function log(bool p0, address p1, address p2) internal view { _sendLogPayload(abi.encodeWithSignature("log(bool,address,address)", p0, p1, p2)); } function log(address p0, uint p1, uint p2) internal view { _sendLogPayload(abi.encodeWithSignature("log(address,uint,uint)", p0, p1, p2)); } function log(address p0, uint p1, string memory p2) internal view { _sendLogPayload(abi.encodeWithSignature("log(address,uint,string)", p0, p1, p2)); } function log(address p0, uint p1, bool p2) internal view { _sendLogPayload(abi.encodeWithSignature("log(address,uint,bool)", p0, p1, p2)); } function log(address p0, uint p1, address p2) internal view { _sendLogPayload(abi.encodeWithSignature("log(address,uint,address)", p0, p1, p2)); } function log(address p0, string memory p1, uint p2) internal view { _sendLogPayload(abi.encodeWithSignature("log(address,string,uint)", p0, p1, p2)); } function log(address p0, string memory p1, string memory p2) internal view { _sendLogPayload(abi.encodeWithSignature("log(address,string,string)", p0, p1, p2)); } function log(address p0, string memory p1, bool p2) internal view { _sendLogPayload(abi.encodeWithSignature("log(address,string,bool)", p0, p1, p2)); } function log(address p0, string memory p1, address p2) internal view { _sendLogPayload(abi.encodeWithSignature("log(address,string,address)", p0, p1, p2)); } function log(address p0, bool p1, uint p2) internal view { _sendLogPayload(abi.encodeWithSignature("log(address,bool,uint)", p0, p1, p2)); } function log(address p0, bool p1, string memory p2) internal view { _sendLogPayload(abi.encodeWithSignature("log(address,bool,string)", p0, p1, p2)); } function log(address p0, bool p1, bool p2) internal view { _sendLogPayload(abi.encodeWithSignature("log(address,bool,bool)", p0, p1, p2)); } function log(address p0, bool p1, address p2) internal view { _sendLogPayload(abi.encodeWithSignature("log(address,bool,address)", p0, p1, p2)); } function log(address p0, address p1, uint p2) internal view { _sendLogPayload(abi.encodeWithSignature("log(address,address,uint)", p0, p1, p2)); } function log(address p0, address p1, string memory p2) internal view { _sendLogPayload(abi.encodeWithSignature("log(address,address,string)", p0, p1, p2)); } function log(address p0, address p1, bool p2) internal view { _sendLogPayload(abi.encodeWithSignature("log(address,address,bool)", p0, p1, p2)); } function log(address p0, address p1, address p2) internal view { _sendLogPayload(abi.encodeWithSignature("log(address,address,address)", p0, p1, p2)); } function log(uint p0, uint p1, uint p2, uint p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(uint,uint,uint,uint)", p0, p1, p2, p3)); } function log(uint p0, uint p1, uint p2, string memory p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(uint,uint,uint,string)", p0, p1, p2, p3)); } function log(uint p0, uint p1, uint p2, bool p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(uint,uint,uint,bool)", p0, p1, p2, p3)); } function log(uint p0, uint p1, uint p2, address p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(uint,uint,uint,address)", p0, p1, p2, p3)); } function log(uint p0, uint p1, string memory p2, uint p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(uint,uint,string,uint)", p0, p1, p2, p3)); } function log(uint p0, uint p1, string memory p2, string memory p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(uint,uint,string,string)", p0, p1, p2, p3)); } function log(uint p0, uint p1, string memory p2, bool p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(uint,uint,string,bool)", p0, p1, p2, p3)); } function log(uint p0, uint p1, string memory p2, address p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(uint,uint,string,address)", p0, p1, p2, p3)); } function log(uint p0, uint p1, bool p2, uint p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(uint,uint,bool,uint)", p0, p1, p2, p3)); } function log(uint p0, uint p1, bool p2, string memory p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(uint,uint,bool,string)", p0, p1, p2, p3)); } function log(uint p0, uint p1, bool p2, bool p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(uint,uint,bool,bool)", p0, p1, p2, p3)); } function log(uint p0, uint p1, bool p2, address p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(uint,uint,bool,address)", p0, p1, p2, p3)); } function log(uint p0, uint p1, address p2, uint p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(uint,uint,address,uint)", p0, p1, p2, p3)); } function log(uint p0, uint p1, address p2, string memory p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(uint,uint,address,string)", p0, p1, p2, p3)); } function log(uint p0, uint p1, address p2, bool p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(uint,uint,address,bool)", p0, p1, p2, p3)); } function log(uint p0, uint p1, address p2, address p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(uint,uint,address,address)", p0, p1, p2, p3)); } function log(uint p0, string memory p1, uint p2, uint p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(uint,string,uint,uint)", p0, p1, p2, p3)); } function log(uint p0, string memory p1, uint p2, string memory p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(uint,string,uint,string)", p0, p1, p2, p3)); } function log(uint p0, string memory p1, uint p2, bool p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(uint,string,uint,bool)", p0, p1, p2, p3)); } function log(uint p0, string memory p1, uint p2, address p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(uint,string,uint,address)", p0, p1, p2, p3)); } function log(uint p0, string memory p1, string memory p2, uint p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(uint,string,string,uint)", p0, p1, p2, p3)); } function log(uint p0, string memory p1, string memory p2, string memory p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(uint,string,string,string)", p0, p1, p2, p3)); } function log(uint p0, string memory p1, string memory p2, bool p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(uint,string,string,bool)", p0, p1, p2, p3)); } function log(uint p0, string memory p1, string memory p2, address p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(uint,string,string,address)", p0, p1, p2, p3)); } function log(uint p0, string memory p1, bool p2, uint p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(uint,string,bool,uint)", p0, p1, p2, p3)); } function log(uint p0, string memory p1, bool p2, string memory p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(uint,string,bool,string)", p0, p1, p2, p3)); } function log(uint p0, string memory p1, bool p2, bool p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(uint,string,bool,bool)", p0, p1, p2, p3)); } function log(uint p0, string memory p1, bool p2, address p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(uint,string,bool,address)", p0, p1, p2, p3)); } function log(uint p0, string memory p1, address p2, uint p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(uint,string,address,uint)", p0, p1, p2, p3)); } function log(uint p0, string memory p1, address p2, string memory p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(uint,string,address,string)", p0, p1, p2, p3)); } function log(uint p0, string memory p1, address p2, bool p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(uint,string,address,bool)", p0, p1, p2, p3)); } function log(uint p0, string memory p1, address p2, address p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(uint,string,address,address)", p0, p1, p2, p3)); } function log(uint p0, bool p1, uint p2, uint p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(uint,bool,uint,uint)", p0, p1, p2, p3)); } function log(uint p0, bool p1, uint p2, string memory p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(uint,bool,uint,string)", p0, p1, p2, p3)); } function log(uint p0, bool p1, uint p2, bool p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(uint,bool,uint,bool)", p0, p1, p2, p3)); } function log(uint p0, bool p1, uint p2, address p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(uint,bool,uint,address)", p0, p1, p2, p3)); } function log(uint p0, bool p1, string memory p2, uint p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(uint,bool,string,uint)", p0, p1, p2, p3)); } function log(uint p0, bool p1, string memory p2, string memory p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(uint,bool,string,string)", p0, p1, p2, p3)); } function log(uint p0, bool p1, string memory p2, bool p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(uint,bool,string,bool)", p0, p1, p2, p3)); } function log(uint p0, bool p1, string memory p2, address p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(uint,bool,string,address)", p0, p1, p2, p3)); } function log(uint p0, bool p1, bool p2, uint p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(uint,bool,bool,uint)", p0, p1, p2, p3)); } function log(uint p0, bool p1, bool p2, string memory p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(uint,bool,bool,string)", p0, p1, p2, p3)); } function log(uint p0, bool p1, bool p2, bool p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(uint,bool,bool,bool)", p0, p1, p2, p3)); } function log(uint p0, bool p1, bool p2, address p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(uint,bool,bool,address)", p0, p1, p2, p3)); } function log(uint p0, bool p1, address p2, uint p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(uint,bool,address,uint)", p0, p1, p2, p3)); } function log(uint p0, bool p1, address p2, string memory p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(uint,bool,address,string)", p0, p1, p2, p3)); } function log(uint p0, bool p1, address p2, bool p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(uint,bool,address,bool)", p0, p1, p2, p3)); } function log(uint p0, bool p1, address p2, address p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(uint,bool,address,address)", p0, p1, p2, p3)); } function log(uint p0, address p1, uint p2, uint p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(uint,address,uint,uint)", p0, p1, p2, p3)); } function log(uint p0, address p1, uint p2, string memory p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(uint,address,uint,string)", p0, p1, p2, p3)); } function log(uint p0, address p1, uint p2, bool p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(uint,address,uint,bool)", p0, p1, p2, p3)); } function log(uint p0, address p1, uint p2, address p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(uint,address,uint,address)", p0, p1, p2, p3)); } function log(uint p0, address p1, string memory p2, uint p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(uint,address,string,uint)", p0, p1, p2, p3)); } function log(uint p0, address p1, string memory p2, string memory p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(uint,address,string,string)", p0, p1, p2, p3)); } function log(uint p0, address p1, string memory p2, bool p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(uint,address,string,bool)", p0, p1, p2, p3)); } function log(uint p0, address p1, string memory p2, address p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(uint,address,string,address)", p0, p1, p2, p3)); } function log(uint p0, address p1, bool p2, uint p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(uint,address,bool,uint)", p0, p1, p2, p3)); } function log(uint p0, address p1, bool p2, string memory p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(uint,address,bool,string)", p0, p1, p2, p3)); } function log(uint p0, address p1, bool p2, bool p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(uint,address,bool,bool)", p0, p1, p2, p3)); } function log(uint p0, address p1, bool p2, address p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(uint,address,bool,address)", p0, p1, p2, p3)); } function log(uint p0, address p1, address p2, uint p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(uint,address,address,uint)", p0, p1, p2, p3)); } function log(uint p0, address p1, address p2, string memory p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(uint,address,address,string)", p0, p1, p2, p3)); } function log(uint p0, address p1, address p2, bool p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(uint,address,address,bool)", p0, p1, p2, p3)); } function log(uint p0, address p1, address p2, address p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(uint,address,address,address)", p0, p1, p2, p3)); } function log(string memory p0, uint p1, uint p2, uint p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(string,uint,uint,uint)", p0, p1, p2, p3)); } function log(string memory p0, uint p1, uint p2, string memory p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(string,uint,uint,string)", p0, p1, p2, p3)); } function log(string memory p0, uint p1, uint p2, bool p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(string,uint,uint,bool)", p0, p1, p2, p3)); } function log(string memory p0, uint p1, uint p2, address p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(string,uint,uint,address)", p0, p1, p2, p3)); } function log(string memory p0, uint p1, string memory p2, uint p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(string,uint,string,uint)", p0, p1, p2, p3)); } function log(string memory p0, uint p1, string memory p2, string memory p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(string,uint,string,string)", p0, p1, p2, p3)); } function log(string memory p0, uint p1, string memory p2, bool p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(string,uint,string,bool)", p0, p1, p2, p3)); } function log(string memory p0, uint p1, string memory p2, address p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(string,uint,string,address)", p0, p1, p2, p3)); } function log(string memory p0, uint p1, bool p2, uint p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(string,uint,bool,uint)", p0, p1, p2, p3)); } function log(string memory p0, uint p1, bool p2, string memory p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(string,uint,bool,string)", p0, p1, p2, p3)); } function log(string memory p0, uint p1, bool p2, bool p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(string,uint,bool,bool)", p0, p1, p2, p3)); } function log(string memory p0, uint p1, bool p2, address p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(string,uint,bool,address)", p0, p1, p2, p3)); } function log(string memory p0, uint p1, address p2, uint p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(string,uint,address,uint)", p0, p1, p2, p3)); } function log(string memory p0, uint p1, address p2, string memory p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(string,uint,address,string)", p0, p1, p2, p3)); } function log(string memory p0, uint p1, address p2, bool p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(string,uint,address,bool)", p0, p1, p2, p3)); } function log(string memory p0, uint p1, address p2, address p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(string,uint,address,address)", p0, p1, p2, p3)); } function log(string memory p0, string memory p1, uint p2, uint p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(string,string,uint,uint)", p0, p1, p2, p3)); } function log(string memory p0, string memory p1, uint p2, string memory p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(string,string,uint,string)", p0, p1, p2, p3)); } function log(string memory p0, string memory p1, uint p2, bool p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(string,string,uint,bool)", p0, p1, p2, p3)); } function log(string memory p0, string memory p1, uint p2, address p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(string,string,uint,address)", p0, p1, p2, p3)); } function log(string memory p0, string memory p1, string memory p2, uint p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(string,string,string,uint)", p0, p1, p2, p3)); } function log(string memory p0, string memory p1, string memory p2, string memory p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(string,string,string,string)", p0, p1, p2, p3)); } function log(string memory p0, string memory p1, string memory p2, bool p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(string,string,string,bool)", p0, p1, p2, p3)); } function log(string memory p0, string memory p1, string memory p2, address p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(string,string,string,address)", p0, p1, p2, p3)); } function log(string memory p0, string memory p1, bool p2, uint p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(string,string,bool,uint)", p0, p1, p2, p3)); } function log(string memory p0, string memory p1, bool p2, string memory p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(string,string,bool,string)", p0, p1, p2, p3)); } function log(string memory p0, string memory p1, bool p2, bool p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(string,string,bool,bool)", p0, p1, p2, p3)); } function log(string memory p0, string memory p1, bool p2, address p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(string,string,bool,address)", p0, p1, p2, p3)); } function log(string memory p0, string memory p1, address p2, uint p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(string,string,address,uint)", p0, p1, p2, p3)); } function log(string memory p0, string memory p1, address p2, string memory p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(string,string,address,string)", p0, p1, p2, p3)); } function log(string memory p0, string memory p1, address p2, bool p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(string,string,address,bool)", p0, p1, p2, p3)); } function log(string memory p0, string memory p1, address p2, address p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(string,string,address,address)", p0, p1, p2, p3)); } function log(string memory p0, bool p1, uint p2, uint p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(string,bool,uint,uint)", p0, p1, p2, p3)); } function log(string memory p0, bool p1, uint p2, string memory p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(string,bool,uint,string)", p0, p1, p2, p3)); } function log(string memory p0, bool p1, uint p2, bool p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(string,bool,uint,bool)", p0, p1, p2, p3)); } function log(string memory p0, bool p1, uint p2, address p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(string,bool,uint,address)", p0, p1, p2, p3)); } function log(string memory p0, bool p1, string memory p2, uint p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(string,bool,string,uint)", p0, p1, p2, p3)); } function log(string memory p0, bool p1, string memory p2, string memory p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(string,bool,string,string)", p0, p1, p2, p3)); } function log(string memory p0, bool p1, string memory p2, bool p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(string,bool,string,bool)", p0, p1, p2, p3)); } function log(string memory p0, bool p1, string memory p2, address p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(string,bool,string,address)", p0, p1, p2, p3)); } function log(string memory p0, bool p1, bool p2, uint p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(string,bool,bool,uint)", p0, p1, p2, p3)); } function log(string memory p0, bool p1, bool p2, string memory p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(string,bool,bool,string)", p0, p1, p2, p3)); } function log(string memory p0, bool p1, bool p2, bool p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(string,bool,bool,bool)", p0, p1, p2, p3)); } function log(string memory p0, bool p1, bool p2, address p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(string,bool,bool,address)", p0, p1, p2, p3)); } function log(string memory p0, bool p1, address p2, uint p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(string,bool,address,uint)", p0, p1, p2, p3)); } function log(string memory p0, bool p1, address p2, string memory p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(string,bool,address,string)", p0, p1, p2, p3)); } function log(string memory p0, bool p1, address p2, bool p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(string,bool,address,bool)", p0, p1, p2, p3)); } function log(string memory p0, bool p1, address p2, address p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(string,bool,address,address)", p0, p1, p2, p3)); } function log(string memory p0, address p1, uint p2, uint p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(string,address,uint,uint)", p0, p1, p2, p3)); } function log(string memory p0, address p1, uint p2, string memory p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(string,address,uint,string)", p0, p1, p2, p3)); } function log(string memory p0, address p1, uint p2, bool p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(string,address,uint,bool)", p0, p1, p2, p3)); } function log(string memory p0, address p1, uint p2, address p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(string,address,uint,address)", p0, p1, p2, p3)); } function log(string memory p0, address p1, string memory p2, uint p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(string,address,string,uint)", p0, p1, p2, p3)); } function log(string memory p0, address p1, string memory p2, string memory p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(string,address,string,string)", p0, p1, p2, p3)); } function log(string memory p0, address p1, string memory p2, bool p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(string,address,string,bool)", p0, p1, p2, p3)); } function log(string memory p0, address p1, string memory p2, address p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(string,address,string,address)", p0, p1, p2, p3)); } function log(string memory p0, address p1, bool p2, uint p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(string,address,bool,uint)", p0, p1, p2, p3)); } function log(string memory p0, address p1, bool p2, string memory p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(string,address,bool,string)", p0, p1, p2, p3)); } function log(string memory p0, address p1, bool p2, bool p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(string,address,bool,bool)", p0, p1, p2, p3)); } function log(string memory p0, address p1, bool p2, address p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(string,address,bool,address)", p0, p1, p2, p3)); } function log(string memory p0, address p1, address p2, uint p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(string,address,address,uint)", p0, p1, p2, p3)); } function log(string memory p0, address p1, address p2, string memory p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(string,address,address,string)", p0, p1, p2, p3)); } function log(string memory p0, address p1, address p2, bool p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(string,address,address,bool)", p0, p1, p2, p3)); } function log(string memory p0, address p1, address p2, address p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(string,address,address,address)", p0, p1, p2, p3)); } function log(bool p0, uint p1, uint p2, uint p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(bool,uint,uint,uint)", p0, p1, p2, p3)); } function log(bool p0, uint p1, uint p2, string memory p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(bool,uint,uint,string)", p0, p1, p2, p3)); } function log(bool p0, uint p1, uint p2, bool p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(bool,uint,uint,bool)", p0, p1, p2, p3)); } function log(bool p0, uint p1, uint p2, address p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(bool,uint,uint,address)", p0, p1, p2, p3)); } function log(bool p0, uint p1, string memory p2, uint p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(bool,uint,string,uint)", p0, p1, p2, p3)); } function log(bool p0, uint p1, string memory p2, string memory p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(bool,uint,string,string)", p0, p1, p2, p3)); } function log(bool p0, uint p1, string memory p2, bool p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(bool,uint,string,bool)", p0, p1, p2, p3)); } function log(bool p0, uint p1, string memory p2, address p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(bool,uint,string,address)", p0, p1, p2, p3)); } function log(bool p0, uint p1, bool p2, uint p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(bool,uint,bool,uint)", p0, p1, p2, p3)); } function log(bool p0, uint p1, bool p2, string memory p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(bool,uint,bool,string)", p0, p1, p2, p3)); } function log(bool p0, uint p1, bool p2, bool p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(bool,uint,bool,bool)", p0, p1, p2, p3)); } function log(bool p0, uint p1, bool p2, address p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(bool,uint,bool,address)", p0, p1, p2, p3)); } function log(bool p0, uint p1, address p2, uint p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(bool,uint,address,uint)", p0, p1, p2, p3)); } function log(bool p0, uint p1, address p2, string memory p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(bool,uint,address,string)", p0, p1, p2, p3)); } function log(bool p0, uint p1, address p2, bool p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(bool,uint,address,bool)", p0, p1, p2, p3)); } function log(bool p0, uint p1, address p2, address p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(bool,uint,address,address)", p0, p1, p2, p3)); } function log(bool p0, string memory p1, uint p2, uint p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(bool,string,uint,uint)", p0, p1, p2, p3)); } function log(bool p0, string memory p1, uint p2, string memory p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(bool,string,uint,string)", p0, p1, p2, p3)); } function log(bool p0, string memory p1, uint p2, bool p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(bool,string,uint,bool)", p0, p1, p2, p3)); } function log(bool p0, string memory p1, uint p2, address p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(bool,string,uint,address)", p0, p1, p2, p3)); } function log(bool p0, string memory p1, string memory p2, uint p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(bool,string,string,uint)", p0, p1, p2, p3)); } function log(bool p0, string memory p1, string memory p2, string memory p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(bool,string,string,string)", p0, p1, p2, p3)); } function log(bool p0, string memory p1, string memory p2, bool p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(bool,string,string,bool)", p0, p1, p2, p3)); } function log(bool p0, string memory p1, string memory p2, address p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(bool,string,string,address)", p0, p1, p2, p3)); } function log(bool p0, string memory p1, bool p2, uint p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(bool,string,bool,uint)", p0, p1, p2, p3)); } function log(bool p0, string memory p1, bool p2, string memory p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(bool,string,bool,string)", p0, p1, p2, p3)); } function log(bool p0, string memory p1, bool p2, bool p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(bool,string,bool,bool)", p0, p1, p2, p3)); } function log(bool p0, string memory p1, bool p2, address p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(bool,string,bool,address)", p0, p1, p2, p3)); } function log(bool p0, string memory p1, address p2, uint p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(bool,string,address,uint)", p0, p1, p2, p3)); } function log(bool p0, string memory p1, address p2, string memory p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(bool,string,address,string)", p0, p1, p2, p3)); } function log(bool p0, string memory p1, address p2, bool p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(bool,string,address,bool)", p0, p1, p2, p3)); } function log(bool p0, string memory p1, address p2, address p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(bool,string,address,address)", p0, p1, p2, p3)); } function log(bool p0, bool p1, uint p2, uint p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(bool,bool,uint,uint)", p0, p1, p2, p3)); } function log(bool p0, bool p1, uint p2, string memory p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(bool,bool,uint,string)", p0, p1, p2, p3)); } function log(bool p0, bool p1, uint p2, bool p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(bool,bool,uint,bool)", p0, p1, p2, p3)); } function log(bool p0, bool p1, uint p2, address p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(bool,bool,uint,address)", p0, p1, p2, p3)); } function log(bool p0, bool p1, string memory p2, uint p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(bool,bool,string,uint)", p0, p1, p2, p3)); } function log(bool p0, bool p1, string memory p2, string memory p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(bool,bool,string,string)", p0, p1, p2, p3)); } function log(bool p0, bool p1, string memory p2, bool p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(bool,bool,string,bool)", p0, p1, p2, p3)); } function log(bool p0, bool p1, string memory p2, address p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(bool,bool,string,address)", p0, p1, p2, p3)); } function log(bool p0, bool p1, bool p2, uint p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(bool,bool,bool,uint)", p0, p1, p2, p3)); } function log(bool p0, bool p1, bool p2, string memory p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(bool,bool,bool,string)", p0, p1, p2, p3)); } function log(bool p0, bool p1, bool p2, bool p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(bool,bool,bool,bool)", p0, p1, p2, p3)); } function log(bool p0, bool p1, bool p2, address p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(bool,bool,bool,address)", p0, p1, p2, p3)); } function log(bool p0, bool p1, address p2, uint p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(bool,bool,address,uint)", p0, p1, p2, p3)); } function log(bool p0, bool p1, address p2, string memory p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(bool,bool,address,string)", p0, p1, p2, p3)); } function log(bool p0, bool p1, address p2, bool p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(bool,bool,address,bool)", p0, p1, p2, p3)); } function log(bool p0, bool p1, address p2, address p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(bool,bool,address,address)", p0, p1, p2, p3)); } function log(bool p0, address p1, uint p2, uint p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(bool,address,uint,uint)", p0, p1, p2, p3)); } function log(bool p0, address p1, uint p2, string memory p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(bool,address,uint,string)", p0, p1, p2, p3)); } function log(bool p0, address p1, uint p2, bool p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(bool,address,uint,bool)", p0, p1, p2, p3)); } function log(bool p0, address p1, uint p2, address p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(bool,address,uint,address)", p0, p1, p2, p3)); } function log(bool p0, address p1, string memory p2, uint p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(bool,address,string,uint)", p0, p1, p2, p3)); } function log(bool p0, address p1, string memory p2, string memory p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(bool,address,string,string)", p0, p1, p2, p3)); } function log(bool p0, address p1, string memory p2, bool p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(bool,address,string,bool)", p0, p1, p2, p3)); } function log(bool p0, address p1, string memory p2, address p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(bool,address,string,address)", p0, p1, p2, p3)); } function log(bool p0, address p1, bool p2, uint p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(bool,address,bool,uint)", p0, p1, p2, p3)); } function log(bool p0, address p1, bool p2, string memory p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(bool,address,bool,string)", p0, p1, p2, p3)); } function log(bool p0, address p1, bool p2, bool p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(bool,address,bool,bool)", p0, p1, p2, p3)); } function log(bool p0, address p1, bool p2, address p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(bool,address,bool,address)", p0, p1, p2, p3)); } function log(bool p0, address p1, address p2, uint p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(bool,address,address,uint)", p0, p1, p2, p3)); } function log(bool p0, address p1, address p2, string memory p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(bool,address,address,string)", p0, p1, p2, p3)); } function log(bool p0, address p1, address p2, bool p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(bool,address,address,bool)", p0, p1, p2, p3)); } function log(bool p0, address p1, address p2, address p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(bool,address,address,address)", p0, p1, p2, p3)); } function log(address p0, uint p1, uint p2, uint p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(address,uint,uint,uint)", p0, p1, p2, p3)); } function log(address p0, uint p1, uint p2, string memory p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(address,uint,uint,string)", p0, p1, p2, p3)); } function log(address p0, uint p1, uint p2, bool p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(address,uint,uint,bool)", p0, p1, p2, p3)); } function log(address p0, uint p1, uint p2, address p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(address,uint,uint,address)", p0, p1, p2, p3)); } function log(address p0, uint p1, string memory p2, uint p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(address,uint,string,uint)", p0, p1, p2, p3)); } function log(address p0, uint p1, string memory p2, string memory p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(address,uint,string,string)", p0, p1, p2, p3)); } function log(address p0, uint p1, string memory p2, bool p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(address,uint,string,bool)", p0, p1, p2, p3)); } function log(address p0, uint p1, string memory p2, address p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(address,uint,string,address)", p0, p1, p2, p3)); } function log(address p0, uint p1, bool p2, uint p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(address,uint,bool,uint)", p0, p1, p2, p3)); } function log(address p0, uint p1, bool p2, string memory p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(address,uint,bool,string)", p0, p1, p2, p3)); } function log(address p0, uint p1, bool p2, bool p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(address,uint,bool,bool)", p0, p1, p2, p3)); } function log(address p0, uint p1, bool p2, address p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(address,uint,bool,address)", p0, p1, p2, p3)); } function log(address p0, uint p1, address p2, uint p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(address,uint,address,uint)", p0, p1, p2, p3)); } function log(address p0, uint p1, address p2, string memory p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(address,uint,address,string)", p0, p1, p2, p3)); } function log(address p0, uint p1, address p2, bool p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(address,uint,address,bool)", p0, p1, p2, p3)); } function log(address p0, uint p1, address p2, address p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(address,uint,address,address)", p0, p1, p2, p3)); } function log(address p0, string memory p1, uint p2, uint p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(address,string,uint,uint)", p0, p1, p2, p3)); } function log(address p0, string memory p1, uint p2, string memory p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(address,string,uint,string)", p0, p1, p2, p3)); } function log(address p0, string memory p1, uint p2, bool p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(address,string,uint,bool)", p0, p1, p2, p3)); } function log(address p0, string memory p1, uint p2, address p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(address,string,uint,address)", p0, p1, p2, p3)); } function log(address p0, string memory p1, string memory p2, uint p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(address,string,string,uint)", p0, p1, p2, p3)); } function log(address p0, string memory p1, string memory p2, string memory p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(address,string,string,string)", p0, p1, p2, p3)); } function log(address p0, string memory p1, string memory p2, bool p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(address,string,string,bool)", p0, p1, p2, p3)); } function log(address p0, string memory p1, string memory p2, address p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(address,string,string,address)", p0, p1, p2, p3)); } function log(address p0, string memory p1, bool p2, uint p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(address,string,bool,uint)", p0, p1, p2, p3)); } function log(address p0, string memory p1, bool p2, string memory p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(address,string,bool,string)", p0, p1, p2, p3)); } function log(address p0, string memory p1, bool p2, bool p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(address,string,bool,bool)", p0, p1, p2, p3)); } function log(address p0, string memory p1, bool p2, address p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(address,string,bool,address)", p0, p1, p2, p3)); } function log(address p0, string memory p1, address p2, uint p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(address,string,address,uint)", p0, p1, p2, p3)); } function log(address p0, string memory p1, address p2, string memory p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(address,string,address,string)", p0, p1, p2, p3)); } function log(address p0, string memory p1, address p2, bool p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(address,string,address,bool)", p0, p1, p2, p3)); } function log(address p0, string memory p1, address p2, address p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(address,string,address,address)", p0, p1, p2, p3)); } function log(address p0, bool p1, uint p2, uint p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(address,bool,uint,uint)", p0, p1, p2, p3)); } function log(address p0, bool p1, uint p2, string memory p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(address,bool,uint,string)", p0, p1, p2, p3)); } function log(address p0, bool p1, uint p2, bool p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(address,bool,uint,bool)", p0, p1, p2, p3)); } function log(address p0, bool p1, uint p2, address p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(address,bool,uint,address)", p0, p1, p2, p3)); } function log(address p0, bool p1, string memory p2, uint p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(address,bool,string,uint)", p0, p1, p2, p3)); } function log(address p0, bool p1, string memory p2, string memory p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(address,bool,string,string)", p0, p1, p2, p3)); } function log(address p0, bool p1, string memory p2, bool p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(address,bool,string,bool)", p0, p1, p2, p3)); } function log(address p0, bool p1, string memory p2, address p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(address,bool,string,address)", p0, p1, p2, p3)); } function log(address p0, bool p1, bool p2, uint p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(address,bool,bool,uint)", p0, p1, p2, p3)); } function log(address p0, bool p1, bool p2, string memory p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(address,bool,bool,string)", p0, p1, p2, p3)); } function log(address p0, bool p1, bool p2, bool p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(address,bool,bool,bool)", p0, p1, p2, p3)); } function log(address p0, bool p1, bool p2, address p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(address,bool,bool,address)", p0, p1, p2, p3)); } function log(address p0, bool p1, address p2, uint p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(address,bool,address,uint)", p0, p1, p2, p3)); } function log(address p0, bool p1, address p2, string memory p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(address,bool,address,string)", p0, p1, p2, p3)); } function log(address p0, bool p1, address p2, bool p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(address,bool,address,bool)", p0, p1, p2, p3)); } function log(address p0, bool p1, address p2, address p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(address,bool,address,address)", p0, p1, p2, p3)); } function log(address p0, address p1, uint p2, uint p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(address,address,uint,uint)", p0, p1, p2, p3)); } function log(address p0, address p1, uint p2, string memory p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(address,address,uint,string)", p0, p1, p2, p3)); } function log(address p0, address p1, uint p2, bool p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(address,address,uint,bool)", p0, p1, p2, p3)); } function log(address p0, address p1, uint p2, address p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(address,address,uint,address)", p0, p1, p2, p3)); } function log(address p0, address p1, string memory p2, uint p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(address,address,string,uint)", p0, p1, p2, p3)); } function log(address p0, address p1, string memory p2, string memory p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(address,address,string,string)", p0, p1, p2, p3)); } function log(address p0, address p1, string memory p2, bool p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(address,address,string,bool)", p0, p1, p2, p3)); } function log(address p0, address p1, string memory p2, address p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(address,address,string,address)", p0, p1, p2, p3)); } function log(address p0, address p1, bool p2, uint p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(address,address,bool,uint)", p0, p1, p2, p3)); } function log(address p0, address p1, bool p2, string memory p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(address,address,bool,string)", p0, p1, p2, p3)); } function log(address p0, address p1, bool p2, bool p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(address,address,bool,bool)", p0, p1, p2, p3)); } function log(address p0, address p1, bool p2, address p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(address,address,bool,address)", p0, p1, p2, p3)); } function log(address p0, address p1, address p2, uint p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(address,address,address,uint)", p0, p1, p2, p3)); } function log(address p0, address p1, address p2, string memory p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(address,address,address,string)", p0, p1, p2, p3)); } function log(address p0, address p1, address p2, bool p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(address,address,address,bool)", p0, p1, p2, p3)); } function log(address p0, address p1, address p2, address p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(address,address,address,address)", p0, p1, p2, p3)); } }
// SPDX-License-Identifier: GPL-3.0-only pragma solidity >=0.8.15; import "@openzeppelin/contracts/access/Ownable.sol"; import "../interfaces/ICodec.sol"; import "../interfaces/ICurvePool.sol"; import "./CurveTokenAddresses.sol"; /** * @title a special codec for pools that implement exchange_underlying() slightly differently than others. * e.g. "sUSD" pool on Ethereum and "aave" on Polygon * @author padoriku * @notice encode/decode calldata */ contract CurveSpecialMetaPoolCodec is ICodec, CurveTokenAddresses { struct SwapCalldata { int128 i; int128 j; uint256 dx; uint256 min_dy; } constructor(address[] memory _pools, address[][] memory _poolTokens) CurveTokenAddresses(_pools, _poolTokens) {} function decodeCalldata(ICodec.SwapDescription calldata _swap) external view returns ( uint256 amountIn, address tokenIn, address tokenOut ) { SwapCalldata memory data = abi.decode((_swap.data[4:]), (SwapCalldata)); amountIn = data.dx; uint256 i = uint256(uint128(data.i)); uint256 j = uint256(uint128(data.j)); address[] memory tokens = poolToTokens[_swap.dex]; if (tokens.length > 0) { // some pool(sUSD)'s implementation of underlying_coins takes uint128 instead of uint256 as input // register these pool's token addresses manually to workaround this. tokenIn = tokens[i]; tokenOut = tokens[j]; } else { tokenIn = ICurvePool(_swap.dex).underlying_coins(i); tokenOut = ICurvePool(_swap.dex).underlying_coins(j); } } function encodeCalldataWithOverride( bytes calldata _data, uint256 _amountInOverride, address // _receiverOverride ) external pure returns (bytes memory swapCalldata) { bytes4 selector = bytes4(_data); SwapCalldata memory data = abi.decode((_data[4:]), (SwapCalldata)); data.dx = _amountInOverride; return abi.encodeWithSelector(selector, data); } }
// SPDX-License-Identifier: GPL-3.0-only pragma solidity >=0.8.15; import "@openzeppelin/contracts/access/Ownable.sol"; contract CurveTokenAddresses is Ownable { event PoolTokensSet(address[] pools, address[][] poolTokens); // Pool address to *underlying* token addresses. position sensitive. // This is needed because some of the metapools fail to implement curve's underlying_coins() spec, // therefore no consistant way to query token addresses by their indices. mapping(address => address[]) public poolToTokens; constructor(address[] memory _pools, address[][] memory _poolTokens) { _setPoolTokens(_pools, _poolTokens); } function setPoolTokens(address[] calldata _pools, address[][] calldata _poolTokens) external onlyOwner { _setPoolTokens(_pools, _poolTokens); } function _setPoolTokens(address[] memory _pools, address[][] memory _poolTokens) private { require(_pools.length == _poolTokens.length, "len mm"); for (uint256 i = 0; i < _pools.length; i++) { poolToTokens[_pools[i]] = _poolTokens[i]; } emit PoolTokensSet(_pools, _poolTokens); } }
// SPDX-License-Identifier: GPL-3.0-only pragma solidity >=0.8.15; import "@openzeppelin/contracts/access/Ownable.sol"; import "../interfaces/ICodec.sol"; import "../interfaces/ICurvePool.sol"; import "./CurveTokenAddresses.sol"; contract CurveMetaPoolCodec is ICodec, CurveTokenAddresses { struct SwapCalldata { int128 i; int128 j; uint256 dx; uint256 min_dy; address _receiver; } constructor(address[] memory _pools, address[][] memory _poolTokens) CurveTokenAddresses(_pools, _poolTokens) {} function decodeCalldata(ICodec.SwapDescription calldata _swap) external view returns ( uint256 amountIn, address tokenIn, address tokenOut ) { SwapCalldata memory data = abi.decode((_swap.data[4:]), (SwapCalldata)); amountIn = data.dx; uint256 i = uint256(int256(data.i)); uint256 j = uint256(int256(data.j)); address[] memory tokens = poolToTokens[_swap.dex]; tokenIn = tokens[i]; tokenOut = tokens[j]; } function encodeCalldataWithOverride( bytes calldata _data, uint256 _amountInOverride, address _receiverOverride ) external pure returns (bytes memory swapCalldata) { bytes4 selector = bytes4(_data); SwapCalldata memory data = abi.decode((_data[4:]), (SwapCalldata)); data.dx = _amountInOverride; data._receiver = _receiverOverride; return abi.encodeWithSelector(selector, data); } }
// SPDX-License-Identifier: GPL-3.0-only pragma solidity >=0.8.15; import "../interfaces/ICodec.sol"; import "../interfaces/ICurvePool.sol"; contract CurvePoolCodec is ICodec { struct SwapCalldata { int128 i; int128 j; uint256 dx; uint256 min_dy; } function decodeCalldata(ICodec.SwapDescription calldata _swap) external view returns ( uint256 amountIn, address tokenIn, address tokenOut ) { SwapCalldata memory data = abi.decode((_swap.data[4:]), (SwapCalldata)); amountIn = data.dx; tokenIn = ICurvePool(_swap.dex).coins(uint256(int256(data.i))); tokenOut = ICurvePool(_swap.dex).coins(uint256(int256(data.j))); } function encodeCalldataWithOverride( bytes calldata _data, uint256 _amountInOverride, address // receiverOverride ) external pure returns (bytes memory swapCalldata) { bytes4 selector = bytes4(_data); SwapCalldata memory data = abi.decode((_data[4:]), (SwapCalldata)); data.dx = _amountInOverride; return abi.encodeWithSelector(selector, data); } }
// SPDX-License-Identifier: GPL-3.0-only pragma solidity >=0.8.15; import "@openzeppelin/contracts/token/ERC20/IERC20.sol"; import "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol"; contract Mock1inch { using SafeERC20 for IERC20; function swap( uint256 amountIn, uint256 amountOutMin, address to, address srcToken, address dstToken ) external payable { // fake dex IERC20(srcToken).safeTransferFrom(msg.sender, address(this), amountIn); IERC20(dstToken).safeTransfer(to, amountOutMin); return; } }
// SPDX-License-Identifier: GPL-3.0-only pragma solidity >=0.8.15; import "@openzeppelin/contracts/token/ERC20/IERC20.sol"; contract MinimalUniswapV2 { function swapExactTokensForTokens( uint256 amountIn, uint256, address[] calldata path, address to, uint256 ) external returns (uint256[] memory amounts) { amounts = new uint256[](2); amounts[0] = amountIn; amounts[1] = amountIn; IERC20(path[path.length - 1]).transfer(to, amountIn); } }
// SPDX-License-Identifier: GPL-3.0-only pragma solidity 0.8.15; import "@openzeppelin/contracts/token/ERC20/IERC20.sol"; import "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol"; import "@openzeppelin/contracts/security/ReentrancyGuard.sol"; import "../interfaces/IWETH.sol"; import "./PbPool.sol"; import "./Pauser.sol"; import "./VolumeControl.sol"; import "./DelayedTransfer.sol"; import "./Signers.sol"; // add liquidity and withdraw // withdraw can be used by user or liquidity provider contract Pool is Signers, ReentrancyGuard, Pauser, VolumeControl, DelayedTransfer { using SafeERC20 for IERC20; uint64 public addseq; // ensure unique LiquidityAdded event, start from 1 mapping(address => uint256) public minAdd; // add _amount must > minAdd // map of successful withdraws, if true means already withdrew money or added to delayedTransfers mapping(bytes32 => bool) public withdraws; // erc20 wrap of gas token of this chain, eg. WETH, when relay ie. pay out, // if request.token equals this, will withdraw and send native token to receiver // note we don't check whether it's zero address. when this isn't set, and request.token // is all 0 address, guarantee fail address public nativeWrap; // liquidity events event LiquidityAdded( uint64 seqnum, address provider, address token, uint256 amount // how many tokens were added ); event WithdrawDone( bytes32 withdrawId, uint64 seqnum, address receiver, address token, uint256 amount, bytes32 refid ); event MinAddUpdated(address token, uint256 amount); /** * @notice Add liquidity to the pool-based bridge. * NOTE: This function DOES NOT SUPPORT fee-on-transfer / rebasing tokens. * NOTE: ONLY call this from an EOA. DO NOT call from a contract address. * @param _token The address of the token. * @param _amount The amount to add. */ function addLiquidity(address _token, uint256 _amount) external nonReentrant whenNotPaused { require(_amount > minAdd[_token], "amount too small"); addseq += 1; IERC20(_token).safeTransferFrom(msg.sender, address(this), _amount); emit LiquidityAdded(addseq, msg.sender, _token, _amount); } /** * @notice Add native token liquidity to the pool-based bridge. * NOTE: ONLY call this from an EOA. DO NOT call from a contract address. * @param _amount The amount to add. */ function addNativeLiquidity(uint256 _amount) external payable nonReentrant whenNotPaused { require(msg.value == _amount, "Amount mismatch"); require(nativeWrap != address(0), "Native wrap not set"); require(_amount > minAdd[nativeWrap], "amount too small"); addseq += 1; IWETH(nativeWrap).deposit{value: _amount}(); emit LiquidityAdded(addseq, msg.sender, nativeWrap, _amount); } /** * @notice Withdraw funds from the bridge pool. * @param _wdmsg The serialized Withdraw protobuf. * @param _sigs The list of signatures sorted by signing addresses in ascending order. A withdrawal must be * signed-off by +2/3 of the bridge's current signing power to be delivered. * @param _signers The sorted list of signers. * @param _powers The signing powers of the signers. */ function withdraw( bytes calldata _wdmsg, bytes[] calldata _sigs, address[] calldata _signers, uint256[] calldata _powers ) external whenNotPaused { bytes32 domain = keccak256(abi.encodePacked(block.chainid, address(this), "WithdrawMsg")); verifySigs(abi.encodePacked(domain, _wdmsg), _sigs, _signers, _powers); // decode and check wdmsg PbPool.WithdrawMsg memory wdmsg = PbPool.decWithdrawMsg(_wdmsg); // len = 8 + 8 + 20 + 20 + 32 = 88 bytes32 wdId = keccak256( abi.encodePacked(wdmsg.chainid, wdmsg.seqnum, wdmsg.receiver, wdmsg.token, wdmsg.amount) ); require(withdraws[wdId] == false, "withdraw already succeeded"); withdraws[wdId] = true; _updateVolume(wdmsg.token, wdmsg.amount); uint256 delayThreshold = delayThresholds[wdmsg.token]; if (delayThreshold > 0 && wdmsg.amount > delayThreshold) { _addDelayedTransfer(wdId, wdmsg.receiver, wdmsg.token, wdmsg.amount); } else { _sendToken(wdmsg.receiver, wdmsg.token, wdmsg.amount); } emit WithdrawDone(wdId, wdmsg.seqnum, wdmsg.receiver, wdmsg.token, wdmsg.amount, wdmsg.refid); } function executeDelayedTransfer(bytes32 id) external whenNotPaused { delayedTransfer memory transfer = _executeDelayedTransfer(id); _sendToken(transfer.receiver, transfer.token, transfer.amount); } function setMinAdd(address[] calldata _tokens, uint256[] calldata _amounts) external onlyGovernor { require(_tokens.length == _amounts.length, "length mismatch"); for (uint256 i = 0; i < _tokens.length; i++) { minAdd[_tokens[i]] = _amounts[i]; emit MinAddUpdated(_tokens[i], _amounts[i]); } } function _sendToken( address _receiver, address _token, uint256 _amount ) internal { if (_token == nativeWrap) { // withdraw then transfer native to receiver IWETH(nativeWrap).withdraw(_amount); (bool sent, ) = _receiver.call{value: _amount, gas: 50000}(""); require(sent, "failed to send native token"); } else { IERC20(_token).safeTransfer(_receiver, _amount); } } // set nativeWrap, for relay requests, if token == nativeWrap, will withdraw first then transfer native to receiver function setWrap(address _weth) external onlyOwner { nativeWrap = _weth; } }
// SPDX-License-Identifier: GPL-3.0-only // Code generated by protoc-gen-sol. DO NOT EDIT. // source: contracts/libraries/proto/pool.proto pragma solidity 0.8.15; import "./Pb.sol"; library PbPool { using Pb for Pb.Buffer; // so we can call Pb funcs on Buffer obj struct WithdrawMsg { uint64 chainid; // tag: 1 uint64 seqnum; // tag: 2 address receiver; // tag: 3 address token; // tag: 4 uint256 amount; // tag: 5 bytes32 refid; // tag: 6 } // end struct WithdrawMsg function decWithdrawMsg(bytes memory raw) internal pure returns (WithdrawMsg memory m) { Pb.Buffer memory buf = Pb.fromBytes(raw); uint256 tag; Pb.WireType wire; while (buf.hasMore()) { (tag, wire) = buf.decKey(); if (false) {} // solidity has no switch/case else if (tag == 1) { m.chainid = uint64(buf.decVarint()); } else if (tag == 2) { m.seqnum = uint64(buf.decVarint()); } else if (tag == 3) { m.receiver = Pb._address(buf.decBytes()); } else if (tag == 4) { m.token = Pb._address(buf.decBytes()); } else if (tag == 5) { m.amount = Pb._uint256(buf.decBytes()); } else if (tag == 6) { m.refid = Pb._bytes32(buf.decBytes()); } else { buf.skipValue(wire); } // skip value of unknown tag } } // end decoder WithdrawMsg }
// SPDX-License-Identifier: GPL-3.0-only pragma solidity 0.8.15; import "@openzeppelin/contracts/access/Ownable.sol"; import "@openzeppelin/contracts/security/Pausable.sol"; abstract contract Pauser is Ownable, Pausable { mapping(address => bool) public pausers; event PauserAdded(address account); event PauserRemoved(address account); constructor() { _addPauser(msg.sender); } modifier onlyPauser() { require(isPauser(msg.sender), "Caller is not pauser"); _; } function pause() public onlyPauser { _pause(); } function unpause() public onlyPauser { _unpause(); } function isPauser(address account) public view returns (bool) { return pausers[account]; } function addPauser(address account) public onlyOwner { _addPauser(account); } function removePauser(address account) public onlyOwner { _removePauser(account); } function renouncePauser() public { _removePauser(msg.sender); } function _addPauser(address account) private { require(!isPauser(account), "Account is already pauser"); pausers[account] = true; emit PauserAdded(account); } function _removePauser(address account) private { require(isPauser(account), "Account is not pauser"); pausers[account] = false; emit PauserRemoved(account); } }
// SPDX-License-Identifier: GPL-3.0-only pragma solidity 0.8.15; import "./Governor.sol"; abstract contract VolumeControl is Governor { uint256 public epochLength; // seconds mapping(address => uint256) public epochVolumes; // key is token mapping(address => uint256) public epochVolumeCaps; // key is token mapping(address => uint256) public lastOpTimestamps; // key is token event EpochLengthUpdated(uint256 length); event EpochVolumeUpdated(address token, uint256 cap); function setEpochLength(uint256 _length) external onlyGovernor { epochLength = _length; emit EpochLengthUpdated(_length); } function setEpochVolumeCaps(address[] calldata _tokens, uint256[] calldata _caps) external onlyGovernor { require(_tokens.length == _caps.length, "length mismatch"); for (uint256 i = 0; i < _tokens.length; i++) { epochVolumeCaps[_tokens[i]] = _caps[i]; emit EpochVolumeUpdated(_tokens[i], _caps[i]); } } function _updateVolume(address _token, uint256 _amount) internal { if (epochLength == 0) { return; } uint256 cap = epochVolumeCaps[_token]; if (cap == 0) { return; } uint256 volume = epochVolumes[_token]; uint256 timestamp = block.timestamp; uint256 epochStartTime = (timestamp / epochLength) * epochLength; if (lastOpTimestamps[_token] < epochStartTime) { volume = _amount; } else { volume += _amount; } require(volume <= cap, "volume exceeds cap"); epochVolumes[_token] = volume; lastOpTimestamps[_token] = timestamp; } }
// SPDX-License-Identifier: GPL-3.0-only pragma solidity 0.8.15; import "./Governor.sol"; abstract contract DelayedTransfer is Governor { struct delayedTransfer { address receiver; address token; uint256 amount; uint256 timestamp; } mapping(bytes32 => delayedTransfer) public delayedTransfers; mapping(address => uint256) public delayThresholds; uint256 public delayPeriod; // in seconds event DelayedTransferAdded(bytes32 id); event DelayedTransferExecuted(bytes32 id, address receiver, address token, uint256 amount); event DelayPeriodUpdated(uint256 period); event DelayThresholdUpdated(address token, uint256 threshold); function setDelayThresholds(address[] calldata _tokens, uint256[] calldata _thresholds) external onlyGovernor { require(_tokens.length == _thresholds.length, "length mismatch"); for (uint256 i = 0; i < _tokens.length; i++) { delayThresholds[_tokens[i]] = _thresholds[i]; emit DelayThresholdUpdated(_tokens[i], _thresholds[i]); } } function setDelayPeriod(uint256 _period) external onlyGovernor { delayPeriod = _period; emit DelayPeriodUpdated(_period); } function _addDelayedTransfer( bytes32 id, address receiver, address token, uint256 amount ) internal { require(delayedTransfers[id].timestamp == 0, "delayed transfer already exists"); delayedTransfers[id] = delayedTransfer({ receiver: receiver, token: token, amount: amount, timestamp: block.timestamp }); emit DelayedTransferAdded(id); } // caller needs to do the actual token transfer function _executeDelayedTransfer(bytes32 id) internal returns (delayedTransfer memory) { delayedTransfer memory transfer = delayedTransfers[id]; require(transfer.timestamp > 0, "delayed transfer not exist"); require(block.timestamp > transfer.timestamp + delayPeriod, "delayed transfer still locked"); delete delayedTransfers[id]; emit DelayedTransferExecuted(id, transfer.receiver, transfer.token, transfer.amount); return transfer; } }
// SPDX-License-Identifier: GPL-3.0-only pragma solidity 0.8.15; import "@openzeppelin/contracts/utils/cryptography/ECDSA.sol"; import "@openzeppelin/contracts/access/Ownable.sol"; import "./interfaces/ISigsVerifier.sol"; contract Signers is Ownable, ISigsVerifier { using ECDSA for bytes32; bytes32 public ssHash; uint256 public triggerTime; // timestamp when last update was triggered // reset can be called by the owner address for emergency recovery uint256 public resetTime; uint256 public noticePeriod; // advance notice period as seconds for reset uint256 constant MAX_INT = 2**256 - 1; event SignersUpdated(address[] _signers, uint256[] _powers); event ResetNotification(uint256 resetTime); /** * @notice Verifies that a message is signed by a quorum among the signers * The sigs must be sorted by signer addresses in ascending order. * @param _msg signed message * @param _sigs list of signatures sorted by signer addresses in ascending order * @param _signers sorted list of current signers * @param _powers powers of current signers */ function verifySigs( bytes memory _msg, bytes[] calldata _sigs, address[] calldata _signers, uint256[] calldata _powers ) public view override { bytes32 h = keccak256(abi.encodePacked(_signers, _powers)); require(ssHash == h, "Mismatch current signers"); _verifySignedPowers(keccak256(_msg).toEthSignedMessageHash(), _sigs, _signers, _powers); } /** * @notice Update new signers. * @param _newSigners sorted list of new signers * @param _curPowers powers of new signers * @param _sigs list of signatures sorted by signer addresses in ascending order * @param _curSigners sorted list of current signers * @param _curPowers powers of current signers */ function updateSigners( uint256 _triggerTime, address[] calldata _newSigners, uint256[] calldata _newPowers, bytes[] calldata _sigs, address[] calldata _curSigners, uint256[] calldata _curPowers ) external { // use trigger time for nonce protection, must be ascending require(_triggerTime > triggerTime, "Trigger time is not increasing"); // make sure triggerTime is not too large, as it cannot be decreased once set require(_triggerTime < block.timestamp + 3600, "Trigger time is too large"); bytes32 domain = keccak256(abi.encodePacked(block.chainid, address(this), "UpdateSigners")); verifySigs(abi.encodePacked(domain, _triggerTime, _newSigners, _newPowers), _sigs, _curSigners, _curPowers); _updateSigners(_newSigners, _newPowers); triggerTime = _triggerTime; } /** * @notice reset signers, only used for init setup and emergency recovery */ function resetSigners(address[] calldata _signers, uint256[] calldata _powers) external onlyOwner { require(block.timestamp > resetTime, "not reach reset time"); resetTime = MAX_INT; _updateSigners(_signers, _powers); } function notifyResetSigners() external onlyOwner { resetTime = block.timestamp + noticePeriod; emit ResetNotification(resetTime); } function increaseNoticePeriod(uint256 period) external onlyOwner { require(period > noticePeriod, "notice period can only be increased"); noticePeriod = period; } // separate from verifySigs func to avoid "stack too deep" issue function _verifySignedPowers( bytes32 _hash, bytes[] calldata _sigs, address[] calldata _signers, uint256[] calldata _powers ) private pure { require(_signers.length == _powers.length, "signers and powers length not match"); uint256 totalPower; // sum of all signer.power for (uint256 i = 0; i < _signers.length; i++) { totalPower += _powers[i]; } uint256 quorum = (totalPower * 2) / 3 + 1; uint256 signedPower; // sum of signer powers who are in sigs address prev = address(0); uint256 index = 0; for (uint256 i = 0; i < _sigs.length; i++) { address signer = _hash.recover(_sigs[i]); require(signer > prev, "signers not in ascending order"); prev = signer; // now find match signer add its power while (signer > _signers[index]) { index += 1; require(index < _signers.length, "signer not found"); } if (signer == _signers[index]) { signedPower += _powers[index]; } if (signedPower >= quorum) { // return early to save gas return; } } revert("quorum not reached"); } function _updateSigners(address[] calldata _signers, uint256[] calldata _powers) private { require(_signers.length == _powers.length, "signers and powers length not match"); address prev = address(0); for (uint256 i = 0; i < _signers.length; i++) { require(_signers[i] > prev, "New signers not in ascending order"); prev = _signers[i]; } ssHash = keccak256(abi.encodePacked(_signers, _powers)); emit SignersUpdated(_signers, _powers); } }
// SPDX-License-Identifier: GPL-3.0-only pragma solidity 0.8.15; // runtime proto sol library library Pb { enum WireType { Varint, Fixed64, LengthDelim, StartGroup, EndGroup, Fixed32 } struct Buffer { uint256 idx; // the start index of next read. when idx=b.length, we're done bytes b; // hold serialized proto msg, readonly } // create a new in-memory Buffer object from raw msg bytes function fromBytes(bytes memory raw) internal pure returns (Buffer memory buf) { buf.b = raw; buf.idx = 0; } // whether there are unread bytes function hasMore(Buffer memory buf) internal pure returns (bool) { return buf.idx < buf.b.length; } // decode current field number and wiretype function decKey(Buffer memory buf) internal pure returns (uint256 tag, WireType wiretype) { uint256 v = decVarint(buf); tag = v / 8; wiretype = WireType(v & 7); } // count tag occurrences, return an array due to no memory map support // have to create array for (maxtag+1) size. cnts[tag] = occurrences // should keep buf.idx unchanged because this is only a count function function cntTags(Buffer memory buf, uint256 maxtag) internal pure returns (uint256[] memory cnts) { uint256 originalIdx = buf.idx; cnts = new uint256[](maxtag + 1); // protobuf's tags are from 1 rather than 0 uint256 tag; WireType wire; while (hasMore(buf)) { (tag, wire) = decKey(buf); cnts[tag] += 1; skipValue(buf, wire); } buf.idx = originalIdx; } // read varint from current buf idx, move buf.idx to next read, return the int value function decVarint(Buffer memory buf) internal pure returns (uint256 v) { bytes10 tmp; // proto int is at most 10 bytes (7 bits can be used per byte) bytes memory bb = buf.b; // get buf.b mem addr to use in assembly v = buf.idx; // use v to save one additional uint variable assembly { tmp := mload(add(add(bb, 32), v)) // load 10 bytes from buf.b[buf.idx] to tmp } uint256 b; // store current byte content v = 0; // reset to 0 for return value for (uint256 i = 0; i < 10; i++) { assembly { b := byte(i, tmp) // don't use tmp[i] because it does bound check and costs extra } v |= (b & 0x7F) << (i * 7); if (b & 0x80 == 0) { buf.idx += i + 1; return v; } } revert(); // i=10, invalid varint stream } // read length delimited field and return bytes function decBytes(Buffer memory buf) internal pure returns (bytes memory b) { uint256 len = decVarint(buf); uint256 end = buf.idx + len; require(end <= buf.b.length); // avoid overflow b = new bytes(len); bytes memory bufB = buf.b; // get buf.b mem addr to use in assembly uint256 bStart; uint256 bufBStart = buf.idx; assembly { bStart := add(b, 32) bufBStart := add(add(bufB, 32), bufBStart) } for (uint256 i = 0; i < len; i += 32) { assembly { mstore(add(bStart, i), mload(add(bufBStart, i))) } } buf.idx = end; } // return packed ints function decPacked(Buffer memory buf) internal pure returns (uint256[] memory t) { uint256 len = decVarint(buf); uint256 end = buf.idx + len; require(end <= buf.b.length); // avoid overflow // array in memory must be init w/ known length // so we have to create a tmp array w/ max possible len first uint256[] memory tmp = new uint256[](len); uint256 i = 0; // count how many ints are there while (buf.idx < end) { tmp[i] = decVarint(buf); i++; } t = new uint256[](i); // init t with correct length for (uint256 j = 0; j < i; j++) { t[j] = tmp[j]; } return t; } // move idx pass current value field, to beginning of next tag or msg end function skipValue(Buffer memory buf, WireType wire) internal pure { if (wire == WireType.Varint) { decVarint(buf); } else if (wire == WireType.LengthDelim) { uint256 len = decVarint(buf); buf.idx += len; // skip len bytes value data require(buf.idx <= buf.b.length); // avoid overflow } else { revert(); } // unsupported wiretype } // type conversion help utils function _bool(uint256 x) internal pure returns (bool v) { return x != 0; } function _uint256(bytes memory b) internal pure returns (uint256 v) { require(b.length <= 32); // b's length must be smaller than or equal to 32 assembly { v := mload(add(b, 32)) } // load all 32bytes to v v = v >> (8 * (32 - b.length)); // only first b.length is valid } function _address(bytes memory b) internal pure returns (address v) { v = _addressPayable(b); } function _addressPayable(bytes memory b) internal pure returns (address payable v) { require(b.length == 20); //load 32bytes then shift right 12 bytes assembly { v := div(mload(add(b, 32)), 0x1000000000000000000000000) } } function _bytes32(bytes memory b) internal pure returns (bytes32 v) { require(b.length == 32); assembly { v := mload(add(b, 32)) } } // uint[] to uint8[] function uint8s(uint256[] memory arr) internal pure returns (uint8[] memory t) { t = new uint8[](arr.length); for (uint256 i = 0; i < t.length; i++) { t[i] = uint8(arr[i]); } } function uint32s(uint256[] memory arr) internal pure returns (uint32[] memory t) { t = new uint32[](arr.length); for (uint256 i = 0; i < t.length; i++) { t[i] = uint32(arr[i]); } } function uint64s(uint256[] memory arr) internal pure returns (uint64[] memory t) { t = new uint64[](arr.length); for (uint256 i = 0; i < t.length; i++) { t[i] = uint64(arr[i]); } } function bools(uint256[] memory arr) internal pure returns (bool[] memory t) { t = new bool[](arr.length); for (uint256 i = 0; i < t.length; i++) { t[i] = arr[i] != 0; } } }
// SPDX-License-Identifier: GPL-3.0-only pragma solidity 0.8.15; import "@openzeppelin/contracts/access/Ownable.sol"; abstract contract Governor is Ownable { mapping(address => bool) public governors; event GovernorAdded(address account); event GovernorRemoved(address account); modifier onlyGovernor() { require(isGovernor(msg.sender), "Caller is not governor"); _; } constructor() { _addGovernor(msg.sender); } function isGovernor(address _account) public view returns (bool) { return governors[_account]; } function addGovernor(address _account) public onlyOwner { _addGovernor(_account); } function removeGovernor(address _account) public onlyOwner { _removeGovernor(_account); } function renounceGovernor() public { _removeGovernor(msg.sender); } function _addGovernor(address _account) private { require(!isGovernor(_account), "Account is already governor"); governors[_account] = true; emit GovernorAdded(_account); } function _removeGovernor(address _account) private { require(isGovernor(_account), "Account is not governor"); governors[_account] = false; emit GovernorRemoved(_account); } }
// SPDX-License-Identifier: GPL-3.0-only pragma solidity 0.8.15; interface ISigsVerifier { /** * @notice Verifies that a message is signed by a quorum among the signers. * @param _msg signed message * @param _sigs list of signatures sorted by signer addresses in ascending order * @param _signers sorted list of current signers * @param _powers powers of current signers */ function verifySigs( bytes memory _msg, bytes[] calldata _sigs, address[] calldata _signers, uint256[] calldata _powers ) external view; }
// SPDX-License-Identifier: GPL-3.0-only pragma solidity 0.8.15; import "./Ownable.sol"; import "./interfaces/ISigsVerifier.sol"; contract MessageBusSender is Ownable { ISigsVerifier public immutable sigsVerifier; uint256 public feeBase; uint256 public feePerByte; mapping(address => uint256) public withdrawnFees; event Message(address indexed sender, address receiver, uint256 dstChainId, bytes message, uint256 fee); event MessageWithTransfer( address indexed sender, address receiver, uint256 dstChainId, address bridge, bytes32 srcTransferId, bytes message, uint256 fee ); event FeeBaseUpdated(uint256 feeBase); event FeePerByteUpdated(uint256 feePerByte); constructor(ISigsVerifier _sigsVerifier) { sigsVerifier = _sigsVerifier; } /** * @notice Sends a message to an app on another chain via MessageBus without an associated transfer. * A fee is charged in the native gas token. * @param _receiver The address of the destination app contract. * @param _dstChainId The destination chain ID. * @param _message Arbitrary message bytes to be decoded by the destination app contract. */ function sendMessage( address _receiver, uint256 _dstChainId, bytes calldata _message ) external payable { uint256 minFee = calcFee(_message); require(msg.value >= minFee, "Insufficient fee"); emit Message(msg.sender, _receiver, _dstChainId, _message, msg.value); } /** * @notice Sends a message associated with a transfer to an app on another chain via MessageBus without an associated transfer. * A fee is charged in the native token. * @param _receiver The address of the destination app contract. * @param _dstChainId The destination chain ID. * @param _srcBridge The bridge contract to send the transfer with. * @param _srcTransferId The transfer ID. * @param _dstChainId The destination chain ID. * @param _message Arbitrary message bytes to be decoded by the destination app contract. */ function sendMessageWithTransfer( address _receiver, uint256 _dstChainId, address _srcBridge, bytes32 _srcTransferId, bytes calldata _message ) external payable { uint256 minFee = calcFee(_message); require(msg.value >= minFee, "Insufficient fee"); // SGN needs to verify // 1. msg.sender matches sender of the src transfer // 2. dstChainId matches dstChainId of the src transfer // 3. bridge is either liquidity bridge, peg src vault, or peg dst bridge emit MessageWithTransfer(msg.sender, _receiver, _dstChainId, _srcBridge, _srcTransferId, _message, msg.value); } /** * @notice Withdraws message fee in the form of native gas token. * @param _account The address receiving the fee. * @param _cumulativeFee The cumulative fee credited to the account. Tracked by SGN. * @param _sigs The list of signatures sorted by signing addresses in ascending order. A withdrawal must be * signed-off by +2/3 of the sigsVerifier's current signing power to be delivered. * @param _signers The sorted list of signers. * @param _powers The signing powers of the signers. */ function withdrawFee( address _account, uint256 _cumulativeFee, bytes[] calldata _sigs, address[] calldata _signers, uint256[] calldata _powers ) external { bytes32 domain = keccak256(abi.encodePacked(block.chainid, address(this), "withdrawFee")); sigsVerifier.verifySigs(abi.encodePacked(domain, _account, _cumulativeFee), _sigs, _signers, _powers); uint256 amount = _cumulativeFee - withdrawnFees[_account]; require(amount > 0, "No new amount to withdraw"); withdrawnFees[_account] = _cumulativeFee; (bool sent, ) = _account.call{value: amount, gas: 50000}(""); require(sent, "failed to withdraw fee"); } /** * @notice Calculates the required fee for the message. * @param _message Arbitrary message bytes to be decoded by the destination app contract. @ @return The required fee. */ function calcFee(bytes calldata _message) public view returns (uint256) { return feeBase + _message.length * feePerByte; } // -------------------- Admin -------------------- function setFeePerByte(uint256 _fee) external onlyOwner { feePerByte = _fee; emit FeePerByteUpdated(feePerByte); } function setFeeBase(uint256 _fee) external onlyOwner { feeBase = _fee; emit FeeBaseUpdated(feeBase); } }
// SPDX-License-Identifier: GPL-3.0-only pragma solidity ^0.8.0; /** * @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. * * This adds a normal func that setOwner if _owner is address(0). So we can't allow * renounceOwnership. So we can support Proxy based upgradable contract */ abstract contract Ownable { address private _owner; event OwnershipTransferred(address indexed previousOwner, address indexed newOwner); /** * @dev Initializes the contract setting the deployer as the initial owner. */ constructor() { _setOwner(msg.sender); } /** * @dev Only to be called by inherit contracts, in their init func called by Proxy * we require _owner == address(0), which is only possible when it's a delegateCall * because constructor sets _owner in contract state. */ function initOwner() internal { require(_owner == address(0), "owner already set"); _setOwner(msg.sender); } /** * @dev Returns the address of the current owner. */ function owner() public view virtual returns (address) { return _owner; } /** * @dev Throws if called by any account other than the owner. */ modifier onlyOwner() { require(owner() == msg.sender, "Ownable: caller is not the owner"); _; } /** * @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"); _setOwner(newOwner); } function _setOwner(address newOwner) private { address oldOwner = _owner; _owner = newOwner; emit OwnershipTransferred(oldOwner, newOwner); } }
// SPDX-License-Identifier: GPL-3.0-only pragma solidity 0.8.15; import "./interfaces/IBridge.sol"; import "./interfaces/IOriginalTokenVault.sol"; import "./interfaces/IOriginalTokenVaultV2.sol"; import "./interfaces/IPeggedTokenBridge.sol"; import "./interfaces/IPeggedTokenBridgeV2.sol"; import "../interfaces/IMessageReceiverApp.sol"; import "./Ownable.sol"; contract MessageBusReceiver is Ownable { enum TransferType { Null, LqSend, // send through liquidity bridge LqWithdraw, // withdraw from liquidity bridge PegMint, // mint through pegged token bridge PegWithdraw, // withdraw from original token vault PegMintV2, // mint through pegged token bridge v2 PegWithdrawV2 // withdraw from original token vault v2 } struct TransferInfo { TransferType t; address sender; address receiver; address token; uint256 amount; uint64 seqnum; // only needed for LqWithdraw uint64 srcChainId; bytes32 refId; } struct RouteInfo { address sender; address receiver; uint64 srcChainId; } enum TxStatus { Null, Success, Fail, Fallback, Pending } mapping(bytes32 => TxStatus) public executedMessages; address public liquidityBridge; // liquidity bridge address address public pegBridge; // peg bridge address address public pegVault; // peg original vault address address public pegBridgeV2; // peg bridge address address public pegVaultV2; // peg original vault address enum MsgType { MessageWithTransfer, MessageOnly } event Executed(MsgType msgType, bytes32 id, TxStatus status); event LiquidityBridgeUpdated(address liquidityBridge); event PegBridgeUpdated(address pegBridge); event PegVaultUpdated(address pegVault); event PegBridgeV2Updated(address pegBridgeV2); event PegVaultV2Updated(address pegVaultV2); constructor( address _liquidityBridge, address _pegBridge, address _pegVault, address _pegBridgeV2, address _pegVaultV2 ) { liquidityBridge = _liquidityBridge; pegBridge = _pegBridge; pegVault = _pegVault; pegBridgeV2 = _pegBridgeV2; pegVaultV2 = _pegVaultV2; } function initReceiver( address _liquidityBridge, address _pegBridge, address _pegVault, address _pegBridgeV2, address _pegVaultV2 ) internal { require(liquidityBridge == address(0), "liquidityBridge already set"); liquidityBridge = _liquidityBridge; pegBridge = _pegBridge; pegVault = _pegVault; pegBridgeV2 = _pegBridgeV2; pegVaultV2 = _pegVaultV2; } // ============== functions called by executor ============== /** * @notice Execute a message with a successful transfer. * @param _message Arbitrary message bytes originated from and encoded by the source app contract * @param _transfer The transfer info. * @param _sigs The list of signatures sorted by signing addresses in ascending order. A relay must be signed-off by * +2/3 of the sigsVerifier's current signing power to be delivered. * @param _signers The sorted list of signers. * @param _powers The signing powers of the signers. */ function executeMessageWithTransfer( bytes calldata _message, TransferInfo calldata _transfer, bytes[] calldata _sigs, address[] calldata _signers, uint256[] calldata _powers ) external payable { // For message with token transfer, message Id is computed through transfer info // in order to guarantee that each transfer can only be used once. // This also indicates that different transfers can carry the exact same messages. bytes32 messageId = verifyTransfer(_transfer); require(executedMessages[messageId] == TxStatus.Null, "transfer already executed"); executedMessages[messageId] = TxStatus.Pending; bytes32 domain = keccak256(abi.encodePacked(block.chainid, address(this), "MessageWithTransfer")); IBridge(liquidityBridge).verifySigs(abi.encodePacked(domain, messageId, _message), _sigs, _signers, _powers); TxStatus status; bool success = executeMessageWithTransfer(_transfer, _message); if (success) { status = TxStatus.Success; } else { success = executeMessageWithTransferFallback(_transfer, _message); if (success) { status = TxStatus.Fallback; } else { status = TxStatus.Fail; } } executedMessages[messageId] = status; emit Executed(MsgType.MessageWithTransfer, messageId, status); } /** * @notice Execute a message with a refunded transfer. * @param _message Arbitrary message bytes originated from and encoded by the source app contract * @param _transfer The transfer info. * @param _sigs The list of signatures sorted by signing addresses in ascending order. A relay must be signed-off by * +2/3 of the sigsVerifier's current signing power to be delivered. * @param _signers The sorted list of signers. * @param _powers The signing powers of the signers. */ function executeMessageWithTransferRefund( bytes calldata _message, // the same message associated with the original transfer TransferInfo calldata _transfer, bytes[] calldata _sigs, address[] calldata _signers, uint256[] calldata _powers ) external payable { // similar to executeMessageWithTransfer bytes32 messageId = verifyTransfer(_transfer); require(executedMessages[messageId] == TxStatus.Null, "transfer already executed"); executedMessages[messageId] = TxStatus.Pending; bytes32 domain = keccak256(abi.encodePacked(block.chainid, address(this), "MessageWithTransferRefund")); IBridge(liquidityBridge).verifySigs(abi.encodePacked(domain, messageId, _message), _sigs, _signers, _powers); TxStatus status; bool success = executeMessageWithTransferRefund(_transfer, _message); if (success) { status = TxStatus.Success; } else { status = TxStatus.Fail; } executedMessages[messageId] = status; emit Executed(MsgType.MessageWithTransfer, messageId, status); } /** * @notice Execute a message not associated with a transfer. * @param _message Arbitrary message bytes originated from and encoded by the source app contract * @param _sigs The list of signatures sorted by signing addresses in ascending order. A relay must be signed-off by * +2/3 of the sigsVerifier's current signing power to be delivered. * @param _signers The sorted list of signers. * @param _powers The signing powers of the signers. */ function executeMessage( bytes calldata _message, RouteInfo calldata _route, bytes[] calldata _sigs, address[] calldata _signers, uint256[] calldata _powers ) external payable { // For message without associated token transfer, message Id is computed through message info, // in order to guarantee that each message can only be applied once bytes32 messageId = computeMessageOnlyId(_route, _message); require(executedMessages[messageId] == TxStatus.Null, "message already executed"); executedMessages[messageId] = TxStatus.Pending; bytes32 domain = keccak256(abi.encodePacked(block.chainid, address(this), "Message")); IBridge(liquidityBridge).verifySigs(abi.encodePacked(domain, messageId), _sigs, _signers, _powers); TxStatus status; bool success = executeMessage(_route, _message); if (success) { status = TxStatus.Success; } else { status = TxStatus.Fail; } executedMessages[messageId] = status; emit Executed(MsgType.MessageOnly, messageId, status); } // ================= utils (to avoid stack too deep) ================= function executeMessageWithTransfer(TransferInfo calldata _transfer, bytes calldata _message) private returns (bool) { (bool ok, bytes memory res) = address(_transfer.receiver).call{value: msg.value}( abi.encodeWithSelector( IMessageReceiverApp.executeMessageWithTransfer.selector, _transfer.sender, _transfer.token, _transfer.amount, _transfer.srcChainId, _message ) ); if (ok) { bool success = abi.decode((res), (bool)); return success; } return false; } function executeMessageWithTransferFallback(TransferInfo calldata _transfer, bytes calldata _message) private returns (bool) { (bool ok, bytes memory res) = address(_transfer.receiver).call{value: msg.value}( abi.encodeWithSelector( IMessageReceiverApp.executeMessageWithTransferFallback.selector, _transfer.sender, _transfer.token, _transfer.amount, _transfer.srcChainId, _message ) ); if (ok) { bool success = abi.decode((res), (bool)); return success; } return false; } function executeMessageWithTransferRefund(TransferInfo calldata _transfer, bytes calldata _message) private returns (bool) { (bool ok, bytes memory res) = address(_transfer.receiver).call{value: msg.value}( abi.encodeWithSelector( IMessageReceiverApp.executeMessageWithTransferRefund.selector, _transfer.token, _transfer.amount, _message ) ); if (ok) { bool success = abi.decode((res), (bool)); return success; } return false; } function verifyTransfer(TransferInfo calldata _transfer) private view returns (bytes32) { bytes32 transferId; address bridgeAddr; if (_transfer.t == TransferType.LqSend) { transferId = keccak256( abi.encodePacked( _transfer.sender, _transfer.receiver, _transfer.token, _transfer.amount, _transfer.srcChainId, uint64(block.chainid), _transfer.refId ) ); bridgeAddr = liquidityBridge; require(IBridge(bridgeAddr).transfers(transferId) == true, "bridge relay not exist"); } else if (_transfer.t == TransferType.LqWithdraw) { transferId = keccak256( abi.encodePacked( uint64(block.chainid), _transfer.seqnum, _transfer.receiver, _transfer.token, _transfer.amount ) ); bridgeAddr = liquidityBridge; require(IBridge(bridgeAddr).withdraws(transferId) == true, "bridge withdraw not exist"); } else if (_transfer.t == TransferType.PegMint || _transfer.t == TransferType.PegWithdraw) { transferId = keccak256( abi.encodePacked( _transfer.receiver, _transfer.token, _transfer.amount, _transfer.sender, _transfer.srcChainId, _transfer.refId ) ); if (_transfer.t == TransferType.PegMint) { bridgeAddr = pegBridge; require(IPeggedTokenBridge(bridgeAddr).records(transferId) == true, "mint record not exist"); } else { // _transfer.t == TransferType.PegWithdraw bridgeAddr = pegVault; require(IOriginalTokenVault(bridgeAddr).records(transferId) == true, "withdraw record not exist"); } } else if (_transfer.t == TransferType.PegMintV2 || _transfer.t == TransferType.PegWithdrawV2) { if (_transfer.t == TransferType.PegMintV2) { bridgeAddr = pegBridgeV2; } else { // TransferType.PegWithdrawV2 bridgeAddr = pegVaultV2; } transferId = keccak256( abi.encodePacked( _transfer.receiver, _transfer.token, _transfer.amount, _transfer.sender, _transfer.srcChainId, _transfer.refId, bridgeAddr ) ); if (_transfer.t == TransferType.PegMintV2) { require(IPeggedTokenBridgeV2(bridgeAddr).records(transferId) == true, "mint record not exist"); } else { // TransferType.PegWithdrawV2 require(IOriginalTokenVaultV2(bridgeAddr).records(transferId) == true, "withdraw record not exist"); } } return keccak256(abi.encodePacked(MsgType.MessageWithTransfer, bridgeAddr, transferId)); } function computeMessageOnlyId(RouteInfo calldata _route, bytes calldata _message) private pure returns (bytes32) { return keccak256( abi.encodePacked(MsgType.MessageOnly, _route.sender, _route.receiver, _route.srcChainId, _message) ); } function executeMessage(RouteInfo calldata _route, bytes calldata _message) private returns (bool) { (bool ok, bytes memory res) = address(_route.receiver).call{value: msg.value}( abi.encodeWithSelector( IMessageReceiverApp.executeMessage.selector, _route.sender, _route.srcChainId, _message ) ); if (ok) { bool success = abi.decode((res), (bool)); return success; } return false; } // ================= contract addr config ================= function setLiquidityBridge(address _addr) public onlyOwner { require(_addr != address(0), "invalid address"); liquidityBridge = _addr; emit LiquidityBridgeUpdated(liquidityBridge); } function setPegBridge(address _addr) public onlyOwner { require(_addr != address(0), "invalid address"); pegBridge = _addr; emit PegBridgeUpdated(pegBridge); } function setPegVault(address _addr) public onlyOwner { require(_addr != address(0), "invalid address"); pegVault = _addr; emit PegVaultUpdated(pegVault); } function setPegBridgeV2(address _addr) public onlyOwner { require(_addr != address(0), "invalid address"); pegBridgeV2 = _addr; emit PegBridgeV2Updated(pegBridgeV2); } function setPegVaultV2(address _addr) public onlyOwner { require(_addr != address(0), "invalid address"); pegVaultV2 = _addr; emit PegVaultV2Updated(pegVaultV2); } }
// SPDX-License-Identifier: GPL-3.0-only pragma solidity >=0.8.0; interface IBridge { function send( address _receiver, address _token, uint256 _amount, uint64 _dstChainId, uint64 _nonce, uint32 _maxSlippage ) external; function relay( bytes calldata _relayRequest, bytes[] calldata _sigs, address[] calldata _signers, uint256[] calldata _powers ) external; function transfers(bytes32 transferId) external view returns (bool); function withdraws(bytes32 withdrawId) external view returns (bool); /** * @notice Verifies that a message is signed by a quorum among the signers. * @param _msg signed message * @param _sigs list of signatures sorted by signer addresses in ascending order * @param _signers sorted list of current signers * @param _powers powers of current signers */ function verifySigs( bytes memory _msg, bytes[] calldata _sigs, address[] calldata _signers, uint256[] calldata _powers ) external view; }
// SPDX-License-Identifier: GPL-3.0-only pragma solidity >=0.8.0; interface IOriginalTokenVault { /** * @notice Lock original tokens to trigger mint at a remote chain's PeggedTokenBridge * @param _token local token address * @param _amount locked token amount * @param _mintChainId destination chainId to mint tokens * @param _mintAccount destination account to receive minted tokens * @param _nonce user input to guarantee unique depositId */ function deposit( address _token, uint256 _amount, uint64 _mintChainId, address _mintAccount, uint64 _nonce ) external; function records(bytes32 recordId) external view returns (bool); }
// SPDX-License-Identifier: GPL-3.0-only pragma solidity >=0.8.0; interface IOriginalTokenVaultV2 { /** * @notice Lock original tokens to trigger mint at a remote chain's PeggedTokenBridge * @param _token local token address * @param _amount locked token amount * @param _mintChainId destination chainId to mint tokens * @param _mintAccount destination account to receive minted tokens * @param _nonce user input to guarantee unique depositId */ function deposit( address _token, uint256 _amount, uint64 _mintChainId, address _mintAccount, uint64 _nonce ) external returns (bytes32); function records(bytes32 recordId) external view returns (bool); }
// SPDX-License-Identifier: GPL-3.0-only pragma solidity >=0.8.0; interface IPeggedTokenBridge { /** * @notice Burn tokens to trigger withdrawal at a remote chain's OriginalTokenVault * @param _token local token address * @param _amount locked token amount * @param _withdrawAccount account who withdraw original tokens on the remote chain * @param _nonce user input to guarantee unique depositId */ function burn( address _token, uint256 _amount, address _withdrawAccount, uint64 _nonce ) external; function records(bytes32 recordId) external view returns (bool); }
// SPDX-License-Identifier: GPL-3.0-only pragma solidity >=0.8.0; interface IPeggedTokenBridgeV2 { /** * @notice Burn pegged tokens to trigger a cross-chain withdrawal of the original tokens at a remote chain's * OriginalTokenVault, or mint at another remote chain * @param _token The pegged token address. * @param _amount The amount to burn. * @param _toChainId If zero, withdraw from original vault; otherwise, the remote chain to mint tokens. * @param _toAccount The account to receive tokens on the remote chain * @param _nonce A number to guarantee unique depositId. Can be timestamp in practice. */ function burn( address _token, uint256 _amount, uint64 _toChainId, address _toAccount, uint64 _nonce ) external returns (bytes32); function records(bytes32 recordId) external view returns (bool); }
// SPDX-License-Identifier: GPL-3.0-only pragma solidity >=0.8.15; import "./IMessageReceiverApp.sol"; interface ITransferSwapper { function nativeWrap() external view returns (address); /** * @notice Called by MessageBus (MessageBusReceiver) to process refund of the original transfer from this contract * @param _token The token address of the original transfer * @param _amount The amount of the original transfer * @param _message The same message associated with the original transfer * @param _executor Address who called the MessageBus execution function */ function executeMessageWithTransferRefundFromAdapter( address _token, uint256 _amount, bytes calldata _message, address _executor ) external payable returns (IMessageReceiverApp.ExecutionStatus); }
// SPDX-License-Identifier: GPL-3.0-only pragma solidity >=0.8.15; import "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol"; import "@openzeppelin/contracts/token/ERC20/IERC20.sol"; import "@openzeppelin/contracts/access/Ownable.sol"; import "../interfaces/IBridgeAdapter.sol"; import "../interfaces/IBridgeStargate.sol"; import "../interfaces/ITransferSwapper.sol"; import "../interfaces/IWETH.sol"; import "../lib/NativeWrap.sol"; contract StargateAdapter is IBridgeAdapter, NativeWrap { using SafeERC20 for IERC20; mapping(address => bool) public supportedRouters; mapping(bytes32 => bool) public transfers; event SupportedRouterUpdated(address router, bool enabled); constructor(address _nativeWrap, address[] memory _routers) NativeWrap(_nativeWrap) { for (uint256 i = 0; i < _routers.length; i++) { require(_routers[i] != address(0), "nop"); supportedRouters[_routers[i]] = true; } } struct StargateParams { // a unique identifier that is uses to dedup transfers // this value is the a timestamp sent from frontend, but in theory can be any unique number uint64 nonce; uint256 srcPoolId; uint256 dstPoolId; uint256 minReceivedAmt; // defines the slippage, the min qty you would accept on the destination uint16 stargateDstChainId; // stargate defines chain id in its way address router; // the target router, should be in the <ref>supportedRouters</ref> } function bridge( uint64 _dstChainId, address _receiver, uint256 _amount, address _token, bytes memory _bridgeParams, bytes memory //_requestMessage // Not used for now, as stargate messaging is not supported in this version ) external payable returns (bytes memory bridgeResp) { StargateParams memory params = abi.decode((_bridgeParams), (StargateParams)); require(supportedRouters[params.router], "illegal router"); bytes32 transferId = keccak256( abi.encodePacked(_receiver, _token, _amount, _dstChainId, params.nonce, uint64(block.chainid)) ); require(transfers[transferId] == false, "transfer exists"); transfers[transferId] = true; IERC20(_token).safeTransferFrom(msg.sender, address(this), _amount); uint64 outboundNonce = swap(_token, _receiver, _amount, params); return abi.encodePacked(outboundNonce); } function swap( address _token, address _receiver, uint256 _amount, StargateParams memory params ) private returns (uint64 outboundNonce) { IBridgeStargate router = IBridgeStargate(params.router); if (_token == nativeWrap) { IWETH(_token).withdraw(_amount); router.swapETH{value: msg.value + _amount}( params.stargateDstChainId, payable(_receiver), abi.encodePacked(_receiver), _amount, params.minReceivedAmt ); } else { IERC20(_token).safeApprove(params.router, _amount); router.swap{value: msg.value}( params.stargateDstChainId, params.srcPoolId, params.dstPoolId, payable(_receiver), _amount, params.minReceivedAmt, IBridgeStargate.lzTxObj(0, 0, "0x"), abi.encodePacked(_receiver), bytes("") // not supported additional msg in this version ); IERC20(_token).safeApprove(params.router, 0); } // query current nonce address stargateInternalBridge; if (_token == nativeWrap) { stargateInternalBridge = IBridgeStargate(router.stargateRouter()).bridge(); } else { stargateInternalBridge = router.bridge(); } address layerZeroEndpoint = IStargateInternalBridge(stargateInternalBridge).layerZeroEndpoint(); outboundNonce = ILayerZeroEndpoint(layerZeroEndpoint).getOutboundNonce( params.stargateDstChainId, stargateInternalBridge ); } function setSupportedRouter(address _router, bool _enabled) external onlyOwner { bool enabled = supportedRouters[_router]; require(enabled != _enabled, "nop"); supportedRouters[_router] = _enabled; emit SupportedRouterUpdated(_router, _enabled); } }
// SPDX-License-Identifier: GPL-3.0-only pragma solidity >=0.8.15; interface IBridgeStargate { struct lzTxObj { uint256 dstGasForCall; uint256 dstNativeAmount; bytes dstNativeAddr; } // only in non RouterETH function swap( uint16 _dstChainId, uint256 _srcPoolId, uint256 _dstPoolId, address payable _refundAddress, uint256 _amountLD, uint256 _minAmountLD, lzTxObj memory _lzTxParams, bytes calldata _to, bytes calldata _payload ) external payable; // only in non RouterETH function bridge() external pure returns (address); // only in RouterETH function swapETH( uint16 _dstChainId, // destination Stargate chainId address payable _refundAddress, // refund additional messageFee to this address bytes calldata _toAddress, // the receiver of the destination ETH uint256 _amountLD, // the amount, in Local Decimals, to be swapped uint256 _minAmountLD // the minimum amount accepted out on destination ) external payable; // only in RouterETH function stargateRouter() external pure returns (address); } interface IStargateInternalBridge { function layerZeroEndpoint() external pure returns (address); } interface ILayerZeroEndpoint { function getOutboundNonce(uint16 _dstChainId, address _srcAddress) external view returns (uint64); }
// SPDX-License-Identifier: GPL-3.0-only pragma solidity >=0.8.15; import "@openzeppelin/contracts/access/Ownable.sol"; /** * @title A codec registry that maps swap function selectors to corresponding codec addresses * @author Padoriku */ abstract contract NativeWrap is Ownable { address public nativeWrap; event NativeWrapUpdated(address nativeWrap); constructor(address _nativeWrap) { require(_nativeWrap != address(0), "zero native wrap"); nativeWrap = _nativeWrap; } function setNativeWrap(address _nativeWrap) external onlyOwner { nativeWrap = _nativeWrap; } receive() external payable {} }
// SPDX-License-Identifier: GPL-3.0-only pragma solidity >=0.8.15; import "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol"; import "@openzeppelin/contracts/token/ERC20/IERC20.sol"; import "@openzeppelin/contracts/access/Ownable.sol"; import "../interfaces/IBridgeAdapter.sol"; import "../interfaces/IHyphenLiquidityPool.sol"; import "../interfaces/IWETH.sol"; import "../lib/NativeWrap.sol"; contract HyphenAdapter is IBridgeAdapter, NativeWrap { using SafeERC20 for IERC20; address public pool; event PoolUpdated(address pool); constructor(address _pool, address _nativeWrap) NativeWrap(_nativeWrap) { require(_pool != address(0), "zero address"); pool = _pool; } function bridge( uint64 _dstChainId, address _receiver, uint256 _amount, address _token, bytes memory, // _bridgeParams bytes memory // _requestMessage ) external payable returns (bytes memory bridgeResp) { IERC20(_token).safeTransferFrom(msg.sender, address(this), _amount); if (_token == nativeWrap) { // depositErc20 doesn't work for WETH, so we have to convert it back to native first IWETH(nativeWrap).withdraw(_amount); IHyphenLiquidityPool(pool).depositNative{value: _amount}(_receiver, _dstChainId, "chainhop"); } else { IERC20(_token).safeIncreaseAllowance(pool, _amount); IHyphenLiquidityPool(pool).depositErc20(_dstChainId, _token, _receiver, _amount, "chainhop"); } // hyphen uses src tx hash to track history so bridgeResp is not needed. returning empty return bridgeResp; } function setPool(address _pool) external onlyOwner { pool = _pool; emit PoolUpdated(_pool); } }
// SPDX-License-Identifier: MIT pragma solidity 0.8.15; interface IHyphenLiquidityPool { function depositErc20( uint256 toChainId, address tokenAddress, address receiver, uint256 amount, string calldata tag ) external; function depositNative( address receiver, uint256 toChainId, string calldata tag ) external payable; }
// SPDX-License-Identifier: GPL-3.0-only pragma solidity >=0.8.15; import "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol"; import "@openzeppelin/contracts/token/ERC20/IERC20.sol"; import "@openzeppelin/contracts/access/Ownable.sol"; import "../interfaces/IBridgeAdapter.sol"; import "../interfaces/IWETH.sol"; import "../interfaces/IHopBridge.sol"; import "../lib/NativeWrap.sol"; contract HopAdapter is IBridgeAdapter, NativeWrap { using SafeERC20 for IERC20; bool public immutable isL1; mapping(address => address) public bridges; event BridgeUpdated(address[] tokens, address[] bridges); constructor( address[] memory _tokens, address[] memory _bridges, bool _isL1, address _nativeWrap ) NativeWrap(_nativeWrap) { isL1 = _isL1; _setBridges(_tokens, _bridges); } struct BridgeParams { uint256 amountOutMin; uint256 deadline; uint256 bonderFee; } function bridge( uint64 _dstChainId, address _receiver, uint256 _amount, address _token, bytes memory _bridgeParams, bytes memory //_requestMessage ) external payable returns (bytes memory bridgeResp) { BridgeParams memory p = abi.decode(_bridgeParams, (BridgeParams)); address _bridge = bridges[_token]; require(_bridge != address(0), "bridge not found"); IERC20(_token).safeTransferFrom(msg.sender, address(this), _amount); if (isL1) { uint256 value; if (_token == nativeWrap) { IWETH(_token).withdraw(_amount); value = _amount; } else { IERC20(_token).safeIncreaseAllowance(_bridge, _amount); } IHopBridge(_bridge).sendToL2{value: value}( _dstChainId, _receiver, _amount, p.amountOutMin, p.deadline, address(0), 0 ); } else { uint256 value; if (_token == nativeWrap && IHopBridge(_bridge).l2CanonicalTokenIsEth()) { IWETH(_token).withdraw(_amount); value = _amount; } else { IERC20(_token).safeIncreaseAllowance(_bridge, _amount); } IHopBridge(_bridge).swapAndSend{value: value}( _dstChainId, _receiver, _amount, p.bonderFee, p.amountOutMin, p.deadline, p.amountOutMin, p.deadline ); } return bridgeResp; } function setBridges(address[] calldata _tokens, address[] calldata _bridges) external onlyOwner { _setBridges(_tokens, _bridges); } function _setBridges(address[] memory _tokens, address[] memory _bridges) private { require(_tokens.length == _bridges.length, "len mismatch"); for (uint8 i = 0; i < _tokens.length; i++) { bridges[_tokens[i]] = _bridges[i]; } emit BridgeUpdated(_tokens, _bridges); } }
// SPDX-License-Identifier: MIT pragma solidity >=0.8.15; import "@openzeppelin/contracts/token/ERC20/ERC20.sol"; interface IHopBridge { // functions in Hop's L1Bridge function sendToL2( uint256 chainId, address recipient, uint256 amount, uint256 amountOutMin, uint256 deadline, address relayer, uint256 relayerFee ) external payable; // functions in Hop's AMM wrapper function l2CanonicalTokenIsEth() external view returns (bool); function swapAndSend( uint256 chainId, address recipient, uint256 amount, uint256 bonderFee, uint256 amountOutMin, uint256 deadline, uint256 destinationAmountOutMin, uint256 destinationDeadline ) external payable; }
// SPDX-License-Identifier: GPL-3.0-only pragma solidity >=0.8.15; import "@openzeppelin/contracts/token/ERC20/ERC20.sol"; contract WETH is ERC20 { constructor() ERC20("WETH", "WETH") { _mint(msg.sender, 1e26); } function deposit() external payable { _mint(msg.sender, msg.value); } function withdraw(uint256 _amount) external { _burn(msg.sender, _amount); (bool sent, ) = msg.sender.call{value: _amount, gas: 50000}(""); require(sent, "failed to send"); } receive() external payable {} }
// SPDX-License-Identifier: GPL-3.0-only pragma solidity 0.8.15; import "@openzeppelin/contracts/token/ERC20/ERC20.sol"; /** * @title A test ERC20 token. */ contract TestERC20 is ERC20 { uint256 public constant INITIAL_SUPPLY = 1e28; /** * @dev Constructor that gives msg.sender all of the existing tokens. */ constructor() ERC20("TestERC20", "TERC20") { _mint(msg.sender, INITIAL_SUPPLY); } }
// SPDX-License-Identifier: GPL-3.0-only pragma solidity >=0.8.15; import "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol"; import "@openzeppelin/contracts/token/ERC20/IERC20.sol"; import "@openzeppelin/contracts/access/Ownable.sol"; import "../lib/MessageSenderLib.sol"; import "../lib/MessageReceiverApp.sol"; import "../interfaces/IBridgeAdapter.sol"; import "../interfaces/ITransferSwapper.sol"; import "../interfaces/IIntermediaryOriginalToken.sol"; contract CBridgeAdapter is MessageReceiverApp, IBridgeAdapter { using SafeERC20 for IERC20; address public mainContract; event MainContractUpdated(address mainContract); modifier onlyMainContract() { require(msg.sender == mainContract, "caller is not main contract"); _; } constructor(address _messageBus) { messageBus = _messageBus; } struct CBridgeParams { // type of the bridge in cBridge to use (i.e. liquidity bridge, pegged token bridge, etc.) MsgDataTypes.BridgeSendType bridgeType; // user defined maximum allowed slippage (pip) at bridge uint32 maxSlippage; // if this field is set, this contract attempts to wrap the input OR src bridge out token // (as specified in the tokenIn field OR the output token in src SwapDescription[]) before // sending to the bridge. This field is determined by the backend when searching for routes address wrappedBridgeToken; // a unique identifier that cBridge uses to dedup transfers // this value is the a timestamp sent from frontend, but in theory can be any unique number uint64 nonce; } function bridge( uint64 _dstChainId, address _receiver, uint256 _amount, address _token, bytes memory _bridgeParams, bytes memory _requestMessage ) external payable onlyMainContract returns (bytes memory bridgeResp) { CBridgeParams memory params = abi.decode((_bridgeParams), (CBridgeParams)); IERC20(_token).safeTransferFrom(msg.sender, address(this), _amount); if (params.wrappedBridgeToken != address(0)) { address canonical = IIntermediaryOriginalToken(params.wrappedBridgeToken).canonical(); require(canonical == _token, "canonical != _token"); // non-standard implementation: actual token wrapping is done inside the token contract's // transferFrom(). Approving the wrapper token contract to pull the token we intend to // send so that when bridge contract calls wrapper.transferFrom() it automatically pulls // the original token from this contract, wraps it, then transfer the wrapper token from // this contract to bridge. IERC20(_token).safeApprove(params.wrappedBridgeToken, _amount); _token = params.wrappedBridgeToken; } bytes32 transferId = MessageSenderLib.sendMessageWithTransfer( _receiver, _token, _amount, _dstChainId, params.nonce, params.maxSlippage, _requestMessage, params.bridgeType, messageBus, msg.value ); if (params.wrappedBridgeToken != address(0)) { IERC20(IIntermediaryOriginalToken(params.wrappedBridgeToken).canonical()).safeApprove( params.wrappedBridgeToken, 0 ); } return abi.encodePacked(transferId); } function updateMainContract(address _mainContract) external onlyOwner { mainContract = _mainContract; emit MainContractUpdated(_mainContract); } /** * @notice Used to trigger refund when bridging fails due to large slippage * @dev only MessageBus can call this function, this requires the user to get sigs of the message from SGN * @dev Bridge contract *always* sends native token to its receiver (this contract) even though the _token field is always an ERC20 token * @param _token the token received by this contract * @param _amount the amount of token received by this contract * @return ok whether the processing is successful */ function executeMessageWithTransferRefund( address _token, uint256 _amount, bytes calldata _message, address _executor ) external payable override onlyMessageBus returns (ExecutionStatus) { uint256 nativeAmt = 0; ITransferSwapper main = ITransferSwapper(mainContract); if (_token != main.nativeWrap()) { IERC20(_token).safeApprove(mainContract, _amount); } else { nativeAmt = _amount; } ExecutionStatus status = main.executeMessageWithTransferRefundFromAdapter{value: nativeAmt}( _token, _amount, _message, _executor ); if (_token != main.nativeWrap()) { IERC20(_token).safeApprove(mainContract, 0); } return status; } receive() external payable {} }
// SPDX-License-Identifier: GPL-3.0-only pragma solidity >=0.8.15; interface IIntermediaryOriginalToken { function canonical() external view returns (address); }
// SPDX-License-Identifier: GPL-3.0-only pragma solidity >=0.8.15; import "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol"; import "@openzeppelin/contracts/token/ERC20/IERC20.sol"; import "@openzeppelin/contracts/access/Ownable.sol"; import "../interfaces/IBridgeAdapter.sol"; import "../interfaces/IBridgeAnyswap.sol"; contract AnyswapAdapter is IBridgeAdapter, Ownable { using SafeERC20 for IERC20; mapping(address => bool) public supportedRouters; mapping(bytes32 => bool) public transfers; event SupportedRouterUpdated(address router, bool enabled); constructor(address[] memory _anyswapRouters) { for (uint256 i = 0; i < _anyswapRouters.length; i++) { require(_anyswapRouters[i] != address(0), "nop"); supportedRouters[_anyswapRouters[i]] = true; } } struct AnyswapParams { // a unique identifier that is uses to dedup transfers // this value is the a timestamp sent from frontend, but in theory can be any unique number uint64 nonce; // the wrapped any token of the native address anyToken; // the target anyswap Router, should be in the <ref>supportedRouters</ref> address router; } function bridge( uint64 _dstChainId, address _receiver, uint256 _amount, address _token, // Note, here uses the address of the native bytes memory _bridgeParams, bytes memory //_requestMessage // Not used for now, as Anyswap messaging is not supported in this version ) external payable returns (bytes memory bridgeResp) { AnyswapParams memory params = abi.decode((_bridgeParams), (AnyswapParams)); require(supportedRouters[params.router], "illegal router"); bytes32 transferId = keccak256( abi.encodePacked(_receiver, _token, _amount, _dstChainId, params.nonce, uint64(block.chainid)) ); require(transfers[transferId] == false, "transfer exists"); transfers[transferId] = true; IERC20(_token).safeTransferFrom(msg.sender, address(this), _amount); IERC20(_token).safeApprove(params.router, _amount); if (IUnderlying(params.anyToken).underlying() != address(0)) { IBridgeAnyswap(params.router).anySwapOutUnderlying(params.anyToken, _receiver, _amount, _dstChainId); } else { IBridgeAnyswap(params.router).anySwapOut(params.anyToken, _receiver, _amount, _dstChainId); } IERC20(_token).safeApprove(params.router, 0); return abi.encodePacked(transferId); } function setSupportedRouter(address _router, bool _enabled) external onlyOwner { bool enabled = supportedRouters[_router]; require(enabled != _enabled, "nop"); supportedRouters[_router] = _enabled; emit SupportedRouterUpdated(_router, _enabled); } }
// SPDX-License-Identifier: GPL-3.0-only pragma solidity >=0.8.15; interface IBridgeAnyswap { // Swaps `amount` `token` from this chain to `toChainID` chain with recipient `to` function anySwapOut(address token, address to, uint amount, uint toChainID) external; // Swaps `amount` `token` from this chain to `toChainID` chain with recipient `to` by minting with `underlying` function anySwapOutUnderlying(address token, address to, uint amount, uint toChainID) external; } interface IUnderlying { function underlying() external view returns (address); }
// SPDX-License-Identifier: GPL-3.0-only pragma solidity >=0.8.15; import "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol"; import "@openzeppelin/contracts/token/ERC20/IERC20.sol"; import "@openzeppelin/contracts/access/Ownable.sol"; import "../interfaces/IBridgeAdapter.sol"; import "../interfaces/ISpokePool.sol"; contract AcrossAdapter is IBridgeAdapter, Ownable { using SafeERC20 for IERC20; address public spokePool; event SpokePoolUpdated(address spokePool); constructor(address _spokePool) { spokePool = _spokePool; } struct BridgeParams { uint64 relayerFeePct; uint32 quoteTimestamp; } function bridge( uint64 _dstChainId, address _receiver, uint256 _amount, address _token, bytes memory _bridgeParams, bytes memory //_requestMessage ) external payable returns (bytes memory bridgeResp) { BridgeParams memory params = abi.decode(_bridgeParams, (BridgeParams)); IERC20(_token).safeTransferFrom(msg.sender, address(this), _amount); IERC20(_token).approve(spokePool, _amount); uint32 depositId = ISpokePool(spokePool).numberOfDeposits(); ISpokePool(spokePool).deposit( _receiver, _token, _amount, _dstChainId, params.relayerFeePct, params.quoteTimestamp ); return abi.encode(depositId); } function setSpokePool(address _spokePool) external onlyOwner { spokePool = _spokePool; emit SpokePoolUpdated(_spokePool); } // convenience function to make encoding bridge params easier using ABI generated go code function encodeBridgeParams(BridgeParams memory _params) external {} }
// SPDX-License-Identifier: GPL-3.0-only pragma solidity ^0.8.0; /** * @notice Contains common data structures and functions used by all SpokePool implementations. */ interface ISpokePool { // This leaf is meant to be decoded in the SpokePool to pay out successful relayers. struct RelayerRefundLeaf { // This is the amount to return to the HubPool. This occurs when there is a PoolRebalanceLeaf netSendAmount that // is negative. This is just the negative of this value. uint256 amountToReturn; // Used to verify that this is being executed on the correct destination chainId. uint256 chainId; // This array designates how much each of those addresses should be refunded. uint256[] refundAmounts; // Used as the index in the bitmap to track whether this leaf has been executed or not. uint32 leafId; // The associated L2TokenAddress that these claims apply to. address l2TokenAddress; // Must be same length as refundAmounts and designates each address that must be refunded. address[] refundAddresses; } // This struct represents the data to fully specify a relay. If any portion of this data differs, the relay is // considered to be completely distinct. Only one relay for a particular depositId, chainId pair should be // considered valid and repaid. This data is hashed and inserted into the slow relay merkle root so that an off // chain validator can choose when to refund slow relayers. struct RelayData { // The address that made the deposit on the origin chain. address depositor; // The recipient address on the destination chain. address recipient; // The corresponding token address on the destination chain. address destinationToken; // The total relay amount before fees are taken out. uint256 amount; // Origin chain id. uint256 originChainId; // Destination chain id. uint256 destinationChainId; // The LP Fee percentage computed by the relayer based on the deposit's quote timestamp // and the HubPool's utilization. uint64 realizedLpFeePct; // The relayer fee percentage specified in the deposit. uint64 relayerFeePct; // The id uniquely identifying this deposit on the origin chain. uint32 depositId; } // Stores collection of merkle roots that can be published to this contract from the HubPool, which are referenced // by "data workers" via inclusion proofs to execute leaves in the roots. struct RootBundle { // Merkle root of slow relays that were not fully filled and whose recipient is still owed funds from the LP pool. bytes32 slowRelayRoot; // Merkle root of relayer refunds for successful relays. bytes32 relayerRefundRoot; // This is a 2D bitmap tracking which leaves in the relayer refund root have been claimed, with max size of // 256x(2^248) leaves per root. mapping(uint256 => uint256) claimedBitmap; } event FilledRelay( uint256 amount, uint256 totalFilledAmount, uint256 fillAmount, uint256 repaymentChainId, uint256 originChainId, uint256 destinationChainId, uint64 relayerFeePct, uint64 appliedRelayerFeePct, uint64 realizedLpFeePct, uint32 depositId, address destinationToken, address indexed relayer, address indexed depositor, address recipient, bool isSlowRelay ); function setCrossDomainAdmin(address newCrossDomainAdmin) external; function setHubPool(address newHubPool) external; function setEnableRoute( address originToken, uint256 destinationChainId, bool enable ) external; function setDepositQuoteTimeBuffer(uint32 buffer) external; function relayRootBundle(bytes32 relayerRefundRoot, bytes32 slowRelayRoot) external; function emergencyDeleteRootBundle(uint256 rootBundleId) external; function numberOfDeposits() external view returns (uint32 numberOfDeposits); function deposit( address recipient, address originToken, uint256 amount, uint256 destinationChainId, uint64 relayerFeePct, uint32 quoteTimestamp ) external payable; function speedUpDeposit( address depositor, uint64 newRelayerFeePct, uint32 depositId, bytes memory depositorSignature ) external; function fillRelay( address depositor, address recipient, address destinationToken, uint256 amount, uint256 maxTokensToSend, uint256 repaymentChainId, uint256 originChainId, uint64 realizedLpFeePct, uint64 relayerFeePct, uint32 depositId ) external; function fillRelayWithUpdatedFee( address depositor, address recipient, address destinationToken, uint256 amount, uint256 maxTokensToSend, uint256 repaymentChainId, uint256 originChainId, uint64 realizedLpFeePct, uint64 relayerFeePct, uint64 newRelayerFeePct, uint32 depositId, bytes memory depositorSignature ) external; function executeSlowRelayLeaf( address depositor, address recipient, address destinationToken, uint256 amount, uint256 originChainId, uint64 realizedLpFeePct, uint64 relayerFeePct, uint32 depositId, uint32 rootBundleId, bytes32[] memory proof ) external; function executeRelayerRefundLeaf( uint32 rootBundleId, ISpokePool.RelayerRefundLeaf memory relayerRefundLeaf, bytes32[] memory proof ) external; function chainId() external view returns (uint256); }
// SPDX-License-Identifier: GPL-3.0-only pragma solidity 0.8.15; import "./MessageBusSender.sol"; import "./MessageBusReceiver.sol"; contract MessageBus is MessageBusSender, MessageBusReceiver { constructor( ISigsVerifier _sigsVerifier, address _liquidityBridge, address _pegBridge, address _pegVault, address _pegBridgeV2, address _pegVaultV2 ) MessageBusSender(_sigsVerifier) MessageBusReceiver(_liquidityBridge, _pegBridge, _pegVault, _pegBridgeV2, _pegVaultV2) {} // this is only to be called by Proxy via delegateCall as initOwner will require _owner is 0. // so calling init on this contract directly will guarantee to fail function init( address _liquidityBridge, address _pegBridge, address _pegVault, address _pegBridgeV2, address _pegVaultV2 ) external { // MUST manually call ownable init and must only call once initOwner(); // we don't need sender init as _sigsVerifier is immutable so already in the deployed code initReceiver(_liquidityBridge, _pegBridge, _pegVault, _pegBridgeV2, _pegVaultV2); } }
// SPDX-License-Identifier: GPL-3.0-only // Code generated by protoc-gen-sol. DO NOT EDIT. // source: bridge.proto pragma solidity 0.8.15; import "./Pb.sol"; library PbBridge { using Pb for Pb.Buffer; // so we can call Pb funcs on Buffer obj struct Relay { address sender; // tag: 1 address receiver; // tag: 2 address token; // tag: 3 uint256 amount; // tag: 4 uint64 srcChainId; // tag: 5 uint64 dstChainId; // tag: 6 bytes32 srcTransferId; // tag: 7 } // end struct Relay function decRelay(bytes memory raw) internal pure returns (Relay memory m) { Pb.Buffer memory buf = Pb.fromBytes(raw); uint256 tag; Pb.WireType wire; while (buf.hasMore()) { (tag, wire) = buf.decKey(); if (false) {} // solidity has no switch/case else if (tag == 1) { m.sender = Pb._address(buf.decBytes()); } else if (tag == 2) { m.receiver = Pb._address(buf.decBytes()); } else if (tag == 3) { m.token = Pb._address(buf.decBytes()); } else if (tag == 4) { m.amount = Pb._uint256(buf.decBytes()); } else if (tag == 5) { m.srcChainId = uint64(buf.decVarint()); } else if (tag == 6) { m.dstChainId = uint64(buf.decVarint()); } else if (tag == 7) { m.srcTransferId = Pb._bytes32(buf.decBytes()); } else { buf.skipValue(wire); } // skip value of unknown tag } } // end decoder Relay }
// SPDX-License-Identifier: GPL-3.0-only pragma solidity 0.8.15; import "@openzeppelin/contracts/token/ERC20/IERC20.sol"; import "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol"; import "./PbBridge.sol"; import "./Pool.sol"; contract Bridge is Pool { using SafeERC20 for IERC20; // liquidity events event Send( bytes32 transferId, address sender, address receiver, address token, uint256 amount, uint64 dstChainId, uint64 nonce, uint32 maxSlippage ); event Relay( bytes32 transferId, address sender, address receiver, address token, uint256 amount, uint64 srcChainId, bytes32 srcTransferId ); // gov events event MinSendUpdated(address token, uint256 amount); event MaxSendUpdated(address token, uint256 amount); mapping(bytes32 => bool) public transfers; mapping(address => uint256) public minSend; // send _amount must > minSend mapping(address => uint256) public maxSend; // min allowed max slippage uint32 value is slippage * 1M, eg. 0.5% -> 5000 uint32 public minimalMaxSlippage; /** * @notice Send a cross-chain transfer via the liquidity pool-based bridge. * NOTE: This function DOES NOT SUPPORT fee-on-transfer / rebasing tokens. * @param _receiver The address of the receiver. * @param _token The address of the token. * @param _amount The amount of the transfer. * @param _dstChainId The destination chain ID. * @param _nonce A number input to guarantee uniqueness of transferId. Can be timestamp in practice. * @param _maxSlippage The max slippage accepted, given as percentage in point (pip). Eg. 5000 means 0.5%. * Must be greater than minimalMaxSlippage. Receiver is guaranteed to receive at least (100% - max slippage percentage) * amount or the * transfer can be refunded. */ function send( address _receiver, address _token, uint256 _amount, uint64 _dstChainId, uint64 _nonce, uint32 _maxSlippage // slippage * 1M, eg. 0.5% -> 5000 ) external nonReentrant whenNotPaused { bytes32 transferId = _send(_receiver, _token, _amount, _dstChainId, _nonce, _maxSlippage); IERC20(_token).safeTransferFrom(msg.sender, address(this), _amount); emit Send(transferId, msg.sender, _receiver, _token, _amount, _dstChainId, _nonce, _maxSlippage); } /** * @notice Send a cross-chain transfer via the liquidity pool-based bridge using the native token. * @param _receiver The address of the receiver. * @param _amount The amount of the transfer. * @param _dstChainId The destination chain ID. * @param _nonce A unique number. Can be timestamp in practice. * @param _maxSlippage The max slippage accepted, given as percentage in point (pip). Eg. 5000 means 0.5%. * Must be greater than minimalMaxSlippage. Receiver is guaranteed to receive at least (100% - max slippage percentage) * amount or the * transfer can be refunded. */ function sendNative( address _receiver, uint256 _amount, uint64 _dstChainId, uint64 _nonce, uint32 _maxSlippage ) external payable nonReentrant whenNotPaused { require(msg.value == _amount, "Amount mismatch"); require(nativeWrap != address(0), "Native wrap not set"); bytes32 transferId = _send(_receiver, nativeWrap, _amount, _dstChainId, _nonce, _maxSlippage); IWETH(nativeWrap).deposit{value: _amount}(); emit Send(transferId, msg.sender, _receiver, nativeWrap, _amount, _dstChainId, _nonce, _maxSlippage); } function _send( address _receiver, address _token, uint256 _amount, uint64 _dstChainId, uint64 _nonce, uint32 _maxSlippage ) private returns (bytes32) { require(_amount > minSend[_token], "amount too small"); require(maxSend[_token] == 0 || _amount <= maxSend[_token], "amount too large"); require(_maxSlippage > minimalMaxSlippage, "max slippage too small"); bytes32 transferId = keccak256( // uint64(block.chainid) for consistency as entire system uses uint64 for chain id // len = 20 + 20 + 20 + 32 + 8 + 8 + 8 = 116 abi.encodePacked(msg.sender, _receiver, _token, _amount, _dstChainId, _nonce, uint64(block.chainid)) ); require(transfers[transferId] == false, "transfer exists"); transfers[transferId] = true; return transferId; } /** * @notice Relay a cross-chain transfer sent from a liquidity pool-based bridge on another chain. * @param _relayRequest The serialized Relay protobuf. * @param _sigs The list of signatures sorted by signing addresses in ascending order. A relay must be signed-off by * +2/3 of the bridge's current signing power to be delivered. * @param _signers The sorted list of signers. * @param _powers The signing powers of the signers. */ function relay( bytes calldata _relayRequest, bytes[] calldata _sigs, address[] calldata _signers, uint256[] calldata _powers ) external whenNotPaused { bytes32 domain = keccak256(abi.encodePacked(block.chainid, address(this), "Relay")); verifySigs(abi.encodePacked(domain, _relayRequest), _sigs, _signers, _powers); PbBridge.Relay memory request = PbBridge.decRelay(_relayRequest); // len = 20 + 20 + 20 + 32 + 8 + 8 + 32 = 140 bytes32 transferId = keccak256( abi.encodePacked( request.sender, request.receiver, request.token, request.amount, request.srcChainId, request.dstChainId, request.srcTransferId ) ); require(transfers[transferId] == false, "transfer exists"); transfers[transferId] = true; _updateVolume(request.token, request.amount); uint256 delayThreshold = delayThresholds[request.token]; if (delayThreshold > 0 && request.amount > delayThreshold) { _addDelayedTransfer(transferId, request.receiver, request.token, request.amount); } else { _sendToken(request.receiver, request.token, request.amount); } emit Relay( transferId, request.sender, request.receiver, request.token, request.amount, request.srcChainId, request.srcTransferId ); } function setMinSend(address[] calldata _tokens, uint256[] calldata _amounts) external onlyGovernor { require(_tokens.length == _amounts.length, "length mismatch"); for (uint256 i = 0; i < _tokens.length; i++) { minSend[_tokens[i]] = _amounts[i]; emit MinSendUpdated(_tokens[i], _amounts[i]); } } function setMaxSend(address[] calldata _tokens, uint256[] calldata _amounts) external onlyGovernor { require(_tokens.length == _amounts.length, "length mismatch"); for (uint256 i = 0; i < _tokens.length; i++) { maxSend[_tokens[i]] = _amounts[i]; emit MaxSendUpdated(_tokens[i], _amounts[i]); } } function setMinimalMaxSlippage(uint32 _minimalMaxSlippage) external onlyGovernor { minimalMaxSlippage = _minimalMaxSlippage; } // This is needed to receive ETH when calling `IWETH.withdraw` receive() external payable {} }
// SPDX-License-Identifier: GPL-3.0-only pragma solidity >=0.8.15; import "../interfaces/ICodec.sol"; import "../interfaces/ISwapRouter.sol"; contract UniswapV3ExactInputCodec is ICodec { function decodeCalldata(ICodec.SwapDescription calldata _swap) external pure returns ( uint256 amountIn, address tokenIn, address tokenOut ) { ISwapRouter.ExactInputParams memory data = abi.decode((_swap.data[4:]), (ISwapRouter.ExactInputParams)); // path is in the format of abi.encodedPacked(address tokenIn, [uint24 fee, address token[, uint24 fee, address token]...]) require((data.path.length - 20) % 23 == 0, "malformed path"); // first 20 bytes is tokenIn tokenIn = address(bytes20(copySubBytes(data.path, 0, 20))); // last 20 bytes is tokenOut tokenOut = address(bytes20(copySubBytes(data.path, data.path.length - 20, data.path.length))); amountIn = data.amountIn; } function encodeCalldataWithOverride( bytes calldata _data, uint256 _amountInOverride, address _receiverOverride ) external pure returns (bytes memory swapCalldata) { bytes4 selector = bytes4(_data); ISwapRouter.ExactInputParams memory data = abi.decode((_data[4:]), (ISwapRouter.ExactInputParams)); data.amountIn = _amountInOverride; data.recipient = _receiverOverride; return abi.encodeWithSelector(selector, data); } // basically a bytes' version of byteN[from:to] execpt it copies function copySubBytes( bytes memory data, uint256 from, uint256 to ) private pure returns (bytes memory ret) { require(to <= data.length, "index overflow"); uint256 len = to - from; ret = new bytes(len); for (uint256 i = 0; i < len; i++) { ret[i] = data[i + from]; } } }
// SPDX-License-Identifier: GPL-2.0-or-later pragma solidity >=0.8.15; pragma abicoder v2; /// @title Callback for IUniswapV3PoolActions#swap /// @notice Any contract that calls IUniswapV3PoolActions#swap must implement this interface interface IUniswapV3SwapCallback { /// @notice Called to `msg.sender` after executing a swap via IUniswapV3Pool#swap. /// @dev In the implementation you must pay the pool tokens owed for the swap. /// The caller of this method must be checked to be a UniswapV3Pool deployed by the canonical UniswapV3Factory. /// amount0Delta and amount1Delta can both be 0 if no tokens were swapped. /// @param amount0Delta The amount of token0 that was sent (negative) or must be received (positive) by the pool by /// the end of the swap. If positive, the callback must send that amount of token0 to the pool. /// @param amount1Delta The amount of token1 that was sent (negative) or must be received (positive) by the pool by /// the end of the swap. If positive, the callback must send that amount of token1 to the pool. /// @param data Any data passed through by the caller via the IUniswapV3PoolActions#swap call function uniswapV3SwapCallback( int256 amount0Delta, int256 amount1Delta, bytes calldata data ) external; } /// @title Router token swapping functionality /// @notice Functions for swapping tokens via Uniswap V3 interface ISwapRouter is IUniswapV3SwapCallback { struct ExactInputSingleParams { address tokenIn; address tokenOut; uint24 fee; address recipient; uint256 deadline; uint256 amountIn; uint256 amountOutMinimum; uint160 sqrtPriceLimitX96; } /// @notice Swaps `amountIn` of one token for as much as possible of another token /// @param params The parameters necessary for the swap, encoded as `ExactInputSingleParams` in calldata /// @return amountOut The amount of the received token function exactInputSingle(ExactInputSingleParams calldata params) external payable returns (uint256 amountOut); struct ExactInputParams { bytes path; address recipient; uint256 deadline; uint256 amountIn; uint256 amountOutMinimum; } /// @notice Swaps `amountIn` of one token for as much as possible of another along the specified path /// @param params The parameters necessary for the multi-hop swap, encoded as `ExactInputParams` in calldata /// @return amountOut The amount of the received token function exactInput(ExactInputParams calldata params) external payable returns (uint256 amountOut); struct ExactOutputSingleParams { address tokenIn; address tokenOut; uint24 fee; address recipient; uint256 deadline; uint256 amountOut; uint256 amountInMaximum; uint160 sqrtPriceLimitX96; } /// @notice Swaps as little as possible of one token for `amountOut` of another token /// @param params The parameters necessary for the swap, encoded as `ExactOutputSingleParams` in calldata /// @return amountIn The amount of the input token function exactOutputSingle(ExactOutputSingleParams calldata params) external payable returns (uint256 amountIn); struct ExactOutputParams { bytes path; address recipient; uint256 deadline; uint256 amountOut; uint256 amountInMaximum; } /// @notice Swaps as little as possible of one token for `amountOut` of another along the specified path (reversed) /// @param params The parameters necessary for the multi-hop swap, encoded as `ExactOutputParams` in calldata /// @return amountIn The amount of the input token function exactOutput(ExactOutputParams calldata params) external payable returns (uint256 amountIn); }
// SPDX-License-Identifier: GPL-3.0-only pragma solidity >=0.8.15; import "../interfaces/ICodec.sol"; contract UniswapV2SwapExactTokensForTokensCodec is ICodec { function decodeCalldata(ICodec.SwapDescription calldata _swap) external pure returns ( uint256 amountIn, address tokenIn, address tokenOut ) { (uint256 _amountIn, , address[] memory path, , ) = abi.decode( (_swap.data[4:]), (uint256, uint256, address[], address, uint256) ); return (_amountIn, path[0], path[path.length - 1]); } function encodeCalldataWithOverride( bytes calldata _data, uint256 _amountInOverride, address _receiverOverride ) external pure returns (bytes memory swapCalldata) { bytes4 selector = bytes4(_data); (, uint256 amountOutMin, address[] memory path, , uint256 ddl) = abi.decode( (_data[4:]), (uint256, uint256, address[], address, uint256) ); return abi.encodeWithSelector(selector, _amountInOverride, amountOutMin, path, _receiverOverride, ddl); } }
// SPDX-License-Identifier: GPL-3.0-only pragma solidity >=0.8.15; import "../interfaces/ICodec.sol"; contract PlatypusRouter01Codec is ICodec { function decodeCalldata(ICodec.SwapDescription calldata _swap) external pure returns ( uint256 amountIn, address tokenIn, address tokenOut ) { (address[] memory tokenPath, , uint256 fromAmount, , , ) = abi.decode( (_swap.data[4:]), (address[], address[], uint256, uint256, address, uint256) ); require(tokenPath.length > 1, "len tk path"); return (fromAmount, tokenPath[0], tokenPath[tokenPath.length - 1]); } function encodeCalldataWithOverride( bytes calldata _data, uint256 _amountInOverride, address _receiverOverride ) external pure returns (bytes memory swapCalldata) { bytes4 selector = bytes4(_data); (address[] memory tokenPath, address[] memory poolPath, , uint256 min, , uint256 ddl) = abi.decode( (_data[4:]), (address[], address[], uint256, uint256, address, uint256) ); return abi.encodeWithSelector(selector, tokenPath, poolPath, _amountInOverride, min, _receiverOverride, ddl); } }
// SPDX-License-Identifier: GPL-3.0-only pragma solidity >=0.8.15; import "../interfaces/IERC20.sol"; import "../interfaces/ICodec.sol"; import "../interfaces/IUniswapV3Pool.sol"; import "../interfaces/IUniswapV2Pair.sol"; contract OneInchCodec is ICodec { uint256 private constant _ONE_FOR_ZERO_MASK = 1 << 255; uint256 private constant _REVERSE_MASK = 0x8000000000000000000000000000000000000000000000000000000000000000; struct OrderRFQ { // lowest 64 bits is the order id, next 64 bits is the expiration timestamp // highest bit is unwrap WETH flag which is set on taker's side // [unwrap eth(1 bit) | unused (127 bits) | expiration timestamp(64 bits) | orderId (64 bits)] uint256 info; IERC20 makerAsset; IERC20 takerAsset; address maker; address allowedSender; // equals to Zero address on public orders uint256 makingAmount; uint256 takingAmount; } struct SwapDesc { IERC20 srcToken; IERC20 dstToken; address payable srcReceiver; address payable dstReceiver; uint256 amount; uint256 minReturnAmount; uint256 flags; bytes permit; } function decodeCalldata(ICodec.SwapDescription calldata _swap) external view returns ( uint256 amountIn, address tokenIn, address tokenOut ) { bytes4 selector = bytes4(_swap.data); if (selector == 0xb0431182) { // "b0431182": "clipperSwap(address srcToken, address dstToken, uint256 amount, uint256 minReturn)", (address srcToken, address dstToken, uint256 amount,) = abi.decode( (_swap.data[4 :]), (address, address, uint256, uint256) ); return (amount, srcToken, dstToken); } else if (selector == 0xd0a3b665) { // "d0a3b665": "fillOrderRFQ((uint256 info, address makerAsset, address takerAsset, address maker, address allowedSender, uint256 makingAmount, uint256 takingAmount) order, bytes signature, uint256 makingAmount, uint256 takingAmount)", (OrderRFQ memory order, , ,) = abi.decode((_swap.data[4 :]), (OrderRFQ, bytes, uint256, uint256)); return (order.takingAmount, address(order.takerAsset), address(order.makerAsset)); } else if (selector == 0x7c025200) { // "7c025200": "swap(address caller,(address srcToken, address dstToken, address srcReceiver, address dstReceiver, uint256 amount, uint256 minReturnAmount, uint256 flags, bytes permit) desc, bytes data)", (, SwapDesc memory desc,) = abi.decode((_swap.data[4 :]), (address, SwapDesc, bytes)); return (desc.amount, address(desc.srcToken), address(desc.dstToken)); } else if (selector == 0xe449022e) { // "e449022e": "uniswapV3Swap(uint256 amount,uint256 minReturn,uint256[] pools)", (uint256 amount, , uint256[] memory pools) = abi.decode((_swap.data[4 :]), (uint256, uint256, uint256[])); (address srcToken,) = decodeV3Pool(pools[0]); (, address dstToken) = decodeV3Pool(pools[pools.length - 1]); return (amount, srcToken, dstToken); } else if (selector == 0x2e95b6c8) { // "2e95b6c8": "unoswap(address srcToken, uint256 amount, uint256 minReturn, bytes32[] pools)" (address srcToken, uint256 amount, , bytes32[] memory pools) = abi.decode( (_swap.data[4:]), (address, uint256, uint256, bytes32[]) ); (, address dstToken) = decodeV2Pool(uint256(pools[pools.length - 1])); return (amount, srcToken, dstToken); } else { // error, unknown selector revert("unknown selector"); } } function encodeCalldataWithOverride( bytes calldata _data, uint256 _amountInOverride, address _receiverOverride ) external pure returns (bytes memory swapCalldata) { bytes4 selector = bytes4(_data); if (selector == 0xb0431182) { // "b0431182": "clipperSwap(address srcToken, address dstToken, uint256 amount, uint256 minReturn)", (address srcToken, address dstToken, , uint256 minReturn) = abi.decode( (_data[4 :]), (address, address, uint256, uint256) ); return abi.encodeWithSelector(selector, srcToken, dstToken, _amountInOverride, minReturn); } else if (selector == 0xd0a3b665) { // "d0a3b665": "fillOrderRFQ((uint256 info, address makerAsset, address takerAsset, address maker, address allowedSender, uint256 makingAmount, uint256 takingAmount) order, bytes signature, uint256 makingAmount, uint256 takingAmount)", (OrderRFQ memory order, bytes memory signature, uint256 makingAmount,) = abi.decode( (_data[4 :]), (OrderRFQ, bytes, uint256, uint256) ); order.takingAmount = _amountInOverride; return abi.encodeWithSelector(selector, order, signature, makingAmount, _amountInOverride); } else if (selector == 0x7c025200) { // "7c025200": "swap(address caller,(address srcToken, address dstToken, address srcReceiver, address dstReceiver, uint256 amount, uint256 minReturnAmount, uint256 flags, bytes permit) desc, bytes data)", (address caller, SwapDesc memory desc, bytes memory data) = abi.decode( (_data[4 :]), (address, SwapDesc, bytes) ); desc.dstReceiver = payable(_receiverOverride); desc.amount = _amountInOverride; return abi.encodeWithSelector(selector, caller, desc, data); } else if (selector == 0xe449022e) { // "e449022e": "uniswapV3Swap(uint256 amount,uint256 minReturn,uint256[] pools)", (, uint256 minReturn, uint256[] memory pools) = abi.decode((_data[4 :]), (uint256, uint256, uint256[])); return abi.encodeWithSelector(selector, _amountInOverride, minReturn, pools); } else if (selector == 0x2e95b6c8) { // "2e95b6c8": "unoswap(address srcToken, uint256 amount, uint256 minReturn, bytes32[] pools)" (address srcToken, , uint256 minReturn, bytes32[] memory pools) = abi.decode( (_data[4 :]), (address, uint256, uint256, bytes32[]) ); return abi.encodeWithSelector(selector, srcToken, _amountInOverride, minReturn, pools); } else { // error, unknown selector revert("unknown selector"); } } function decodeV3Pool(uint256 pool) private view returns (address srcToken, address dstToken) { bool zeroForOne = pool & _ONE_FOR_ZERO_MASK == 0; address poolAddr = address(uint160(pool)); if (zeroForOne) { return (IUniswapV3Pool(poolAddr).token0(), IUniswapV3Pool(poolAddr).token1()); } else { return (IUniswapV3Pool(poolAddr).token1(), IUniswapV3Pool(poolAddr).token0()); } } function decodeV2Pool(uint256 pool) private view returns (address srcToken, address dstToken) { bool zeroForOne = pool & _REVERSE_MASK == 0; address poolAddr = address(uint160(pool)); if (zeroForOne) { return (IUniswapV2Pair(poolAddr).token0(), IUniswapV2Pair(poolAddr).token1()); } else { return (IUniswapV2Pair(poolAddr).token1(), IUniswapV2Pair(poolAddr).token0()); } } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.5.0) (token/ERC20/IERC20.sol) pragma solidity ^0.8.0; /** * @dev Interface of the ERC20 standard as defined in the EIP. */ interface IERC20 { /** * @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); /** * @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); }
// SPDX-License-Identifier: GPL-3.0-only pragma solidity >=0.8.15; interface IUniswapV3Pool { /// @notice Swap token0 for token1, or token1 for token0 /// @dev The caller of this method receives a callback in the form of IUniswapV3SwapCallback#uniswapV3SwapCallback /// @param recipient The address to receive the output of the swap /// @param zeroForOne The direction of the swap, true for token0 to token1, false for token1 to token0 /// @param amountSpecified The amount of the swap, which implicitly configures the swap as exact input (positive), or exact output (negative) /// @param sqrtPriceLimitX96 The Q64.96 sqrt price limit. If zero for one, the price cannot be less than this /// value after the swap. If one for zero, the price cannot be greater than this value after the swap /// @param data Any data to be passed through to the callback /// @return amount0 The delta of the balance of token0 of the pool, exact when negative, minimum when positive /// @return amount1 The delta of the balance of token1 of the pool, exact when negative, minimum when positive function swap( address recipient, bool zeroForOne, int256 amountSpecified, uint160 sqrtPriceLimitX96, bytes calldata data ) external returns (int256 amount0, int256 amount1); /// @notice The first of the two tokens of the pool, sorted by address /// @return The token contract address function token0() external view returns (address); /// @notice The second of the two tokens of the pool, sorted by address /// @return The token contract address function token1() external view returns (address); /// @notice The pool's fee in hundredths of a bip, i.e. 1e-6 /// @return The fee function fee() external view returns (uint24); }
// SPDX-License-Identifier: GPL-3.0-only pragma solidity >=0.8.15; interface IUniswapV2Pair { function getReserves() external view returns ( uint112 reserve0, uint112 reserve1, uint32 blockTimestampLast ); function token0() external view returns (address); function token1() external view returns (address); }
{ "optimizer": { "enabled": true, "runs": 800, "details": { "yul": false } }, "outputSelection": { "*": { "*": [ "evm.bytecode", "evm.deployedBytecode", "abi" ] } }, "metadata": { "useLiteralContent": true } }
Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
[{"inputs":[{"internalType":"address","name":"_messageBus","type":"address"},{"internalType":"address","name":"_nativeWrap","type":"address"},{"internalType":"address","name":"_signer","type":"address"},{"internalType":"address","name":"_feeCollector","type":"address"},{"internalType":"string[]","name":"_funcSigs","type":"string[]"},{"internalType":"address[]","name":"_codecs","type":"address[]"},{"internalType":"address[]","name":"_supportedDexList","type":"address[]"},{"internalType":"string[]","name":"_supportedDexFuncs","type":"string[]"},{"internalType":"bool","name":"_testMode","type":"bool"}],"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"bytes4","name":"selector","type":"bytes4"},{"indexed":false,"internalType":"address","name":"codec","type":"address"}],"name":"CodecUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"bytes32","name":"id","type":"bytes32"},{"indexed":false,"internalType":"uint256","name":"amountIn","type":"uint256"},{"indexed":false,"internalType":"address","name":"tokenIn","type":"address"},{"indexed":false,"internalType":"uint256","name":"amountOut","type":"uint256"},{"indexed":false,"internalType":"address","name":"tokenOut","type":"address"}],"name":"DirectSwap","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"from","type":"address"},{"indexed":false,"internalType":"address","name":"to","type":"address"}],"name":"FeeCollectorUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"messageBus","type":"address"}],"name":"MessageBusUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"nativeWrap","type":"address"}],"name":"NativeWrapUpdated","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":"account","type":"address"}],"name":"PauserAdded","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"account","type":"address"}],"name":"PauserRemoved","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"bytes32","name":"id","type":"bytes32"},{"indexed":false,"internalType":"uint256","name":"dstAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"refundAmount","type":"uint256"},{"indexed":false,"internalType":"address","name":"refundToken","type":"address"},{"indexed":false,"internalType":"uint256","name":"feeCollected","type":"uint256"},{"indexed":false,"internalType":"enum Types.RequestStatus","name":"status","type":"uint8"},{"indexed":false,"internalType":"bytes","name":"forwardResp","type":"bytes"}],"name":"RequestDone","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"bytes32","name":"id","type":"bytes32"},{"indexed":false,"internalType":"bytes","name":"bridgeResp","type":"bytes"},{"indexed":false,"internalType":"uint64","name":"dstChainId","type":"uint64"},{"indexed":false,"internalType":"uint256","name":"srcAmount","type":"uint256"},{"indexed":false,"internalType":"address","name":"srcToken","type":"address"},{"indexed":false,"internalType":"address","name":"dstToken","type":"address"},{"indexed":false,"internalType":"address","name":"bridgeOutReceiver","type":"address"},{"indexed":false,"internalType":"address","name":"bridgeToken","type":"address"},{"indexed":false,"internalType":"uint256","name":"bridgeAmount","type":"uint256"},{"indexed":false,"internalType":"string","name":"bridgeProvider","type":"string"}],"name":"RequestSent","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"from","type":"address"},{"indexed":false,"internalType":"address","name":"to","type":"address"}],"name":"SignerUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"string[]","name":"_bridgeProviders","type":"string[]"},{"indexed":false,"internalType":"address[]","name":"_bridgeAdapters","type":"address[]"}],"name":"SupportedBridgesUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"dex","type":"address"},{"indexed":false,"internalType":"bytes4","name":"selector","type":"bytes4"},{"indexed":false,"internalType":"bool","name":"enabled","type":"bool"}],"name":"SupportedDexUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"account","type":"address"}],"name":"Unpaused","type":"event"},{"inputs":[],"name":"CBRIDGE_PROVIDER_HASH","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"addPauser","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"name":"bridges","outputs":[{"internalType":"contract IBridgeAdapter","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"codecs","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address[]","name":"_tokens","type":"address[]"},{"internalType":"address","name":"_to","type":"address"}],"name":"collectFee","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"bytes4","name":"","type":"bytes4"}],"name":"dexRegistry","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_sender","type":"address"},{"internalType":"uint64","name":"_srcChainId","type":"uint64"},{"internalType":"bytes","name":"_message","type":"bytes"},{"internalType":"address","name":"_executor","type":"address"}],"name":"executeMessage","outputs":[{"internalType":"enum IMessageReceiverApp.ExecutionStatus","name":"","type":"uint8"}],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"address","name":"_token","type":"address"},{"internalType":"uint256","name":"_amount","type":"uint256"},{"internalType":"uint64","name":"","type":"uint64"},{"internalType":"bytes","name":"_message","type":"bytes"},{"internalType":"address","name":"_executor","type":"address"}],"name":"executeMessageWithTransfer","outputs":[{"internalType":"enum IMessageReceiverApp.ExecutionStatus","name":"","type":"uint8"}],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"address","name":"_token","type":"address"},{"internalType":"uint256","name":"_amount","type":"uint256"},{"internalType":"uint64","name":"","type":"uint64"},{"internalType":"bytes","name":"_message","type":"bytes"},{"internalType":"address","name":"","type":"address"}],"name":"executeMessageWithTransferFallback","outputs":[{"internalType":"enum IMessageReceiverApp.ExecutionStatus","name":"","type":"uint8"}],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"_token","type":"address"},{"internalType":"uint256","name":"_amount","type":"uint256"},{"internalType":"bytes","name":"_message","type":"bytes"},{"internalType":"address","name":"_executor","type":"address"}],"name":"executeMessageWithTransferRefund","outputs":[{"internalType":"enum IMessageReceiverApp.ExecutionStatus","name":"","type":"uint8"}],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"_token","type":"address"},{"internalType":"uint256","name":"_amount","type":"uint256"},{"internalType":"bytes","name":"_message","type":"bytes"},{"internalType":"address","name":"","type":"address"}],"name":"executeMessageWithTransferRefundFromAdapter","outputs":[{"internalType":"enum IMessageReceiverApp.ExecutionStatus","name":"","type":"uint8"}],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"feeCollector","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"isPauser","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"messageBus","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"nativeWrap","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"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":[{"internalType":"address","name":"","type":"address"}],"name":"pausers","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"removePauser","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"renounceOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"renouncePauser","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes4","name":"","type":"bytes4"}],"name":"selector2codec","outputs":[{"internalType":"contract ICodec","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"string","name":"_funcSig","type":"string"},{"internalType":"address","name":"_codec","type":"address"}],"name":"setCodec","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_feeCollector","type":"address"}],"name":"setFeeCollector","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_messageBus","type":"address"}],"name":"setMessageBus","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_nativeWrap","type":"address"}],"name":"setNativeWrap","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_signer","type":"address"}],"name":"setSigner","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"string[]","name":"_bridgeProviders","type":"string[]"},{"internalType":"address[]","name":"_bridgeAdapters","type":"address[]"}],"name":"setSupportedBridges","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_dex","type":"address"},{"internalType":"bytes4","name":"_selector","type":"bytes4"},{"internalType":"bool","name":"_enabled","type":"bool"}],"name":"setSupportedDex","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"signer","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"testMode","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"components":[{"internalType":"address","name":"receiver","type":"address"},{"internalType":"uint64","name":"dstChainId","type":"uint64"},{"internalType":"address","name":"dstTransferSwapper","type":"address"},{"internalType":"uint64","name":"nonce","type":"uint64"},{"internalType":"string","name":"bridgeProvider","type":"string"},{"internalType":"bytes","name":"bridgeParams","type":"bytes"},{"internalType":"bool","name":"nativeIn","type":"bool"},{"internalType":"bool","name":"nativeOut","type":"bool"},{"internalType":"uint256","name":"fee","type":"uint256"},{"internalType":"uint256","name":"feeDeadline","type":"uint256"},{"internalType":"bytes","name":"feeSig","type":"bytes"},{"internalType":"uint256","name":"amountIn","type":"uint256"},{"internalType":"address","name":"tokenIn","type":"address"},{"internalType":"address","name":"dstTokenOut","type":"address"},{"internalType":"bool","name":"allowPartialFill","type":"bool"},{"internalType":"bytes","name":"forward","type":"bytes"}],"internalType":"struct Types.TransferDescription","name":"_desc","type":"tuple"},{"components":[{"internalType":"address","name":"dex","type":"address"},{"internalType":"bytes","name":"data","type":"bytes"}],"internalType":"struct ICodec.SwapDescription[]","name":"_srcSwaps","type":"tuple[]"},{"components":[{"internalType":"address","name":"dex","type":"address"},{"internalType":"bytes","name":"data","type":"bytes"}],"internalType":"struct ICodec.SwapDescription[]","name":"_dstSwaps","type":"tuple[]"}],"name":"transferWithSwap","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"unpause","outputs":[],"stateMutability":"nonpayable","type":"function"},{"stateMutability":"payable","type":"receive"}]
Deployed Bytecode
0x6080604052600436106102385760003560e01c806382dc1ec411610138578063c0404998116100b0578063eeaaa6511161007f578063f2fde38b11610064578063f2fde38b14610683578063fb453787146106a3578063fbf5d763146106b657600080fd5b8063eeaaa65114610620578063efcfd8f51461066357600080fd5b8063c04049981461057e578063c415b95c146105bf578063c5bccca3146105df578063cd9ea342146105ff57600080fd5b806391ec04b511610107578063a1a227fa116100ec578063a1a227fa1461052b578063a42dce801461054b578063a6131ca01461056b57600080fd5b806391ec04b5146104e25780639c649fdf1461051d57600080fd5b806382dc1ec41461046f5780638456cb591461048f5780638da5cb5b146104a4578063918ead76146104c257600080fd5b80635c975abb116101cb5780636ef8d66d1161019a5780637cd2bffc1161017f5780637cd2bffc1461040c57806380f51c121461041f57806382665a8f1461044f57600080fd5b80636ef8d66d146103e2578063715018a6146103f757600080fd5b80635c975abb1461036a578063675df759146103825780636b2c0f55146103a25780636c19e783146103c257600080fd5b806346fbf68e1161020757806346fbf68e146102d1578063547cad12146103175780635ab7afc6146103375780635b5a66a71461034a57600080fd5b80630bcb498214610244578063238ac9331461026d5780633f4ba83a1461029a578063457bfa2f146102b157600080fd5b3661023f57005b600080fd5b6102576102523660046132a7565b6106ec565b604051610264919061337a565b60405180910390f35b34801561027957600080fd5b5060055461028d906001600160a01b031681565b6040516102649190613391565b3480156102a657600080fd5b506102af61073c565b005b3480156102bd57600080fd5b50600b5461028d906001600160a01b031681565b3480156102dd57600080fd5b5061030a6102ec36600461339f565b6001600160a01b03166000908152600a602052604090205460ff1690565b60405161026491906133c8565b34801561032357600080fd5b506102af61033236600461339f565b610775565b6102576103453660046134df565b6107d4565b34801561035657600080fd5b506102af61036536600461339f565b6108ff565b34801561037657600080fd5b5060095460ff1661030a565b34801561038e57600080fd5b506102af61039d3660046135b2565b610952565b3480156103ae57600080fd5b506102af6103bd36600461339f565b6109a5565b3480156103ce57600080fd5b506102af6103dd36600461339f565b6109b9565b3480156103ee57600080fd5b506102af610a20565b34801561040357600080fd5b506102af610a29565b61025761041a3660046134df565b610a3b565b34801561042b57600080fd5b5061030a61043a36600461339f565b600a6020526000908152604090205460ff1681565b34801561045b57600080fd5b5061028d61046a366004613602565b610e15565b34801561047b57600080fd5b506102af61048a36600461339f565b610e3f565b34801561049b57600080fd5b506102af610e50565b3480156104b057600080fd5b506000546001600160a01b031661028d565b3480156104ce57600080fd5b506102af6104dd36600461366e565b610e87565b3480156104ee57600080fd5b5061030a6104fd3660046136e7565b600460209081526000928352604080842090915290825290205460ff1681565b610257610252366004613724565b34801561053757600080fd5b5060015461028d906001600160a01b031681565b34801561055757600080fd5b506102af61056636600461339f565b610fa7565b6102af610579366004613778565b611002565b34801561058a57600080fd5b506105b27f87d218bfcd262745694c36930f68b5dd697460f1af499de15378f8ddddb1d74f81565b6040516102649190613828565b3480156105cb57600080fd5b5060065461028d906001600160a01b031681565b3480156105eb57600080fd5b506102af6105fa366004613836565b611346565b34801561060b57600080fd5b5060015461030a90600160a01b900460ff1681565b34801561062c57600080fd5b5061065661063b366004613602565b6008602052600090815260409020546001600160a01b031681565b60405161026491906138c9565b34801561066f57600080fd5b506102af61067e3660046138d7565b611412565b34801561068f57600080fd5b506102af61069e36600461339f565b6115f8565b6102576106b13660046132a7565b61162f565b3480156106c257600080fd5b506106566106d1366004613915565b6002602052600090815260409020546001600160a01b031681565b600154600090600160a01b900460ff16610733576001546001600160a01b031633146107335760405162461bcd60e51b815260040161072a9061396d565b60405180910390fd5b95945050505050565b336000908152600a602052604090205460ff1661076b5760405162461bcd60e51b815260040161072a906139b1565b61077361174f565b565b61077d61179b565b600180546001600160a01b0319166001600160a01b0383169081179091556040517f3f8223bcd8b3b875473e9f9e14e1ad075451a2b5ffd31591655da9a01516bf5e916107c991613391565b60405180910390a150565b600154600090600160a01b900460ff16610812576001546001600160a01b031633146108125760405162461bcd60e51b815260040161072a9061396d565b6002600754036108345760405162461bcd60e51b815260040161072a906139f5565b600260075560095460ff161561084c575060026108f0565b6000838060200190518101906108629190613cb3565b905061086e87876117c5565b60008160800151876108809190613d04565b905061089388828460400151600061194a565b8151608083015160408051602081018252600080825291517ffd53a0c19886b8e3b5a497eb3ab7a50cb59734988891978e5f6709e86af805c3946108e19490939287928f9291600291613d64565b60405180910390a16001925050505b60016007559695505050505050565b61090761179b565b600b80546001600160a01b0319166001600160a01b0383161790556040517fb878cd71628ac64b2df1872301925e01164824535b02e8601077749eeeb88c3d906107c9908390613391565b61095a61179b565b610965838383611a7a565b7f5e20184b00709d9f103306958e9fb9d509f78bec1829ca7080f2c43eb2ff21a883838360405161099893929190613de2565b60405180910390a1505050565b6109ad61179b565b6109b681611b10565b50565b6109c161179b565b600580546001600160a01b038381166001600160a01b03198316179092556040519116907f2d025324f0a785e8c12d0a0d91a9caa49df4ef20ff87e0df7213a1d4f3157beb90610a149083908590613e0a565b60405180910390a15050565b61077333611b10565b610a3161179b565b6107736000611b98565b600154600090600160a01b900460ff16610a79576001546001600160a01b03163314610a795760405162461bcd60e51b815260040161072a9061396d565b600260075403610a9b5760405162461bcd60e51b815260040161072a906139f5565b600260075560095460ff1615610ab3575060026108f0565b600083806020019051810190610ac99190613cb3565b90508060800151861015610b3b5760808101869052805160408051602081018252600080825291517ffd53a0c19886b8e3b5a497eb3ab7a50cb59734988891978e5f6709e86af805c393610b29939092909182918d918d91600191613e25565b60405180910390a160019150506108f0565b6080810151610b4a9087613d04565b95508560006060610b5b8a846117c5565b6020840151518a9015610bdf5760606000610b798760200151611be8565b90955093509150506001600160a01b03808216908e1614610bac5760405162461bcd60e51b815260040161072a90613e81565b610bc08760200151838e8a60a00151611e16565b90965094508415610bdc57610bdc8d868960400151600061194a565b50505b60c08501515115610d195760008560c00151806020019051810190610c049190613ec9565b7f87d218bfcd262745694c36930f68b5dd697460f1af499de15378f8ddddb1d74f6000908152600860205260409020549091506001600160a01b031680610c5d5760405162461bcd60e51b815260040161072a90613f38565b610c716001600160a01b0384168288612159565b6000610c8588600001518960400151612242565b83516040808b0151602087015191516341a5e1f560e11b81529394506001600160a01b0386169363834bc3ea933493610cc89391928e918c918a90600401613f58565b60006040518083038185885af1158015610ce6573d6000803e3d6000fd5b50505050506040513d6000823e601f3d908101601f19168201604052610d0f9190810190613fbf565b9450505050610db1565b3415610d9d576000876001600160a01b031634604051610d3890613ffa565b60006040518083038185875af1925050503d8060008114610d75576040519150601f19603f3d011682016040523d82523d6000602084013e610d7a565b606091505b5050905080610d9b5760405162461bcd60e51b815260040161072a90614039565b505b610db181858760400151886060015161194a565b507ffd53a0c19886b8e3b5a497eb3ab7a50cb59734988891978e5f6709e86af805c3846000015184848d8860800151600187604051610df69796959493929190614049565b60405180910390a1600194505050505060016007559695505050505050565b60038181548110610e2557600080fd5b6000918252602090912001546001600160a01b0316905081565b610e4761179b565b6109b6816122b3565b336000908152600a602052604090205460ff16610e7f5760405162461bcd60e51b815260040161072a906139b1565b61077361233f565b610e8f61179b565b828114610eae5760405162461bcd60e51b815260040161072a90614098565b60005b83811015610f6357828282818110610ecb57610ecb6140a8565b9050602002016020810190610ee0919061339f565b60086000878785818110610ef657610ef66140a8565b9050602002810190610f0891906140be565b604051610f16929190614128565b6040518091039020815260200190815260200160002060006101000a8154816001600160a01b0302191690836001600160a01b031602179055508080610f5b90614135565b915050610eb1565b507f68d2b5e14eb61b73f2dfa46a255dcba81a3b53259093a83c90da69c3ade70b9684848484604051610f99949392919061429b565b60405180910390a150505050565b610faf61179b565b600680546001600160a01b038381166001600160a01b03198316179092556040519116907f5d16ad41baeb009cd23eb8f6c7cde5c2e0cd5acf4a33926ab488875c37c37f3890610a149083908590613e0a565b6002600754036110245760405162461bcd60e51b815260040161072a906139f5565b600260075561103161237c565b82151580611062575067ffffffffffffffff461661105560408701602088016142cc565b67ffffffffffffffff1614155b61107e5760405162461bcd60e51b815260040161072a90614307565b821515806110b65750610160850135158015906110b6575060006110aa6101a08701610180880161339f565b6001600160a01b031614155b6110d25760405162461bcd60e51b815260040161072a90614307565b60006110e160808701876140be565b6040516110ef929190614128565b60405190819003902090508115801561111557506111116101e08701876140be565b1590505b8061113f57507f87d218bfcd262745694c36930f68b5dd697460f1af499de15378f8ddddb1d74f81145b61115b5760405162461bcd60e51b815260040161072a9061434b565b600081815260086020908152604091829020546001600160a01b03169167ffffffffffffffff461691611192918a01908a016142cc565b67ffffffffffffffff1614806111b057506001600160a01b03811615155b6111cc5760405162461bcd60e51b815260040161072a9061438f565b610160870135606060006111e86101a08b016101808c0161339f565b905060006111fe6101a08c016101808d0161339f565b90508815611223576112186112138a8c614466565b611be8565b929650919450925090505b61123360e08c0160c08d01614473565b156112f357600b546001600160a01b038381169116146112655760405162461bcd60e51b815260040161072a906144c8565b833410156112855760405162461bcd60e51b815260040161072a9061450c565b600b60009054906101000a90046001600160a01b03166001600160a01b031663d0e30db0856040518263ffffffff1660e01b81526004016000604051808303818588803b1580156112d557600080fd5b505af11580156112e9573d6000803e3d6000fd5b5050505050611308565b6113086001600160a01b03831633308761239f565b6113348282866113178f6146fc565b8e8e906113249190614466565b61132e8d8f614466565b896123c0565b50506001600755505050505050505050565b61134e61179b565b60008383604051611360929190614128565b604051809103902090506113e181836001600160e01b0319909116600090815260026020526040812080546001600160a01b039093166001600160a01b031993841681179091556003805460018101825592527fc2575a0e9e593c00f959f8c92f12db2869c3395a3b0502d05e2516446f71f85b9091018054909216179055565b7f58ddcdb40971f55ad1b6a8a28067274a4ffc7e9d77c3ea14a17652faa705e1978183604051610f99929190614708565b6006546001600160a01b0316331461143c5760405162461bcd60e51b815260040161072a9061474a565b60005b828110156115f257600084848381811061145b5761145b6140a8565b9050602002016020810190611470919061339f565b6001600160a01b03160361150b5760004790506000836001600160a01b03168261c350906040516114a090613ffa565b600060405180830381858888f193505050503d80600081146114de576040519150601f19603f3d011682016040523d82523d6000602084013e6114e3565b606091505b50509050806115045760405162461bcd60e51b815260040161072a9061478e565b50506115e0565b600084848381811061151f5761151f6140a8565b9050602002016020810190611534919061339f565b6001600160a01b03166370a08231306040518263ffffffff1660e01b815260040161155f9190613391565b602060405180830381865afa15801561157c573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906115a0919061479e565b90506115de83828787868181106115b9576115b96140a8565b90506020020160208101906115ce919061339f565b6001600160a01b031691906124a2565b505b806115ea81614135565b91505061143f565b50505050565b61160061179b565b6001600160a01b0381166116265760405162461bcd60e51b815260040161072a9061481c565b6109b681611b98565b60006002600754036116535760405162461bcd60e51b815260040161072a906139f5565b600260075560095460ff161561166b57506002611741565b600b546001600160a01b0387811691161461169a576116956001600160a01b03871633308861239f565b6116ba565b843410156116ba5760405162461bcd60e51b815260040161072a90614860565b60006116c88486018661496c565b90506116d487876117c5565b6116e587878360400151600061194a565b8051608082015160408051602081018252600080825291517ffd53a0c19886b8e3b5a497eb3ab7a50cb59734988891978e5f6709e86af805c394611733949093928c928e9291600291613d64565b60405180910390a160019150505b600160075595945050505050565b6117576124c1565b6009805460ff191690557f5db9ee0a495bf2e6ff9c91a7834c1ba4fdd244a5e8aa4e537bd38aeae4b073aa335b6040516117919190613391565b60405180910390a1565b6000546001600160a01b031633146107735760405162461bcd60e51b815260040161072a906149d9565b600b546001600160a01b039081169083160361194657600154604080516320a6037160e21b815290516000926001600160a01b0316916382980dc49160048083019260209291908290030181865afa158015611825573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061184991906149e9565b9050600b60009054906101000a90046001600160a01b03166001600160a01b0316816001600160a01b031663457bfa2f6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156118a8573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906118cc91906149e9565b6001600160a01b03160361194457600b60009054906101000a90046001600160a01b03166001600160a01b031663d0e30db0836040518263ffffffff1660e01b81526004016000604051808303818588803b15801561192a57600080fd5b505af115801561193e573d6000803e3d6000fd5b50505050505b505b5050565b8015611a6657600b546001600160a01b0385811691161461197d5760405162461bcd60e51b815260040161072a90614a3e565b600b54604051632e1a7d4d60e01b81526001600160a01b0390911690632e1a7d4d906119ad908690600401613828565b600060405180830381600087803b1580156119c757600080fd5b505af11580156119db573d6000803e3d6000fd5b505050506000826001600160a01b03168461c350906040516119fc90613ffa565b600060405180830381858888f193505050503d8060008114611a3a576040519150601f19603f3d011682016040523d82523d6000602084013e611a3f565b606091505b5050905080611a605760405162461bcd60e51b815260040161072a90614039565b506115f2565b6115f26001600160a01b03851683856124a2565b6001600160a01b03831660009081526004602090815260408083206001600160e01b03198616845290915290205460ff1681151581151503611ace5760405162461bcd60e51b815260040161072a90614307565b506001600160a01b0390921660009081526004602090815260408083206001600160e01b0319909416835292905220805491151560ff19909216919091179055565b6001600160a01b0381166000908152600a602052604090205460ff16611b485760405162461bcd60e51b815260040161072a90614a82565b6001600160a01b0381166000908152600a602052604090819020805460ff19169055517fcd265ebaf09df2871cc7bd4133404a235ba12eff2041bb89d9c714a2621c7c7e906107c9908390613391565b600080546001600160a01b038381166001600160a01b0319831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b60008060006060600080611bfb876124e3565b925060005b8751811015611e0c5760046000898381518110611c1f57611c1f6140a8565b6020026020010151600001516001600160a01b03166001600160a01b031681526020019081526020016000206000898381518110611c5f57611c5f6140a8565b602002602001015160200151611c7490614aa6565b6001600160e01b031916815260208101919091526040016000205460ff16611cae5760405162461bcd60e51b815260040161072a90614b1f565b6000806000868481518110611cc557611cc56140a8565b60200260200101516001600160a01b031663358f0e1c8c8681518110611ced57611ced6140a8565b60200260200101516040518263ffffffff1660e01b8152600401611d119190614b5b565b606060405180830381865afa158015611d2e573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611d529190614b6c565b919450925090506001600160a01b0386161580611d805750816001600160a01b0316866001600160a01b0316145b611d9c5760405162461bcd60e51b815260040161072a90614be6565b90945084906001600160a01b0385161580611dc85750806001600160a01b0316856001600160a01b0316145b611de45760405162461bcd60e51b815260040161072a90614c2a565b935083611df1838b614c3a565b99509097509550819050611e0481614135565b915050611c00565b5050509193509193565b6000806000806000611e2989888a612622565b9250925092506000816001600160a01b03166370a08231306040518263ffffffff1660e01b8152600401611e5d9190613391565b602060405180830381865afa158015611e7a573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611e9e919061479e565b905060005b8a518110156120ac5760008a8281518110611ec057611ec06140a8565b60200260200101516001600160a01b0316634c6da2698d8481518110611ee857611ee86140a8565b602002602001015160200151888581518110611f0657611f066140a8565b6020026020010151306040518463ffffffff1660e01b8152600401611f2d93929190614c52565b600060405180830381865afa158015611f4a573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052611f729190810190613fbf565b9050611fc88c8381518110611f8957611f896140a8565b602002602001015160000151878481518110611fa757611fa76140a8565b6020026020010151876001600160a01b03166121599092919063ffffffff16565b60008c8381518110611fdc57611fdc6140a8565b6020026020010151600001516001600160a01b031682604051611fff9190614ca1565b6000604051808303816000865af19150503d806000811461203c576040519150601f19603f3d011682016040523d82523d6000602084013e612041565b606091505b50509050808061204e5750895b61206a5760405162461bcd60e51b815260040161072a90614ce1565b8061209757868381518110612081576120816140a8565b6020026020010151886120949190614c3a565b97505b505080806120a490614135565b915050611ea3565b506040516370a0823160e01b81526000906001600160a01b038416906370a08231906120dc903090600401613391565b602060405180830381865afa1580156120f9573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061211d919061479e565b90506121298282613d04565b96506000871161214b5760405162461bcd60e51b815260040161072a90614d25565b505050505094509492505050565b600081846001600160a01b031663dd62ed3e30866040518363ffffffff1660e01b815260040161218a929190613e0a565b602060405180830381865afa1580156121a7573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906121cb919061479e565b6121d59190614c3a565b90506115f28463095ea7b360e01b85846040516024016121f6929190614d35565b60408051601f198184030181529190526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff166001600160e01b0319909316929092179091526127d7565b60608060606040518060e00160405280868152602001838152602001856001600160a01b03168152602001600015158152602001600081526020016000151581526020018281525060405160200161229a9190614e47565b6040516020818303038152906040529250505092915050565b6001600160a01b0381166000908152600a602052604090205460ff16156122ec5760405162461bcd60e51b815260040161072a90614e8c565b6001600160a01b0381166000908152600a602052604090819020805460ff19166001179055517f6719d08c1888103bea251a4ed56406bd0c3e69723c8a1686e017e7bbe159b6f8906107c9908390613391565b61234761237c565b6009805460ff191660011790557f62e78cea01bee320cd4e420270b5ea74000d11b0c9f74754ebdbfc544b05a2586117843390565b60095460ff16156107735760405162461bcd60e51b815260040161072a90614ed0565b6115f2846323b872dd60e01b8585856040516024016121f693929190614ee0565b82518590156123f85760006123d58584612866565b92509050806123f65760405162461bcd60e51b815260040161072a90614f3c565b505b600061240c86600001518760600151612bb0565b90504667ffffffffffffffff16866020015167ffffffffffffffff1603612487577f0e248ac8be20725176a5f0ab093c5fbb964634d4675012f3d3ad66e69e56d5b781888b858c604051612464959493929190614f4c565b60405180910390a1612480888388600001518960e0015161194a565b5050612499565b612496818a8a89888c88612be8565b50505b50505050505050565b6119448363a9059cbb60e01b84846040516024016121f6929190614d35565b60095460ff166107735760405162461bcd60e51b815260040161072a90614fc2565b60606000825167ffffffffffffffff811115612501576125016133f1565b60405190808252806020026020018201604052801561252a578160200160208202803683370190505b50905060005b835181101561261b57600084828151811061254d5761254d6140a8565b60200260200101516020015161256290614aa6565b6001600160e01b0319811660009081526002602052604090205484519192506001600160a01b03169084908490811061259d5761259d6140a8565b60200260200101906001600160a01b031690816001600160a01b03168152505060006001600160a01b03168383815181106125da576125da6140a8565b60200260200101516001600160a01b0316036126085760405162461bcd60e51b815260040161072a90615006565b508061261381614135565b915050612530565b5092915050565b60606000806000865167ffffffffffffffff811115612643576126436133f1565b60405190808252806020026020018201604052801561266c578160200160208202803683370190505b50935060005b875181101561276057600086828151811061268f5761268f6140a8565b60200260200101516001600160a01b031663358f0e1c8a84815181106126b7576126b76140a8565b60200260200101516040518263ffffffff1660e01b81526004016126db9190614b5b565b606060405180830381865afa1580156126f8573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061271c9190614b6c565b9096509450905061272d8184614c3a565b925080868381518110612742576127426140a8565b6020908102919091010152508061275881614135565b915050612672565b5060005b84518110156127cc5781858281518110612780576127806140a8565b6020026020010151886127939190615016565b61279d919061504b565b8582815181106127af576127af6140a8565b6020908102919091010152806127c481614135565b915050612764565b505093509350939050565b600061282c826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b0316612d689092919063ffffffff16565b805190915015611944578080602001905181019061284a919061505f565b6119445760405162461bcd60e51b815260040161072a906150da565b60008060005b8451811015612ba757600080600086848151811061288c5761288c6140a8565b60200260200101516001600160a01b031663358f0e1c8986815181106128b4576128b46140a8565b60200260200101516040518263ffffffff1660e01b81526004016128d89190614b5b565b606060405180830381865afa1580156128f5573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906129199190614b6c565b9250925092506000878581518110612933576129336140a8565b60200260200101516001600160a01b0316634c6da2698a878151811061295b5761295b6140a8565b60200260200101516020015186306040518463ffffffff1660e01b815260040161298793929190614c52565b600060405180830381865afa1580156129a4573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526129cc9190810190613fbf565b9050612a008986815181106129e3576129e36140a8565b6020908102919091010151516001600160a01b0385169086612159565b6040516370a0823160e01b81526000906001600160a01b038416906370a0823190612a2f903090600401613391565b602060405180830381865afa158015612a4c573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612a70919061479e565b9050898681518110612a8457612a846140a8565b6020026020010151600001516001600160a01b031682604051612aa79190614ca1565b6000604051808303816000865af19150503d8060008114612ae4576040519150601f19603f3d011682016040523d82523d6000602084013e612ae9565b606091505b50508098505087612b065760008097509750505050505050612ba9565b6040516370a0823160e01b81526000906001600160a01b038516906370a0823190612b35903090600401613391565b602060405180830381865afa158015612b52573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612b76919061479e565b9050612b828282613d04565b612b8c9089614c3a565b97505050505050508080612b9f90614135565b91505061286c565b505b9250929050565b600033834684604051602001612bc99493929190615131565b6040516020818303038152906040528051906020012090505b92915050565b60008084511180612bff57506000856101e0015151115b612c0a578451612c10565b84604001515b90506060612c1f86858a612d81565b60c0860151349015612c3857612c358534613d04565b90505b608087015180516020918201206000908152600890915260409020546001600160a01b0390811690612c6d908a168287612159565b6000612c7a8c8a8a612e0b565b9050816001600160a01b031663834bc3ea848b60200151888a8f8f60a00151886040518863ffffffff1660e01b8152600401612cbb96959493929190613f58565b60006040518083038185885af1158015612cd9573d6000803e3d6000fd5b50505050506040513d6000823e601f3d908101601f19168201604052612d029190810190613fbf565b93505050507f082e2f634ceec1af5105aa53f234b7efad94428a54a714e3b7c7115ee549308089828860200151878c8b6101a00151888e8b8f60800151604051612d559a99989796959493929190615179565b60405180910390a1505050505050505050565b6060612d778484600085612e8c565b90505b9392505050565b60004684602001518484876101200151886101000151604051602001612dac9695949392919061521b565b6040516020818303038152906040528051906020012090506000612dcf82612f50565b9050612de081866101400151612f80565b4285610120015111612e045760405162461bcd60e51b815260040161072a906152df565b5050505050565b60606040518060e0016040528085815260200183815260200184600001516001600160a01b031681526020018460e00151151581526020018461010001518152602001846101c0015115158152602001846101e00151815250604051602001612e749190614e47565b60405160208183030381529060405290509392505050565b606082471015612eae5760405162461bcd60e51b815260040161072a90615349565b6001600160a01b0385163b612ed55760405162461bcd60e51b815260040161072a9061538d565b600080866001600160a01b03168587604051612ef19190614ca1565b60006040518083038185875af1925050503d8060008114612f2e576040519150601f19603f3d011682016040523d82523d6000602084013e612f33565b606091505b5091509150612f43828286612fbc565b925050505b949350505050565b600081604051602001612f63919061539d565b604051602081830303815290604052805190602001209050919050565b6000612f8c8383612ff5565b6005549091506001600160a01b038083169116146119445760405162461bcd60e51b815260040161072a9061540c565b60608315612fcb575081612d7a565b825115612fdb5782518084602001fd5b8160405162461bcd60e51b815260040161072a919061541c565b60008060006130048585613019565b915091506130118161305b565b509392505050565b600080825160410361304f5760208301516040840151606085015160001a6130438782858561313b565b94509450505050612ba9565b50600090506002612ba9565b600081600481111561306f5761306f61332b565b036130775750565b600181600481111561308b5761308b61332b565b036130a85760405162461bcd60e51b815260040161072a90615461565b60028160048111156130bc576130bc61332b565b036130d95760405162461bcd60e51b815260040161072a906154a5565b60038160048111156130ed576130ed61332b565b0361310a5760405162461bcd60e51b815260040161072a906154f4565b600481600481111561311e5761311e61332b565b036109b65760405162461bcd60e51b815260040161072a90615543565b6000807f7fffffffffffffffffffffffffffffff5d576e7357a4501ddfe92f46681b20a08311156131725750600090506003613212565b8460ff16601b1415801561318a57508460ff16601c14155b1561319b5750600090506004613212565b6000600187878787604051600081526020016040526040516131c0949392919061555c565b6020604051602081039080840390855afa1580156131e2573d6000803e3d6000fd5b5050604051601f1901519150506001600160a01b03811661320b57600060019250925050613212565b9150600090505b94509492505050565b60006001600160a01b038216612be2565b6132358161321b565b81146109b657600080fd5b8035612be28161322c565b80613235565b8035612be28161324b565b60008083601f84011261327157613271600080fd5b50813567ffffffffffffffff81111561328c5761328c600080fd5b602083019150836001820283011115612ba957612ba9600080fd5b6000806000806000608086880312156132c2576132c2600080fd5b60006132ce8888613240565b95505060206132df88828901613251565b945050604086013567ffffffffffffffff8111156132ff576132ff600080fd5b61330b8882890161325c565b9350935050606061331e88828901613240565b9150509295509295909350565b634e487b7160e01b600052602160045260246000fd5b600381106109b6576109b661332b565b8061335b81613341565b919050565b6000612be282613351565b61337481613360565b82525050565b60208101612be2828461336b565b6133748161321b565b60208101612be28284613388565b6000602082840312156133b4576133b4600080fd5b6000612f488484613240565b801515613374565b60208101612be282846133c0565b67ffffffffffffffff8116613235565b8035612be2816133d6565b634e487b7160e01b600052604160045260246000fd5b601f19601f830116810181811067ffffffffffffffff8211171561342d5761342d6133f1565b6040525050565b600061343f60405190565b905061335b8282613407565b600067ffffffffffffffff821115613465576134656133f1565b601f19601f83011660200192915050565b82818337506000910152565b60006134956134908461344b565b613434565b9050828152602081018484840111156134b0576134b0600080fd5b613011848285613476565b600082601f8301126134cf576134cf600080fd5b8135612f48848260208601613482565b60008060008060008060c087890312156134fb576134fb600080fd5b60006135078989613240565b965050602061351889828a01613240565b955050604061352989828a01613251565b945050606061353a89828a016133e6565b935050608087013567ffffffffffffffff81111561355a5761355a600080fd5b61356689828a016134bb565b92505060a061357789828a01613240565b9150509295509295509295565b6001600160e01b03198116613235565b8035612be281613584565b801515613235565b8035612be28161359f565b6000806000606084860312156135ca576135ca600080fd5b60006135d68686613240565b93505060206135e786828701613594565b92505060406135f8868287016135a7565b9150509250925092565b60006020828403121561361757613617600080fd5b6000612f488484613251565b60008083601f84011261363857613638600080fd5b50813567ffffffffffffffff81111561365357613653600080fd5b602083019150836020820283011115612ba957612ba9600080fd5b6000806000806040858703121561368757613687600080fd5b843567ffffffffffffffff8111156136a1576136a1600080fd5b6136ad87828801613623565b9450945050602085013567ffffffffffffffff8111156136cf576136cf600080fd5b6136db87828801613623565b95989497509550505050565b600080604083850312156136fd576136fd600080fd5b60006137098585613240565b925050602061371a85828601613594565b9150509250929050565b60008060008060006080868803121561373f5761373f600080fd5b600061374b8888613240565b95505060206132df888289016133e6565b6000610200828403121561377257613772600080fd5b50919050565b60008060008060006060868803121561379357613793600080fd5b853567ffffffffffffffff8111156137ad576137ad600080fd5b6137b98882890161375c565b955050602086013567ffffffffffffffff8111156137d9576137d9600080fd5b6137e588828901613623565b9450945050604086013567ffffffffffffffff81111561380757613807600080fd5b61381388828901613623565b92509250509295509295909350565b80613374565b60208101612be28284613822565b60008060006040848603121561384e5761384e600080fd5b833567ffffffffffffffff81111561386857613868600080fd5b6138748682870161325c565b935093505060206135f886828701613240565b6000612be26001600160a01b03831661389e565b90565b6001600160a01b031690565b6000612be282613887565b6000612be2826138aa565b613374816138b5565b60208101612be282846138c0565b6000806000604084860312156138ef576138ef600080fd5b833567ffffffffffffffff81111561390957613909600080fd5b61387486828701613623565b60006020828403121561392a5761392a600080fd5b6000612f488484613594565b601981526000602082017f63616c6c6572206973206e6f74206d6573736167652062757300000000000000815291505b5060200190565b60208082528101612be281613936565b601481526000602082017f43616c6c6572206973206e6f742070617573657200000000000000000000000081529150613966565b60208082528101612be28161397d565b601f81526000602082017f5265656e7472616e637947756172643a207265656e7472616e742063616c6c0081529150613966565b60208082528101612be2816139c1565b8051612be28161324b565b600067ffffffffffffffff821115613a2a57613a2a6133f1565b5060209081020190565b8051612be28161322c565b60005b83811015613a5a578181015183820152602001613a42565b838111156115f25750506000910152565b6000613a796134908461344b565b905082815260208101848484011115613a9457613a94600080fd5b613011848285613a3f565b600082601f830112613ab357613ab3600080fd5b8151612f48848260208601613a6b565b600060408284031215613ad857613ad8600080fd5b613ae26040613434565b90506000613af08484613a34565b825250602082015167ffffffffffffffff811115613b1057613b10600080fd5b613b1c84828501613a9f565b60208301525092915050565b6000613b3661349084613a10565b83815290506020808201908402830185811115613b5557613b55600080fd5b835b81811015613b9657805167ffffffffffffffff811115613b7957613b79600080fd5b808601613b868982613ac3565b8552505060209283019201613b57565b5050509392505050565b600082601f830112613bb457613bb4600080fd5b8151612f48848260208601613b28565b8051612be28161359f565b600060e08284031215613be457613be4600080fd5b613bee60e0613434565b90506000613bfc8484613a05565b825250602082015167ffffffffffffffff811115613c1c57613c1c600080fd5b613c2884828501613ba0565b6020830152506040613c3c84828501613a34565b6040830152506060613c5084828501613bc4565b6060830152506080613c6484828501613a05565b60808301525060a0613c7884828501613bc4565b60a08301525060c082015167ffffffffffffffff811115613c9b57613c9b600080fd5b613ca784828501613a9f565b60c08301525092915050565b600060208284031215613cc857613cc8600080fd5b815167ffffffffffffffff811115613ce257613ce2600080fd5b612f4884828501613bcf565b634e487b7160e01b600052601160045260246000fd5b600082821015613d1657613d16613cee565b500390565b6000612be261389b8381565b61337481613d1b565b6000613d3a825190565b808452602084019350613d51818560208601613a3f565b601f19601f8201165b9093019392505050565b60e08101613d72828a613822565b613d7f6020830189613d27565b613d8c6040830188613822565b613d996060830187613388565b613da66080830186613822565b613db360a083018561336b565b81810360c0830152613dc58184613d30565b9998505050505050505050565b6001600160e01b03198116613374565b60608101613df08286613388565b613dfd6020830185613dd2565b612f4860408301846133c0565b60408101613e188285613388565b612d7a6020830184613388565b60e08101613e33828a613822565b613e406020830189613d27565b613d8c6040830188613d27565b600781526000602082017f746b696e206d6d0000000000000000000000000000000000000000000000000081529150613966565b60208082528101612be281613e4d565b8051612be2816133d6565b600060408284031215613eb157613eb1600080fd5b613ebb6040613434565b90506000613af08484613e91565b600060208284031215613ede57613ede600080fd5b815167ffffffffffffffff811115613ef857613ef8600080fd5b612f4884828501613e9c565b600f81526000602082017f63627269646765206e6f7420736574000000000000000000000000000000000081529150613966565b60208082528101612be281613f04565b67ffffffffffffffff8116613374565b60c08101613f668289613f48565b613f736020830188613388565b613f806040830187613822565b613f8d6060830186613388565b8181036080830152613f9f8185613d30565b905081810360a0830152613fb38184613d30565b98975050505050505050565b600060208284031215613fd457613fd4600080fd5b815167ffffffffffffffff811115613fee57613fee600080fd5b612f4884828501613a9f565b6000612be28261389b565b600981526000602082017f73656e64206661696c000000000000000000000000000000000000000000000081529150613966565b60208082528101612be281614005565b60e08101614057828a613822565b613d7f6020830189613822565b601481526000602082017f706172616d732073697a65206d69736d6174636800000000000000000000000081529150613966565b60208082528101612be281614064565b634e487b7160e01b600052603260045260246000fd5b6000808335601e19368590030181126140d9576140d9600080fd5b80840192508235915067ffffffffffffffff8211156140fa576140fa600080fd5b602083019250600182023603831315612ba757612ba7600080fd5b6000614122838584613476565b50500190565b6000612f48828486614115565b6000600019820361414857614148613cee565b5060010190565b8183526000602084019350614165838584613476565b601f19601f840116613d5a565b6000612d7784848461414f565b6000808335601e193685900301811261419a5761419a600080fd5b83810160208101935035915067ffffffffffffffff8211156141be576141be600080fd5b36829003831315612ba757612ba7600080fd5b818352600060208401935083602084028101838060005b878110156142235784840389526141ff828461417f565b61420a868284614172565b95506020840160209b909b019a935050506001016141e8565b5091979650505050505050565b600061423c8383613388565b505060200190565b6000612d7a6020840184613240565b8183526000602084019350818060005b85811015614290576142758284614244565b61427f8882614230565b975060208301925050600101614263565b509495945050505050565b604080825281016142ad8186886141d1565b905081810360208301526142c2818486614253565b9695505050505050565b6000602082840312156142e1576142e1600080fd5b6000612f4884846133e6565b600381526000602082016206e6f760ec1b81529150613966565b60208082528101612be2816142ed565b601b81526000602082017f62726964676520646f6573206e6f7420737570706f7274206d7367000000000081529150613966565b60208082528101612be281614317565b601281526000602082017f756e737570706f7274656420627269646765000000000000000000000000000081529150613966565b60208082528101612be28161435b565b6000604082840312156143b4576143b4600080fd5b6143be6040613434565b905060006143cc8484613240565b825250602082013567ffffffffffffffff8111156143ec576143ec600080fd5b613b1c848285016134bb565b600061440661349084613a10565b8381529050602080820190840283018581111561442557614425600080fd5b835b81811015613b9657803567ffffffffffffffff81111561444957614449600080fd5b808601614456898261439f565b8552505060209283019201614427565b6000612d7a3684846143f8565b60006020828403121561448857614488600080fd5b6000612f4884846135a7565b601281526000602082017f746b696e206e6f206e617469766557726170000000000000000000000000000081529150613966565b60208082528101612be281614494565b600b81526000602082017f696e7366636e7420616d7400000000000000000000000000000000000000000081529150613966565b60208082528101612be2816144d8565b6000610200828403121561453257614532600080fd5b61453d610200613434565b9050600061454b8484613240565b825250602061455c848483016133e6565b602083015250604061457084828501613240565b6040830152506060614584848285016133e6565b606083015250608082013567ffffffffffffffff8111156145a7576145a7600080fd5b6145b3848285016134bb565b60808301525060a082013567ffffffffffffffff8111156145d6576145d6600080fd5b6145e2848285016134bb565b60a08301525060c06145f6848285016135a7565b60c08301525060e061460a848285016135a7565b60e08301525061010061461f84828501613251565b6101008301525061012061463584828501613251565b6101208301525061014082013567ffffffffffffffff81111561465a5761465a600080fd5b614666848285016134bb565b6101408301525061016061467c84828501613251565b6101608301525061018061469284828501613240565b610180830152506101a06146a884828501613240565b6101a0830152506101c06146be848285016135a7565b6101c0830152506101e082013567ffffffffffffffff8111156146e3576146e3600080fd5b6146ef848285016134bb565b6101e08301525092915050565b6000612be2368361451c565b60408101613e188285613dd2565b601181526000602082017f6e6f742066656520636f6c6c6563746f7200000000000000000000000000000081529150613966565b60208082528101612be281614716565b601281526000602082017f73656e64206e6174697665206661696c6564000000000000000000000000000081529150613966565b60208082528101612be28161475a565b6000602082840312156147b3576147b3600080fd5b6000612f488484613a05565b602681526000602082017f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206181527f6464726573730000000000000000000000000000000000000000000000000000602082015291505b5060400190565b60208082528101612be2816147bf565b601881526000602082017f6e6f206e6174697665207472616e7366657272656420696e000000000000000081529150613966565b60208082528101612be28161482c565b600082601f83011261488457614884600080fd5b8135612f488482602086016143f8565b600060e082840312156148a9576148a9600080fd5b6148b360e0613434565b905060006148c18484613251565b825250602082013567ffffffffffffffff8111156148e1576148e1600080fd5b6148ed84828501614870565b602083015250604061490184828501613240565b6040830152506060614915848285016135a7565b606083015250608061492984828501613251565b60808301525060a061493d848285016135a7565b60a08301525060c082013567ffffffffffffffff81111561496057614960600080fd5b613ca7848285016134bb565b60006020828403121561498157614981600080fd5b813567ffffffffffffffff81111561499b5761499b600080fd5b612f4884828501614894565b60208082527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e657291019081526000613966565b60208082528101612be2816149a7565b6000602082840312156149fe576149fe600080fd5b6000612f488484613a34565b600c81526000602082017f746b206e6f206e6174697665000000000000000000000000000000000000000081529150613966565b60208082528101612be281614a0a565b601581526000602082017f4163636f756e74206973206e6f7420706175736572000000000000000000000081529150613966565b60208082528101612be281614a4e565b6000612be282516001600160e01b03191690565b6000614ab0825190565b60208301614abd81614a92565b92506004821015614ae457614adf6001600160e01b0319836004036008021b90565b831692505b5050919050565b600f81526000602082017f756e737570706f7274656420646578000000000000000000000000000000000081529150613966565b60208082528101612be281614aeb565b80516000906040840190614b438582613388565b50602083015184820360208601526107338282613d30565b60208082528101612d7a8184614b2f565b600080600060608486031215614b8457614b84600080fd5b6000614b908686613a05565b9350506020614ba186828701613a34565b92505060406135f886828701613a34565b600d81526000602082017f746b696e206d69736d617463680000000000000000000000000000000000000081529150613966565b60208082528101612be281614bb2565b600c81526000602082017f746b6f206d69736d61746368000000000000000000000000000000000000000081529150613966565b60208082528101612be281614bf6565b60008219821115614c4d57614c4d613cee565b500190565b60608082528101614c638186613d30565b9050614c726020830185613822565b612f486040830184613388565b6000614c89825190565b614c97818560208601613a3f565b9290920192915050565b6000612d7a8284614c7f565b600b81526000602082017f73776170206661696c656400000000000000000000000000000000000000000081529150613966565b60208082528101612be281614cad565b601081526000602082017f616c6c207377617073206661696c65640000000000000000000000000000000081529150613966565b60208082528101612be281614cf1565b60408101614d438285613388565b612d7a6020830184613822565b6000612d7a8383614b2f565b6000614d66825190565b80845260208401935083602082028501614d808560200190565b8060005b858110156142235784840389528151614d9d8582614d50565b94506020830160209a909a0199925050600101614d84565b805160009060e0840190614dc98582613822565b5060208301518482036020860152614de18282614d5c565b9150506040830151614df66040860182613388565b506060830151614e0960608601826133c0565b506080830151614e1c6080860182613822565b5060a0830151614e2f60a08601826133c0565b5060c083015184820360c08601526107338282613d30565b60208082528101612d7a8184614db5565b601981526000602082017f4163636f756e7420697320616c7265616479207061757365720000000000000081529150613966565b60208082528101612be281614e58565b601081526000602082017f5061757361626c653a207061757365640000000000000000000000000000000081529150613966565b60208082528101612be281614e9c565b60608101614eee8286613388565b614efb6020830185613388565b612f486040830184613822565b600981526000602082017f73776170206661696c000000000000000000000000000000000000000000000081529150613966565b60208082528101612be281614f08565b60a08101614f5a8288613822565b614f676020830187613822565b614f746040830186613388565b614f816060830185613822565b6142c26080830184613388565b601481526000602082017f5061757361626c653a206e6f742070617573656400000000000000000000000081529150613966565b60208082528101612be281614f8e565b600c81526000602082017f636463206e6f20666f756e64000000000000000000000000000000000000000081529150613966565b60208082528101612be281614fd2565b600081600019048311821515161561503057615030613cee565b500290565b634e487b7160e01b600052601260045260246000fd5b60008261505a5761505a615035565b500490565b60006020828403121561507457615074600080fd5b6000612f488484613bc4565b602a81526000602082017f5361666545524332303a204552433230206f7065726174696f6e20646964206e81527f6f7420737563636565640000000000000000000000000000000000000000000060208201529150614815565b60208082528101612be281615080565b6000612be28260601b90565b6000612be2826150ea565b61337461510d8261321b565b6150f6565b6000612be28260c01b90565b61337467ffffffffffffffff8216615112565b600061513d8287615101565b60148201915061514d8286615101565b60148201915061515d828561511e565b60088201915061516d828461511e565b50600801949350505050565b6101408101615188828d613822565b818103602083015261519a818c613d30565b90506151a9604083018b613f48565b6151b6606083018a613822565b6151c36080830189613388565b6151d060a0830188613388565b6151dd60c0830187613388565b6151ea60e0830186613388565b6151f8610100830185613822565b81810361012083015261520b8184613d30565b9c9b505050505050505050505050565b7f6578656375746f722066656500000000000000000000000000000000000000008152600c01600061524d828961511e565b60088201915061525d828861511e565b60088201915061526d8287613822565b60208201915061527d8286615101565b60148201915061528d8285613822565b60208201915061529d8284613822565b506020019695505050505050565b601181526000602082017f646561646c696e6520657863656564656400000000000000000000000000000081529150613966565b60208082528101612be2816152ab565b602681526000602082017f416464726573733a20696e73756666696369656e742062616c616e636520666f81527f722063616c6c000000000000000000000000000000000000000000000000000060208201529150614815565b60208082528101612be2816152ef565b601d81526000602082017f416464726573733a2063616c6c20746f206e6f6e2d636f6e747261637400000081529150613966565b60208082528101612be281615359565b7f19457468657265756d205369676e6564204d6573736167653a0a3332000000008152601c0160006153cf8284613822565b50602001919050565b600e81526000602082017f696e76616c6964207369676e657200000000000000000000000000000000000081529150613966565b60208082528101612be2816153d8565b60208082528101612d7a8184613d30565b601881526000602082017f45434453413a20696e76616c6964207369676e6174757265000000000000000081529150613966565b60208082528101612be28161542d565b601f81526000602082017f45434453413a20696e76616c6964207369676e6174757265206c656e6774680081529150613966565b60208082528101612be281615471565b602281526000602082017f45434453413a20696e76616c6964207369676e6174757265202773272076616c815261756560f01b60208201529150614815565b60208082528101612be2816154b5565b602281526000602082017f45434453413a20696e76616c6964207369676e6174757265202776272076616c815261756560f01b60208201529150614815565b60208082528101612be281615504565b60ff8116613374565b6080810161556a8287613822565b6155776020830186615553565b6155846040830185613822565b610733606083018461382256fea2646970667358221220601cde2b0e9fb0a8794427468b4ad9b1137bde8b2ee75fa69c11706fd8bf49b664736f6c634300080f0033
Deployed Bytecode Sourcemap
870:19398:18:-:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;3470:234:56;;;;;;:::i;:::-;;:::i;:::-;;;;;;;:::i;:::-;;;;;;;;344:21:16;;;;;;;;;;-1:-1:-1;344:21:16;;;;-1:-1:-1;;;;;344:21:16;;;;;;;;;;:::i;594:64:60:-;;;;;;;;;;;;;:::i;:::-;;1211:25:18;;;;;;;;;;-1:-1:-1;1211:25:18;;;;-1:-1:-1;;;;;1211:25:18;;;664:102:60;;;;;;;;;;-1:-1:-1;664:102:60;;;;;:::i;:::-;-1:-1:-1;;;;;743:16:60;720:4;743:16;;;:7;:16;;;;;;;;;664:102;;;;;;;;:::i;256:146:55:-;;;;;;;;;;-1:-1:-1;256:146:55;;;;;:::i;:::-;;:::i;14104:822:18:-;;;;;;:::i;:::-;;:::i;20015:149::-;;;;;;;;;;-1:-1:-1;20015:149:18;;;;;:::i;:::-;;:::i;1615:84:1:-;;;;;;;;;;-1:-1:-1;1685:7:1;;;;1615:84;;1484:242:14;;;;;;;;;;-1:-1:-1;1484:242:14;;;;;:::i;:::-;;:::i;867:95:60:-;;;;;;;;;;-1:-1:-1;867:95:60;;;;;:::i;:::-;;:::i;492:170:16:-;;;;;;;;;;-1:-1:-1;492:170:16;;;;;:::i;:::-;;:::i;968:75:60:-;;;;;;;;;;;;;:::i;1831:101:0:-;;;;;;;;;;;;;:::i;10387:3255:18:-;;;;;;:::i;:::-;;:::i;231:39:60:-;;;;;;;;;;-1:-1:-1;231:39:60;;;;;:::i;:::-;;;;;;;;;;;;;;;;452:23:13;;;;;;;;;;-1:-1:-1;452:23:13;;;;;:::i;:::-;;:::i;772:89:60:-;;;;;;;;;;-1:-1:-1;772:89:60;;;;;:::i;:::-;;:::i;528:60::-;;;;;;;;;;;;;:::i;1201:85:0:-;;;;;;;;;;-1:-1:-1;1247:7:0;1273:6;-1:-1:-1;;;;;1273:6:0;1201:85;;529:485:12;;;;;;;;;;-1:-1:-1;529:485:12;;;;;:::i;:::-;;:::i;1102:62:14:-;;;;;;;;;;-1:-1:-1;1102:62:14;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;4107:220:56;;;;;;:::i;224:25:55:-;;;;;;;;;;-1:-1:-1;224:25:55;;;;-1:-1:-1;;;;;224:25:55;;;1357:226:15;;;;;;;;;;-1:-1:-1;1357:226:15;;;;;:::i;:::-;;:::i;4996:1895:18:-;;;;;;:::i;:::-;;:::i;1089:46::-;;;;;;;;;;;;;;;;;;;;;;:::i;444:27:15:-;;;;;;;;;;-1:-1:-1;444:27:15;;;;-1:-1:-1;;;;;444:27:15;;;862:228:13;;;;;;;;;;-1:-1:-1;862:228:13;;;;;:::i;:::-;;:::i;512:20:56:-;;;;;;;;;;-1:-1:-1;512:20:56;;;;-1:-1:-1;;;512:20:56;;;;;;381:49:12;;;;;;;;;;-1:-1:-1;381:49:12;;;;;:::i;:::-;;;;;;;;;;;;-1:-1:-1;;;;;381:49:12;;;;;;;;;;:::i;740:611:15:-;;;;;;;;;;-1:-1:-1;740:611:15;;;;;:::i;:::-;;:::i;2081:198:0:-;;;;;;;;;;-1:-1:-1;2081:198:0;;;;;:::i;:::-;;:::i;15461:841:18:-;;;;;;:::i;:::-;;:::i;328:47:13:-;;;;;;;;;;-1:-1:-1;328:47:13;;;;;:::i;:::-;;;;;;;;;;;;-1:-1:-1;;;;;328:47:13;;;3470:234:56;580:8;;3685:15;;-1:-1:-1;;;580:8:56;;;;575:102;;626:10;;-1:-1:-1;;;;;626:10:56;612;:24;604:62;;;;-1:-1:-1;;;604:62:56;;;;;;;:::i;:::-;;;;;;;;;3470:234;;;;;;;:::o;594:64:60:-;468:10;720:4;743:16;;;:7;:16;;;;;;;;451:53;;;;-1:-1:-1;;;451:53:60;;;;;;;:::i;:::-;641:10:::1;:8;:10::i;:::-;594:64::o:0;256:146:55:-;1094:13:0;:11;:13::i;:::-;327:10:55::1;:24:::0;;-1:-1:-1;;;;;;327:24:55::1;-1:-1:-1::0;;;;;327:24:55;::::1;::::0;;::::1;::::0;;;366:29:::1;::::0;::::1;::::0;::::1;::::0;::::1;:::i;:::-;;;;;;;;256:146:::0;:::o;14104:822:18:-;580:8:56;;14386:15:18;;-1:-1:-1;;;580:8:56;;;;575:102;;626:10;;-1:-1:-1;;;;;626:10:56;612;:24;604:62;;;;-1:-1:-1;;;604:62:56;;;;;;;:::i;:::-;1744:1:2::1;2325:7;;:19:::0;2317:63:::1;;;;-1:-1:-1::0;;;2317:63:2::1;;;;;;;:::i;:::-;1744:1;2455:7;:18:::0;1685:7:1;;;;14413:67:18::2;;;-1:-1:-1::0;14448:21:18::2;14441:28;;14413:67;14489:22;14526:8;14514:39;;;;;;;;;;;;:::i;:::-;14489:64;;14563:36;14583:6;14591:7;14563:19;:36::i;:::-;14609:20;14642:1;:5;;;14632:7;:15;;;;:::i;:::-;14609:38;;14722:51;14733:6;14741:12;14755:1;:10;;;14767:5;14722:10;:51::i;:::-;14801:4:::0;;14832:5:::2;::::0;::::2;::::0;14869:9:::2;::::0;;::::2;::::0;::::2;::::0;;14801:4:::2;14869:9:::0;;;14789:90;;::::2;::::0;::::2;::::0;14801:4;;;14810:12;;14824:6;;14832:5;14839:28:::2;::::0;14789:90:::2;:::i;:::-;;;;;;;;14896:23;14889:30;;;;2484:1:2;1701::::1;2628:7;:22:::0;14104:822:18;;-1:-1:-1;;;;;;14104:822:18:o;20015:149::-;1094:13:0;:11;:13::i;:::-;20088:10:18::1;:24:::0;;-1:-1:-1;;;;;;20088:24:18::1;-1:-1:-1::0;;;;;20088:24:18;::::1;;::::0;;20127:30:::1;::::0;::::1;::::0;::::1;::::0;20088:24;;20127:30:::1;:::i;1484:242:14:-:0;1094:13:0;:11;:13::i;:::-;1615:43:14::1;1632:4;1638:9;1649:8;1615:16;:43::i;:::-;1673:46;1693:4;1699:9;1710:8;1673:46;;;;;;;;:::i;:::-;;;;;;;;1484:242:::0;;;:::o;867:95:60:-;1094:13:0;:11;:13::i;:::-;933:22:60::1;947:7;933:13;:22::i;:::-;867:95:::0;:::o;492:170:16:-;1094:13:0;:11;:13::i;:::-;575:6:16::1;::::0;;-1:-1:-1;;;;;591:16:16;;::::1;-1:-1:-1::0;;;;;;591:16:16;::::1;;::::0;;;622:33:::1;::::0;575:6;::::1;::::0;622:33:::1;::::0;::::1;::::0;575:6;;600:7;;622:33:::1;:::i;:::-;;;;;;;;545:117;492:170:::0;:::o;968:75:60:-;1011:25;1025:10;1011:13;:25::i;1831:101:0:-;1094:13;:11;:13::i;:::-;1895:30:::1;1922:1;1895:18;:30::i;10387:3255:18:-:0;580:8:56;;10658:15:18;;-1:-1:-1;;;580:8:56;;;;575:102;;626:10;;-1:-1:-1;;;;;626:10:56;612;:24;604:62;;;;-1:-1:-1;;;604:62:56;;;;;;;:::i;:::-;1744:1:2::1;2325:7;;:19:::0;2317:63:::1;;;;-1:-1:-1::0;;;2317:63:2::1;;;;;;;:::i;:::-;1744:1;2455:7;:18:::0;1685:7:1;;;;10685:67:18::2;;;-1:-1:-1::0;10720:21:18::2;10713:28;;10685:67;10761:22;10798:8;10786:39;;;;;;;;;;;;:::i;:::-;10761:64;;10924:1;:5;;;10914:7;:15;10910:260;;;10945:5;::::0;::::2;:15:::0;;;10991:4;;11049:9:::2;::::0;;::::2;::::0;::::2;::::0;;10991:4:::2;11049:9:::0;;;10979:80;;::::2;::::0;::::2;::::0;10991:4;;;;;;11003:6;;10953:7;;11018:29:::2;::::0;10979:80:::2;:::i;:::-;;;;;;;;11080:23;11073:30;;;;;10910:260;11154:5;::::0;::::2;::::0;11144:15:::2;::::0;:7;:15:::2;:::i;:::-;11134:25;;11200:7:::0;11180:17:::2;11247:24;11496:36;11516:6:::0;11200:7;11496:19:::2;:36::i;:::-;11590:7;::::0;::::2;::::0;:14;11566:6;;11590:19;11586:679:::2;;11629:22;11669:15;11801:22;11815:1;:7;;;11801:13;:22::i;:::-;11769:54:::0;;-1:-1:-1;11769:54:18;-1:-1:-1;11769:54:18;-1:-1:-1;;;;;;;11849:17:18;;::::2;::::0;;::::2;;11841:37;;;;-1:-1:-1::0;;;11841:37:18::2;;;;;;;:::i;:::-;11944:70;11969:1;:7;;;11978:6;11986:7;11995:1;:18;;;11944:24;:70::i;:::-;11916:98:::0;;-1:-1:-1;11916:98:18;-1:-1:-1;12141:16:18;;12137:114:::2;;12181:51;12192:6;12200:12;12214:1;:10;;;12226:5;12181:10;:51::i;:::-;11611:654;;11586:679;12283:9;::::0;::::2;::::0;:16;:20;12279:1069:::2;;12323:22;12359:1;:9;;;12348:38;;;;;;;;;;;;:::i;:::-;12437:21;12404:22;12429:30:::0;;;:7:::2;:30;::::0;;;;;12323:63;;-1:-1:-1;;;;;;12429:30:18::2;::::0;12477:58:::2;;;;-1:-1:-1::0;;;12477:58:18::2;;;;;;;:::i;:::-;12553:67;-1:-1:-1::0;;;;;12553:38:18;::::2;12600:7:::0;12610:9;12553:38:::2;:67::i;:::-;12638:27;12668:39;12690:1;:4;;;12696:1;:10;;;12668:21;:39::i;:::-;12793:10:::0;;12825::::2;::::0;;::::2;::::0;12918:8:::2;::::0;::::2;::::0;12739:241;;-1:-1:-1;;;12739:241:18;;12638:69;;-1:-1:-1;;;;;;12739:14:18;::::2;::::0;::::2;::::0;12761:9:::2;::::0;12739:241:::2;::::0;12793:10;;12857:9;;12888:8;;12638:69;;12739:241:::2;;;:::i;:::-;;;;;;;;;;;;;;;;;;;::::0;::::2;;;;;;;;;;;;;;;;;;::::0;;::::2;-1:-1:-1::0;;12739:241:18::2;::::0;::::2;;::::0;::::2;::::0;;;::::2;::::0;::::2;:::i;:::-;12725:255;;12305:690;;;12279:1069;;;13104:9;:13:::0;13100:160:::2;;13142:9;13157;-1:-1:-1::0;;;;;13157:14:18::2;13179:9;13157:36;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;13141:52;;;13223:4;13215:26;;;;-1:-1:-1::0;;;13215:26:18::2;;;;;;;:::i;:::-;13119:141;13100:160;13277:56;13288:8;13298:9;13309:1;:10;;;13321:1;:11;;;13277:10;:56::i;:::-;11281:2077;13494:101;13506:1;:4;;;13512:9;13523:12;13537:6;13545:1;:5;;;13552:29;13583:11;13494:101;;;;;;;;;;;;:::i;:::-;;;;;;;;13612:23;13605:30;;;;;;1701:1:2::1;2628:7;:22:::0;10387:3255:18;;-1:-1:-1;;;;;;10387:3255:18:o;452:23:13:-;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;;;452:23:13;;-1:-1:-1;452:23:13;:::o;772:89:60:-;1094:13:0;:11;:13::i;:::-;835:19:60::1;846:7;835:10;:19::i;528:60::-:0;468:10;720:4;743:16;;;:7;:16;;;;;;;;451:53;;;;-1:-1:-1;;;451:53:60;;;;;;;:::i;:::-;573:8:::1;:6;:8::i;529:485:12:-:0;1094:13:0;:11;:13::i;:::-;689:49:12;;::::1;681:82;;;;-1:-1:-1::0;;;681:82:12::1;;;;;;;:::i;:::-;778:9;773:162;793:27:::0;;::::1;773:162;;;905:15;;921:1;905:18;;;;;;;:::i;:::-;;;;;;;;;;;;;;:::i;:::-;841:7;:46;865:16;;882:1;865:19;;;;;;;:::i;:::-;;;;;;;;;;;;:::i;:::-;849:37;;;;;;;:::i;:::-;;;;;;;;841:46;;;;;;;;;;;;:83;;;;;-1:-1:-1::0;;;;;841:83:12::1;;;;;-1:-1:-1::0;;;;;841:83:12::1;;;;;;822:3;;;;;:::i;:::-;;;;773:162;;;;949:58;973:16;;991:15;;949:58;;;;;;;;;:::i;:::-;;;;;;;;529:485:::0;;;;:::o;1357:226:15:-;1094:13:0;:11;:13::i;:::-;1460:12:15::1;::::0;;-1:-1:-1;;;;;1482:28:15;;::::1;-1:-1:-1::0;;;;;;1482:28:15;::::1;;::::0;;;1525:51:::1;::::0;1460:12;::::1;::::0;1525:51:::1;::::0;::::1;::::0;1460:12;;1497:13;;1525:51:::1;:::i;4996:1895:18:-:0;1744:1:2;2325:7;;:19;2317:63;;;;-1:-1:-1;;;2317:63:2;;;;;;;:::i;:::-;1744:1;2455:7;:18;1239:19:1::1;:17;:19::i;:::-;5364:21:18::0;;::::2;::::0;:66:::2;;-1:-1:-1::0;5389:41:18::2;5416:13;5389:41;:16;::::0;;;::::2;::::0;::::2;;:::i;:::-;:41;;;;5364:66;5356:82;;;;-1:-1:-1::0;;;5356:82:18::2;;;;;;;:::i;:::-;5456:21:::0;;::::2;::::0;:77:::2;;-1:-1:-1::0;5482:14:18::2;::::0;::::2;;:19:::0;;::::2;::::0;:50:::2;;-1:-1:-1::0;5530:1:18::2;5505:13;::::0;;;::::2;::::0;::::2;;:::i;:::-;-1:-1:-1::0;;;;;5505:27:18::2;;;5482:50;5448:93;;;;-1:-1:-1::0;;;5448:93:18::2;;;;;;;:::i;:::-;5651:26;5696:20;;::::0;::::2;:5:::0;:20:::2;:::i;:::-;5680:38;;;;;;;:::i;:::-;;::::0;;;;::::2;::::0;;;-1:-1:-1;5750:21:18;;:50;::::2;;;-1:-1:-1::0;5775:13:18::2;;::::0;::::2;:5:::0;:13:::2;:::i;:::-;:25:::0;;-1:-1:-1;5750:50:18::2;5749:99;;;;5827:21;5805:18;:43;5749:99;5728:173;;;;-1:-1:-1::0;;;5728:173:18::2;;;;;;;:::i;:::-;5912:21;5936:27:::0;;;:7:::2;:27;::::0;;;;;;;;;-1:-1:-1;;;;;5936:27:18::2;::::0;6053:41:::2;6080:13;6053:41;::::0;:16:::2;::::0;;;;;::::2;;:::i;:::-;:41;;;:74;;;-1:-1:-1::0;;;;;;6098:29:18;::::2;::::0;::::2;6053:74;6045:105;;;;-1:-1:-1::0;;;6045:105:18::2;;;;;;;:::i;:::-;6180:14;::::0;::::2;;6204:22;6161:16;6256:13;::::0;;;::::2;::::0;::::2;;:::i;:::-;6237:32:::0;-1:-1:-1;6279:19:18::2;6301:13;::::0;;;::::2;::::0;::::2;;:::i;:::-;6279:35:::0;-1:-1:-1;6328:21:18;;6324:120:::2;;6409:24;;6423:9:::0;;6409:24:::2;:::i;:::-;:13;:24::i;:::-;6365:68:::0;;-1:-1:-1;6365:68:18;;-1:-1:-1;6365:68:18;-1:-1:-1;6365:68:18;-1:-1:-1;6324:120:18::2;6457:14;::::0;;;::::2;::::0;::::2;;:::i;:::-;6453:339;;;6507:10;::::0;-1:-1:-1;;;;;6495:22:18;;::::2;6507:10:::0;::::2;6495:22;6487:53;;;;-1:-1:-1::0;;;6487:53:18::2;;;;;;;:::i;:::-;6575:8;6562:9;:21;;6554:45;;;;-1:-1:-1::0;;;6554:45:18::2;;;;;;;:::i;:::-;6642:10;;;;;;;;;-1:-1:-1::0;;;;;6642:10:18::2;-1:-1:-1::0;;;;;6636:25:18::2;;6669:8;6636:44;;;;;;;;;;;;;;;;;;;;;;;;;;;;::::0;::::2;;;;;;;;;;;;::::0;::::2;;;;;;;;;;6453:339;;;6711:70;-1:-1:-1::0;;;;;6711:33:18;::::2;6745:10;6765:4;6772:8:::0;6711:33:::2;:70::i;:::-;6802:82;6815:8:::0;6825:11;6838:8;6802:82:::2;6848:5:::0;6802:82:::2;:::i;:::-;6855:9;;6802:82;;;;;:::i;:::-;;6866:9:::0;;6802:82:::2;:::i;:::-;6877:6;6802:12;:82::i;:::-;-1:-1:-1::0;;1701:1:2;2628:7;:22;-1:-1:-1;;;;;;;;;4996:1895:18:o;862:228:13:-;1094:13:0;:11;:13::i;:::-;949:15:13::1;990:8;;974:26;;;;;;;:::i;:::-;;;;;;;;949:52;;1011:27;1021:8;1031:6;-1:-1:-1::0;;;;;;1167:25:13;;;;;;;:14;:25;;;;;:42;;-1:-1:-1;;;;;1167:42:13;;;-1:-1:-1;;;;;;1167:42:13;;;;;;;;1219:6;:19;;1167:42;1219:19;;;;;;;;;;;;;;;;;;1096:149;1011:27:::1;1053:30;1066:8;1076:6;1053:30;;;;;;;:::i;740:611:15:-:0;596:12;;-1:-1:-1;;;;;596:12:15;582:10;:26;574:56;;;;-1:-1:-1;;;574:56:15;;;;;;;:::i;:::-;842:9:::1;837:508;857:18:::0;;::::1;837:508;;;977:1;955:7:::0;;963:1;955:10;;::::1;;;;;:::i;:::-;;;;;;;;;;;;;;:::i;:::-;-1:-1:-1::0;;;;;955:24:15::1;::::0;951:384:::1;;999:11;1013:21;999:35;;1053:9;1068:3;-1:-1:-1::0;;;;;1068:8:15::1;1084:3;1094:5;1068:36;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;1052:52;;;1130:4;1122:35;;;;-1:-1:-1::0;;;1122:35:15::1;;;;;;;:::i;:::-;981:191;;951:384;;;1196:15;1221:7;;1229:1;1221:10;;;;;;;:::i;:::-;;;;;;;;;;;;;;:::i;:::-;-1:-1:-1::0;;;;;1214:28:15::1;;1251:4;1214:43;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;::::0;::::1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;1196:61;;1275:45;1307:3;1312:7;1282;;1290:1;1282:10;;;;;;;:::i;:::-;;;;;;;;;;;;;;:::i;:::-;-1:-1:-1::0;;;;;1275:31:15::1;::::0;:45;:31:::1;:45::i;:::-;1178:157;951:384;877:3:::0;::::1;::::0;::::1;:::i;:::-;;;;837:508;;;;740:611:::0;;;:::o;2081:198:0:-;1094:13;:11;:13::i;:::-;-1:-1:-1;;;;;2169:22:0;::::1;2161:73;;;;-1:-1:-1::0;;;2161:73:0::1;;;;;;;:::i;:::-;2244:28;2263:8;2244:18;:28::i;15461:841:18:-:0;15671:15;1744:1:2;2325:7;;:19;2317:63;;;;-1:-1:-1;;;2317:63:2;;;;;;;:::i;:::-;1744:1;2455:7;:18;1685:7:1;;;;15698:67:18::1;;;-1:-1:-1::0;15733:21:18::1;15726:28;;15698:67;15788:10;::::0;-1:-1:-1;;;;;15778:20:18;;::::1;15788:10:::0;::::1;15778:20;15774:206;;15814:67;-1:-1:-1::0;;;;;15814:31:18;::::1;15846:10;15866:4;15873:7:::0;15814:31:::1;:67::i;:::-;15774:206;;;15933:7;15920:9;:20;;15912:57;;;;-1:-1:-1::0;;;15912:57:18::1;;;;;;;:::i;:::-;15989:22;16014:39;::::0;;::::1;16026:8:::0;16014:39:::1;:::i;:::-;15989:64;;16063:36;16083:6;16091:7;16063:19;:36::i;:::-;16109:46;16120:6;16128:7;16137:1;:10;;;16149:5;16109:10;:46::i;:::-;16182:4:::0;;16208:5:::1;::::0;::::1;::::0;16245:9:::1;::::0;;::::1;::::0;::::1;::::0;;16182:4:::1;16245:9:::0;;;16170:85;;::::1;::::0;::::1;::::0;16182:4;;;16191:7;;16200:6;;16208:5;16215:28:::1;::::0;16170:85:::1;:::i;:::-;;;;;;;;16272:23;16265:30;;;2484:1:2;1701::::0;2628:7;:22;15461:841:18;;-1:-1:-1;;;;;15461:841:18:o;2433:117:1:-;1486:16;:14;:16::i;:::-;2491:7:::1;:15:::0;;-1:-1:-1;;2491:15:1::1;::::0;;2521:22:::1;719:10:9::0;2530:12:1::1;2521:22;;;;;;:::i;:::-;;;;;;;;2433:117::o:0;1359:130:0:-;1247:7;1273:6;-1:-1:-1;;;;;1273:6:0;719:10:9;1422:23:0;1414:68;;;;-1:-1:-1;;;1414:68:0;;;;;;;:::i;17838:1048:18:-;18236:10;;-1:-1:-1;;;;;18236:10:18;;;18226:20;;;;18222:658;;18509:10;;18497:41;;;-1:-1:-1;;;18497:41:18;;;;18480:14;;-1:-1:-1;;;;;18509:10:18;;18497:39;;:41;;;;;;;;;;;;;;18509:10;18497:41;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;18480:58;;18782:10;;;;;;;;;-1:-1:-1;;;;;18782:10:18;-1:-1:-1;;;;;18745:47:18;18758:6;-1:-1:-1;;;;;18745:31:18;;:33;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;-1:-1:-1;;;;;18745:47:18;;18741:129;;18818:10;;;;;;;;;-1:-1:-1;;;;;18818:10:18;-1:-1:-1;;;;;18812:25:18;;18845:7;18812:43;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;18741:129;18248:632;18222:658;17838:1048;;:::o;18892:480::-;19041:10;19037:329;;;19085:10;;-1:-1:-1;;;;;19075:20:18;;;19085:10;;19075:20;19067:45;;;;-1:-1:-1;;;19067:45:18;;;;;;;:::i;:::-;19132:10;;19126:35;;-1:-1:-1;;;19126:35:18;;-1:-1:-1;;;;;19132:10:18;;;;19126:26;;:35;;19153:7;;19126:35;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;19176:9;19191;-1:-1:-1;;;;;19191:14:18;19213:7;19227:5;19191:46;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;19175:62;;;19259:4;19251:26;;;;-1:-1:-1;;;19251:26:18;;;;;;;:::i;:::-;19053:235;19037:329;;;19308:47;-1:-1:-1;;;;;19308:27:18;;19336:9;19347:7;19308:27;:47::i;1732:265:14:-;-1:-1:-1;;;;;1868:17:14;;1853:12;1868:17;;;:11;:17;;;;;;;;-1:-1:-1;;;;;;1868:28:14;;;;;;;;;;;;1914:19;;;;;;;1906:35;;;;-1:-1:-1;;;1906:35:14;;;;;;;:::i;:::-;-1:-1:-1;;;;;;1951:17:14;;;;;;;:11;:17;;;;;;;;-1:-1:-1;;;;;;1951:28:14;;;;;;;;;:39;;;;;-1:-1:-1;;1951:39:14;;;;;;;;;1732:265::o;1241:187:60:-;-1:-1:-1;;;;;743:16:60;;720:4;743:16;;;:7;:16;;;;;;;;1299:51;;;;-1:-1:-1;;;1299:51:60;;;;;;;:::i;:::-;-1:-1:-1;;;;;1360:16:60;;1379:5;1360:16;;;:7;:16;;;;;;;:24;;-1:-1:-1;;1360:24:60;;;1399:22;;;;;1368:7;;1399:22;:::i;2433:187:0:-;2506:16;2525:6;;-1:-1:-1;;;;;2541:17:0;;;-1:-1:-1;;;;;;2541:17:0;;;;;;2573:40;;2525:6;;;;;;;2573:40;;2506:16;2573:40;2496:124;2433:187;:::o;1228:1010:17:-;1351:16;1381:15;1410:16;1440:22;1518:19;1547:20;1586:18;1597:6;1586:10;:18::i;:::-;1577:27;;1620:9;1615:617;1639:6;:13;1635:1;:17;1615:617;;;1681:11;:26;1693:6;1700:1;1693:9;;;;;;;;:::i;:::-;;;;;;;:13;;;-1:-1:-1;;;;;1681:26:17;-1:-1:-1;;;;;1681:26:17;;;;;;;;;;;;:50;1715:6;1722:1;1715:9;;;;;;;;:::i;:::-;;;;;;;:14;;;1708:22;;;:::i;:::-;-1:-1:-1;;;;;;1681:50:17;;;;;;;;;;;;-1:-1:-1;1681:50:17;;;;1673:78;;;;-1:-1:-1;;;1673:78:17;;;;;;;:::i;:::-;1766:17;1785:16;1803:17;1824:6;1831:1;1824:9;;;;;;;;:::i;:::-;;;;;;;-1:-1:-1;;;;;1824:24:17;;1849:6;1856:1;1849:9;;;;;;;;:::i;:::-;;;;;;;1824:35;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;1765:94;;-1:-1:-1;1765:94:17;-1:-1:-1;1765:94:17;-1:-1:-1;;;;;;1881:25:17;;;;:52;;;1925:8;-1:-1:-1;;;;;1910:23:17;:11;-1:-1:-1;;;;;1910:23:17;;1881:52;1873:78;;;;-1:-1:-1;;;1873:78:17;;;;;;;:::i;:::-;1979:8;;-1:-1:-1;1979:8:17;;-1:-1:-1;;;;;2009:26:17;;;;:55;;;2055:9;-1:-1:-1;;;;;2039:25:17;:12;-1:-1:-1;;;;;2039:25:17;;2009:55;2001:80;;;;-1:-1:-1;;;2001:80:17;;;;;;;:::i;:::-;2110:9;-1:-1:-1;2110:9:17;2134:21;2146:9;2134:21;;:::i;:::-;;-1:-1:-1;2179:8:17;;-1:-1:-1;2212:9:17;-1:-1:-1;1654:3:17;;-1:-1:-1;1654:3:17;;;:::i;:::-;;;;1615:617;;;;1508:730;;1228:1010;;;;;:::o;4484:1286::-;4721:17;4740:20;4773:26;4801:15;4818:16;4838:103;4873:6;4893:17;4924:7;4838:21;:103::i;:::-;4772:169;;;;;;4951:17;4978:8;-1:-1:-1;;;;;4971:26:17;;5006:4;4971:41;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;4951:61;;5080:9;5075:525;5099:6;:13;5095:1;:17;5075:525;;;5133:25;5161:7;5169:1;5161:10;;;;;;;;:::i;:::-;;;;;;;-1:-1:-1;;;;;5161:37:17;;5216:6;5223:1;5216:9;;;;;;;;:::i;:::-;;;;;;;:14;;;5248:9;5258:1;5248:12;;;;;;;;:::i;:::-;;;;;;;5286:4;5161:144;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;5161:144:17;;;;;;;;;;;;:::i;:::-;5133:172;;5319:66;5357:6;5364:1;5357:9;;;;;;;;:::i;:::-;;;;;;;:13;;;5372:9;5382:1;5372:12;;;;;;;;:::i;:::-;;;;;;;5326:7;-1:-1:-1;;;;;5319:37:17;;;:66;;;;;:::i;:::-;5400:7;5413:6;5420:1;5413:9;;;;;;;;:::i;:::-;;;;;;;:13;;;-1:-1:-1;;;;;5413:18:17;5432:12;5413:32;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;5399:46;;;5467:2;:23;;;;5473:17;5467:23;5459:47;;;;-1:-1:-1;;;5459:47:17;;;;;;;:::i;:::-;5525:2;5520:70;;5563:9;5573:1;5563:12;;;;;;;;:::i;:::-;;;;;;;5547:28;;;;;:::i;:::-;;;5520:70;5119:481;;5114:3;;;;;:::i;:::-;;;;5075:525;;;-1:-1:-1;5628:41:17;;-1:-1:-1;;;5628:41:17;;5609:16;;-1:-1:-1;;;;;5628:26:17;;;;;:41;;5663:4;;5628:41;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;5609:60;-1:-1:-1;5691:20:17;5702:9;5609:60;5691:20;:::i;:::-;5679:32;;5741:1;5729:9;:13;5721:42;;;;-1:-1:-1;;;5721:42:17;;;;;;;:::i;:::-;4762:1008;;;;;4484:1286;;;;;;;:::o;2084:310:7:-;2210:20;2275:5;2233;-1:-1:-1;;;;;2233:15:7;;2257:4;2264:7;2233:39;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;:47;;;;:::i;:::-;2210:70;;2290:97;2310:5;2340:22;;;2364:7;2373:12;2317:69;;;;;;;;;:::i;:::-;;;;-1:-1:-1;;2317:69:7;;;;;;;;;;;;;;;;-1:-1:-1;;;;;;2317:69:7;;;;;;;;;;2290:19;:97::i;17326:506:18:-;17412:20;17444:42;17496:18;17558:257;;;;;;;;17594:3;17558:257;;;;17622:10;17558:257;;;;17660:9;-1:-1:-1;;;;;17558:257:18;;;;;17698:5;17558:257;;;;;;17726:1;17558:257;;;;17763:5;17558:257;;;;;;17795:5;17558:257;;;17534:291;;;;;;;;:::i;:::-;;;;;;;;;;;;;17524:301;;17434:398;;17326:506;;;;:::o;1049:186:60:-;-1:-1:-1;;;;;743:16:60;;720:4;743:16;;;:7;:16;;;;;;;;1112:18;1104:56;;;;-1:-1:-1;;;1104:56:60;;;;;;;:::i;:::-;-1:-1:-1;;;;;1170:16:60;;;;;;:7;:16;;;;;;;:23;;-1:-1:-1;;1170:23:60;1189:4;1170:23;;;1208:20;;;;;1178:7;;1208:20;:::i;2186:115:1:-;1239:19;:17;:19::i;:::-;2245:7:::1;:14:::0;;-1:-1:-1;;2245:14:1::1;2255:4;2245:14;::::0;;2274:20:::1;2281:12;719:10:9::0;;640:96;1767:106:1;1685:7;;;;1836:9;1828:38;;;;-1:-1:-1;;;1828:38:1;;;;;;;:::i;974:241:7:-;1112:96;1132:5;1162:27;;;1191:4;1197:2;1201:5;1139:68;;;;;;;;;;:::i;6897:972:18:-;7277:16;;7254:9;;7277:21;7273:161;;7314:7;7353:32;7366:9;7377:7;7353:12;:32::i;:::-;7335:50;-1:-1:-1;7335:50:18;-1:-1:-1;7335:50:18;7399:24;;;;-1:-1:-1;;;7399:24:18;;;;;;;:::i;:::-;7300:134;7273:161;7444:10;7457:39;7468:5;:14;;;7484:5;:11;;;7457:10;:39::i;:::-;7444:52;;7570:13;7543:41;;:5;:16;;;:41;;;7539:237;;7605:59;7616:2;7620:9;7631:8;7641:9;7652:11;7605:59;;;;;;;;;;:::i;:::-;;;;;;;;7678:67;7689:11;7702:9;7713:5;:14;;;7729:5;:15;;;7678:10;:67::i;:::-;7759:7;;;;7539:237;7786:76;7796:2;7800:8;7810:11;7823:5;7830:9;7841;7852;7786;:76::i;:::-;7198:671;;6897:972;;;;;;;;:::o;763:205:7:-;875:86;895:5;925:23;;;950:2;954:5;902:58;;;;;;;;;:::i;1945:106:1:-;1685:7;;;;2003:41;;;;-1:-1:-1;;;2003:41:1;;;;;;;:::i;1251:437:13:-;1334:15;1361:23;1400:6;:13;1387:27;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;1387:27:13;;1361:53;;1429:9;1424:232;1448:6;:13;1444:1;:17;1424:232;;;1482:15;1507:6;1514:1;1507:9;;;;;;;;:::i;:::-;;;;;;;:14;;;1500:22;;;:::i;:::-;-1:-1:-1;;;;;;1549:24:13;;;;;;:14;:24;;;;;;1536:10;;1482:40;;-1:-1:-1;;;;;;1549:24:13;;1536:7;;1544:1;;1536:10;;;;;;:::i;:::-;;;;;;:37;-1:-1:-1;;;;;1536:37:13;;;-1:-1:-1;;;;;1536:37:13;;;;;1626:1;-1:-1:-1;;;;;1595:33:13;1603:7;1611:1;1603:10;;;;;;;;:::i;:::-;;;;;;;-1:-1:-1;;;;;1595:33:13;;1587:58;;;;-1:-1:-1;;;1587:58:13;;;;;;;:::i;:::-;-1:-1:-1;1463:3:13;;;;:::i;:::-;;;;1424:232;;;-1:-1:-1;1673:7:13;1251:437;-1:-1:-1;;1251:437:13:o;5887:935:17:-;6099:26;6139:15;6168:16;6209;6261:6;:13;6247:28;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;6247:28:17;;6235:40;;6341:9;6336:238;6360:6;:13;6356:1;:17;6336:238;;;6394:16;6456:7;6464:1;6456:10;;;;;;;;:::i;:::-;;;;;;;-1:-1:-1;;;;;6456:25:17;;6482:6;6489:1;6482:9;;;;;;;;:::i;:::-;;;;;;;6456:36;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;6424:68;;-1:-1:-1;6424:68:17;-1:-1:-1;6424:68:17;-1:-1:-1;6506:20:17;6424:68;6506:20;;:::i;:::-;;;6555:8;6540:9;6550:1;6540:12;;;;;;;;:::i;:::-;;;;;;;;;;:23;-1:-1:-1;6375:3:17;;;;:::i;:::-;;;;6336:238;;;;6689:9;6684:132;6708:9;:16;6704:1;:20;6684:132;;;6797:8;6781:9;6791:1;6781:12;;;;;;;;:::i;:::-;;;;;;;6761:17;:32;;;;:::i;:::-;6760:45;;;;:::i;:::-;6745:9;6755:1;6745:12;;;;;;;;:::i;:::-;;;;;;;;;;:60;6726:3;;;;:::i;:::-;;;;6684:132;;;;6199:623;5887:935;;;;;;;:::o;3747:706:7:-;4166:23;4192:69;4220:4;4192:69;;;;;;;;;;;;;;;;;4200:5;-1:-1:-1;;;;;4192:27:7;;;:69;;;;;:::i;:::-;4275:17;;4166:95;;-1:-1:-1;4275:21:7;4271:176;;4370:10;4359:30;;;;;;;;;;;;:::i;:::-;4351:85;;;;-1:-1:-1;;;4351:85:7;;;;;;;:::i;2793:866:17:-;2951:7;2960:17;2994:9;2989:664;3013:6;:13;3009:1;:17;2989:664;;;3048:16;3066:15;3083:16;3103:7;3111:1;3103:10;;;;;;;;:::i;:::-;;;;;;;-1:-1:-1;;;;;3103:25:17;;3129:6;3136:1;3129:9;;;;;;;;:::i;:::-;;;;;;;3103:36;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;3047:92;;;;;;3153:17;3173:7;3181:1;3173:10;;;;;;;;:::i;:::-;;;;;;;-1:-1:-1;;;;;3173:37:17;;3211:6;3218:1;3211:9;;;;;;;;:::i;:::-;;;;;;;:14;;;3227:8;3245:4;3173:78;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;3173:78:17;;;;;;;;;;;;:::i;:::-;3153:98;;3265:62;3303:6;3310:1;3303:9;;;;;;;;:::i;:::-;;;;;;;;;;;:13;-1:-1:-1;;;;;3265:37:17;;;3318:8;3265:37;:62::i;:::-;3361:41;;-1:-1:-1;;;3361:41:17;;3341:17;;-1:-1:-1;;;;;3361:26:17;;;;;:41;;3396:4;;3361:41;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;3341:61;;3425:6;3432:1;3425:9;;;;;;;;:::i;:::-;;;;;;;:13;;;-1:-1:-1;;;;;3425:18:17;3444:4;3425:24;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;3416:33;;;;;3468:2;3463:59;;3498:5;3505:1;3490:17;;;;;;;;;;;;3463:59;3554:41;;-1:-1:-1;;;3554:41:17;;3535:16;;-1:-1:-1;;;;;3554:26:17;;;;;:41;;3589:4;;3554:41;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;3535:60;-1:-1:-1;3622:20:17;3633:9;3535:60;3622:20;:::i;:::-;3609:33;;;;:::i;:::-;;;3033:620;;;;;;3028:3;;;;;:::i;:::-;;;;2989:664;;;;2793:866;;;;;;:::o;16563:190:18:-;16639:7;16692:10;16704:9;16722:13;16738:6;16675:70;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;16665:81;;;;;;16658:88;;16563:190;;;;;:::o;7875:1573::-;8237:25;8285:1;8266:9;:16;:20;:48;;;;8313:1;8290:5;:13;;;:20;:24;8266:48;8265:118;;8369:14;;8265:118;;;8330:5;:24;;;8265:118;8237:146;;8393:23;8440:38;8451:5;8458:9;8469:8;8440:10;:38::i;:::-;8536:14;;;;8509:9;;8532:83;;;8579:21;8591:9;8579;:21;:::i;:::-;8570:30;;8532:83;8676:20;;;;8660:38;;;;;;;8628:21;8652:47;;;:7;:47;;;;;;;-1:-1:-1;;;;;8652:47:18;;;;8713:70;;:41;;8652:47;8772:10;8713:41;:70::i;:::-;8797:27;8827:44;8849:3;8854:5;8861:9;8827:21;:44::i;:::-;8797:74;;8898:6;-1:-1:-1;;;;;8898:13:18;;8919:6;8944:5;:16;;;8978:17;9013:10;9041:11;9070:5;:18;;;9106:14;8898:236;;;;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;8898:236:18;;;;;;;;;;;;:::i;:::-;8885:249;;8426:719;;;9159:282;9184:3;9201:10;9225:5;:16;;;9255:9;9278:8;9300:5;:17;;;9331;9362:11;9387:10;9411:5;:20;;;9159:282;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;8138:1310;;7875:1573;;;;;;;:::o;3861:223:8:-;3994:12;4025:52;4047:6;4055:4;4061:1;4064:12;4025:21;:52::i;:::-;4018:59;;3861:223;;;;;;:::o;19378:631:18:-;19528:12;19639:13;19671:5;:16;;;19705:9;19732:8;19758:5;:17;;;19793:5;:9;;;19566:250;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;19543:283;;;;;;19528:298;;19836:16;19855:29;:4;:27;:29::i;:::-;19836:48;;19894:33;19904:8;19914:5;:12;;;19894:9;:33::i;:::-;19965:15;19945:5;:17;;;:35;19937:65;;;;-1:-1:-1;;;19937:65:18;;;;;;;:::i;:::-;19518:491;;19378:631;;;:::o;16759:561::-;16936:20;17002:301;;;;;;;;17038:3;17002:301;;;;17066:6;17002:301;;;;17100:5;:14;;;-1:-1:-1;;;;;17002:301:18;;;;;17143:5;:15;;;17002:301;;;;;;17181:5;:9;;;17002:301;;;;17226:5;:22;;;17002:301;;;;;;17275:5;:13;;;17002:301;;;16978:335;;;;;;;;:::i;:::-;;;;;;;;;;;;;16968:345;;16759:561;;;;;:::o;4948:499:8:-;5113:12;5170:5;5145:21;:30;;5137:81;;;;-1:-1:-1;;;5137:81:8;;;;;;;:::i;:::-;-1:-1:-1;;;;;1465:19:8;;;5228:60;;;;-1:-1:-1;;;5228:60:8;;;;;;;:::i;:::-;5300:12;5314:23;5341:6;-1:-1:-1;;;;;5341:11:8;5360:5;5367:4;5341:31;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;5299:73;;;;5389:51;5406:7;5415:10;5427:12;5389:16;:51::i;:::-;5382:58;;;;4948:499;;;;;;;:::o;7463:265:11:-;7532:7;7715:4;7662:58;;;;;;;;:::i;:::-;;;;;;;;;;;;;7652:69;;;;;;7645:76;;7463:265;;;:::o;668:181:16:-;748:15;766:22;:5;780:7;766:13;:22::i;:::-;817:6;;748:40;;-1:-1:-1;;;;;;806:17:16;;;817:6;;806:17;798:44;;;;-1:-1:-1;;;798:44:16;;;;;;;:::i;7561:742:8:-;7707:12;7735:7;7731:566;;;-1:-1:-1;7765:10:8;7758:17;;7731:566;7876:17;;:21;7872:415;;8120:10;8114:17;8180:15;8167:10;8163:2;8159:19;8152:44;7872:415;8259:12;8252:20;;-1:-1:-1;;;8252:20:8;;;;;;;;:::i;3759:227:11:-;3837:7;3857:17;3876:18;3898:27;3909:4;3915:9;3898:10;:27::i;:::-;3856:69;;;;3935:18;3947:5;3935:11;:18::i;:::-;-1:-1:-1;3970:9:11;3759:227;-1:-1:-1;;;3759:227:11:o;2243:730::-;2324:7;2333:12;2361:9;:16;2381:2;2361:22;2357:610;;2697:4;2682:20;;2676:27;2746:4;2731:20;;2725:27;2803:4;2788:20;;2782:27;2399:9;2774:36;2844:25;2855:4;2774:36;2676:27;2725;2844:10;:25::i;:::-;2837:32;;;;;;;;;2357:610;-1:-1:-1;2916:1:11;;-1:-1:-1;2920:35:11;2900:56;;548:631;625:20;616:5;:29;;;;;;;;:::i;:::-;;612:561;;548:631;:::o;612:561::-;721:29;712:5;:38;;;;;;;;:::i;:::-;;708:465;;766:34;;-1:-1:-1;;;766:34:11;;;;;;;:::i;708:465::-;830:35;821:5;:44;;;;;;;;:::i;:::-;;817:356;;881:41;;-1:-1:-1;;;881:41:11;;;;;;;:::i;817:356::-;952:30;943:5;:39;;;;;;;;:::i;:::-;;939:234;;998:44;;-1:-1:-1;;;998:44:11;;;;;;;:::i;939:234::-;1072:30;1063:5;:39;;;;;;;;:::i;:::-;;1059:114;;1118:44;;-1:-1:-1;;;1118:44:11;;;;;;;:::i;5167:1603::-;5293:7;;6217:66;6204:79;;6200:161;;;-1:-1:-1;6315:1:11;;-1:-1:-1;6319:30:11;6299:51;;6200:161;6374:1;:7;;6379:2;6374:7;;:18;;;;;6385:1;:7;;6390:2;6385:7;;6374:18;6370:100;;;-1:-1:-1;6424:1:11;;-1:-1:-1;6428:30:11;6408:51;;6370:100;6564:14;6581:24;6591:4;6597:1;6600;6603;6581:24;;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;6581:24:11;;-1:-1:-1;;6581:24:11;;;-1:-1:-1;;;;;;;6619:20:11;;6615:101;;6671:1;6675:29;6655:50;;;;;;;6615:101;6734:6;-1:-1:-1;6742:20:11;;-1:-1:-1;5167:1603:11;;;;;;;;:::o;466:96:90:-;503:7;-1:-1:-1;;;;;400:54:90;;532:24;334:126;568:122;641:24;659:5;641:24;:::i;:::-;634:5;631:35;621:63;;680:1;677;670:12;696:139;767:20;;796:33;767:20;796:33;:::i;924:122::-;1015:5;997:24;841:77;1052:139;1123:20;;1152:33;1123:20;1152:33;:::i;1579:552::-;1636:8;1646:6;1696:3;1689:4;1681:6;1677:17;1673:27;1663:122;;1704:79;870:19398:18;;;1704:79:90;-1:-1:-1;1804:20:90;;1847:18;1836:30;;1833:117;;;1869:79;870:19398:18;;;1869:79:90;1983:4;1975:6;1971:17;1959:29;;2037:3;2029:4;2021:6;2017:17;2007:8;2003:32;2000:41;1997:128;;;2044:79;870:19398:18;;;2137:963:90;2234:6;2242;2250;2258;2266;2315:3;2303:9;2294:7;2290:23;2286:33;2283:120;;;2322:79;870:19398:18;;;2322:79:90;2442:1;2467:53;2512:7;2492:9;2467:53;:::i;:::-;2457:63;;2413:117;2569:2;2595:53;2640:7;2631:6;2620:9;2616:22;2595:53;:::i;:::-;2585:63;;2540:118;2725:2;2714:9;2710:18;2697:32;2756:18;2748:6;2745:30;2742:117;;;2778:79;870:19398:18;;;2778:79:90;2891:64;2947:7;2938:6;2927:9;2923:22;2891:64;:::i;:::-;2873:82;;;;2668:297;3004:2;3030:53;3075:7;3066:6;3055:9;3051:22;3030:53;:::i;:::-;3020:63;;2975:118;2137:963;;;;;;;;:::o;3106:180::-;-1:-1:-1;;;3151:1:90;3144:88;3251:4;3248:1;3241:15;3275:4;3272:1;3265:15;3292:125;3385:1;3378:5;3375:12;3365:46;;3391:18;;:::i;3423:151::-;3509:5;3515:53;3509:5;3515:53;:::i;:::-;3423:151;;;:::o;3580:::-;3648:9;3681:44;3719:5;3681:44;:::i;3737:167::-;3842:55;3891:5;3842:55;:::i;:::-;3837:3;3830:68;3737:167;;:::o;3910:258::-;4059:2;4044:18;;4072:89;4048:9;4134:6;4072:89;:::i;4174:118::-;4261:24;4279:5;4261:24;:::i;4298:222::-;4429:2;4414:18;;4442:71;4418:9;4486:6;4442:71;:::i;4526:329::-;4585:6;4634:2;4622:9;4613:7;4609:23;4605:32;4602:119;;;4640:79;870:19398:18;;;4640:79:90;4760:1;4785:53;4830:7;4810:9;4785:53;:::i;4957:109::-;4931:13;;4924:21;5038;4861:90;5072:210;5197:2;5182:18;;5210:65;5186:9;5248:6;5210:65;:::i;5395:120::-;5364:18;5353:30;;5467:23;5288:101;5521:137;5591:20;;5620:32;5591:20;5620:32;:::i;5895:180::-;-1:-1:-1;;;5940:1:90;5933:88;6040:4;6037:1;6030:15;6064:4;6061:1;6054:15;6081:281;-1:-1:-1;;5879:2:90;5859:14;;5855:28;6156:6;6152:40;6294:6;6282:10;6279:22;6258:18;6246:10;6243:34;6240:62;6237:88;;;6305:18;;:::i;:::-;6341:2;6334:22;-1:-1:-1;;6081:281:90:o;6368:129::-;6402:6;6429:20;73:2;67:9;;7:75;6429:20;6419:30;;6458:33;6486:4;6478:6;6458:33;:::i;6503:307::-;6564:4;6654:18;6646:6;6643:30;6640:56;;;6676:18;;:::i;:::-;-1:-1:-1;;5879:2:90;5859:14;;5855:28;6798:4;6788:15;;6503:307;-1:-1:-1;;6503:307:90:o;6816:154::-;6900:6;6895:3;6890;6877:30;-1:-1:-1;6962:1:90;6944:16;;6937:27;6816:154::o;6976:410::-;7053:5;7078:65;7094:48;7135:6;7094:48;:::i;:::-;7078:65;:::i;:::-;7069:74;;7166:6;7159:5;7152:21;7204:4;7197:5;7193:16;7242:3;7233:6;7228:3;7224:16;7221:25;7218:112;;;7249:79;870:19398:18;;;7249:79:90;7339:41;7373:6;7368:3;7363;7339:41;:::i;7405:338::-;7460:5;7509:3;7502:4;7494:6;7490:17;7486:27;7476:122;;7517:79;870:19398:18;;;7517:79:90;7634:6;7621:20;7659:78;7733:3;7725:6;7718:4;7710:6;7706:17;7659:78;:::i;7749:1233::-;7861:6;7869;7877;7885;7893;7901;7950:3;7938:9;7929:7;7925:23;7921:33;7918:120;;;7957:79;870:19398:18;;;7957:79:90;8077:1;8102:53;8147:7;8127:9;8102:53;:::i;:::-;8092:63;;8048:117;8204:2;8230:53;8275:7;8266:6;8255:9;8251:22;8230:53;:::i;:::-;8220:63;;8175:118;8332:2;8358:53;8403:7;8394:6;8383:9;8379:22;8358:53;:::i;:::-;8348:63;;8303:118;8460:2;8486:52;8530:7;8521:6;8510:9;8506:22;8486:52;:::i;:::-;8476:62;;8431:117;8615:3;8604:9;8600:19;8587:33;8647:18;8639:6;8636:30;8633:117;;;8669:79;870:19398:18;;;8669:79:90;8774:62;8828:7;8819:6;8808:9;8804:22;8774:62;:::i;:::-;8764:72;;8558:288;8885:3;8912:53;8957:7;8948:6;8937:9;8933:22;8912:53;:::i;:::-;8902:63;;8856:119;7749:1233;;;;;;;;:::o;9143:120::-;-1:-1:-1;;;;;;9053:78:90;;9215:23;8988:149;9269:137;9339:20;;9368:32;9339:20;9368:32;:::i;9412:116::-;4931:13;;4924:21;9482;4861:90;9534:133;9602:20;;9631:30;9602:20;9631:30;:::i;9673:611::-;9746:6;9754;9762;9811:2;9799:9;9790:7;9786:23;9782:32;9779:119;;;9817:79;870:19398:18;;;9817:79:90;9937:1;9962:53;10007:7;9987:9;9962:53;:::i;:::-;9952:63;;9908:117;10064:2;10090:52;10134:7;10125:6;10114:9;10110:22;10090:52;:::i;:::-;10080:62;;10035:117;10191:2;10217:50;10259:7;10250:6;10239:9;10235:22;10217:50;:::i;:::-;10207:60;;10162:115;9673:611;;;;;:::o;10290:329::-;10349:6;10398:2;10386:9;10377:7;10373:23;10369:32;10366:119;;;10404:79;870:19398:18;;;10404:79:90;10524:1;10549:53;10594:7;10574:9;10549:53;:::i;10641:580::-;10726:8;10736:6;10786:3;10779:4;10771:6;10767:17;10763:27;10753:122;;10794:79;870:19398:18;;;10794:79:90;-1:-1:-1;10894:20:90;;10937:18;10926:30;;10923:117;;;10959:79;870:19398:18;;;10959:79:90;11073:4;11065:6;11061:17;11049:29;;11127:3;11119:4;11111:6;11107:17;11097:8;11093:32;11090:41;11087:128;;;11134:79;870:19398:18;;;11818:958:90;11952:6;11960;11968;11976;12025:2;12013:9;12004:7;12000:23;11996:32;11993:119;;;12031:79;870:19398:18;;;12031:79:90;12151:31;;12209:18;12198:30;;12195:117;;;12231:79;870:19398:18;;;12231:79:90;12344:92;12428:7;12419:6;12408:9;12404:22;12344:92;:::i;:::-;12326:110;;;;12122:324;12513:2;12502:9;12498:18;12485:32;12544:18;12536:6;12533:30;12530:117;;;12566:79;870:19398:18;;;12566:79:90;12679:80;12751:7;12742:6;12731:9;12727:22;12679:80;:::i;:::-;11818:958;;;;-1:-1:-1;12661:98:90;-1:-1:-1;;;;11818:958:90:o;12782:472::-;12849:6;12857;12906:2;12894:9;12885:7;12881:23;12877:32;12874:119;;;12912:79;870:19398:18;;;12912:79:90;13032:1;13057:53;13102:7;13082:9;13057:53;:::i;:::-;13047:63;;13003:117;13159:2;13185:52;13229:7;13220:6;13209:9;13205:22;13185:52;:::i;:::-;13175:62;;13130:117;12782:472;;;;;:::o;13260:961::-;13356:6;13364;13372;13380;13388;13437:3;13425:9;13416:7;13412:23;13408:33;13405:120;;;13444:79;870:19398:18;;;13444:79:90;13564:1;13589:53;13634:7;13614:9;13589:53;:::i;:::-;13579:63;;13535:117;13691:2;13717:52;13761:7;13752:6;13741:9;13737:22;13717:52;:::i;14390:245::-;14476:5;14517:3;14508:6;14503:3;14499:16;14495:26;14492:113;;;14524:79;870:19398:18;;;14524:79:90;-1:-1:-1;14623:6:90;14390:245;-1:-1:-1;14390:245:90:o;15289:1459::-;15530:6;15538;15546;15554;15562;15611:2;15599:9;15590:7;15586:23;15582:32;15579:119;;;15617:79;870:19398:18;;;15617:79:90;15737:31;;15795:18;15784:30;;15781:117;;;15817:79;870:19398:18;;;15817:79:90;15922:93;16007:7;15998:6;15987:9;15983:22;15922:93;:::i;:::-;15912:103;;15708:317;16092:2;16081:9;16077:18;16064:32;16123:18;16115:6;16112:30;16109:117;;;16145:79;870:19398:18;;;16145:79:90;16258:115;16365:7;16356:6;16345:9;16341:22;16258:115;:::i;:::-;16240:133;;;;16035:348;16450:2;16439:9;16435:18;16422:32;16481:18;16473:6;16470:30;16467:117;;;16503:79;870:19398:18;;;16503:79:90;16616:115;16723:7;16714:6;16703:9;16699:22;16616:115;:::i;:::-;16598:133;;;;16393:348;15289:1459;;;;;;;;:::o;16837:118::-;16942:5;16924:24;841:77;16961:222;17092:2;17077:18;;17105:71;17081:9;17149:6;17105:71;:::i;17762:674::-;17842:6;17850;17858;17907:2;17895:9;17886:7;17882:23;17878:32;17875:119;;;17913:79;870:19398:18;;;17913:79:90;18033:31;;18091:18;18080:30;;18077:117;;;18113:79;870:19398:18;;;18113:79:90;18226:65;18283:7;18274:6;18263:9;18259:22;18226:65;:::i;:::-;18208:83;;;;18004:297;18340:2;18366:53;18411:7;18402:6;18391:9;18387:22;18366:53;:::i;19116:142::-;19166:9;19199:53;-1:-1:-1;;;;;400:54:90;;19217:34;841:77;19226:24;907:5;841:77;19217:34;-1:-1:-1;;;;;400:54:90;;334:126;19264;19314:9;19347:37;19378:5;19347:37;:::i;19396:149::-;19469:9;19502:37;19533:5;19502:37;:::i;19551:177::-;19661:60;19715:5;19661:60;:::i;19734:268::-;19888:2;19873:18;;19901:94;19877:9;19968:6;19901:94;:::i;20008:704::-;20103:6;20111;20119;20168:2;20156:9;20147:7;20143:23;20139:32;20136:119;;;20174:79;870:19398:18;;;20174:79:90;20294:31;;20352:18;20341:30;;20338:117;;;20374:79;870:19398:18;;;20374:79:90;20487:80;20559:7;20550:6;20539:9;20535:22;20487:80;:::i;20718:327::-;20776:6;20825:2;20813:9;20804:7;20800:23;20796:32;20793:119;;;20831:79;870:19398:18;;;20831:79:90;20951:1;20976:52;21020:7;21000:9;20976:52;:::i;21979:366::-;22206:2;21729:19;;22121:3;21781:4;21772:14;;21938:27;21915:51;;22135:74;-1:-1:-1;22218:93:90;-1:-1:-1;22336:2:90;22327:12;;21979:366::o;22351:419::-;22555:2;22568:47;;;22540:18;;22632:131;22540:18;22632:131;:::i;22952:366::-;23179:2;21729:19;;23094:3;21781:4;21772:14;;22916:22;22893:46;;23108:74;-1:-1:-1;23191:93:90;22776:170;23324:419;23528:2;23541:47;;;23513:18;;23605:131;23513:18;23605:131;:::i;23936:366::-;24163:2;21729:19;;24078:3;21781:4;21772:14;;23889:33;23866:57;;24092:74;-1:-1:-1;24175:93:90;23749:181;24308:419;24512:2;24525:47;;;24497:18;;24589:131;24497:18;24589:131;:::i;24979:143::-;25061:13;;25083:33;25061:13;25083:33;:::i;25128:344::-;25238:4;25328:18;25320:6;25317:30;25314:56;;;25350:18;;:::i;:::-;-1:-1:-1;25400:4:90;25388:17;;;25450:15;;25128:344::o;25478:143::-;25560:13;;25582:33;25560:13;25582:33;:::i;25627:307::-;25695:1;25705:113;25719:6;25716:1;25713:13;25705:113;;;25795:11;;;25789:18;25776:11;;;25769:39;25741:2;25734:10;25705:113;;;25836:6;25833:1;25830:13;25827:101;;;-1:-1:-1;;25916:1:90;25898:16;;25891:27;25627:307::o;25940:419::-;26028:5;26053:65;26069:48;26110:6;26069:48;:::i;26053:65::-;26044:74;;26141:6;26134:5;26127:21;26179:4;26172:5;26168:16;26217:3;26208:6;26203:3;26199:16;26196:25;26193:112;;;26224:79;870:19398:18;;;26224:79:90;26314:39;26346:6;26341:3;26336;26314:39;:::i;26378:353::-;26444:5;26493:3;26486:4;26478:6;26474:17;26470:27;26460:122;;26501:79;870:19398:18;;;26501:79:90;26611:6;26605:13;26636:89;26721:3;26713:6;26706:4;26698:6;26694:17;26636:89;:::i;26774:776::-;26867:5;26911:4;26899:9;26894:3;26890:19;26886:30;26883:117;;;26919:79;870:19398:18;;;26919:79:90;27018:21;27034:4;27018:21;:::i;:::-;27009:30;-1:-1:-1;27097:1:90;27137:60;27193:3;27173:9;27137:60;:::i;:::-;27112:86;;-1:-1:-1;27289:2:90;27274:18;;27268:25;27320:18;27309:30;;27306:117;;;27342:79;870:19398:18;;;27342:79:90;27462:69;27527:3;27518:6;27507:9;27503:22;27462:69;:::i;:::-;27455:4;27448:5;27444:16;27437:95;27219:324;26774:776;;;;:::o;27595:1029::-;27735:5;27760:114;27776:97;27866:6;27776:97;:::i;27760:114::-;27909:21;;;27751:123;-1:-1:-1;27957:4:90;27946:16;;;;27998:17;;27986:30;;28028:15;;;28025:122;;;28058:79;870:19398:18;;;28058:79:90;28173:6;28156:462;28190:6;28185:3;28182:15;28156:462;;;28272:3;28266:10;28308:18;28295:11;28292:35;28289:122;;;28330:79;870:19398:18;;;28330:79:90;28454:11;28446:6;28442:24;28492:81;28569:3;28557:10;28492:81;:::i;:::-;28480:94;;-1:-1:-1;;28603:4:90;28594:14;;;;28207;28156:462;;;28160:21;27741:883;;27595:1029;;;;;:::o;28669:451::-;28784:5;28833:3;28826:4;28818:6;28814:17;28810:27;28800:122;;28841:79;870:19398:18;;;28841:79:90;28951:6;28945:13;28976:138;29110:3;29102:6;29095:4;29087:6;29083:17;28976:138;:::i;29126:137::-;29205:13;;29227:30;29205:13;29227:30;:::i;29446:1860::-;29532:5;29576:4;29564:9;29559:3;29555:19;29551:30;29548:117;;;29584:79;870:19398:18;;;29584:79:90;29683:21;29699:4;29683:21;:::i;:::-;29674:30;-1:-1:-1;29761:1:90;29801:60;29857:3;29837:9;29801:60;:::i;:::-;29776:86;;-1:-1:-1;29954:2:90;29939:18;;29933:25;29985:18;29974:30;;29971:117;;;30007:79;870:19398:18;;;30007:79:90;30127:118;30241:3;30232:6;30221:9;30217:22;30127:118;:::i;:::-;30120:4;30113:5;30109:16;30102:144;29883:374;30320:2;30361:60;30417:3;30408:6;30397:9;30393:22;30361:60;:::i;:::-;30354:4;30347:5;30343:16;30336:86;30267:166;30497:2;30538:57;30591:3;30582:6;30571:9;30567:22;30538:57;:::i;:::-;30531:4;30524:5;30520:16;30513:83;30443:164;30665:3;30707:60;30763:3;30754:6;30743:9;30739:22;30707:60;:::i;:::-;30700:4;30693:5;30689:16;30682:86;30617:162;30850:3;30892:57;30945:3;30936:6;30925:9;30921:22;30892:57;:::i;:::-;30885:4;30878:5;30874:16;30867:83;30789:172;31044:3;31033:9;31029:19;31023:26;31076:18;31068:6;31065:30;31062:117;;;31098:79;870:19398:18;;;31098:79:90;31218:69;31283:3;31274:6;31263:9;31259:22;31218:69;:::i;:::-;31211:4;31204:5;31200:16;31193:95;30971:328;29446:1860;;;;:::o;31312:556::-;31408:6;31457:2;31445:9;31436:7;31432:23;31428:32;31425:119;;;31463:79;870:19398:18;;;31463:79:90;31583:24;;31634:18;31623:30;;31620:117;;;31656:79;870:19398:18;;;31656:79:90;31761:90;31843:7;31834:6;31823:9;31819:22;31761:90;:::i;31874:180::-;-1:-1:-1;;;31919:1:90;31912:88;32019:4;32016:1;32009:15;32043:4;32040:1;32033:15;32060:191;32100:4;32193:1;32190;32187:8;32184:34;;;32198:18;;:::i;:::-;-1:-1:-1;32236:9:90;;32060:191::o;32348:158::-;32406:9;32439:61;32457:42;32492:5;32457:42;841:77;32512:147;32607:45;32646:5;32607:45;:::i;33678:360::-;33764:3;33792:38;33824:5;33479:12;;33400:98;33792:38;21729:19;;;21781:4;21772:14;;33839:77;;33925:52;33970:6;33965:3;33958:4;33951:5;33947:16;33925:52;:::i;:::-;-1:-1:-1;;5879:2:90;5859:14;;5855:28;34002:29;33993:39;;;;33678:360;-1:-1:-1;;;33678:360:90:o;34044:1023::-;34386:3;34371:19;;34400:71;34375:9;34444:6;34400:71;:::i;:::-;34481:80;34557:2;34546:9;34542:18;34533:6;34481:80;:::i;:::-;34571:72;34639:2;34628:9;34624:18;34615:6;34571:72;:::i;:::-;34653;34721:2;34710:9;34706:18;34697:6;34653:72;:::i;:::-;34735:73;34803:3;34792:9;34788:19;34779:6;34735:73;:::i;:::-;34818:90;34903:3;34892:9;34888:19;34879:6;34818:90;:::i;:::-;34956:9;34950:4;34946:20;34940:3;34929:9;34925:19;34918:49;34984:76;35055:4;35046:6;34984:76;:::i;:::-;34976:84;34044:1023;-1:-1:-1;;;;;;;;;34044:1023:90:o;35073:115::-;-1:-1:-1;;;;;;9053:78:90;;35158:23;8988:149;35194:426;35373:2;35358:18;;35386:71;35362:9;35430:6;35386:71;:::i;:::-;35467:70;35533:2;35522:9;35518:18;35509:6;35467:70;:::i;:::-;35547:66;35609:2;35598:9;35594:18;35585:6;35547:66;:::i;35626:332::-;35785:2;35770:18;;35798:71;35774:9;35842:6;35798:71;:::i;:::-;35879:72;35947:2;35936:9;35932:18;35923:6;35879:72;:::i;35964:1039::-;36314:3;36299:19;;36328:71;36303:9;36372:6;36328:71;:::i;:::-;36409:80;36485:2;36474:9;36470:18;36461:6;36409:80;:::i;:::-;36499;36575:2;36564:9;36560:18;36551:6;36499:80;:::i;37172:365::-;37399:1;21729:19;;37314:3;21781:4;21772:14;;37149:9;37126:33;;37328:73;-1:-1:-1;37410:93:90;37009:157;37543:419;37747:2;37760:47;;;37732:18;;37824:131;37732:18;37824:131;:::i;37968:141::-;38049:13;;38071:32;38049:13;38071:32;:::i;38143:775::-;38229:5;38273:4;38261:9;38256:3;38252:19;38248:30;38245:117;;;38281:79;870:19398:18;;;38281:79:90;38380:21;38396:4;38380:21;:::i;:::-;38371:30;-1:-1:-1;38464:1:90;38504:59;38559:3;38539:9;38504:59;:::i;38924:556::-;39020:6;39069:2;39057:9;39048:7;39044:23;39040:32;39037:119;;;39075:79;870:19398:18;;;39075:79:90;39195:24;;39246:18;39235:30;;39232:117;;;39268:79;870:19398:18;;;39268:79:90;39373:90;39455:7;39446:6;39435:9;39431:22;39373:90;:::i;39657:366::-;39884:2;21729:19;;39799:3;21781:4;21772:14;;39626:17;39603:41;;39813:74;-1:-1:-1;39896:93:90;39486:165;40029:419;40233:2;40246:47;;;40218:18;;40310:131;40218:18;40310:131;:::i;40454:115::-;5364:18;5353:30;;40539:23;5288:101;40575:945;40880:3;40865:19;;40894:69;40869:9;40936:6;40894:69;:::i;:::-;40973:72;41041:2;41030:9;41026:18;41017:6;40973:72;:::i;:::-;41055;41123:2;41112:9;41108:18;41099:6;41055:72;:::i;:::-;41137;41205:2;41194:9;41190:18;41181:6;41137:72;:::i;:::-;41257:9;41251:4;41247:20;41241:3;41230:9;41226:19;41219:49;41285:76;41356:4;41347:6;41285:76;:::i;:::-;41277:84;;41409:9;41403:4;41399:20;41393:3;41382:9;41378:19;41371:49;41437:76;41508:4;41499:6;41437:76;:::i;:::-;41429:84;40575:945;-1:-1:-1;;;;;;;;40575:945:90:o;41526:522::-;41605:6;41654:2;41642:9;41633:7;41629:23;41625:32;41622:119;;;41660:79;870:19398:18;;;41660:79:90;41780:24;;41831:18;41820:30;;41817:117;;;41853:79;870:19398:18;;;41853:79:90;41958:73;42023:7;42014:6;42003:9;41999:22;41958:73;:::i;42731:379::-;42915:3;42937:147;43080:3;42937:147;:::i;43281:365::-;43508:1;21729:19;;43423:3;21781:4;21772:14;;43256:11;43233:35;;43437:73;-1:-1:-1;43519:93:90;43116:159;43652:419;43856:2;43869:47;;;43841:18;;43933:131;43841:18;43933:131;:::i;44077:1007::-;44411:3;44396:19;;44425:71;44400:9;44469:6;44425:71;:::i;:::-;44506:72;44574:2;44563:9;44559:18;44550:6;44506:72;:::i;45266:366::-;45493:2;21729:19;;45408:3;21781:4;21772:14;;45230:22;45207:46;;45422:74;-1:-1:-1;45505:93:90;45090:170;45638:419;45842:2;45855:47;;;45827:18;;45919:131;45827:18;45919:131;:::i;46063:180::-;-1:-1:-1;;;46108:1:90;46101:88;46208:4;46205:1;46198:15;46232:4;46229:1;46222:15;46618:725;46696:4;;46745:25;;-1:-1:-1;;46821:14:90;46817:29;;;46813:48;46789:73;;46779:168;;46866:79;870:19398:18;;;46866:79:90;46978:18;46968:8;46964:33;46956:41;;47030:4;47017:18;47007:28;;47058:18;47050:6;47047:30;47044:117;;;47080:79;870:19398:18;;;47080:79:90;47188:2;47182:4;47178:13;47170:21;;47245:4;47237:6;47233:17;47217:14;47213:38;47207:4;47203:49;47200:136;;;47255:79;870:19398:18;;;47371:314:90;47485:3;47604:43;47640:6;47635:3;47628:5;47604:43;:::i;:::-;-1:-1:-1;;47663:16:90;;47371:314::o;47691:291::-;47831:3;47853:103;47952:3;47943:6;47935;47853:103;:::i;47988:233::-;48027:3;-1:-1:-1;;48089:5:90;48086:77;48083:103;;48166:18;;:::i;:::-;-1:-1:-1;48213:1:90;48202:13;;47988:233::o;48736:284::-;21729:19;;;48824:3;21781:4;21772:14;;48838:68;;48916:43;48952:6;48947:3;48940:5;48916:43;:::i;:::-;-1:-1:-1;;5879:2:90;5859:14;;5855:28;48984:29;5787:102;49026:216;49125:10;49160:76;49232:3;49224:6;49216;49160:76;:::i;49617:712::-;49682:5;;49732:17;;-1:-1:-1;;49800:14:90;49796:29;;;49792:48;49768:73;;49758:168;;49845:79;870:19398:18;;;49845:79:90;49944:33;;;50045:4;50034:16;;;-1:-1:-1;49997:19:90;;-1:-1:-1;50073:18:90;50062:30;;50059:117;;;50095:79;870:19398:18;;;50095:79:90;50203:14;50199:38;;;50188:50;;50185:137;;;50241:79;870:19398:18;;;50496:998:90;21729:19;;;50647:3;21781:4;21772:14;;50663:103;-1:-1:-1;50663:103:90;50837:4;50825:17;;50816:27;;50931:5;50960:7;50991:1;50976:473;51001:6;50998:1;50995:13;50976:473;;;51072:9;51066:4;51062:20;51057:3;51050:33;51132:54;51179:6;51170:7;51132:54;:::i;:::-;51207:101;51303:4;51288:13;51273;51207:101;:::i;:::-;51199:109;-1:-1:-1;50451:4:90;50442:14;;51434:4;51425:14;;;;;51321:84;-1:-1:-1;;;51023:1:90;51016:9;50976:473;;;-1:-1:-1;51465:4:90;;50496:998;-1:-1:-1;;;;;;;50496:998:90:o;51912:179::-;51981:10;52002:46;52044:3;52036:6;52002:46;:::i;:::-;-1:-1:-1;;52080:4:90;52071:14;;51912:179::o;52097:122::-;52149:5;52174:39;52209:2;52204:3;52200:12;52195:3;52174:39;:::i;52376:699::-;21729:19;;;52505:3;21781:4;21772:14;;52521:93;-1:-1:-1;52690:5:90;52719:7;52750:1;52735:315;52760:6;52757:1;52754:13;52735:315;;;52830:42;52865:6;52856:7;52830:42;:::i;:::-;52892:63;52951:3;52936:13;52892:63;:::i;:::-;52885:70;-1:-1:-1;50451:4:90;50442:14;;52968:72;-1:-1:-1;;52782:1:90;52775:9;52735:315;;;-1:-1:-1;53066:3:90;;52376:699;-1:-1:-1;;;;;52376:699:90:o;53081:718::-;53382:2;53395:47;;;53367:18;;53459:140;53367:18;53585:6;53577;53459:140;:::i;:::-;53451:148;;53646:9;53640:4;53636:20;53631:2;53620:9;53616:18;53609:48;53674:118;53787:4;53778:6;53770;53674:118;:::i;:::-;53666:126;53081:718;-1:-1:-1;;;;;;53081:718:90:o;53805:327::-;53863:6;53912:2;53900:9;53891:7;53887:23;53883:32;53880:119;;;53918:79;870:19398:18;;;53918:79:90;54038:1;54063:52;54107:7;54087:9;54063:52;:::i;54297:365::-;54524:1;21729:19;;54439:3;21781:4;21772:14;;-1:-1:-1;;;54255:29:90;;54453:73;-1:-1:-1;54535:93:90;54138:153;54668:419;54872:2;54885:47;;;54857:18;;54949:131;54857:18;54949:131;:::i;56006:366::-;56233:2;21729:19;;56148:3;21781:4;21772:14;;55963:29;55940:53;;56162:74;-1:-1:-1;56245:93:90;55823:177;56378:419;56582:2;56595:47;;;56567:18;;56659:131;56567:18;56659:131;:::i;56977:366::-;57204:2;21729:19;;57119:3;21781:4;21772:14;;56943:20;56920:44;;57133:74;-1:-1:-1;57216:93:90;56803:168;57349:419;57553:2;57566:47;;;57538:18;;57630:131;57538:18;57630:131;:::i;57811:750::-;57893:5;57937:4;57925:9;57920:3;57916:19;57912:30;57909:117;;;57945:79;870:19398:18;;;57945:79:90;58044:21;58060:4;58044:21;:::i;:::-;58035:30;-1:-1:-1;58123:1:90;58163:49;58208:3;58188:9;58163:49;:::i;:::-;58138:75;;-1:-1:-1;58311:2:90;58296:18;;58283:32;58342:18;58331:30;;58328:117;;;58364:79;870:19398:18;;;58364:79:90;58484:58;58538:3;58529:6;58518:9;58514:22;58484:58;:::i;58606:1014::-;58735:5;58760:114;58776:97;58866:6;58776:97;:::i;58760:114::-;58909:21;;;58751:123;-1:-1:-1;58957:4:90;58946:16;;;;58998:17;;58986:30;;59028:15;;;59025:122;;;59058:79;870:19398:18;;;59058:79:90;59173:6;59156:458;59190:6;59185:3;59182:15;59156:458;;;59279:3;59266:17;59315:18;59302:11;59299:35;59296:122;;;59337:79;870:19398:18;;;59337:79:90;59461:11;59453:6;59449:24;59499:70;59565:3;59553:10;59499:70;:::i;:::-;59487:83;;-1:-1:-1;;59599:4:90;59590:14;;;;59207;59156:458;;59626:416;59810:9;59909:126;60020:14;60012:6;60005:5;59909:126;:::i;60048:323::-;60104:6;60153:2;60141:9;60132:7;60128:23;60124:32;60121:119;;;60159:79;870:19398:18;;;60159:79:90;60279:1;60304:50;60346:7;60326:9;60304:50;:::i;60551:366::-;60778:2;21729:19;;60693:3;21781:4;21772:14;;60517:20;60494:44;;60707:74;-1:-1:-1;60790:93:90;60377:168;60923:419;61127:2;61140:47;;;61112:18;;61204:131;61112:18;61204:131;:::i;61515:366::-;61742:2;21729:19;;61657:3;21781:4;21772:14;;61488:13;61465:37;;61671:74;-1:-1:-1;61754:93:90;61348:161;61887:419;62091:2;62104:47;;;62076:18;;62168:131;62076:18;62168:131;:::i;63444:3628::-;63531:5;63575:6;63563:9;63558:3;63554:19;63550:32;63547:119;;;63585:79;870:19398:18;;;63585:79:90;63684:23;63700:6;63684:23;:::i;:::-;63675:32;-1:-1:-1;63770:1:90;63810:49;63855:3;63835:9;63810:49;:::i;:::-;63785:75;;-1:-1:-1;63936:2:90;63977:48;64021:3;63997:22;;;63977:48;:::i;:::-;63970:4;63963:5;63959:16;63952:74;63881:156;64110:2;64151:49;64196:3;64187:6;64176:9;64172:22;64151:49;:::i;:::-;64144:4;64137:5;64133:16;64126:75;64047:165;64272:2;64313:48;64357:3;64348:6;64337:9;64333:22;64313:48;:::i;:::-;64306:4;64299:5;64295:16;64288:74;64222:151;64470:3;64459:9;64455:19;64442:33;64502:18;64494:6;64491:30;64488:117;;;64524:79;870:19398:18;;;64524:79:90;64644:59;64699:3;64690:6;64679:9;64675:22;64644:59;:::i;:::-;64637:4;64630:5;64626:16;64619:85;64383:332;64810:3;64799:9;64795:19;64782:33;64842:18;64834:6;64831:30;64828:117;;;64864:79;870:19398:18;;;64864:79:90;64984:58;65038:3;65029:6;65018:9;65014:22;64984:58;:::i;:::-;64977:4;64970:5;64966:16;64959:84;64725:329;65117:3;65159:46;65201:3;65192:6;65181:9;65177:22;65159:46;:::i;:::-;65152:4;65145:5;65141:16;65134:72;65064:153;65281:3;65323:46;65365:3;65356:6;65345:9;65341:22;65323:46;:::i;:::-;65316:4;65309:5;65305:16;65298:72;65227:154;65439:3;65483:49;65528:3;65519:6;65508:9;65504:22;65483:49;:::i;:::-;65474:6;65467:5;65463:18;65456:77;65391:153;65610:3;65654:49;65699:3;65690:6;65679:9;65675:22;65654:49;:::i;:::-;65645:6;65638:5;65634:18;65627:77;65554:161;65804:3;65793:9;65789:19;65776:33;65836:18;65828:6;65825:30;65822:117;;;65858:79;870:19398:18;;;65858:79:90;65980:58;66034:3;66025:6;66014:9;66010:22;65980:58;:::i;:::-;65971:6;65964:5;65960:18;65953:86;65725:325;66113:3;66157:49;66202:3;66193:6;66182:9;66178:22;66157:49;:::i;:::-;66148:6;66141:5;66137:18;66130:77;66060:158;66280:3;66324:49;66369:3;66360:6;66349:9;66345:22;66324:49;:::i;:::-;66315:6;66308:5;66304:18;66297:77;66228:157;66451:3;66495:49;66540:3;66531:6;66520:9;66516:22;66495:49;:::i;:::-;66486:6;66479:5;66475:18;66468:77;66395:161;66627:3;66671:46;66713:3;66704:6;66693:9;66689:22;66671:46;:::i;:::-;66662:6;66655:5;66651:18;66644:74;66566:163;66819:3;66808:9;66804:19;66791:33;66851:18;66843:6;66840:30;66837:117;;;66873:79;870:19398:18;;;66873:79:90;66995:58;67049:3;67040:6;67029:9;67025:22;66995:58;:::i;:::-;66986:6;66979:5;66975:18;66968:86;66739:326;63444:3628;;;;:::o;67078:250::-;67206:9;67240:81;67306:14;67299:5;67240:81;:::i;67334:328::-;67491:2;67476:18;;67504:69;67480:9;67546:6;67504:69;:::i;67841:366::-;68068:2;21729:19;;67983:3;21781:4;21772:14;;67808:19;67785:43;;67997:74;-1:-1:-1;68080:93:90;67668:167;68213:419;68417:2;68430:47;;;68402:18;;68494:131;68402:18;68494:131;:::i;68812:366::-;69039:2;21729:19;;68954:3;21781:4;21772:14;;68778:20;68755:44;;68968:74;-1:-1:-1;69051:93:90;68638:168;69184:419;69388:2;69401:47;;;69373:18;;69465:131;69373:18;69465:131;:::i;69609:351::-;69679:6;69728:2;69716:9;69707:7;69703:23;69699:32;69696:119;;;69734:79;870:19398:18;;;69734:79:90;69854:1;69879:64;69935:7;69915:9;69879:64;:::i;70197:366::-;70424:2;21729:19;;70339:3;21781:4;21772:14;;70106:34;70083:58;;70175:8;70170:2;70158:15;;70151:33;70353:74;-1:-1:-1;70436:93:90;-1:-1:-1;70554:2:90;70545:12;;70197:366::o;70569:419::-;70773:2;70786:47;;;70758:18;;70850:131;70758:18;70850:131;:::i;71174:366::-;71401:2;21729:19;;71316:3;21781:4;21772:14;;71134:26;71111:50;;71330:74;-1:-1:-1;71413:93:90;70994:174;71546:419;71750:2;71763:47;;;71735:18;;71827:131;71735:18;71827:131;:::i;72010:436::-;72114:5;72163:3;72156:4;72148:6;72144:17;72140:27;72130:122;;72171:79;870:19398:18;;;72171:79:90;72288:6;72275:20;72313:127;72436:3;72428:6;72421:4;72413:6;72409:17;72313:127;:::i;72480:1786::-;72555:5;72599:4;72587:9;72582:3;72578:19;72574:30;72571:117;;;72607:79;870:19398:18;;;72607:79:90;72706:21;72722:4;72706:21;:::i;:::-;72697:30;-1:-1:-1;72784:1:90;72824:49;72869:3;72849:9;72824:49;:::i;:::-;72799:75;;-1:-1:-1;72973:2:90;72958:18;;72945:32;73004:18;72993:30;;72990:117;;;73026:79;870:19398:18;;;73026:79:90;73146:107;73249:3;73240:6;73229:9;73225:22;73146:107;:::i;:::-;73139:4;73132:5;73128:16;73121:133;72895:370;73328:2;73369:49;73414:3;73405:6;73394:9;73390:22;73369:49;:::i;:::-;73362:4;73355:5;73351:16;73344:75;73275:155;73494:2;73535:46;73577:3;73568:6;73557:9;73553:22;73535:46;:::i;:::-;73528:4;73521:5;73517:16;73510:72;73440:153;73651:3;73693:49;73738:3;73729:6;73718:9;73714:22;73693:49;:::i;:::-;73686:4;73679:5;73675:16;73668:75;73603:151;73825:3;73867:46;73909:3;73900:6;73889:9;73885:22;73867:46;:::i;:::-;73860:4;73853:5;73849:16;73842:72;73764:161;74015:3;74004:9;74000:19;73987:33;74047:18;74039:6;74036:30;74033:117;;;74069:79;870:19398:18;;;74069:79:90;74189:58;74243:3;74234:6;74223:9;74219:22;74189:58;:::i;74272:541::-;74357:6;74406:2;74394:9;74385:7;74381:23;74377:32;74374:119;;;74412:79;870:19398:18;;;74412:79:90;74532:31;;74590:18;74579:30;;74576:117;;;74612:79;870:19398:18;;;74612:79:90;74717;74788:7;74779:6;74768:9;74764:22;74717:79;:::i;75007:366::-;75234:2;21729:19;;;74959:34;21772:14;;74936:58;;;75149:3;75246:93;74819:182;75379:419;75583:2;75596:47;;;75568:18;;75660:131;75568:18;75660:131;:::i;75804:351::-;75874:6;75923:2;75911:9;75902:7;75898:23;75894:32;75891:119;;;75929:79;870:19398:18;;;75929:79:90;76049:1;76074:64;76130:7;76110:9;76074:64;:::i;76329:366::-;76556:2;21729:19;;76471:3;21781:4;21772:14;;76301;76278:38;;76485:74;-1:-1:-1;76568:93:90;76161:162;76701:419;76905:2;76918:47;;;76890:18;;76982:131;76890:18;76982:131;:::i;77531:366::-;77758:2;21729:19;;77673:3;21781:4;21772:14;;77494:23;77471:47;;77687:74;-1:-1:-1;77770:93:90;77354:171;77903:419;78107:2;78120:47;;;78092:18;;78184:131;78092:18;78184:131;:::i;78450:152::-;78492:11;78528:28;78551:3;78545:10;-1:-1:-1;;;;;;9053:78:90;;8988:149;78721:590;78804:5;78835:38;78867:5;33479:12;;33400:98;78835:38;78432:4;78423:14;;78984:34;78423:14;78984:34;:::i;:::-;78975:43;;79042:1;79034:6;79031:13;79028:276;;;79112:168;-1:-1:-1;;;;;;79166:6:90;79163:1;79159:14;79156:1;79152:22;78692:16;;78608:107;79112:168;79089:5;79068:226;79059:235;;79028:276;78810:501;;78721:590;;;:::o;79488:366::-;79715:2;21729:19;;79630:3;21781:4;21772:14;;79457:17;79434:41;;79644:74;-1:-1:-1;79727:93:90;79317:165;79860:419;80064:2;80077:47;;;80049:18;;80141:131;80049:18;80141:131;:::i;80865:619::-;81105:23;;81000:3;;81036:4;81027:14;;;81141:63;81031:3;81105:23;81141:63;:::i;:::-;81051:163;81296:4;81289:5;81285:16;81279:23;81349:3;81343:4;81339:14;81332:4;81327:3;81323:14;81316:38;81375:71;81441:4;81427:12;81375:71;:::i;81490:405::-;81687:2;81700:47;;;81672:18;;81764:124;81672:18;81874:6;81764:124;:::i;81901:663::-;81989:6;81997;82005;82054:2;82042:9;82033:7;82029:23;82025:32;82022:119;;;82060:79;870:19398:18;;;82060:79:90;82180:1;82205:64;82261:7;82241:9;82205:64;:::i;:::-;82195:74;;82151:128;82318:2;82344:64;82400:7;82391:6;82380:9;82376:22;82344:64;:::i;:::-;82334:74;;82289:129;82457:2;82483:64;82539:7;82530:6;82519:9;82515:22;82483:64;:::i;82739:366::-;82966:2;21729:19;;82881:3;21781:4;21772:14;;82710:15;82687:39;;82895:74;-1:-1:-1;82978:93:90;82570:163;83111:419;83315:2;83328:47;;;83300:18;;83392:131;83300:18;83392:131;:::i;83704:366::-;83931:2;21729:19;;83846:3;21781:4;21772:14;;83676;83653:38;;83860:74;-1:-1:-1;83943:93:90;83536:162;84076:419;84280:2;84293:47;;;84265:18;;84357:131;84265:18;84357:131;:::i;84501:305::-;84541:3;84676:74;;84670:81;;84667:107;;;84754:18;;:::i;:::-;-1:-1:-1;84791:9:90;;84501:305::o;84812:529::-;85017:2;85030:47;;;85002:18;;85094:76;85002:18;85156:6;85094:76;:::i;:::-;85086:84;;85180:72;85248:2;85237:9;85233:18;85224:6;85180:72;:::i;:::-;85262;85330:2;85319:9;85315:18;85306:6;85262:72;:::i;85347:373::-;85451:3;85479:38;85511:5;33479:12;;33400:98;85479:38;85630:52;85675:6;85670:3;85663:4;85656:5;85652:16;85630:52;:::i;:::-;85698:16;;;;;85347:373;-1:-1:-1;;85347:373:90:o;85726:271::-;85856:3;85878:93;85967:3;85958:6;85878:93;:::i;86170:366::-;86397:2;21729:19;;86312:3;21781:4;21772:14;;86143:13;86120:37;;86326:74;-1:-1:-1;86409:93:90;86003:161;86542:419;86746:2;86759:47;;;86731:18;;86823:131;86731:18;86823:131;:::i;87139:366::-;87366:2;21729:19;;87281:3;21781:4;21772:14;;87107:18;87084:42;;87295:74;-1:-1:-1;87378:93:90;86967:166;87511:419;87715:2;87728:47;;;87700:18;;87792:131;87700:18;87792:131;:::i;87936:332::-;88095:2;88080:18;;88108:71;88084:9;88152:6;88108:71;:::i;:::-;88189:72;88257:2;88246:9;88242:18;88233:6;88189:72;:::i;89610:288::-;89745:10;89780:112;89888:3;89880:6;89780:112;:::i;90130:1155::-;90305:3;90334:87;90415:5;33479:12;;33400:98;90334:87;21729:19;;;21781:4;21772:14;;90430:116;;90572:3;90617:4;90609:6;90605:17;90600:3;90596:27;90647:89;90730:5;78432:4;78423:14;;78328:116;90647:89;90759:7;90790:1;90775:465;90800:6;90797:1;90794:13;90775:465;;;90871:9;90865:4;90861:20;90856:3;90849:33;90922:6;90916:13;90950:130;91075:4;91060:13;90950:130;:::i;:::-;90942:138;-1:-1:-1;50451:4:90;50442:14;;91225:4;91216:14;;;;;91093:103;-1:-1:-1;;90822:1:90;90815:9;90775:465;;91562:1653;91787:23;;91683:3;;91719:4;91710:14;;;91823:63;91714:3;91787:23;91823:63;:::i;:::-;91734:162;91979:4;91972:5;91968:16;91962:23;92032:3;92026:4;92022:14;92015:4;92010:3;92006:14;91999:38;92058:169;92222:4;92208:12;92058:169;:::i;:::-;92050:177;;91906:332;92324:4;92317:5;92313:16;92307:23;92343:63;92400:4;92395:3;92391:14;92377:12;92343:63;:::i;:::-;92248:168;92503:4;92496:5;92492:16;92486:23;92522:57;92573:4;92568:3;92564:14;92550:12;92522:57;:::i;:::-;92426:163;92670:4;92663:5;92659:16;92653:23;92689:63;92746:4;92741:3;92737:14;92723:12;92689:63;:::i;:::-;92599:163;92856:4;92849:5;92845:16;92839:23;92875:57;92926:4;92921:3;92917:14;92903:12;92875:57;:::i;:::-;92772:170;93027:4;93020:5;93016:16;93010:23;93080:3;93074:4;93070:14;93063:4;93058:3;93054:14;93047:38;93106:71;93172:4;93158:12;93106:71;:::i;93221:377::-;93404:2;93417:47;;;93389:18;;93481:110;93389:18;93577:6;93481:110;:::i;93785:366::-;94012:2;21729:19;;93927:3;21781:4;21772:14;;93744:27;93721:51;;93941:74;-1:-1:-1;94024:93:90;93604:175;94157:419;94361:2;94374:47;;;94346:18;;94438:131;94346:18;94438:131;:::i;94754:366::-;94981:2;21729:19;;94896:3;21781:4;21772:14;;94722:18;94699:42;;94910:74;-1:-1:-1;94993:93:90;94582:166;95126:419;95330:2;95343:47;;;95315:18;;95407:131;95315:18;95407:131;:::i;95551:442::-;95738:2;95723:18;;95751:71;95727:9;95795:6;95751:71;:::i;:::-;95832:72;95900:2;95889:9;95885:18;95876:6;95832:72;:::i;:::-;95914;95982:2;95971:9;95967:18;95958:6;95914:72;:::i;96164:365::-;96391:1;21729:19;;96306:3;21781:4;21772:14;;96139:11;96116:35;;96320:73;-1:-1:-1;96402:93:90;95999:159;96535:419;96739:2;96752:47;;;96724:18;;96816:131;96724:18;96816:131;:::i;96960:664::-;97203:3;97188:19;;97217:71;97192:9;97261:6;97217:71;:::i;:::-;97298:72;97366:2;97355:9;97351:18;97342:6;97298:72;:::i;:::-;97380;97448:2;97437:9;97433:18;97424:6;97380:72;:::i;:::-;97462;97530:2;97519:9;97515:18;97506:6;97462:72;:::i;:::-;97544:73;97612:3;97601:9;97597:19;97588:6;97544:73;:::i;97806:366::-;98033:2;21729:19;;97948:3;21781:4;21772:14;;97770:22;97747:46;;97962:74;-1:-1:-1;98045:93:90;97630:170;98178:419;98382:2;98395:47;;;98367:18;;98459:131;98367:18;98459:131;:::i;98771:366::-;98998:2;21729:19;;98913:3;21781:4;21772:14;;98743;98720:38;;98927:74;-1:-1:-1;99010:93:90;98603:162;99143:419;99347:2;99360:47;;;99332:18;;99424:131;99332:18;99424:131;:::i;99568:348::-;99608:7;99853:1;-1:-1:-1;;99781:74:90;99778:1;99775:81;99770:1;99763:9;99756:17;99752:105;99749:131;;;99860:18;;:::i;:::-;-1:-1:-1;99901:9:90;;99568:348::o;99922:180::-;-1:-1:-1;;;99967:1:90;99960:88;100067:4;100064:1;100057:15;100091:4;100088:1;100081:15;100108:185;100148:1;100238;100228:35;;100243:18;;:::i;:::-;-1:-1:-1;100278:9:90;;100108:185::o;100299:345::-;100366:6;100415:2;100403:9;100394:7;100390:23;100386:32;100383:119;;;100421:79;870:19398:18;;;100421:79:90;100541:1;100566:61;100619:7;100599:9;100566:61;:::i;100885:366::-;101112:2;21729:19;;101027:3;21781:4;21772:14;;100790:34;100767:58;;100859:12;100854:2;100842:15;;100835:37;101041:74;-1:-1:-1;101124:93:90;100650:229;101257:419;101461:2;101474:47;;;101446:18;;101538:131;101446:18;101538:131;:::i;101782:94::-;101821:7;101850:20;101864:5;101759:2;101755:14;;101682:94;101882:100;101921:7;101950:26;101970:5;101950:26;:::i;101988:157::-;102093:45;102113:24;102131:5;102113:24;:::i;:::-;102093:45;:::i;102253:94::-;102291:7;102320:21;102335:5;102229:3;102225:15;;102151:96;102353:153;102456:43;5364:18;5353:30;;102456:43;:::i;102512:669::-;102704:3;102719:75;102790:3;102781:6;102719:75;:::i;:::-;102819:2;102814:3;102810:12;102803:19;;102832:75;102903:3;102894:6;102832:75;:::i;:::-;102932:2;102927:3;102923:12;102916:19;;102945:73;103014:3;103005:6;102945:73;:::i;:::-;103043:1;103038:3;103034:11;103027:18;;103055:73;103124:3;103115:6;103055:73;:::i;:::-;-1:-1:-1;103153:1:90;103144:11;;102512:669;-1:-1:-1;;;;102512:669:90:o;103662:1393::-;104081:3;104066:19;;104095:71;104070:9;104139:6;104095:71;:::i;:::-;104213:9;104207:4;104203:20;104198:2;104187:9;104183:18;104176:48;104241:76;104312:4;104303:6;104241:76;:::i;:::-;104233:84;;104327:70;104393:2;104382:9;104378:18;104369:6;104327:70;:::i;:::-;104407:72;104475:2;104464:9;104460:18;104451:6;104407:72;:::i;:::-;104489:73;104557:3;104546:9;104542:19;104533:6;104489:73;:::i;:::-;104572;104640:3;104629:9;104625:19;104616:6;104572:73;:::i;:::-;104655;104723:3;104712:9;104708:19;104699:6;104655:73;:::i;:::-;104738;104806:3;104795:9;104791:19;104782:6;104738:73;:::i;:::-;104821;104889:3;104878:9;104874:19;104865:6;104821:73;:::i;:::-;104942:9;104936:4;104932:20;104926:3;104915:9;104911:19;104904:49;104970:78;105043:4;105034:6;104970:78;:::i;:::-;104962:86;103662:1393;-1:-1:-1;;;;;;;;;;;;103662:1393:90:o;106039:1217::-;105355:14;105332:38;;105776:2;105767:12;106388:3;106568:73;105767:12;106628:6;106568:73;:::i;:::-;106666:1;106661:3;106657:11;106650:18;;106678:73;106747:3;106738:6;106678:73;:::i;:::-;106776:1;106771:3;106767:11;106760:18;;106788:75;106859:3;106850:6;106788:75;:::i;:::-;106888:2;106883:3;106879:12;106872:19;;106901:75;106972:3;106963:6;106901:75;:::i;:::-;107001:2;106996:3;106992:12;106985:19;;107014:75;107085:3;107076:6;107014:75;:::i;:::-;107114:2;107109:3;107105:12;107098:19;;107127:75;107198:3;107189:6;107127:75;:::i;:::-;-1:-1:-1;107227:2:90;107218:12;;106039:1217;-1:-1:-1;;;;;;106039:1217:90:o;107435:366::-;107662:2;21729:19;;107577:3;21781:4;21772:14;;107402:19;107379:43;;107591:74;-1:-1:-1;107674:93:90;107262:167;107807:419;108011:2;108024:47;;;107996:18;;108088:131;107996:18;108088:131;:::i;108463:366::-;108690:2;21729:19;;108605:3;21781:4;21772:14;;108372:34;108349:58;;108441:8;108436:2;108424:15;;108417:33;108619:74;-1:-1:-1;108702:93:90;108232:225;108835:419;109039:2;109052:47;;;109024:18;;109116:131;109024:18;109116:131;:::i;109445:366::-;109672:2;21729:19;;109587:3;21781:4;21772:14;;109400:31;109377:55;;109601:74;-1:-1:-1;109684:93:90;109260:179;109817:419;110021:2;110034:47;;;110006:18;;110098:131;110006:18;110098:131;:::i;111118:522::-;110382:66;110359:90;;110855:2;110846:12;111331:3;111511:75;110846:12;111573:6;111511:75;:::i;:::-;-1:-1:-1;111611:2:90;111602:12;;111118:522;-1:-1:-1;111118:522:90:o;111816:366::-;112043:2;21729:19;;111958:3;21781:4;21772:14;;111786:16;111763:40;;111972:74;-1:-1:-1;112055:93:90;111646:164;112188:419;112392:2;112405:47;;;112377:18;;112469:131;112377:18;112469:131;:::i;112613:313::-;112764:2;112777:47;;;112749:18;;112841:78;112749:18;112905:6;112841:78;:::i;113112:366::-;113339:2;21729:19;;113254:3;21781:4;21772:14;;113072:26;113049:50;;113268:74;-1:-1:-1;113351:93:90;112932:174;113484:419;113688:2;113701:47;;;113673:18;;113765:131;113673:18;113765:131;:::i;114096:366::-;114323:2;21729:19;;114238:3;21781:4;21772:14;;114049:33;114026:57;;114252:74;-1:-1:-1;114335:93:90;113909:181;114468:419;114672:2;114685:47;;;114657:18;;114749:131;114657:18;114749:131;:::i;115120:366::-;115347:2;21729:19;;115262:3;21781:4;21772:14;;115033:34;115010:58;;-1:-1:-1;;;115097:2:90;115085:15;;115078:29;115276:74;-1:-1:-1;115359:93:90;114893:221;115492:419;115696:2;115709:47;;;115681:18;;115773:131;115681:18;115773:131;:::i;116144:366::-;116371:2;21729:19;;116286:3;21781:4;21772:14;;116057:34;116034:58;;-1:-1:-1;;;116121:2:90;116109:15;;116102:29;116300:74;-1:-1:-1;116383:93:90;115917:221;116516:419;116720:2;116733:47;;;116705:18;;116797:131;116705:18;116797:131;:::i;117033:112::-;117016:4;117005:16;;117116:22;116941:86;117151:545;117362:3;117347:19;;117376:71;117351:9;117420:6;117376:71;:::i;:::-;117457:68;117521:2;117510:9;117506:18;117497:6;117457:68;:::i;:::-;117535:72;117603:2;117592:9;117588:18;117579:6;117535:72;:::i;:::-;117617;117685:2;117674:9;117670:18;117661:6;117617:72;:::i
Swarm Source
ipfs://601cde2b0e9fb0a8794427468b4ad9b1137bde8b2ee75fa69c11706fd8bf49b6
Loading...
Loading
Loading...
Loading
[ Download: CSV Export ]
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.