More Info
Private Name Tags
ContractCreator
Transaction Hash |
Method
|
Block
|
From
|
To
|
|||||
---|---|---|---|---|---|---|---|---|---|
0xe2948ba95973f6636bb2f7259e233eef7fbe521901431b070a33b63d0c1e3554 | Swap And Deposit | (pending) | 5 days ago | IN | 0.001 ETH | (Pending) | |||
Swap In Same Cha... | 21308273 | 39 days ago | IN | 0 ETH | 0.00445851 | ||||
Swap In Same Cha... | 21308270 | 39 days ago | IN | 0 ETH | 0.00434046 | ||||
Swap In Same Cha... | 21308259 | 39 days ago | IN | 0 ETH | 0.00341054 | ||||
Swap In Same Cha... | 21308254 | 39 days ago | IN | 0 ETH | 0.00719502 | ||||
Swap In Same Cha... | 21308241 | 39 days ago | IN | 0 ETH | 0.00402354 | ||||
Swap In Same Cha... | 21308237 | 39 days ago | IN | 0 ETH | 0.00759107 | ||||
Swap In Same Cha... | 21308161 | 39 days ago | IN | 0.486 ETH | 0.00328552 | ||||
Swap In Same Cha... | 21308154 | 39 days ago | IN | 0.486 ETH | 0.00351991 | ||||
Swap In Same Cha... | 21308151 | 39 days ago | IN | 0.486 ETH | 0.00344153 | ||||
Swap And Deposit | 21307868 | 39 days ago | IN | 0 ETH | 0.00548418 | ||||
Swap And Deposit | 21306210 | 40 days ago | IN | 0 ETH | 0.00223477 | ||||
Swap And Deposit | 21306184 | 40 days ago | IN | 0 ETH | 0.00244346 | ||||
Swap And Deposit | 21306058 | 40 days ago | IN | 0 ETH | 0.0019233 | ||||
Swap And Deposit | 21305469 | 40 days ago | IN | 0.0065 ETH | 0.00343959 | ||||
Swap And Deposit | 21304676 | 40 days ago | IN | 0.26 ETH | 0.00258647 | ||||
Swap And Deposit | 21304117 | 40 days ago | IN | 0 ETH | 0.00307155 | ||||
Swap And Deposit | 21302194 | 40 days ago | IN | 0 ETH | 0.00578808 | ||||
Swap And Deposit | 21300911 | 40 days ago | IN | 0.107 ETH | 0.00303572 | ||||
Swap And Deposit | 21300461 | 40 days ago | IN | 0 ETH | 0.00074563 | ||||
Swap And Deposit | 21300449 | 40 days ago | IN | 0 ETH | 0.00089983 | ||||
Swap And Deposit | 21299445 | 40 days ago | IN | 0 ETH | 0.00201847 | ||||
Swap And Deposit | 21299217 | 41 days ago | IN | 0.01 ETH | 0.00400942 | ||||
Swap And Deposit | 21299151 | 41 days ago | IN | 0.0001 ETH | 0.00366749 | ||||
Swap And Deposit | 21296835 | 41 days ago | IN | 0 ETH | 0.00245531 |
Latest 25 internal transactions (View All)
Advanced mode:
Parent Transaction Hash | Block |
From
|
To
|
|||
---|---|---|---|---|---|---|
21308259 | 39 days ago | 0.34813417 ETH | ||||
21308259 | 39 days ago | 0.34813417 ETH | ||||
21308161 | 39 days ago | 0.486 ETH | ||||
21308154 | 39 days ago | 0.486 ETH | ||||
21308151 | 39 days ago | 0.486 ETH | ||||
21308142 | 39 days ago | 0.49065176 ETH | ||||
21308142 | 39 days ago | 0.49065176 ETH | ||||
21305469 | 40 days ago | 0.0065 ETH | ||||
21304676 | 40 days ago | 0.26 ETH | ||||
21304090 | 40 days ago | 0.00845406 ETH | ||||
21304090 | 40 days ago | 0.00845406 ETH | ||||
21302648 | 40 days ago | 0.99227034 ETH | ||||
21302648 | 40 days ago | 0.99227034 ETH | ||||
21300911 | 40 days ago | 0.107 ETH | ||||
21299217 | 41 days ago | 0.01 ETH | ||||
21299151 | 41 days ago | 0.0001 ETH | ||||
21296656 | 41 days ago | 0.08 ETH | ||||
21293446 | 41 days ago | 0.03 ETH | ||||
21287337 | 42 days ago | 0.02 ETH | ||||
21287176 | 42 days ago | 0.03577591 ETH | ||||
21287176 | 42 days ago | 0.03577591 ETH | ||||
21286887 | 42 days ago | 0.8 ETH | ||||
21285131 | 42 days ago | 0.1009 ETH | ||||
21281120 | 43 days ago | 0.00015 ETH | ||||
21280019 | 43 days ago | 0.083 ETH |
Loading...
Loading
This contract may be a proxy contract. Click on More Options and select Is this a proxy? to confirm and enable the "Read as Proxy" & "Write as Proxy" tabs.
Contract Name:
DexSpan
Compiler Version
v0.8.21+commit.d9974bed
Optimization Enabled:
Yes with 999999 runs
Other Settings:
paris EvmVersion
Contract Source Code (Solidity Standard Json-Input format)
// SPDX-License-Identifier: MIT pragma solidity ^0.8.20; import "@openzeppelin/contracts/utils/math/SafeMath.sol"; import "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol"; import "@openzeppelin/contracts-upgradeable/token/ERC20/IERC20Upgradeable.sol"; import "@openzeppelin/contracts/access/Ownable.sol"; import "@openzeppelin/contracts/access/AccessControl.sol"; import "@openzeppelin/contracts/utils/Multicall.sol"; import "./interface/IUniswapFactory.sol"; import "./interface/IUniswapV2Factory.sol"; import "./interface/IHandlerReserve.sol"; import "./interface/IEthHandler.sol"; import "./IDexSpan.sol"; import "./UniversalERC20.sol"; import "./interface/IWETH.sol"; import "./libraries/TransferHelper.sol"; // import "./libraries/Multicall.sol"; import "./interface/IAugustusSwapper.sol"; import "../interfaces/IAssetForwarder.sol"; import "./interface/IEthHandler.sol"; import "./DexSpanRoot.sol"; import { IDexSpanView } from "./DexSpanView.sol"; import "../interfaces/IMessageHandler.sol"; contract DexSpan is DexSpanFlags, DexSpanRoot, AccessControl, Multicall { using UniversalERC20 for IERC20Upgradeable; using SafeMath for uint256; using DisableFlags for uint256; using UniswapV2ExchangeLib for IUniswapV2Exchange; IAssetForwarder public assetForwarder; address public assetBridge; address public univ2SkimAddress; address public newOwner; // IWETH public wnativeAddress; mapping(uint256 => address) public flagToAddress; event Swap( string indexed funcName, IERC20Upgradeable[] tokenPath, uint256 amount, address indexed sender, address indexed receiver, uint256 finalAmt, uint256[] flags, uint256 widgetID ); event SwapWithRecipient( string indexed funcName, IERC20Upgradeable[] tokenPath, uint256 amount, address indexed sender, address indexed receiver, uint256 finalAmt, uint256[] flags, uint256 widgetID ); event SwapOnSameChain( IERC20Upgradeable fromToken, IERC20Upgradeable destToken, uint amount, bytes _data, uint256 flags ); event SetAssetForwarder(address assetForwarder, address admin); event SetAssetBridge(address assetBridge, address admin); event SetFlagToFactory(uint flag, address factoryAddress); event SetFactorySetter(address factorySetter); event SetWNativeAddresses(address wrappedNative); event TransferOwnership(address newOwner); event ClaimOwnership(address newOwner); error InvalidPool(); error InvalidCaller(); error ZeroAddress(); error ZeroFlag(); error RestrictNativeToken(); error WrongTokenSent(); error WrongDataLength(); error AmountTooLow(); error ExcecutionFailed(); error AlreadyFactorySetter(); error InvalidDepositType(); struct DexesArgs { IERC20Upgradeable factoryAddress; uint256 _exchangeCode; } struct SwapParams { IERC20Upgradeable[] tokens; uint256 amount; uint256 minReturn; uint256[] flags; bytes[] dataTx; bool isWrapper; address recipient; bytes destToken; } bytes32 public constant FACTORY_SETTER_ROLE = keccak256("FACTORY_SETTER_ROLE"); bytes4 internal constant SWAP_MULTI_WITH_RECEPIENT_SELECTOR = 0xe738aa8d; receive() external payable {} constructor( address _assetForwarderAddress, address _native, address _wrappedNative, address _univ2SkimAddress ) { if (_assetForwarderAddress == address(0)) revert ZeroAddress(); if (_native == address(0)) revert ZeroAddress(); if (_wrappedNative == address(0)) revert ZeroAddress(); if (_univ2SkimAddress == address(0)) revert ZeroAddress(); _setupRole(DEFAULT_ADMIN_ROLE, msg.sender); assetForwarder = IAssetForwarder(_assetForwarderAddress); nativeAddress = IERC20Upgradeable(_native); wnativeAddress = IWETH(_wrappedNative); univ2SkimAddress = _univ2SkimAddress; } function transferOwnership( address _newOwner ) external onlyRole(DEFAULT_ADMIN_ROLE) { if (_newOwner == address(0)) revert ZeroAddress(); newOwner = _newOwner; emit TransferOwnership(_newOwner); } function claimOwnership() external { if (newOwner != msg.sender) { revert InvalidCaller(); } _setupRole(DEFAULT_ADMIN_ROLE, msg.sender); emit ClaimOwnership(msg.sender); } function setAssetForwarder( address _forwarder ) external onlyRole(DEFAULT_ADMIN_ROLE) { if (_forwarder == address(0)) revert ZeroAddress(); assetForwarder = IAssetForwarder(_forwarder); emit SetAssetForwarder(_forwarder, msg.sender); } function setAssetBridge( address _assetBridge ) external onlyRole(DEFAULT_ADMIN_ROLE) { if (_assetBridge == address(0)) revert ZeroAddress(); assetBridge = _assetBridge; emit SetAssetBridge(_assetBridge, msg.sender); } function setFlagToFactoryAddress( uint256 _flagCode, address _factoryAddress ) external onlyRole(FACTORY_SETTER_ROLE) { if (_flagCode == 0) revert ZeroFlag(); if (_factoryAddress == address(0)) revert ZeroAddress(); flagToAddress[_flagCode] = address(_factoryAddress); emit SetFlagToFactory(_flagCode, _factoryAddress); } function setFactorySetter( address _factorySetter ) external onlyRole(DEFAULT_ADMIN_ROLE) { if (_factorySetter == address(0)) revert ZeroAddress(); if (hasRole(FACTORY_SETTER_ROLE, _factorySetter)) revert AlreadyFactorySetter(); _setupRole(FACTORY_SETTER_ROLE, _factorySetter); emit SetFactorySetter(_factorySetter); } function setWNativeAddresses( address _native, address _wrappedNative ) external onlyRole(DEFAULT_ADMIN_ROLE) { if (_native == address(0)) revert ZeroAddress(); if (_wrappedNative == address(0)) revert ZeroAddress(); nativeAddress = IERC20Upgradeable(_native); wnativeAddress = IWETH(_wrappedNative); emit SetWNativeAddresses(_wrappedNative); } function handleMessage( address _tokenSent, uint256 _amount, bytes memory message ) external { if ( msg.sender != address(assetForwarder) && msg.sender != address(assetBridge) ) revert InvalidCaller(); messageHandler(_tokenSent, _amount, message); } function swapInSameChain( IERC20Upgradeable[] memory tokens, uint256 amount, uint256 minReturn, uint256[] memory flags, bytes[] memory dataTx, bool isWrapper, address recipient, uint256 widgetID ) public payable returns (uint256 returnAmount) { returnAmount = swapMultiWithRecipient( tokens, amount, minReturn, flags, dataTx, isWrapper, recipient ); emit Swap( "swapInSameChain", tokens, amount, msg.sender, recipient, returnAmount, flags, widgetID ); } function swapMultiWithRecipient( IERC20Upgradeable[] memory tokens, uint256 amount, uint256 minReturn, uint256[] memory flags, bytes[] memory dataTx, bool isWrapper, address recipient ) public payable returns (uint256 returnAmount) { returnAmount = _swapMultiInternal( tokens, amount, minReturn, flags, dataTx, isWrapper, recipient ); emit SwapWithRecipient( "swapMultiWithRecipient", tokens, amount, msg.sender, recipient, returnAmount, flags, 0 ); } function swapAndDeposit( uint256 partnerId, bytes32 destChainIdBytes, bytes calldata recipient, uint8 depositType, uint256 destAmount, bytes memory message, SwapParams memory swapData, address refundRecipient ) public payable { _swapMultiInternal( swapData.tokens, swapData.amount, swapData.minReturn, swapData.flags, swapData.dataTx, swapData.isWrapper, address(this) ); IERC20Upgradeable reserveToken = swapData.tokens[ swapData.tokens.length - 1 ]; // swapAndDeposit if (depositType == 0) { uint256 amount = reserveToken.universalBalanceOf(address(this)); reserveToken.universalApprove(address(assetForwarder), amount); assetForwarder.iDeposit{value: reserveToken.isETH() ? amount : 0}( IAssetForwarder.DepositData( partnerId, amount, destAmount, address(reserveToken), refundRecipient, destChainIdBytes ), swapData.destToken, recipient ); return; } // swapAndDepositWithMessage if (depositType == 1) { uint256 amount = reserveToken.universalBalanceOf(address(this)); reserveToken.universalApprove( address(assetForwarder), swapData.minReturn ); assetForwarder.iDepositMessage{ value: reserveToken.isETH() ? amount : 0 }( IAssetForwarder.DepositData( partnerId, swapData.minReturn, destAmount, address(reserveToken), refundRecipient, destChainIdBytes ), swapData.destToken, recipient, message ); if (amount > swapData.minReturn) { reserveToken.universalTransfer( refundRecipient, amount - swapData.minReturn ); } return; } revert InvalidDepositType(); } function messageHandler( address _tokenSent, uint256 _amount, bytes memory message ) internal { ( IERC20Upgradeable[] memory tokens, uint256 minReturn, bytes[] memory dataTx, uint256[] memory flags, address recipient, bool isInstruction, bytes memory instruction ) = abi.decode( message, ( IERC20Upgradeable[], uint256, bytes[], uint256[], address, bool, bytes ) ); if (_tokenSent != address(tokens[0])) revert WrongTokenSent(); bytes memory execData; bool execFlag; (execFlag, execData) = address(this).call( abi.encodeWithSelector( SWAP_MULTI_WITH_RECEPIENT_SELECTOR, tokens, _amount, minReturn, flags, dataTx, true, recipient ) ); if (!execFlag) { tokens[0].universalTransfer(recipient, _amount); } if (isInstruction) { uint256 finalAmount = execFlag ? uint256(bytes32(execData)) : _amount; address finalToken = execFlag ? address(tokens[tokens.length - 1]) : _tokenSent; (execFlag, execData) = recipient.call( abi.encodeWithSelector( IMessageHandler.handleMessage.selector, finalToken, finalAmount, instruction ) ); } } function _swapMultiInternal( IERC20Upgradeable[] memory tokens, uint256 amount, uint256 minReturn, uint256[] memory flags, bytes[] memory dataTx, bool isWrapper, address recipient ) internal returns (uint256 returnAmount) { if (recipient == address(0)) revert ZeroAddress(); if (tokens.length - 1 != flags.length) { revert WrongDataLength(); } if (!isWrapper) { if (!tokens[0].isETH() && msg.value != 0) { revert RestrictNativeToken(); } tokens[0].universalTransferFrom(msg.sender, address(this), amount); } returnAmount = tokens[0].universalBalanceOf(address(this)); IERC20Upgradeable destinationToken = tokens[tokens.length - 1]; for (uint256 i = 1; i < tokens.length; i++) { if (tokens[i - 1] == tokens[i]) { continue; } returnAmount = _swapFloor( tokens[i - 1], tokens[i], returnAmount, 0, flags[i - 1], dataTx[i - 1] ); } if (destinationToken.isETH()) { returnAmount = wnativeAddress.balanceOf(address(this)); wnativeAddress.withdraw(returnAmount); } if (recipient != address(this)) { uint256 userBalanceOld = destinationToken.universalBalanceOf( recipient ); destinationToken.universalTransfer(recipient, returnAmount); uint256 userBalanceNew = destinationToken.universalBalanceOf( recipient ); uint receivedTokens = userBalanceNew - userBalanceOld; if (receivedTokens <= minReturn) { revert AmountTooLow(); } returnAmount = receivedTokens; } } function _swapFloor( IERC20Upgradeable fromToken, IERC20Upgradeable destToken, uint256 amount, uint256 minReturn, uint256 flags, bytes memory _data ) internal returns (uint returnAmount) { returnAmount = _swap( fromToken, destToken, amount, minReturn, flags, _data ); } function _swap( IERC20Upgradeable fromToken, IERC20Upgradeable destToken, uint256 amount, uint256 minReturn, uint256 flags, bytes memory _data ) internal returns (uint256 returnAmount) { if (fromToken == destToken) { return amount; } function( IERC20Upgradeable, IERC20Upgradeable, uint256, bytes memory, uint256 ) reserve = _getReserveExchange(flags); uint256 remainingAmount = fromToken.universalBalanceOf(address(this)); reserve(fromToken, destToken, remainingAmount, _data, flags); returnAmount = destToken.universalBalanceOf(address(this)); } function _getReserveExchange( uint256 flag ) internal pure returns ( function( IERC20Upgradeable, IERC20Upgradeable, uint256, bytes memory, uint256 ) ) { if (flag < 0x03E9 && flag >= 0x0001) { // 1 - 1000 return _swapOnUniswapV2; } else if (flag == 0x07D2) { return _swapOnParaswap; // 2002 } else { return _swapOnGenericAggregator; } revert("RA: Exchange not found"); } function _swapOnUniswapV2( IERC20Upgradeable fromToken, IERC20Upgradeable destToken, uint256 amount, bytes memory _data, uint256 flags ) internal { _swapOnExchangeInternal(fromToken, destToken, amount, flags); } function _swapOnGenericAggregator( IERC20Upgradeable fromToken, IERC20Upgradeable destToken, uint256 amount, bytes memory _data, uint256 flagCode ) internal { if (_data.length < 0) { revert WrongDataLength(); } address aggregatorFactoryAddress = flagToAddress[flagCode]; if (aggregatorFactoryAddress == address(0)) { revert ZeroAddress(); } if (fromToken.isETH()) { wnativeAddress.deposit{value: amount}(); } IERC20Upgradeable fromTokenReal = fromToken.isETH() ? wnativeAddress : fromToken; fromTokenReal.universalApprove(address(aggregatorFactoryAddress), amount); // solhint-disable-next-line avoid-low-level-calls (bool success, ) = address(aggregatorFactoryAddress).call(_data); if (!success) revert ExcecutionFailed(); } function _swapOnParaswap( IERC20Upgradeable fromToken, IERC20Upgradeable destToken, uint256 amount, bytes memory _data, uint256 flagCode ) internal { if (_data.length < 0) { revert WrongDataLength(); } address paraswap = flagToAddress[flagCode]; if (paraswap == address(0)) { revert ZeroAddress(); } if (fromToken.isETH()) { wnativeAddress.deposit{value: amount}(); } IERC20Upgradeable fromTokenReal = fromToken.isETH() ? wnativeAddress : fromToken; fromTokenReal.universalApprove( IAugustusSwapper(paraswap).getTokenTransferProxy(), amount ); // solhint-disable-next-line avoid-low-level-calls (bool success, ) = address(paraswap).call(_data); if (!success) { revert ExcecutionFailed(); } } function _swapOnExchangeInternal( IERC20Upgradeable fromToken, IERC20Upgradeable destToken, uint256 amount, uint256 flagCode ) internal returns (uint256 returnAmount) { if (fromToken.isETH()) { wnativeAddress.deposit{value: amount}(); } address dexAddress = flagToAddress[flagCode]; require(dexAddress != address(0), "RA: Exchange not found"); IUniswapV2Factory factory = IUniswapV2Factory(address(dexAddress)); IERC20Upgradeable fromTokenReal = fromToken.isETH() ? wnativeAddress : fromToken; IERC20Upgradeable toTokenReal = destToken.isETH() ? wnativeAddress : destToken; if (fromTokenReal == toTokenReal) { return amount; } IUniswapV2Exchange pool = factory.getPair(fromTokenReal, toTokenReal); if (address(pool) == address(0)) revert InvalidPool(); bool needSync; bool needSkim; (returnAmount, needSync, needSkim) = pool.getReturn( fromTokenReal, toTokenReal, amount ); if (needSync) { pool.sync(); } else if (needSkim) { pool.skim(univ2SkimAddress); } fromTokenReal.universalTransfer(address(pool), amount); if ( uint256(uint160(address(fromTokenReal))) < uint256(uint160(address(toTokenReal))) ) { pool.swap(0, returnAmount, address(this), ""); } else { pool.swap(returnAmount, 0, address(this), ""); } } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.9.0) (utils/math/SafeMath.sol) pragma solidity ^0.8.0; // CAUTION // This version of SafeMath should only be used with Solidity 0.8 or later, // because it relies on the compiler's built in overflow checks. /** * @dev Wrappers over Solidity's arithmetic operations. * * NOTE: `SafeMath` is generally not needed starting with Solidity 0.8, since the compiler * now has built in overflow checking. */ library SafeMath { /** * @dev Returns the addition of two unsigned integers, with an overflow flag. * * _Available since v3.4._ */ function tryAdd(uint256 a, uint256 b) internal pure returns (bool, uint256) { unchecked { uint256 c = a + b; if (c < a) return (false, 0); return (true, c); } } /** * @dev Returns the subtraction of two unsigned integers, with an overflow flag. * * _Available since v3.4._ */ function trySub(uint256 a, uint256 b) internal pure returns (bool, uint256) { unchecked { if (b > a) return (false, 0); return (true, a - b); } } /** * @dev Returns the multiplication of two unsigned integers, with an overflow flag. * * _Available since v3.4._ */ function tryMul(uint256 a, uint256 b) internal pure returns (bool, uint256) { unchecked { // Gas optimization: this is cheaper than requiring 'a' not being zero, but the // benefit is lost if 'b' is also tested. // See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522 if (a == 0) return (true, 0); uint256 c = a * b; if (c / a != b) return (false, 0); return (true, c); } } /** * @dev Returns the division of two unsigned integers, with a division by zero flag. * * _Available since v3.4._ */ function tryDiv(uint256 a, uint256 b) internal pure returns (bool, uint256) { unchecked { if (b == 0) return (false, 0); return (true, a / b); } } /** * @dev Returns the remainder of dividing two unsigned integers, with a division by zero flag. * * _Available since v3.4._ */ function tryMod(uint256 a, uint256 b) internal pure returns (bool, uint256) { unchecked { if (b == 0) return (false, 0); return (true, a % b); } } /** * @dev Returns the addition of two unsigned integers, reverting on * overflow. * * Counterpart to Solidity's `+` operator. * * Requirements: * * - Addition cannot overflow. */ function add(uint256 a, uint256 b) internal pure returns (uint256) { return a + b; } /** * @dev Returns the subtraction of two unsigned integers, reverting on * overflow (when the result is negative). * * Counterpart to Solidity's `-` operator. * * Requirements: * * - Subtraction cannot overflow. */ function sub(uint256 a, uint256 b) internal pure returns (uint256) { return a - b; } /** * @dev Returns the multiplication of two unsigned integers, reverting on * overflow. * * Counterpart to Solidity's `*` operator. * * Requirements: * * - Multiplication cannot overflow. */ function mul(uint256 a, uint256 b) internal pure returns (uint256) { return a * b; } /** * @dev Returns the integer division of two unsigned integers, reverting on * division by zero. The result is rounded towards zero. * * Counterpart to Solidity's `/` operator. * * Requirements: * * - The divisor cannot be zero. */ function div(uint256 a, uint256 b) internal pure returns (uint256) { return a / b; } /** * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo), * reverting when dividing by zero. * * Counterpart to Solidity's `%` operator. This function uses a `revert` * opcode (which leaves remaining gas untouched) while Solidity uses an * invalid opcode to revert (consuming all remaining gas). * * Requirements: * * - The divisor cannot be zero. */ function mod(uint256 a, uint256 b) internal pure returns (uint256) { return a % b; } /** * @dev Returns the subtraction of two unsigned integers, reverting with custom message on * overflow (when the result is negative). * * CAUTION: This function is deprecated because it requires allocating memory for the error * message unnecessarily. For custom revert reasons use {trySub}. * * Counterpart to Solidity's `-` operator. * * Requirements: * * - Subtraction cannot overflow. */ function sub(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) { unchecked { require(b <= a, errorMessage); return a - b; } } /** * @dev Returns the integer division of two unsigned integers, reverting with custom message on * division by zero. The result is rounded towards zero. * * Counterpart to Solidity's `/` operator. Note: this function uses a * `revert` opcode (which leaves remaining gas untouched) while Solidity * uses an invalid opcode to revert (consuming all remaining gas). * * Requirements: * * - The divisor cannot be zero. */ function div(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) { unchecked { require(b > 0, errorMessage); return a / b; } } /** * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo), * reverting with custom message when dividing by zero. * * CAUTION: This function is deprecated because it requires allocating memory for the error * message unnecessarily. For custom revert reasons use {tryMod}. * * Counterpart to Solidity's `%` operator. This function uses a `revert` * opcode (which leaves remaining gas untouched) while Solidity uses an * invalid opcode to revert (consuming all remaining gas). * * Requirements: * * - The divisor cannot be zero. */ function mod(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) { unchecked { require(b > 0, errorMessage); return a % b; } } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.9.3) (token/ERC20/utils/SafeERC20.sol) pragma solidity ^0.8.0; import "../IERC20.sol"; import "../extensions/IERC20Permit.sol"; import "../../../utils/Address.sol"; /** * @title SafeERC20 * @dev Wrappers around ERC20 operations that throw on failure (when the token * contract returns false). Tokens that return no value (and instead revert or * throw on failure) are also supported, non-reverting calls are assumed to be * successful. * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract, * which allows you to call the safe operations as `token.safeTransfer(...)`, etc. */ library SafeERC20 { using Address for address; /** * @dev Transfer `value` amount of `token` from the calling contract to `to`. If `token` returns no value, * non-reverting calls are assumed to be successful. */ function safeTransfer(IERC20 token, address to, uint256 value) internal { _callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value)); } /** * @dev Transfer `value` amount of `token` from `from` to `to`, spending the approval given by `from` to the * calling contract. If `token` returns no value, non-reverting calls are assumed to be successful. */ function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal { _callOptionalReturn(token, abi.encodeWithSelector(token.transferFrom.selector, from, to, value)); } /** * @dev Deprecated. This function has issues similar to the ones found in * {IERC20-approve}, and its usage is discouraged. * * Whenever possible, use {safeIncreaseAllowance} and * {safeDecreaseAllowance} instead. */ function safeApprove(IERC20 token, address spender, uint256 value) internal { // safeApprove should only be called when setting an initial allowance, // or when resetting it to zero. To increase and decrease it, use // 'safeIncreaseAllowance' and 'safeDecreaseAllowance' require( (value == 0) || (token.allowance(address(this), spender) == 0), "SafeERC20: approve from non-zero to non-zero allowance" ); _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, value)); } /** * @dev Increase the calling contract's allowance toward `spender` by `value`. If `token` returns no value, * non-reverting calls are assumed to be successful. */ function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal { uint256 oldAllowance = token.allowance(address(this), spender); _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, oldAllowance + value)); } /** * @dev Decrease the calling contract's allowance toward `spender` by `value`. If `token` returns no value, * non-reverting calls are assumed to be successful. */ function safeDecreaseAllowance(IERC20 token, address spender, uint256 value) internal { unchecked { uint256 oldAllowance = token.allowance(address(this), spender); require(oldAllowance >= value, "SafeERC20: decreased allowance below zero"); _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, oldAllowance - value)); } } /** * @dev Set the calling contract's allowance toward `spender` to `value`. If `token` returns no value, * non-reverting calls are assumed to be successful. Meant to be used with tokens that require the approval * to be set to zero before setting it to a non-zero value, such as USDT. */ function forceApprove(IERC20 token, address spender, uint256 value) internal { bytes memory approvalCall = abi.encodeWithSelector(token.approve.selector, spender, value); if (!_callOptionalReturnBool(token, approvalCall)) { _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, 0)); _callOptionalReturn(token, approvalCall); } } /** * @dev Use a ERC-2612 signature to set the `owner` approval toward `spender` on `token`. * Revert on invalid signature. */ function safePermit( IERC20Permit token, address owner, address spender, uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s ) internal { uint256 nonceBefore = token.nonces(owner); token.permit(owner, spender, value, deadline, v, r, s); uint256 nonceAfter = token.nonces(owner); require(nonceAfter == nonceBefore + 1, "SafeERC20: permit did not succeed"); } /** * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement * on the return value: the return value is optional (but if data is returned, it must not be false). * @param token The token targeted by the call. * @param data The call data (encoded using abi.encode or one of its variants). */ function _callOptionalReturn(IERC20 token, bytes memory data) private { // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since // we're implementing it ourselves. We use {Address-functionCall} to perform this call, which verifies that // the target address contains contract code and also asserts for success in the low-level call. bytes memory returndata = address(token).functionCall(data, "SafeERC20: low-level call failed"); require(returndata.length == 0 || abi.decode(returndata, (bool)), "SafeERC20: ERC20 operation did not succeed"); } /** * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement * on the return value: the return value is optional (but if data is returned, it must not be false). * @param token The token targeted by the call. * @param data The call data (encoded using abi.encode or one of its variants). * * This is a variant of {_callOptionalReturn} that silents catches all reverts and returns a bool instead. */ function _callOptionalReturnBool(IERC20 token, bytes memory data) private returns (bool) { // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since // we're implementing it ourselves. We cannot use {Address-functionCall} here since this should return false // and not revert is the subcall reverts. (bool success, bytes memory returndata) = address(token).call(data); return success && (returndata.length == 0 || abi.decode(returndata, (bool))) && Address.isContract(address(token)); } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.9.0) (token/ERC20/IERC20.sol) pragma solidity ^0.8.0; /** * @dev Interface of the ERC20 standard as defined in the EIP. */ interface IERC20Upgradeable { /** * @dev Emitted when `value` tokens are moved from one account (`from`) to * another (`to`). * * Note that `value` may be zero. */ event Transfer(address indexed from, address indexed to, uint256 value); /** * @dev Emitted when the allowance of a `spender` for an `owner` is set by * a call to {approve}. `value` is the new allowance. */ event Approval(address indexed owner, address indexed spender, uint256 value); /** * @dev Returns the amount of tokens in existence. */ function totalSupply() external view returns (uint256); /** * @dev Returns the amount of tokens owned by `account`. */ function balanceOf(address account) external view returns (uint256); /** * @dev Moves `amount` tokens from the caller's account to `to`. * * Returns a boolean value indicating whether the operation succeeded. * * Emits a {Transfer} event. */ function transfer(address to, uint256 amount) external returns (bool); /** * @dev Returns the remaining number of tokens that `spender` will be * allowed to spend on behalf of `owner` through {transferFrom}. This is * zero by default. * * This value changes when {approve} or {transferFrom} are called. */ function allowance(address owner, address spender) external view returns (uint256); /** * @dev Sets `amount` as the allowance of `spender` over the caller's tokens. * * Returns a boolean value indicating whether the operation succeeded. * * IMPORTANT: Beware that changing an allowance with this method brings the risk * that someone may use both the old and the new allowance by unfortunate * transaction ordering. One possible solution to mitigate this race * condition is to first reduce the spender's allowance to 0 and set the * desired value afterwards: * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729 * * Emits an {Approval} event. */ function approve(address spender, uint256 amount) external returns (bool); /** * @dev Moves `amount` tokens from `from` to `to` using the * allowance mechanism. `amount` is then deducted from the caller's * allowance. * * Returns a boolean value indicating whether the operation succeeded. * * Emits a {Transfer} event. */ function transferFrom(address from, address to, uint256 amount) external returns (bool); }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.9.0) (access/Ownable.sol) pragma solidity ^0.8.0; import "../utils/Context.sol"; /** * @dev Contract module which provides a basic access control mechanism, where * there is an account (an owner) that can be granted exclusive access to * specific functions. * * By default, the owner account will be the one that deploys the contract. This * can later be changed with {transferOwnership}. * * This module is used through inheritance. It will make available the modifier * `onlyOwner`, which can be applied to your functions to restrict their use to * the owner. */ abstract contract Ownable is Context { address private _owner; event OwnershipTransferred(address indexed previousOwner, address indexed newOwner); /** * @dev Initializes the contract setting the deployer as the initial owner. */ constructor() { _transferOwnership(_msgSender()); } /** * @dev Throws if called by any account other than the owner. */ modifier onlyOwner() { _checkOwner(); _; } /** * @dev Returns the address of the current owner. */ function owner() public view virtual returns (address) { return _owner; } /** * @dev Throws if the sender is not the owner. */ function _checkOwner() internal view virtual { require(owner() == _msgSender(), "Ownable: caller is not the owner"); } /** * @dev Leaves the contract without owner. It will not be possible to call * `onlyOwner` functions. Can only be called by the current owner. * * NOTE: Renouncing ownership will leave the contract without an owner, * thereby disabling any functionality that is only available to the owner. */ function renounceOwnership() public virtual onlyOwner { _transferOwnership(address(0)); } /** * @dev Transfers ownership of the contract to a new account (`newOwner`). * Can only be called by the current owner. */ function transferOwnership(address newOwner) public virtual onlyOwner { require(newOwner != address(0), "Ownable: new owner is the zero address"); _transferOwnership(newOwner); } /** * @dev Transfers ownership of the contract to a new account (`newOwner`). * Internal function without access restriction. */ function _transferOwnership(address newOwner) internal virtual { address oldOwner = _owner; _owner = newOwner; emit OwnershipTransferred(oldOwner, newOwner); } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.9.0) (access/AccessControl.sol) pragma solidity ^0.8.0; import "./IAccessControl.sol"; import "../utils/Context.sol"; import "../utils/Strings.sol"; import "../utils/introspection/ERC165.sol"; /** * @dev Contract module that allows children to implement role-based access * control mechanisms. This is a lightweight version that doesn't allow enumerating role * members except through off-chain means by accessing the contract event logs. Some * applications may benefit from on-chain enumerability, for those cases see * {AccessControlEnumerable}. * * Roles are referred to by their `bytes32` identifier. These should be exposed * in the external API and be unique. The best way to achieve this is by * using `public constant` hash digests: * * ```solidity * bytes32 public constant MY_ROLE = keccak256("MY_ROLE"); * ``` * * Roles can be used to represent a set of permissions. To restrict access to a * function call, use {hasRole}: * * ```solidity * function foo() public { * require(hasRole(MY_ROLE, msg.sender)); * ... * } * ``` * * Roles can be granted and revoked dynamically via the {grantRole} and * {revokeRole} functions. Each role has an associated admin role, and only * accounts that have a role's admin role can call {grantRole} and {revokeRole}. * * By default, the admin role for all roles is `DEFAULT_ADMIN_ROLE`, which means * that only accounts with this role will be able to grant or revoke other * roles. More complex role relationships can be created by using * {_setRoleAdmin}. * * WARNING: The `DEFAULT_ADMIN_ROLE` is also its own admin: it has permission to * grant and revoke this role. Extra precautions should be taken to secure * accounts that have been granted it. We recommend using {AccessControlDefaultAdminRules} * to enforce additional security measures for this role. */ abstract contract AccessControl is Context, IAccessControl, ERC165 { struct RoleData { mapping(address => bool) members; bytes32 adminRole; } mapping(bytes32 => RoleData) private _roles; bytes32 public constant DEFAULT_ADMIN_ROLE = 0x00; /** * @dev Modifier that checks that an account has a specific role. Reverts * with a standardized message including the required role. * * The format of the revert reason is given by the following regular expression: * * /^AccessControl: account (0x[0-9a-f]{40}) is missing role (0x[0-9a-f]{64})$/ * * _Available since v4.1._ */ modifier onlyRole(bytes32 role) { _checkRole(role); _; } /** * @dev See {IERC165-supportsInterface}. */ function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) { return interfaceId == type(IAccessControl).interfaceId || super.supportsInterface(interfaceId); } /** * @dev Returns `true` if `account` has been granted `role`. */ function hasRole(bytes32 role, address account) public view virtual override returns (bool) { return _roles[role].members[account]; } /** * @dev Revert with a standard message if `_msgSender()` is missing `role`. * Overriding this function changes the behavior of the {onlyRole} modifier. * * Format of the revert message is described in {_checkRole}. * * _Available since v4.6._ */ function _checkRole(bytes32 role) internal view virtual { _checkRole(role, _msgSender()); } /** * @dev Revert with a standard message if `account` is missing `role`. * * The format of the revert reason is given by the following regular expression: * * /^AccessControl: account (0x[0-9a-f]{40}) is missing role (0x[0-9a-f]{64})$/ */ function _checkRole(bytes32 role, address account) internal view virtual { if (!hasRole(role, account)) { revert( string( abi.encodePacked( "AccessControl: account ", Strings.toHexString(account), " is missing role ", Strings.toHexString(uint256(role), 32) ) ) ); } } /** * @dev Returns the admin role that controls `role`. See {grantRole} and * {revokeRole}. * * To change a role's admin, use {_setRoleAdmin}. */ function getRoleAdmin(bytes32 role) public view virtual override returns (bytes32) { return _roles[role].adminRole; } /** * @dev Grants `role` to `account`. * * If `account` had not been already granted `role`, emits a {RoleGranted} * event. * * Requirements: * * - the caller must have ``role``'s admin role. * * May emit a {RoleGranted} event. */ function grantRole(bytes32 role, address account) public virtual override onlyRole(getRoleAdmin(role)) { _grantRole(role, account); } /** * @dev Revokes `role` from `account`. * * If `account` had been granted `role`, emits a {RoleRevoked} event. * * Requirements: * * - the caller must have ``role``'s admin role. * * May emit a {RoleRevoked} event. */ function revokeRole(bytes32 role, address account) public virtual override onlyRole(getRoleAdmin(role)) { _revokeRole(role, account); } /** * @dev Revokes `role` from the calling account. * * Roles are often managed via {grantRole} and {revokeRole}: this function's * purpose is to provide a mechanism for accounts to lose their privileges * if they are compromised (such as when a trusted device is misplaced). * * If the calling account had been revoked `role`, emits a {RoleRevoked} * event. * * Requirements: * * - the caller must be `account`. * * May emit a {RoleRevoked} event. */ function renounceRole(bytes32 role, address account) public virtual override { require(account == _msgSender(), "AccessControl: can only renounce roles for self"); _revokeRole(role, account); } /** * @dev Grants `role` to `account`. * * If `account` had not been already granted `role`, emits a {RoleGranted} * event. Note that unlike {grantRole}, this function doesn't perform any * checks on the calling account. * * May emit a {RoleGranted} event. * * [WARNING] * ==== * This function should only be called from the constructor when setting * up the initial roles for the system. * * Using this function in any other way is effectively circumventing the admin * system imposed by {AccessControl}. * ==== * * NOTE: This function is deprecated in favor of {_grantRole}. */ function _setupRole(bytes32 role, address account) internal virtual { _grantRole(role, account); } /** * @dev Sets `adminRole` as ``role``'s admin role. * * Emits a {RoleAdminChanged} event. */ function _setRoleAdmin(bytes32 role, bytes32 adminRole) internal virtual { bytes32 previousAdminRole = getRoleAdmin(role); _roles[role].adminRole = adminRole; emit RoleAdminChanged(role, previousAdminRole, adminRole); } /** * @dev Grants `role` to `account`. * * Internal function without access restriction. * * May emit a {RoleGranted} event. */ function _grantRole(bytes32 role, address account) internal virtual { if (!hasRole(role, account)) { _roles[role].members[account] = true; emit RoleGranted(role, account, _msgSender()); } } /** * @dev Revokes `role` from `account`. * * Internal function without access restriction. * * May emit a {RoleRevoked} event. */ function _revokeRole(bytes32 role, address account) internal virtual { if (hasRole(role, account)) { _roles[role].members[account] = false; emit RoleRevoked(role, account, _msgSender()); } } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.9.0) (utils/Multicall.sol) pragma solidity ^0.8.0; import "./Address.sol"; /** * @dev Provides a function to batch together multiple calls in a single external call. * * _Available since v4.1._ */ abstract contract Multicall { /** * @dev Receives and executes a batch of function calls on this contract. * @custom:oz-upgrades-unsafe-allow-reachable delegatecall */ function multicall(bytes[] calldata data) external virtual returns (bytes[] memory results) { results = new bytes[](data.length); for (uint256 i = 0; i < data.length; i++) { results[i] = Address.functionDelegateCall(address(this), data[i]); } return results; } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.20; import "./IUniswapExchange.sol"; interface IUniswapFactory { function getExchange( IERC20Upgradeable token ) external view returns (IUniswapExchange exchange); }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.20; import "./IUniswapV2Exchange.sol"; interface IUniswapV2Factory { function getPair( IERC20Upgradeable tokenA, IERC20Upgradeable tokenB ) external view returns (IUniswapV2Exchange pair); }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.20; interface IHandlerReserve { function _lpToContract(address token) external returns (address); function _contractToLP(address token) external returns (address); }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.20; interface IEthHandler { function withdraw(address WETH, uint256) external; }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.20; import "@openzeppelin/contracts-upgradeable/token/ERC20/IERC20Upgradeable.sol"; contract DexSpanFlags { // flags = FLAG_DISABLE_UNISWAP + FLAG_DISABLE_BANCOR + ... uint256 internal constant FLAG_DISABLE_UNISWAP = 0x400; uint256 internal constant FLAG_DISABLE_SPLIT_RECALCULATION = 0x800000000000; uint256 internal constant FLAG_DISABLE_ALL_SPLIT_SOURCES = 0x20000000; uint256 internal constant FLAG_DISABLE_UNISWAP_V2_ALL = 0x400; uint256 internal constant FLAG_DISABLE_EMPTY = 0x100000000000; uint256 internal constant FLAG_DISABLE_DFYN = 0x800; uint256 internal constant FLAG_DISABLE_PANCAKESWAP = 0x80; uint256 internal constant FLAG_DISABLE_QUICKSWAP = 0x40000000000; uint256 internal constant FLAG_DISABLE_SUSHISWAP = 0x1000000; uint256 internal constant FLAG_DISABLE_ONEINCH = 0x100000; } abstract contract IDexSpan is DexSpanFlags { function getExpectedReturn( IERC20Upgradeable fromToken, IERC20Upgradeable destToken, uint256 amount, uint256 parts, uint256 flags // See constants in IOneSplit.sol ) public view virtual returns (uint256 returnAmount, uint256[] memory distribution); function getExpectedReturnWithGasMulti( IERC20Upgradeable[] memory tokens, uint256 amount, uint256[] memory parts, uint256[] memory flags, uint256[] memory destTokenEthPriceTimesGasPrices ) public view virtual returns ( uint256[] memory returnAmounts, uint256 estimateGasAmount, uint256[] memory distribution ); function getExpectedReturnWithGas( IERC20Upgradeable fromToken, IERC20Upgradeable destToken, uint256 amount, uint256 parts, uint256 flags, // See constants in IOneSplit.sol uint256 destTokenEthPriceTimesGasPrice ) public view virtual returns ( uint256 returnAmount, uint256 estimateGasAmount, uint256[] memory distribution ); function setHandlerAddress( address _handlerAddress ) external virtual returns (bool); function setReserveAddress( address _reserveAddress ) external virtual returns (bool); function setBridgeAddress( address _bridgeAddress ) external virtual returns (bool); function withdraw( address tokenAddress, address recipient, uint256 amount ) public payable virtual returns (bool); function swap( IERC20Upgradeable fromToken, IERC20Upgradeable destToken, uint256 amount, uint256 minReturn, uint256 flags, bytes memory dataTx, bool isWrapper ) public payable virtual returns (uint256 returnAmount); function swapWithRecipient( IERC20Upgradeable fromToken, IERC20Upgradeable destToken, uint256 amount, uint256 minReturn, uint256 flags, bytes memory dataTx, bool isWrapper, address recipient ) public payable virtual returns (uint256 returnAmount); function swapMulti( IERC20Upgradeable[] memory tokens, uint256 amount, uint256 minReturn, uint256[] memory flags, bytes[] memory dataTx, bool isWrapper ) public payable virtual returns (uint256 returnAmount); function swapMultiWithRecipient( IERC20Upgradeable[] memory tokens, uint256 amount, uint256 minReturn, uint256[] memory flags, bytes[] memory dataTx, bool isWrapper, address recipient ) public payable virtual returns (uint256 returnAmount); function getExpectedReturnETH( IERC20Upgradeable srcStablefromtoken, uint256 srcStableFromTokenAmount, uint256 parts, uint256 flags ) public view virtual returns (uint256 returnAmount); function swapInSameChain( address[] memory tokens, uint256 amount, uint256 minReturn, uint256[] memory flags, bytes[] memory dataTx, bool isWrapper, address recipient, uint256 widgetID ) public payable virtual returns (uint256 returnAmount); }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.20; import "@openzeppelin/contracts-upgradeable/utils/math/SafeMathUpgradeable.sol"; import "@openzeppelin/contracts-upgradeable/token/ERC20/IERC20Upgradeable.sol"; import "@openzeppelin/contracts-upgradeable/token/ERC20/utils/SafeERC20Upgradeable.sol"; import "./libraries/TransferHelper.sol"; library UniversalERC20 { using SafeMathUpgradeable for uint256; using SafeERC20Upgradeable for IERC20Upgradeable; IERC20Upgradeable private constant ZERO_ADDRESS = IERC20Upgradeable(0x0000000000000000000000000000000000000000); IERC20Upgradeable private constant ETH_ADDRESS = IERC20Upgradeable(0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE); function universalTransfer( IERC20Upgradeable token, address to, uint256 amount ) internal returns (bool) { if (amount == 0) { return true; } if (isETH(token)) { (bool success, ) = payable(address(uint160(to))).call{ value: amount }(""); assert(success == true); } else { TransferHelper.safeTransfer(address(token), to, amount); return true; } } function universalTransferFrom( IERC20Upgradeable token, address from, address to, uint256 amount ) internal { if (amount == 0) { return; } if (isETH(token)) { require( from == msg.sender && msg.value >= amount, "Wrong usage of ETH.universalTransferFrom()" ); if (to != address(this)) { (bool success, ) = payable(address(uint160(to))).call{ value: amount }(""); assert(success == true); } if (msg.value > amount) { (bool success, ) = payable(msg.sender).call{ value: msg.value.sub(amount) }(""); assert(success == true); } } else { TransferHelper.safeTransferFrom(address(token), from, to, amount); } } function universalTransferFromSenderToThis( IERC20Upgradeable token, uint256 amount ) internal { if (amount == 0) { return; } if (isETH(token)) { if (msg.value > amount) { // Return remainder if exist (bool success, ) = payable(msg.sender).call{ value: msg.value.sub(amount) }(""); assert(success == true); } } else { TransferHelper.safeTransferFrom( address(token), msg.sender, address(this), amount ); } } function universalApprove( IERC20Upgradeable token, address to, uint256 amount ) internal { if (!isETH(token)) { // if (amount == 0) { // TransferHelper.safeApprove(address(token), to, 0); // return; // } // uint256 allowance = token.allowance(address(this), to); // if (allowance < amount) { // if (allowance > 0) { // TransferHelper.safeApprove(address(token), to, 0); // } // TransferHelper.safeApprove(address(token), to, amount); // } TransferHelper.safeApprove(address(token), to, 0); TransferHelper.safeApprove(address(token), to, amount); } } function universalBalanceOf( IERC20Upgradeable token, address who ) internal view returns (uint256) { if (isETH(token)) { return who.balance; } else { return token.balanceOf(who); } } function isETH(IERC20Upgradeable token) internal pure returns (bool) { return (address(token) == address(ZERO_ADDRESS) || address(token) == address(ETH_ADDRESS)); } function eq( IERC20Upgradeable a, IERC20Upgradeable b ) internal pure returns (bool) { return a == b || (isETH(a) && isETH(b)); } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.20; import "@openzeppelin/contracts-upgradeable/token/ERC20/IERC20Upgradeable.sol"; abstract contract IWETH is IERC20Upgradeable { function deposit() external payable virtual; function withdraw(uint256 amount) external virtual; }
// SPDX-License-Identifier: GPL-3.0-or-later pragma solidity ^0.8.20; // helper methods for interacting with ERC20 tokens and sending ETH that do not consistently return true/false library TransferHelper { function safeApprove(address token, address to, uint256 value) internal { // bytes4(keccak256(bytes('approve(address,uint256)'))); (bool success, bytes memory data) = token.call( abi.encodeWithSelector(0x095ea7b3, to, value) ); require( success && (data.length == 0 || abi.decode(data, (bool))), "TransferHelper::safeApprove: approve failed" ); } function safeTransfer(address token, address to, uint256 value) internal { // bytes4(keccak256(bytes('transfer(address,uint256)'))); (bool success, bytes memory data) = token.call( abi.encodeWithSelector(0xa9059cbb, to, value) ); require( success && (data.length == 0 || abi.decode(data, (bool))), "TransferHelper::safeTransfer: transfer failed" ); } function safeTransferFrom( address token, address from, address to, uint256 value ) internal { // bytes4(keccak256(bytes('transferFrom(address,address,uint256)'))); (bool success, bytes memory data) = token.call( abi.encodeWithSelector(0x23b872dd, from, to, value) ); require( success && (data.length == 0 || abi.decode(data, (bool))), "TransferHelper::transferFrom: transferFrom failed" ); } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.20; interface IAugustusSwapper { function getTokenTransferProxy() external view returns (address); }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.20; /// @title Interface for handler contracts that support deposits and deposit executions. /// @author Router Protocol. interface IAssetForwarder { event FundsDeposited( uint256 partnerId, uint256 amount, bytes32 destChainIdBytes, uint256 destAmount, uint256 depositId, address srcToken, address depositor, bytes recipient, bytes destToken ); event FundsDepositedWithMessage( uint256 partnerId, uint256 amount, bytes32 destChainIdBytes, uint256 destAmount, uint256 depositId, address srcToken, bytes recipient, address depositor, bytes destToken, bytes message ); event FundsPaid(bytes32 messageHash, address forwarder, uint256 nonce); event DepositInfoUpdate( address srcToken, uint256 feeAmount, uint256 depositId, uint256 eventNonce, bool initiatewithdrawal, address depositor ); event FundsPaidWithMessage( bytes32 messageHash, address forwarder, uint256 nonce, bool execFlag, bytes execData ); struct RelayData { uint256 amount; bytes32 srcChainId; uint256 depositId; address destToken; address recipient; } struct RelayDataMessage { uint256 amount; bytes32 srcChainId; uint256 depositId; address destToken; address recipient; bytes message; } struct DepositData { uint256 partnerId; uint256 amount; uint256 destAmount; address srcToken; address refundRecipient; bytes32 destChainIdBytes; } function iDeposit( DepositData memory depositData, bytes memory destToken, bytes memory recipient ) external payable; function iDepositInfoUpdate( address srcToken, uint256 feeAmount, uint256 depositId, bool initiatewithdrawal ) external payable; function iDepositMessage( DepositData memory depositData, bytes memory destToken, bytes memory recipient, bytes memory message ) external payable; function iRelay(RelayData memory relayData) external payable; function iRelayMessage(RelayDataMessage memory relayData) external payable; }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.20; import "@openzeppelin/contracts/utils/math/SafeMath.sol"; import "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol"; import "@openzeppelin/contracts-upgradeable/token/ERC20/IERC20Upgradeable.sol"; import "@openzeppelin/contracts/access/Ownable.sol"; import "@openzeppelin/contracts/access/AccessControl.sol"; import "@openzeppelin/contracts/utils/Multicall.sol"; import "./interface/IUniswapFactory.sol"; import "./interface/IUniswapV2Factory.sol"; import "./interface/IHandlerReserve.sol"; import "./interface/IEthHandler.sol"; import "./IDexSpan.sol"; import "./UniversalERC20.sol"; import "./interface/IWETH.sol"; import "./libraries/TransferHelper.sol"; // import "./libraries/Multicall.sol"; import "./interface/IAugustusSwapper.sol"; import "../interfaces/IAssetForwarder.sol"; import "./interface/IEthHandler.sol"; import "../interfaces/IMessageHandler.sol"; library DisableFlags { function check(uint256 flags, uint256 flag) internal pure returns (bool) { return (flags & flag) != 0; } } contract DexSpanRoot { using SafeMath for uint256; using DisableFlags for uint256; using UniversalERC20 for IERC20Upgradeable; using UniversalERC20 for IWETH; using UniswapV2ExchangeLib for IUniswapV2Exchange; uint256 internal constant DEXES_COUNT = 4; uint256 public constant DEXES_COUNT_UPDATED = 1; IERC20Upgradeable internal ZERO_ADDRESS; int256 internal constant VERY_NEGATIVE_VALUE = -1e72; IWETH public wnativeAddress; IERC20Upgradeable public nativeAddress; function _findBestDistribution( uint256 s, // parts int256[][] memory amounts // exchangesReturns ) internal pure returns (int256 returnAmount, uint256[] memory distribution) { uint256 n = amounts.length; int256[][] memory answer = new int256[][](n); // int[n][s+1] uint256[][] memory parent = new uint256[][](n); // int[n][s+1] for (uint256 i; i < n; i++) { answer[i] = new int256[](s + 1); parent[i] = new uint256[](s + 1); } for (uint256 j; j <= s; j++) { answer[0][j] = amounts[0][j]; for (uint256 i = 1; i < n; i++) { answer[i][j] = -1e72; } parent[0][j] = 0; } for (uint256 i = 1; i < n; i++) { for (uint256 j; j <= s; j++) { answer[i][j] = answer[i - 1][j]; parent[i][j] = j; for (uint256 k = 1; k <= j; k++) { if (answer[i - 1][j - k] + amounts[i][k] > answer[i][j]) { answer[i][j] = answer[i - 1][j - k] + amounts[i][k]; parent[i][j] = j - k; } } } } distribution = new uint256[](DEXES_COUNT_UPDATED); uint256 partsLeft = s; for (uint256 curExchange = n - 1; partsLeft > 0; curExchange--) { distribution[curExchange] = partsLeft - parent[curExchange][partsLeft]; partsLeft = parent[curExchange][partsLeft]; } returnAmount = (answer[n - 1][s] == VERY_NEGATIVE_VALUE) ? int256(0) : answer[n - 1][s]; } function _linearInterpolation( uint256 value, uint256 parts ) internal pure returns (uint256[] memory rets) { rets = new uint256[](parts); for (uint256 i = 0; i < parts; i++) { rets[i] = value.mul(i + 1).div(parts); } } function _tokensEqual( IERC20Upgradeable tokenA, IERC20Upgradeable tokenB ) internal pure returns (bool) { return ((tokenA.isETH() && tokenB.isETH()) || tokenA == tokenB); } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.20; import "@openzeppelin/contracts/utils/math/SafeMath.sol"; import "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol"; import "@openzeppelin/contracts-upgradeable/token/ERC20/IERC20Upgradeable.sol"; import "@openzeppelin/contracts/access/Ownable.sol"; import "@openzeppelin/contracts/access/AccessControl.sol"; import "./interface/IUniswapFactory.sol"; import "./interface/IUniswapV2Factory.sol"; import "./interface/IHandlerReserve.sol"; import "./interface/IEthHandler.sol"; import "./IDexSpan.sol"; import "./UniversalERC20.sol"; import "./interface/IWETH.sol"; import "./libraries/TransferHelper.sol"; import "./libraries/Multicall.sol"; import "./interface/IAugustusSwapper.sol"; import "../interfaces/IAssetForwarder.sol"; import "./interface/IEthHandler.sol"; import { DexSpanRoot, DisableFlags } from "./DexSpanRoot.sol"; import "../interfaces/IMessageHandler.sol"; abstract contract IDexSpanView is DexSpanFlags { function getExpectedReturn( IERC20Upgradeable fromToken, IERC20Upgradeable destToken, uint256 amount, uint256 parts, uint256 flags ) public view virtual returns (uint256 returnAmount, uint256[] memory distribution); function getExpectedReturnWithGas( IERC20Upgradeable fromToken, IERC20Upgradeable destToken, uint256 amount, uint256 parts, uint256 flags, uint256 destTokenEthPriceTimesGasPrice ) public view virtual returns ( uint256 returnAmount, uint256 estimateGasAmount, uint256[] memory distribution ); } contract DexSpanView is IDexSpanView, DexSpanRoot, AccessControl { using SafeMath for uint256; using DisableFlags for uint256; using SafeERC20 for IERC20Upgradeable; using UniversalERC20 for IERC20Upgradeable; constructor() { _setupRole(DEFAULT_ADMIN_ROLE, _msgSender()); } function getExpectedReturn( IERC20Upgradeable fromToken, IERC20Upgradeable destToken, uint256 amount, uint256 parts, uint256 flags // See constants in IOneSplit.sol ) public view override returns (uint256 returnAmount, uint256[] memory distribution) { (returnAmount, , distribution) = getExpectedReturnWithGas( fromToken, destToken, amount, parts, flags, 0 ); } function getExpectedReturnWithGas( IERC20Upgradeable fromToken, IERC20Upgradeable destToken, uint256 amount, uint256 parts, uint256 flags, // See constants in IOneSplit.sol uint256 destTokenEthPriceTimesGasPrice ) public view override returns ( uint256 returnAmount, uint256 estimateGasAmount, uint256[] memory distribution ) { distribution = new uint256[](DEXES_COUNT_UPDATED); if (fromToken == destToken) { return (amount, 0, distribution); } function(IERC20Upgradeable, IERC20Upgradeable, uint256, uint256) view returns (uint256[] memory, uint256)[DEXES_COUNT_UPDATED] memory reserves = _getAllReserves(flags); int256[][] memory matrix = new int256[][](DEXES_COUNT_UPDATED); uint256[DEXES_COUNT_UPDATED] memory gases; bool atLeastOnePositive = false; for (uint256 i; i < DEXES_COUNT_UPDATED; i++) { uint256[] memory rets; (rets, gases[i]) = reserves[i](fromToken, destToken, amount, parts); // Prepend zero and sub gas int256 gas = int256( gases[i].mul(destTokenEthPriceTimesGasPrice).div(1e18) ); matrix[i] = new int256[](parts + 1); for (uint256 j; j < rets.length; j++) { matrix[i][j + 1] = int256(rets[j]) - gas; atLeastOnePositive = atLeastOnePositive || (matrix[i][j + 1] > 0); } } if (!atLeastOnePositive) { for (uint256 i; i < DEXES_COUNT_UPDATED; i++) { for (uint256 j = 1; j < parts + 1; j++) { if (matrix[i][j] == 0) { matrix[i][j] = VERY_NEGATIVE_VALUE; } } } } (, distribution) = _findBestDistribution(parts, matrix); (returnAmount, estimateGasAmount) = _getReturnAndGasByDistribution( Args({ fromToken: fromToken, destToken: destToken, amount: amount, parts: parts, flags: flags, destTokenEthPriceTimesGasPrice: destTokenEthPriceTimesGasPrice, distribution: distribution, matrix: matrix, gases: gases, reserves: reserves }) ); return (returnAmount, estimateGasAmount, distribution); } struct Args { IERC20Upgradeable fromToken; IERC20Upgradeable destToken; uint256 amount; uint256 parts; uint256 flags; uint256 destTokenEthPriceTimesGasPrice; uint256[] distribution; int256[][] matrix; uint256[DEXES_COUNT_UPDATED] gases; function(IERC20Upgradeable, IERC20Upgradeable, uint256, uint256) view returns (uint256[] memory, uint256)[DEXES_COUNT_UPDATED] reserves; } function _getReturnAndGasByDistribution( Args memory args ) internal view returns (uint256 returnAmount, uint256 estimateGasAmount) { bool[DEXES_COUNT_UPDATED] memory exact = [ true //empty ]; for (uint256 i; i < DEXES_COUNT_UPDATED; i++) { if (args.distribution[i] > 0) { if ( args.distribution[i] == args.parts || exact[i] || args.flags.check(FLAG_DISABLE_SPLIT_RECALCULATION) ) { estimateGasAmount = estimateGasAmount.add(args.gases[i]); int256 value = args.matrix[i][args.distribution[i]]; returnAmount = returnAmount.add( uint256( (value == VERY_NEGATIVE_VALUE ? int256(0) : value) + int256( args .gases[i] .mul( args.destTokenEthPriceTimesGasPrice ) .div(1e18) ) ) ); } else { (uint256[] memory rets, uint256 gas) = args.reserves[i]( args.fromToken, args.destToken, args.amount.mul(args.distribution[i]).div(args.parts), 1 ); estimateGasAmount = estimateGasAmount.add(gas); returnAmount = returnAmount.add(rets[0]); } } } } function _getAllReserves( uint256 flags ) internal pure returns ( function(IERC20Upgradeable, IERC20Upgradeable, uint256, uint256) view returns (uint256[] memory, uint256)[DEXES_COUNT_UPDATED] memory ) { return [_calculateNoReturn]; } function _calculateUniswapFormula( uint256 fromBalance, uint256 toBalance, uint256 amount ) internal pure returns (uint256) { if (amount == 0) { return 0; } return amount.mul(toBalance).mul(997).div( fromBalance.mul(1000).add(amount.mul(997)) ); } function _calculateSwap( IERC20Upgradeable fromToken, IERC20Upgradeable destToken, uint256[] memory amounts, IUniswapV2Factory exchangeInstance ) internal view returns (uint256[] memory rets, uint256 gas) { rets = new uint256[](amounts.length); IERC20Upgradeable fromTokenReal = fromToken.isETH() ? wnativeAddress : fromToken; IERC20Upgradeable destTokenReal = destToken.isETH() ? wnativeAddress : destToken; IUniswapV2Exchange exchange = exchangeInstance.getPair( fromTokenReal, destTokenReal ); if (exchange != IUniswapV2Exchange(address(0))) { uint256 fromTokenBalance = fromTokenReal.universalBalanceOf( address(exchange) ); uint256 destTokenBalance = destTokenReal.universalBalanceOf( address(exchange) ); for (uint256 i = 0; i < amounts.length; i++) { rets[i] = _calculateUniswapFormula( fromTokenBalance, destTokenBalance, amounts[i] ); } return (rets, 50_000); } } function _calculateNoReturn( IERC20Upgradeable /*fromToken*/, IERC20Upgradeable /*destToken*/, uint256 /*amount*/, uint256 parts ) internal view returns (uint256[] memory rets, uint256 gas) { this; return (new uint256[](parts), 0); } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.20; /// @title Handles ERC20 deposits and deposit executions. /// @author Router Protocol. /// @notice This contract is intended to be used with the Bridge contract. interface IMessageHandler { function handleMessage( address tokenSent, uint256 amount, bytes memory message ) external; }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.9.0) (token/ERC20/IERC20.sol) pragma solidity ^0.8.0; /** * @dev Interface of the ERC20 standard as defined in the EIP. */ interface IERC20 { /** * @dev Emitted when `value` tokens are moved from one account (`from`) to * another (`to`). * * Note that `value` may be zero. */ event Transfer(address indexed from, address indexed to, uint256 value); /** * @dev Emitted when the allowance of a `spender` for an `owner` is set by * a call to {approve}. `value` is the new allowance. */ event Approval(address indexed owner, address indexed spender, uint256 value); /** * @dev Returns the amount of tokens in existence. */ function totalSupply() external view returns (uint256); /** * @dev Returns the amount of tokens owned by `account`. */ function balanceOf(address account) external view returns (uint256); /** * @dev Moves `amount` tokens from the caller's account to `to`. * * Returns a boolean value indicating whether the operation succeeded. * * Emits a {Transfer} event. */ function transfer(address to, uint256 amount) external returns (bool); /** * @dev Returns the remaining number of tokens that `spender` will be * allowed to spend on behalf of `owner` through {transferFrom}. This is * zero by default. * * This value changes when {approve} or {transferFrom} are called. */ function allowance(address owner, address spender) external view returns (uint256); /** * @dev Sets `amount` as the allowance of `spender` over the caller's tokens. * * Returns a boolean value indicating whether the operation succeeded. * * IMPORTANT: Beware that changing an allowance with this method brings the risk * that someone may use both the old and the new allowance by unfortunate * transaction ordering. One possible solution to mitigate this race * condition is to first reduce the spender's allowance to 0 and set the * desired value afterwards: * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729 * * Emits an {Approval} event. */ function approve(address spender, uint256 amount) external returns (bool); /** * @dev Moves `amount` tokens from `from` to `to` using the * allowance mechanism. `amount` is then deducted from the caller's * allowance. * * Returns a boolean value indicating whether the operation succeeded. * * Emits a {Transfer} event. */ function transferFrom(address from, address to, uint256 amount) external returns (bool); }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.9.0) (token/ERC20/extensions/IERC20Permit.sol) pragma solidity ^0.8.0; /** * @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in * https://eips.ethereum.org/EIPS/eip-2612[EIP-2612]. * * Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by * presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't * need to send a transaction, and thus is not required to hold Ether at all. */ interface IERC20Permit { /** * @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens, * given ``owner``'s signed approval. * * IMPORTANT: The same issues {IERC20-approve} has related to transaction * ordering also apply here. * * Emits an {Approval} event. * * Requirements: * * - `spender` cannot be the zero address. * - `deadline` must be a timestamp in the future. * - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner` * over the EIP712-formatted function arguments. * - the signature must use ``owner``'s current nonce (see {nonces}). * * For more information on the signature format, see the * https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP * section]. */ function permit( address owner, address spender, uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s ) external; /** * @dev Returns the current nonce for `owner`. This value must be * included whenever a signature is generated for {permit}. * * Every successful call to {permit} increases ``owner``'s nonce by one. This * prevents a signature from being used multiple times. */ function nonces(address owner) external view returns (uint256); /** * @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}. */ // solhint-disable-next-line func-name-mixedcase function DOMAIN_SEPARATOR() external view returns (bytes32); }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.9.0) (utils/Address.sol) pragma solidity ^0.8.1; /** * @dev Collection of functions related to the address type */ library Address { /** * @dev Returns true if `account` is a contract. * * [IMPORTANT] * ==== * It is unsafe to assume that an address for which this function returns * false is an externally-owned account (EOA) and not a contract. * * Among others, `isContract` will return false for the following * types of addresses: * * - an externally-owned account * - a contract in construction * - an address where a contract will be created * - an address where a contract lived, but was destroyed * * Furthermore, `isContract` will also return true if the target contract within * the same transaction is already scheduled for destruction by `SELFDESTRUCT`, * which only has an effect at the end of a transaction. * ==== * * [IMPORTANT] * ==== * You shouldn't rely on `isContract` to protect against flash loan attacks! * * Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets * like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract * constructor. * ==== */ function isContract(address account) internal view returns (bool) { // This method relies on extcodesize/address.code.length, which returns 0 // for contracts in construction, since the code is only stored at the end // of the constructor execution. return account.code.length > 0; } /** * @dev Replacement for Solidity's `transfer`: sends `amount` wei to * `recipient`, forwarding all available gas and reverting on errors. * * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost * of certain opcodes, possibly making contracts go over the 2300 gas limit * imposed by `transfer`, making them unable to receive funds via * `transfer`. {sendValue} removes this limitation. * * https://consensys.net/diligence/blog/2019/09/stop-using-soliditys-transfer-now/[Learn more]. * * IMPORTANT: because control is transferred to `recipient`, care must be * taken to not create reentrancy vulnerabilities. Consider using * {ReentrancyGuard} or the * https://solidity.readthedocs.io/en/v0.8.0/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern]. */ function sendValue(address payable recipient, uint256 amount) internal { require(address(this).balance >= amount, "Address: insufficient balance"); (bool success, ) = recipient.call{value: amount}(""); require(success, "Address: unable to send value, recipient may have reverted"); } /** * @dev Performs a Solidity function call using a low level `call`. A * plain `call` is an unsafe replacement for a function call: use this * function instead. * * If `target` reverts with a revert reason, it is bubbled up by this * function (like regular Solidity function calls). * * Returns the raw returned data. To convert to the expected return value, * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`]. * * Requirements: * * - `target` must be a contract. * - calling `target` with `data` must not revert. * * _Available since v3.1._ */ function functionCall(address target, bytes memory data) internal returns (bytes memory) { return functionCallWithValue(target, data, 0, "Address: low-level call failed"); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with * `errorMessage` as a fallback revert reason when `target` reverts. * * _Available since v3.1._ */ function functionCall( address target, bytes memory data, string memory errorMessage ) internal returns (bytes memory) { return functionCallWithValue(target, data, 0, errorMessage); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], * but also transferring `value` wei to `target`. * * Requirements: * * - the calling contract must have an ETH balance of at least `value`. * - the called Solidity function must be `payable`. * * _Available since v3.1._ */ function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) { return functionCallWithValue(target, data, value, "Address: low-level call with value failed"); } /** * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but * with `errorMessage` as a fallback revert reason when `target` reverts. * * _Available since v3.1._ */ function functionCallWithValue( address target, bytes memory data, uint256 value, string memory errorMessage ) internal returns (bytes memory) { require(address(this).balance >= value, "Address: insufficient balance for call"); (bool success, bytes memory returndata) = target.call{value: value}(data); return verifyCallResultFromTarget(target, success, returndata, errorMessage); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], * but performing a static call. * * _Available since v3.3._ */ function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) { return functionStaticCall(target, data, "Address: low-level static call failed"); } /** * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`], * but performing a static call. * * _Available since v3.3._ */ function functionStaticCall( address target, bytes memory data, string memory errorMessage ) internal view returns (bytes memory) { (bool success, bytes memory returndata) = target.staticcall(data); return verifyCallResultFromTarget(target, success, returndata, errorMessage); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], * but performing a delegate call. * * _Available since v3.4._ */ function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) { return functionDelegateCall(target, data, "Address: low-level delegate call failed"); } /** * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`], * but performing a delegate call. * * _Available since v3.4._ */ function functionDelegateCall( address target, bytes memory data, string memory errorMessage ) internal returns (bytes memory) { (bool success, bytes memory returndata) = target.delegatecall(data); return verifyCallResultFromTarget(target, success, returndata, errorMessage); } /** * @dev Tool to verify that a low level call to smart-contract was successful, and revert (either by bubbling * the revert reason or using the provided one) in case of unsuccessful call or if target was not a contract. * * _Available since v4.8._ */ function verifyCallResultFromTarget( address target, bool success, bytes memory returndata, string memory errorMessage ) internal view returns (bytes memory) { if (success) { if (returndata.length == 0) { // only check isContract if the call was successful and the return data is empty // otherwise we already know that it was a contract require(isContract(target), "Address: call to non-contract"); } return returndata; } else { _revert(returndata, errorMessage); } } /** * @dev Tool to verify that a low level call was successful, and revert if it wasn't, either by bubbling the * revert reason or using the provided one. * * _Available since v4.3._ */ function verifyCallResult( bool success, bytes memory returndata, string memory errorMessage ) internal pure returns (bytes memory) { if (success) { return returndata; } else { _revert(returndata, errorMessage); } } function _revert(bytes memory returndata, string memory errorMessage) private pure { // Look for revert reason and bubble it up if present if (returndata.length > 0) { // The easiest way to bubble the revert reason is using memory via assembly /// @solidity memory-safe-assembly assembly { let returndata_size := mload(returndata) revert(add(32, returndata), returndata_size) } } else { revert(errorMessage); } } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts v4.4.1 (utils/Context.sol) pragma solidity ^0.8.0; /** * @dev Provides information about the current execution context, including the * sender of the transaction and its data. While these are generally available * via msg.sender and msg.data, they should not be accessed in such a direct * manner, since when dealing with meta-transactions the account sending and * paying for execution may not be the actual sender (as far as an application * is concerned). * * This contract is only required for intermediate, library-like contracts. */ abstract contract Context { function _msgSender() internal view virtual returns (address) { return msg.sender; } function _msgData() internal view virtual returns (bytes calldata) { return msg.data; } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts v4.4.1 (access/IAccessControl.sol) pragma solidity ^0.8.0; /** * @dev External interface of AccessControl declared to support ERC165 detection. */ interface IAccessControl { /** * @dev Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole` * * `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite * {RoleAdminChanged} not being emitted signaling this. * * _Available since v3.1._ */ event RoleAdminChanged(bytes32 indexed role, bytes32 indexed previousAdminRole, bytes32 indexed newAdminRole); /** * @dev Emitted when `account` is granted `role`. * * `sender` is the account that originated the contract call, an admin role * bearer except when using {AccessControl-_setupRole}. */ event RoleGranted(bytes32 indexed role, address indexed account, address indexed sender); /** * @dev Emitted when `account` is revoked `role`. * * `sender` is the account that originated the contract call: * - if using `revokeRole`, it is the admin role bearer * - if using `renounceRole`, it is the role bearer (i.e. `account`) */ event RoleRevoked(bytes32 indexed role, address indexed account, address indexed sender); /** * @dev Returns `true` if `account` has been granted `role`. */ function hasRole(bytes32 role, address account) external view returns (bool); /** * @dev Returns the admin role that controls `role`. See {grantRole} and * {revokeRole}. * * To change a role's admin, use {AccessControl-_setRoleAdmin}. */ function getRoleAdmin(bytes32 role) external view returns (bytes32); /** * @dev Grants `role` to `account`. * * If `account` had not been already granted `role`, emits a {RoleGranted} * event. * * Requirements: * * - the caller must have ``role``'s admin role. */ function grantRole(bytes32 role, address account) external; /** * @dev Revokes `role` from `account`. * * If `account` had been granted `role`, emits a {RoleRevoked} event. * * Requirements: * * - the caller must have ``role``'s admin role. */ function revokeRole(bytes32 role, address account) external; /** * @dev Revokes `role` from the calling account. * * Roles are often managed via {grantRole} and {revokeRole}: this function's * purpose is to provide a mechanism for accounts to lose their privileges * if they are compromised (such as when a trusted device is misplaced). * * If the calling account had been granted `role`, emits a {RoleRevoked} * event. * * Requirements: * * - the caller must be `account`. */ function renounceRole(bytes32 role, address account) external; }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.9.0) (utils/Strings.sol) pragma solidity ^0.8.0; import "./math/Math.sol"; import "./math/SignedMath.sol"; /** * @dev String operations. */ library Strings { bytes16 private constant _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) { unchecked { uint256 length = Math.log10(value) + 1; string memory buffer = new string(length); uint256 ptr; /// @solidity memory-safe-assembly assembly { ptr := add(buffer, add(32, length)) } while (true) { ptr--; /// @solidity memory-safe-assembly assembly { mstore8(ptr, byte(mod(value, 10), _SYMBOLS)) } value /= 10; if (value == 0) break; } return buffer; } } /** * @dev Converts a `int256` to its ASCII `string` decimal representation. */ function toString(int256 value) internal pure returns (string memory) { return string(abi.encodePacked(value < 0 ? "-" : "", toString(SignedMath.abs(value)))); } /** * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation. */ function toHexString(uint256 value) internal pure returns (string memory) { unchecked { return toHexString(value, Math.log256(value) + 1); } } /** * @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] = _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); } /** * @dev Returns true if the two strings are equal. */ function equal(string memory a, string memory b) internal pure returns (bool) { return keccak256(bytes(a)) == keccak256(bytes(b)); } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts v4.4.1 (utils/introspection/ERC165.sol) pragma solidity ^0.8.0; import "./IERC165.sol"; /** * @dev Implementation of the {IERC165} interface. * * Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check * for the additional interface id that will be supported. For example: * * ```solidity * function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) { * return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId); * } * ``` * * Alternatively, {ERC165Storage} provides an easier to use but more expensive implementation. */ abstract contract ERC165 is IERC165 { /** * @dev See {IERC165-supportsInterface}. */ function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) { return interfaceId == type(IERC165).interfaceId; } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.20; import "@openzeppelin/contracts-upgradeable/token/ERC20/IERC20Upgradeable.sol"; interface IUniswapExchange { function getEthToTokenInputPrice( uint256 ethSold ) external view returns (uint256 tokensBought); function getTokenToEthInputPrice( uint256 tokensSold ) external view returns (uint256 ethBought); function ethToTokenSwapInput( uint256 minTokens, uint256 deadline ) external payable returns (uint256 tokensBought); function tokenToEthSwapInput( uint256 tokensSold, uint256 minEth, uint256 deadline ) external returns (uint256 ethBought); function tokenToTokenSwapInput( uint256 tokensSold, uint256 minTokensBought, uint256 minEthBought, uint256 deadline, address tokenAddr ) external returns (uint256 tokensBought); }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.20; import "@openzeppelin/contracts-upgradeable/utils/math/MathUpgradeable.sol"; import "@openzeppelin/contracts-upgradeable/utils/math/SafeMathUpgradeable.sol"; import "@openzeppelin/contracts-upgradeable/token/ERC20/IERC20Upgradeable.sol"; import "../UniversalERC20.sol"; interface IUniswapV2Exchange { function getReserves() external view returns ( uint112 _reserve0, uint112 _reserve1, uint32 _blockTimestampLast ); function swap( uint256 amount0Out, uint256 amount1Out, address to, bytes calldata data ) external; function skim(address to) external; function sync() external; } library UniswapV2ExchangeLib { using MathUpgradeable for uint256; using SafeMathUpgradeable for uint256; using UniversalERC20 for IERC20Upgradeable; function getReturn( IUniswapV2Exchange exchange, IERC20Upgradeable fromToken, IERC20Upgradeable destToken, uint256 amountIn ) internal view returns (uint256 result, bool needSync, bool needSkim) { uint256 reserveIn = fromToken.universalBalanceOf(address(exchange)); uint256 reserveOut = destToken.universalBalanceOf(address(exchange)); (uint112 reserve0, uint112 reserve1, ) = exchange.getReserves(); if (fromToken > destToken) { (reserve0, reserve1) = (reserve1, reserve0); } needSync = (reserveIn < reserve0 || reserveOut < reserve1); needSkim = !needSync && (reserveIn > reserve0 || reserveOut > reserve1); uint256 amountInWithFee = amountIn.mul(997); uint256 numerator = amountInWithFee.mul( MathUpgradeable.min(reserveOut, reserve1) ); uint256 denominator = MathUpgradeable .min(reserveIn, reserve0) .mul(1000) .add(amountInWithFee); result = (denominator == 0) ? 0 : numerator.div(denominator); } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.9.0) (utils/math/SafeMath.sol) pragma solidity ^0.8.0; // CAUTION // This version of SafeMath should only be used with Solidity 0.8 or later, // because it relies on the compiler's built in overflow checks. /** * @dev Wrappers over Solidity's arithmetic operations. * * NOTE: `SafeMath` is generally not needed starting with Solidity 0.8, since the compiler * now has built in overflow checking. */ library SafeMathUpgradeable { /** * @dev Returns the addition of two unsigned integers, with an overflow flag. * * _Available since v3.4._ */ function tryAdd(uint256 a, uint256 b) internal pure returns (bool, uint256) { unchecked { uint256 c = a + b; if (c < a) return (false, 0); return (true, c); } } /** * @dev Returns the subtraction of two unsigned integers, with an overflow flag. * * _Available since v3.4._ */ function trySub(uint256 a, uint256 b) internal pure returns (bool, uint256) { unchecked { if (b > a) return (false, 0); return (true, a - b); } } /** * @dev Returns the multiplication of two unsigned integers, with an overflow flag. * * _Available since v3.4._ */ function tryMul(uint256 a, uint256 b) internal pure returns (bool, uint256) { unchecked { // Gas optimization: this is cheaper than requiring 'a' not being zero, but the // benefit is lost if 'b' is also tested. // See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522 if (a == 0) return (true, 0); uint256 c = a * b; if (c / a != b) return (false, 0); return (true, c); } } /** * @dev Returns the division of two unsigned integers, with a division by zero flag. * * _Available since v3.4._ */ function tryDiv(uint256 a, uint256 b) internal pure returns (bool, uint256) { unchecked { if (b == 0) return (false, 0); return (true, a / b); } } /** * @dev Returns the remainder of dividing two unsigned integers, with a division by zero flag. * * _Available since v3.4._ */ function tryMod(uint256 a, uint256 b) internal pure returns (bool, uint256) { unchecked { if (b == 0) return (false, 0); return (true, a % b); } } /** * @dev Returns the addition of two unsigned integers, reverting on * overflow. * * Counterpart to Solidity's `+` operator. * * Requirements: * * - Addition cannot overflow. */ function add(uint256 a, uint256 b) internal pure returns (uint256) { return a + b; } /** * @dev Returns the subtraction of two unsigned integers, reverting on * overflow (when the result is negative). * * Counterpart to Solidity's `-` operator. * * Requirements: * * - Subtraction cannot overflow. */ function sub(uint256 a, uint256 b) internal pure returns (uint256) { return a - b; } /** * @dev Returns the multiplication of two unsigned integers, reverting on * overflow. * * Counterpart to Solidity's `*` operator. * * Requirements: * * - Multiplication cannot overflow. */ function mul(uint256 a, uint256 b) internal pure returns (uint256) { return a * b; } /** * @dev Returns the integer division of two unsigned integers, reverting on * division by zero. The result is rounded towards zero. * * Counterpart to Solidity's `/` operator. * * Requirements: * * - The divisor cannot be zero. */ function div(uint256 a, uint256 b) internal pure returns (uint256) { return a / b; } /** * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo), * reverting when dividing by zero. * * Counterpart to Solidity's `%` operator. This function uses a `revert` * opcode (which leaves remaining gas untouched) while Solidity uses an * invalid opcode to revert (consuming all remaining gas). * * Requirements: * * - The divisor cannot be zero. */ function mod(uint256 a, uint256 b) internal pure returns (uint256) { return a % b; } /** * @dev Returns the subtraction of two unsigned integers, reverting with custom message on * overflow (when the result is negative). * * CAUTION: This function is deprecated because it requires allocating memory for the error * message unnecessarily. For custom revert reasons use {trySub}. * * Counterpart to Solidity's `-` operator. * * Requirements: * * - Subtraction cannot overflow. */ function sub(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) { unchecked { require(b <= a, errorMessage); return a - b; } } /** * @dev Returns the integer division of two unsigned integers, reverting with custom message on * division by zero. The result is rounded towards zero. * * Counterpart to Solidity's `/` operator. Note: this function uses a * `revert` opcode (which leaves remaining gas untouched) while Solidity * uses an invalid opcode to revert (consuming all remaining gas). * * Requirements: * * - The divisor cannot be zero. */ function div(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) { unchecked { require(b > 0, errorMessage); return a / b; } } /** * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo), * reverting with custom message when dividing by zero. * * CAUTION: This function is deprecated because it requires allocating memory for the error * message unnecessarily. For custom revert reasons use {tryMod}. * * Counterpart to Solidity's `%` operator. This function uses a `revert` * opcode (which leaves remaining gas untouched) while Solidity uses an * invalid opcode to revert (consuming all remaining gas). * * Requirements: * * - The divisor cannot be zero. */ function mod(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) { unchecked { require(b > 0, errorMessage); return a % b; } } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.9.3) (token/ERC20/utils/SafeERC20.sol) pragma solidity ^0.8.0; import "../IERC20Upgradeable.sol"; import "../extensions/IERC20PermitUpgradeable.sol"; import "../../../utils/AddressUpgradeable.sol"; /** * @title SafeERC20 * @dev Wrappers around ERC20 operations that throw on failure (when the token * contract returns false). Tokens that return no value (and instead revert or * throw on failure) are also supported, non-reverting calls are assumed to be * successful. * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract, * which allows you to call the safe operations as `token.safeTransfer(...)`, etc. */ library SafeERC20Upgradeable { using AddressUpgradeable for address; /** * @dev Transfer `value` amount of `token` from the calling contract to `to`. If `token` returns no value, * non-reverting calls are assumed to be successful. */ function safeTransfer(IERC20Upgradeable token, address to, uint256 value) internal { _callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value)); } /** * @dev Transfer `value` amount of `token` from `from` to `to`, spending the approval given by `from` to the * calling contract. If `token` returns no value, non-reverting calls are assumed to be successful. */ function safeTransferFrom(IERC20Upgradeable token, address from, address to, uint256 value) internal { _callOptionalReturn(token, abi.encodeWithSelector(token.transferFrom.selector, from, to, value)); } /** * @dev Deprecated. This function has issues similar to the ones found in * {IERC20-approve}, and its usage is discouraged. * * Whenever possible, use {safeIncreaseAllowance} and * {safeDecreaseAllowance} instead. */ function safeApprove(IERC20Upgradeable token, address spender, uint256 value) internal { // safeApprove should only be called when setting an initial allowance, // or when resetting it to zero. To increase and decrease it, use // 'safeIncreaseAllowance' and 'safeDecreaseAllowance' require( (value == 0) || (token.allowance(address(this), spender) == 0), "SafeERC20: approve from non-zero to non-zero allowance" ); _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, value)); } /** * @dev Increase the calling contract's allowance toward `spender` by `value`. If `token` returns no value, * non-reverting calls are assumed to be successful. */ function safeIncreaseAllowance(IERC20Upgradeable token, address spender, uint256 value) internal { uint256 oldAllowance = token.allowance(address(this), spender); _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, oldAllowance + value)); } /** * @dev Decrease the calling contract's allowance toward `spender` by `value`. If `token` returns no value, * non-reverting calls are assumed to be successful. */ function safeDecreaseAllowance(IERC20Upgradeable token, address spender, uint256 value) internal { unchecked { uint256 oldAllowance = token.allowance(address(this), spender); require(oldAllowance >= value, "SafeERC20: decreased allowance below zero"); _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, oldAllowance - value)); } } /** * @dev Set the calling contract's allowance toward `spender` to `value`. If `token` returns no value, * non-reverting calls are assumed to be successful. Meant to be used with tokens that require the approval * to be set to zero before setting it to a non-zero value, such as USDT. */ function forceApprove(IERC20Upgradeable token, address spender, uint256 value) internal { bytes memory approvalCall = abi.encodeWithSelector(token.approve.selector, spender, value); if (!_callOptionalReturnBool(token, approvalCall)) { _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, 0)); _callOptionalReturn(token, approvalCall); } } /** * @dev Use a ERC-2612 signature to set the `owner` approval toward `spender` on `token`. * Revert on invalid signature. */ function safePermit( IERC20PermitUpgradeable token, address owner, address spender, uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s ) internal { uint256 nonceBefore = token.nonces(owner); token.permit(owner, spender, value, deadline, v, r, s); uint256 nonceAfter = token.nonces(owner); require(nonceAfter == nonceBefore + 1, "SafeERC20: permit did not succeed"); } /** * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement * on the return value: the return value is optional (but if data is returned, it must not be false). * @param token The token targeted by the call. * @param data The call data (encoded using abi.encode or one of its variants). */ function _callOptionalReturn(IERC20Upgradeable token, bytes memory data) private { // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since // we're implementing it ourselves. We use {Address-functionCall} to perform this call, which verifies that // the target address contains contract code and also asserts for success in the low-level call. bytes memory returndata = address(token).functionCall(data, "SafeERC20: low-level call failed"); require(returndata.length == 0 || abi.decode(returndata, (bool)), "SafeERC20: ERC20 operation did not succeed"); } /** * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement * on the return value: the return value is optional (but if data is returned, it must not be false). * @param token The token targeted by the call. * @param data The call data (encoded using abi.encode or one of its variants). * * This is a variant of {_callOptionalReturn} that silents catches all reverts and returns a bool instead. */ function _callOptionalReturnBool(IERC20Upgradeable token, bytes memory data) private returns (bool) { // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since // we're implementing it ourselves. We cannot use {Address-functionCall} here since this should return false // and not revert is the subcall reverts. (bool success, bytes memory returndata) = address(token).call(data); return success && (returndata.length == 0 || abi.decode(returndata, (bool))) && AddressUpgradeable.isContract(address(token)); } }
// SPDX-License-Identifier: GPL-3.0-or-later pragma solidity ^0.8.20; import "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol"; /// @notice Helper utility that enables calling multiple local methods in a single call. /// @author Modified from Uniswap (https://github.com/Uniswap/v3-periphery/blob/main/contracts/base/Multicall.sol) /// License-Identifier: GPL-2.0-or-later abstract contract Multicall is Initializable { function __Multicall_init() internal onlyInitializing {} function __Multicall_init_unchained() internal onlyInitializing {} function multicall( bytes[] calldata data ) public payable returns (bytes[] memory results) { results = new bytes[](data.length); for (uint256 i; i < data.length; ) { (bool success, bytes memory result) = address(this).delegatecall( data[i] ); if (!success) { // Next 5 lines from https://ethereum.stackexchange.com/a/83577 if (result.length < 68) revert(); assembly { result := add(result, 0x04) } revert(abi.decode(result, (string))); } results[i] = result; // cannot realistically overflow on human timescales unchecked { ++i; } } } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.9.0) (utils/math/Math.sol) pragma solidity ^0.8.0; /** * @dev Standard math utilities missing in the Solidity language. */ library Math { enum Rounding { Down, // Toward negative infinity Up, // Toward infinity Zero // Toward zero } /** * @dev Returns the largest of two numbers. */ function max(uint256 a, uint256 b) internal pure returns (uint256) { return a > b ? a : b; } /** * @dev Returns the smallest of two numbers. */ function min(uint256 a, uint256 b) internal pure returns (uint256) { return a < b ? a : b; } /** * @dev Returns the average of two numbers. The result is rounded towards * zero. */ function average(uint256 a, uint256 b) internal pure returns (uint256) { // (a + b) / 2 can overflow. return (a & b) + (a ^ b) / 2; } /** * @dev Returns the ceiling of the division of two numbers. * * This differs from standard division with `/` in that it rounds up instead * of rounding down. */ function ceilDiv(uint256 a, uint256 b) internal pure returns (uint256) { // (a + b - 1) / b can overflow on addition, so we distribute. return a == 0 ? 0 : (a - 1) / b + 1; } /** * @notice Calculates floor(x * y / denominator) with full precision. Throws if result overflows a uint256 or denominator == 0 * @dev Original credit to Remco Bloemen under MIT license (https://xn--2-umb.com/21/muldiv) * with further edits by Uniswap Labs also under MIT license. */ function mulDiv(uint256 x, uint256 y, uint256 denominator) internal pure returns (uint256 result) { unchecked { // 512-bit multiply [prod1 prod0] = x * y. Compute the product mod 2^256 and mod 2^256 - 1, then use // use the Chinese Remainder Theorem to reconstruct the 512 bit result. The result is stored in two 256 // variables such that product = prod1 * 2^256 + prod0. uint256 prod0; // Least significant 256 bits of the product uint256 prod1; // Most significant 256 bits of the product assembly { let mm := mulmod(x, y, not(0)) prod0 := mul(x, y) prod1 := sub(sub(mm, prod0), lt(mm, prod0)) } // Handle non-overflow cases, 256 by 256 division. if (prod1 == 0) { // Solidity will revert if denominator == 0, unlike the div opcode on its own. // The surrounding unchecked block does not change this fact. // See https://docs.soliditylang.org/en/latest/control-structures.html#checked-or-unchecked-arithmetic. return prod0 / denominator; } // Make sure the result is less than 2^256. Also prevents denominator == 0. require(denominator > prod1, "Math: mulDiv overflow"); /////////////////////////////////////////////// // 512 by 256 division. /////////////////////////////////////////////// // Make division exact by subtracting the remainder from [prod1 prod0]. uint256 remainder; assembly { // Compute remainder using mulmod. remainder := mulmod(x, y, denominator) // Subtract 256 bit number from 512 bit number. prod1 := sub(prod1, gt(remainder, prod0)) prod0 := sub(prod0, remainder) } // Factor powers of two out of denominator and compute largest power of two divisor of denominator. Always >= 1. // See https://cs.stackexchange.com/q/138556/92363. // Does not overflow because the denominator cannot be zero at this stage in the function. uint256 twos = denominator & (~denominator + 1); assembly { // Divide denominator by twos. denominator := div(denominator, twos) // Divide [prod1 prod0] by twos. prod0 := div(prod0, twos) // Flip twos such that it is 2^256 / twos. If twos is zero, then it becomes one. twos := add(div(sub(0, twos), twos), 1) } // Shift in bits from prod1 into prod0. prod0 |= prod1 * twos; // Invert denominator mod 2^256. Now that denominator is an odd number, it has an inverse modulo 2^256 such // that denominator * inv = 1 mod 2^256. Compute the inverse by starting with a seed that is correct for // four bits. That is, denominator * inv = 1 mod 2^4. uint256 inverse = (3 * denominator) ^ 2; // Use the Newton-Raphson iteration to improve the precision. Thanks to Hensel's lifting lemma, this also works // in modular arithmetic, doubling the correct bits in each step. inverse *= 2 - denominator * inverse; // inverse mod 2^8 inverse *= 2 - denominator * inverse; // inverse mod 2^16 inverse *= 2 - denominator * inverse; // inverse mod 2^32 inverse *= 2 - denominator * inverse; // inverse mod 2^64 inverse *= 2 - denominator * inverse; // inverse mod 2^128 inverse *= 2 - denominator * inverse; // inverse mod 2^256 // Because the division is now exact we can divide by multiplying with the modular inverse of denominator. // This will give us the correct result modulo 2^256. Since the preconditions guarantee that the outcome is // less than 2^256, this is the final result. We don't need to compute the high bits of the result and prod1 // is no longer required. result = prod0 * inverse; return result; } } /** * @notice Calculates x * y / denominator with full precision, following the selected rounding direction. */ function mulDiv(uint256 x, uint256 y, uint256 denominator, Rounding rounding) internal pure returns (uint256) { uint256 result = mulDiv(x, y, denominator); if (rounding == Rounding.Up && mulmod(x, y, denominator) > 0) { result += 1; } return result; } /** * @dev Returns the square root of a number. If the number is not a perfect square, the value is rounded down. * * Inspired by Henry S. Warren, Jr.'s "Hacker's Delight" (Chapter 11). */ function sqrt(uint256 a) internal pure returns (uint256) { if (a == 0) { return 0; } // For our first guess, we get the biggest power of 2 which is smaller than the square root of the target. // // We know that the "msb" (most significant bit) of our target number `a` is a power of 2 such that we have // `msb(a) <= a < 2*msb(a)`. This value can be written `msb(a)=2**k` with `k=log2(a)`. // // This can be rewritten `2**log2(a) <= a < 2**(log2(a) + 1)` // → `sqrt(2**k) <= sqrt(a) < sqrt(2**(k+1))` // → `2**(k/2) <= sqrt(a) < 2**((k+1)/2) <= 2**(k/2 + 1)` // // Consequently, `2**(log2(a) / 2)` is a good first approximation of `sqrt(a)` with at least 1 correct bit. uint256 result = 1 << (log2(a) >> 1); // At this point `result` is an estimation with one bit of precision. We know the true value is a uint128, // since it is the square root of a uint256. Newton's method converges quadratically (precision doubles at // every iteration). We thus need at most 7 iteration to turn our partial result with one bit of precision // into the expected uint128 result. unchecked { result = (result + a / result) >> 1; result = (result + a / result) >> 1; result = (result + a / result) >> 1; result = (result + a / result) >> 1; result = (result + a / result) >> 1; result = (result + a / result) >> 1; result = (result + a / result) >> 1; return min(result, a / result); } } /** * @notice Calculates sqrt(a), following the selected rounding direction. */ function sqrt(uint256 a, Rounding rounding) internal pure returns (uint256) { unchecked { uint256 result = sqrt(a); return result + (rounding == Rounding.Up && result * result < a ? 1 : 0); } } /** * @dev Return the log in base 2, rounded down, of a positive value. * Returns 0 if given 0. */ function log2(uint256 value) internal pure returns (uint256) { uint256 result = 0; unchecked { if (value >> 128 > 0) { value >>= 128; result += 128; } if (value >> 64 > 0) { value >>= 64; result += 64; } if (value >> 32 > 0) { value >>= 32; result += 32; } if (value >> 16 > 0) { value >>= 16; result += 16; } if (value >> 8 > 0) { value >>= 8; result += 8; } if (value >> 4 > 0) { value >>= 4; result += 4; } if (value >> 2 > 0) { value >>= 2; result += 2; } if (value >> 1 > 0) { result += 1; } } return result; } /** * @dev Return the log in base 2, following the selected rounding direction, of a positive value. * Returns 0 if given 0. */ function log2(uint256 value, Rounding rounding) internal pure returns (uint256) { unchecked { uint256 result = log2(value); return result + (rounding == Rounding.Up && 1 << result < value ? 1 : 0); } } /** * @dev Return the log in base 10, rounded down, of a positive value. * Returns 0 if given 0. */ function log10(uint256 value) internal pure returns (uint256) { uint256 result = 0; unchecked { if (value >= 10 ** 64) { value /= 10 ** 64; result += 64; } if (value >= 10 ** 32) { value /= 10 ** 32; result += 32; } if (value >= 10 ** 16) { value /= 10 ** 16; result += 16; } if (value >= 10 ** 8) { value /= 10 ** 8; result += 8; } if (value >= 10 ** 4) { value /= 10 ** 4; result += 4; } if (value >= 10 ** 2) { value /= 10 ** 2; result += 2; } if (value >= 10 ** 1) { result += 1; } } return result; } /** * @dev Return the log in base 10, following the selected rounding direction, of a positive value. * Returns 0 if given 0. */ function log10(uint256 value, Rounding rounding) internal pure returns (uint256) { unchecked { uint256 result = log10(value); return result + (rounding == Rounding.Up && 10 ** result < value ? 1 : 0); } } /** * @dev Return the log in base 256, rounded down, of a positive value. * Returns 0 if given 0. * * Adding one to the result gives the number of pairs of hex symbols needed to represent `value` as a hex string. */ function log256(uint256 value) internal pure returns (uint256) { uint256 result = 0; unchecked { if (value >> 128 > 0) { value >>= 128; result += 16; } if (value >> 64 > 0) { value >>= 64; result += 8; } if (value >> 32 > 0) { value >>= 32; result += 4; } if (value >> 16 > 0) { value >>= 16; result += 2; } if (value >> 8 > 0) { result += 1; } } return result; } /** * @dev Return the log in base 256, following the selected rounding direction, of a positive value. * Returns 0 if given 0. */ function log256(uint256 value, Rounding rounding) internal pure returns (uint256) { unchecked { uint256 result = log256(value); return result + (rounding == Rounding.Up && 1 << (result << 3) < value ? 1 : 0); } } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.8.0) (utils/math/SignedMath.sol) pragma solidity ^0.8.0; /** * @dev Standard signed math utilities missing in the Solidity language. */ library SignedMath { /** * @dev Returns the largest of two signed numbers. */ function max(int256 a, int256 b) internal pure returns (int256) { return a > b ? a : b; } /** * @dev Returns the smallest of two signed numbers. */ function min(int256 a, int256 b) internal pure returns (int256) { return a < b ? a : b; } /** * @dev Returns the average of two signed numbers without overflow. * The result is rounded towards zero. */ function average(int256 a, int256 b) internal pure returns (int256) { // Formula from the book "Hacker's Delight" int256 x = (a & b) + ((a ^ b) >> 1); return x + (int256(uint256(x) >> 255) & (a ^ b)); } /** * @dev Returns the absolute unsigned value of a signed value. */ function abs(int256 n) internal pure returns (uint256) { unchecked { // must be unchecked in order to support `n = type(int256).min` return uint256(n >= 0 ? n : -n); } } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts v4.4.1 (utils/introspection/IERC165.sol) pragma solidity ^0.8.0; /** * @dev Interface of the ERC165 standard, as defined in the * https://eips.ethereum.org/EIPS/eip-165[EIP]. * * Implementers can declare support of contract interfaces, which can then be * queried by others ({ERC165Checker}). * * For an implementation, see {ERC165}. */ interface IERC165 { /** * @dev Returns true if this contract implements the interface defined by * `interfaceId`. See the corresponding * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section] * to learn more about how these ids are created. * * This function call must use less than 30 000 gas. */ function supportsInterface(bytes4 interfaceId) external view returns (bool); }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.9.0) (utils/math/Math.sol) pragma solidity ^0.8.0; /** * @dev Standard math utilities missing in the Solidity language. */ library MathUpgradeable { enum Rounding { Down, // Toward negative infinity Up, // Toward infinity Zero // Toward zero } /** * @dev Returns the largest of two numbers. */ function max(uint256 a, uint256 b) internal pure returns (uint256) { return a > b ? a : b; } /** * @dev Returns the smallest of two numbers. */ function min(uint256 a, uint256 b) internal pure returns (uint256) { return a < b ? a : b; } /** * @dev Returns the average of two numbers. The result is rounded towards * zero. */ function average(uint256 a, uint256 b) internal pure returns (uint256) { // (a + b) / 2 can overflow. return (a & b) + (a ^ b) / 2; } /** * @dev Returns the ceiling of the division of two numbers. * * This differs from standard division with `/` in that it rounds up instead * of rounding down. */ function ceilDiv(uint256 a, uint256 b) internal pure returns (uint256) { // (a + b - 1) / b can overflow on addition, so we distribute. return a == 0 ? 0 : (a - 1) / b + 1; } /** * @notice Calculates floor(x * y / denominator) with full precision. Throws if result overflows a uint256 or denominator == 0 * @dev Original credit to Remco Bloemen under MIT license (https://xn--2-umb.com/21/muldiv) * with further edits by Uniswap Labs also under MIT license. */ function mulDiv(uint256 x, uint256 y, uint256 denominator) internal pure returns (uint256 result) { unchecked { // 512-bit multiply [prod1 prod0] = x * y. Compute the product mod 2^256 and mod 2^256 - 1, then use // use the Chinese Remainder Theorem to reconstruct the 512 bit result. The result is stored in two 256 // variables such that product = prod1 * 2^256 + prod0. uint256 prod0; // Least significant 256 bits of the product uint256 prod1; // Most significant 256 bits of the product assembly { let mm := mulmod(x, y, not(0)) prod0 := mul(x, y) prod1 := sub(sub(mm, prod0), lt(mm, prod0)) } // Handle non-overflow cases, 256 by 256 division. if (prod1 == 0) { // Solidity will revert if denominator == 0, unlike the div opcode on its own. // The surrounding unchecked block does not change this fact. // See https://docs.soliditylang.org/en/latest/control-structures.html#checked-or-unchecked-arithmetic. return prod0 / denominator; } // Make sure the result is less than 2^256. Also prevents denominator == 0. require(denominator > prod1, "Math: mulDiv overflow"); /////////////////////////////////////////////// // 512 by 256 division. /////////////////////////////////////////////// // Make division exact by subtracting the remainder from [prod1 prod0]. uint256 remainder; assembly { // Compute remainder using mulmod. remainder := mulmod(x, y, denominator) // Subtract 256 bit number from 512 bit number. prod1 := sub(prod1, gt(remainder, prod0)) prod0 := sub(prod0, remainder) } // Factor powers of two out of denominator and compute largest power of two divisor of denominator. Always >= 1. // See https://cs.stackexchange.com/q/138556/92363. // Does not overflow because the denominator cannot be zero at this stage in the function. uint256 twos = denominator & (~denominator + 1); assembly { // Divide denominator by twos. denominator := div(denominator, twos) // Divide [prod1 prod0] by twos. prod0 := div(prod0, twos) // Flip twos such that it is 2^256 / twos. If twos is zero, then it becomes one. twos := add(div(sub(0, twos), twos), 1) } // Shift in bits from prod1 into prod0. prod0 |= prod1 * twos; // Invert denominator mod 2^256. Now that denominator is an odd number, it has an inverse modulo 2^256 such // that denominator * inv = 1 mod 2^256. Compute the inverse by starting with a seed that is correct for // four bits. That is, denominator * inv = 1 mod 2^4. uint256 inverse = (3 * denominator) ^ 2; // Use the Newton-Raphson iteration to improve the precision. Thanks to Hensel's lifting lemma, this also works // in modular arithmetic, doubling the correct bits in each step. inverse *= 2 - denominator * inverse; // inverse mod 2^8 inverse *= 2 - denominator * inverse; // inverse mod 2^16 inverse *= 2 - denominator * inverse; // inverse mod 2^32 inverse *= 2 - denominator * inverse; // inverse mod 2^64 inverse *= 2 - denominator * inverse; // inverse mod 2^128 inverse *= 2 - denominator * inverse; // inverse mod 2^256 // Because the division is now exact we can divide by multiplying with the modular inverse of denominator. // This will give us the correct result modulo 2^256. Since the preconditions guarantee that the outcome is // less than 2^256, this is the final result. We don't need to compute the high bits of the result and prod1 // is no longer required. result = prod0 * inverse; return result; } } /** * @notice Calculates x * y / denominator with full precision, following the selected rounding direction. */ function mulDiv(uint256 x, uint256 y, uint256 denominator, Rounding rounding) internal pure returns (uint256) { uint256 result = mulDiv(x, y, denominator); if (rounding == Rounding.Up && mulmod(x, y, denominator) > 0) { result += 1; } return result; } /** * @dev Returns the square root of a number. If the number is not a perfect square, the value is rounded down. * * Inspired by Henry S. Warren, Jr.'s "Hacker's Delight" (Chapter 11). */ function sqrt(uint256 a) internal pure returns (uint256) { if (a == 0) { return 0; } // For our first guess, we get the biggest power of 2 which is smaller than the square root of the target. // // We know that the "msb" (most significant bit) of our target number `a` is a power of 2 such that we have // `msb(a) <= a < 2*msb(a)`. This value can be written `msb(a)=2**k` with `k=log2(a)`. // // This can be rewritten `2**log2(a) <= a < 2**(log2(a) + 1)` // → `sqrt(2**k) <= sqrt(a) < sqrt(2**(k+1))` // → `2**(k/2) <= sqrt(a) < 2**((k+1)/2) <= 2**(k/2 + 1)` // // Consequently, `2**(log2(a) / 2)` is a good first approximation of `sqrt(a)` with at least 1 correct bit. uint256 result = 1 << (log2(a) >> 1); // At this point `result` is an estimation with one bit of precision. We know the true value is a uint128, // since it is the square root of a uint256. Newton's method converges quadratically (precision doubles at // every iteration). We thus need at most 7 iteration to turn our partial result with one bit of precision // into the expected uint128 result. unchecked { result = (result + a / result) >> 1; result = (result + a / result) >> 1; result = (result + a / result) >> 1; result = (result + a / result) >> 1; result = (result + a / result) >> 1; result = (result + a / result) >> 1; result = (result + a / result) >> 1; return min(result, a / result); } } /** * @notice Calculates sqrt(a), following the selected rounding direction. */ function sqrt(uint256 a, Rounding rounding) internal pure returns (uint256) { unchecked { uint256 result = sqrt(a); return result + (rounding == Rounding.Up && result * result < a ? 1 : 0); } } /** * @dev Return the log in base 2, rounded down, of a positive value. * Returns 0 if given 0. */ function log2(uint256 value) internal pure returns (uint256) { uint256 result = 0; unchecked { if (value >> 128 > 0) { value >>= 128; result += 128; } if (value >> 64 > 0) { value >>= 64; result += 64; } if (value >> 32 > 0) { value >>= 32; result += 32; } if (value >> 16 > 0) { value >>= 16; result += 16; } if (value >> 8 > 0) { value >>= 8; result += 8; } if (value >> 4 > 0) { value >>= 4; result += 4; } if (value >> 2 > 0) { value >>= 2; result += 2; } if (value >> 1 > 0) { result += 1; } } return result; } /** * @dev Return the log in base 2, following the selected rounding direction, of a positive value. * Returns 0 if given 0. */ function log2(uint256 value, Rounding rounding) internal pure returns (uint256) { unchecked { uint256 result = log2(value); return result + (rounding == Rounding.Up && 1 << result < value ? 1 : 0); } } /** * @dev Return the log in base 10, rounded down, of a positive value. * Returns 0 if given 0. */ function log10(uint256 value) internal pure returns (uint256) { uint256 result = 0; unchecked { if (value >= 10 ** 64) { value /= 10 ** 64; result += 64; } if (value >= 10 ** 32) { value /= 10 ** 32; result += 32; } if (value >= 10 ** 16) { value /= 10 ** 16; result += 16; } if (value >= 10 ** 8) { value /= 10 ** 8; result += 8; } if (value >= 10 ** 4) { value /= 10 ** 4; result += 4; } if (value >= 10 ** 2) { value /= 10 ** 2; result += 2; } if (value >= 10 ** 1) { result += 1; } } return result; } /** * @dev Return the log in base 10, following the selected rounding direction, of a positive value. * Returns 0 if given 0. */ function log10(uint256 value, Rounding rounding) internal pure returns (uint256) { unchecked { uint256 result = log10(value); return result + (rounding == Rounding.Up && 10 ** result < value ? 1 : 0); } } /** * @dev Return the log in base 256, rounded down, of a positive value. * Returns 0 if given 0. * * Adding one to the result gives the number of pairs of hex symbols needed to represent `value` as a hex string. */ function log256(uint256 value) internal pure returns (uint256) { uint256 result = 0; unchecked { if (value >> 128 > 0) { value >>= 128; result += 16; } if (value >> 64 > 0) { value >>= 64; result += 8; } if (value >> 32 > 0) { value >>= 32; result += 4; } if (value >> 16 > 0) { value >>= 16; result += 2; } if (value >> 8 > 0) { result += 1; } } return result; } /** * @dev Return the log in base 256, following the selected rounding direction, of a positive value. * Returns 0 if given 0. */ function log256(uint256 value, Rounding rounding) internal pure returns (uint256) { unchecked { uint256 result = log256(value); return result + (rounding == Rounding.Up && 1 << (result << 3) < value ? 1 : 0); } } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.9.0) (token/ERC20/extensions/IERC20Permit.sol) pragma solidity ^0.8.0; /** * @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in * https://eips.ethereum.org/EIPS/eip-2612[EIP-2612]. * * Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by * presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't * need to send a transaction, and thus is not required to hold Ether at all. */ interface IERC20PermitUpgradeable { /** * @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens, * given ``owner``'s signed approval. * * IMPORTANT: The same issues {IERC20-approve} has related to transaction * ordering also apply here. * * Emits an {Approval} event. * * Requirements: * * - `spender` cannot be the zero address. * - `deadline` must be a timestamp in the future. * - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner` * over the EIP712-formatted function arguments. * - the signature must use ``owner``'s current nonce (see {nonces}). * * For more information on the signature format, see the * https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP * section]. */ function permit( address owner, address spender, uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s ) external; /** * @dev Returns the current nonce for `owner`. This value must be * included whenever a signature is generated for {permit}. * * Every successful call to {permit} increases ``owner``'s nonce by one. This * prevents a signature from being used multiple times. */ function nonces(address owner) external view returns (uint256); /** * @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}. */ // solhint-disable-next-line func-name-mixedcase function DOMAIN_SEPARATOR() external view returns (bytes32); }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.9.0) (utils/Address.sol) pragma solidity ^0.8.1; /** * @dev Collection of functions related to the address type */ library AddressUpgradeable { /** * @dev Returns true if `account` is a contract. * * [IMPORTANT] * ==== * It is unsafe to assume that an address for which this function returns * false is an externally-owned account (EOA) and not a contract. * * Among others, `isContract` will return false for the following * types of addresses: * * - an externally-owned account * - a contract in construction * - an address where a contract will be created * - an address where a contract lived, but was destroyed * * Furthermore, `isContract` will also return true if the target contract within * the same transaction is already scheduled for destruction by `SELFDESTRUCT`, * which only has an effect at the end of a transaction. * ==== * * [IMPORTANT] * ==== * You shouldn't rely on `isContract` to protect against flash loan attacks! * * Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets * like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract * constructor. * ==== */ function isContract(address account) internal view returns (bool) { // This method relies on extcodesize/address.code.length, which returns 0 // for contracts in construction, since the code is only stored at the end // of the constructor execution. return account.code.length > 0; } /** * @dev Replacement for Solidity's `transfer`: sends `amount` wei to * `recipient`, forwarding all available gas and reverting on errors. * * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost * of certain opcodes, possibly making contracts go over the 2300 gas limit * imposed by `transfer`, making them unable to receive funds via * `transfer`. {sendValue} removes this limitation. * * https://consensys.net/diligence/blog/2019/09/stop-using-soliditys-transfer-now/[Learn more]. * * IMPORTANT: because control is transferred to `recipient`, care must be * taken to not create reentrancy vulnerabilities. Consider using * {ReentrancyGuard} or the * https://solidity.readthedocs.io/en/v0.8.0/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern]. */ function sendValue(address payable recipient, uint256 amount) internal { require(address(this).balance >= amount, "Address: insufficient balance"); (bool success, ) = recipient.call{value: amount}(""); require(success, "Address: unable to send value, recipient may have reverted"); } /** * @dev Performs a Solidity function call using a low level `call`. A * plain `call` is an unsafe replacement for a function call: use this * function instead. * * If `target` reverts with a revert reason, it is bubbled up by this * function (like regular Solidity function calls). * * Returns the raw returned data. To convert to the expected return value, * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`]. * * Requirements: * * - `target` must be a contract. * - calling `target` with `data` must not revert. * * _Available since v3.1._ */ function functionCall(address target, bytes memory data) internal returns (bytes memory) { return functionCallWithValue(target, data, 0, "Address: low-level call failed"); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with * `errorMessage` as a fallback revert reason when `target` reverts. * * _Available since v3.1._ */ function functionCall( address target, bytes memory data, string memory errorMessage ) internal returns (bytes memory) { return functionCallWithValue(target, data, 0, errorMessage); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], * but also transferring `value` wei to `target`. * * Requirements: * * - the calling contract must have an ETH balance of at least `value`. * - the called Solidity function must be `payable`. * * _Available since v3.1._ */ function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) { return functionCallWithValue(target, data, value, "Address: low-level call with value failed"); } /** * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but * with `errorMessage` as a fallback revert reason when `target` reverts. * * _Available since v3.1._ */ function functionCallWithValue( address target, bytes memory data, uint256 value, string memory errorMessage ) internal returns (bytes memory) { require(address(this).balance >= value, "Address: insufficient balance for call"); (bool success, bytes memory returndata) = target.call{value: value}(data); return verifyCallResultFromTarget(target, success, returndata, errorMessage); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], * but performing a static call. * * _Available since v3.3._ */ function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) { return functionStaticCall(target, data, "Address: low-level static call failed"); } /** * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`], * but performing a static call. * * _Available since v3.3._ */ function functionStaticCall( address target, bytes memory data, string memory errorMessage ) internal view returns (bytes memory) { (bool success, bytes memory returndata) = target.staticcall(data); return verifyCallResultFromTarget(target, success, returndata, errorMessage); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], * but performing a delegate call. * * _Available since v3.4._ */ function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) { return functionDelegateCall(target, data, "Address: low-level delegate call failed"); } /** * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`], * but performing a delegate call. * * _Available since v3.4._ */ function functionDelegateCall( address target, bytes memory data, string memory errorMessage ) internal returns (bytes memory) { (bool success, bytes memory returndata) = target.delegatecall(data); return verifyCallResultFromTarget(target, success, returndata, errorMessage); } /** * @dev Tool to verify that a low level call to smart-contract was successful, and revert (either by bubbling * the revert reason or using the provided one) in case of unsuccessful call or if target was not a contract. * * _Available since v4.8._ */ function verifyCallResultFromTarget( address target, bool success, bytes memory returndata, string memory errorMessage ) internal view returns (bytes memory) { if (success) { if (returndata.length == 0) { // only check isContract if the call was successful and the return data is empty // otherwise we already know that it was a contract require(isContract(target), "Address: call to non-contract"); } return returndata; } else { _revert(returndata, errorMessage); } } /** * @dev Tool to verify that a low level call was successful, and revert if it wasn't, either by bubbling the * revert reason or using the provided one. * * _Available since v4.3._ */ function verifyCallResult( bool success, bytes memory returndata, string memory errorMessage ) internal pure returns (bytes memory) { if (success) { return returndata; } else { _revert(returndata, errorMessage); } } function _revert(bytes memory returndata, string memory errorMessage) private pure { // Look for revert reason and bubble it up if present if (returndata.length > 0) { // The easiest way to bubble the revert reason is using memory via assembly /// @solidity memory-safe-assembly assembly { let returndata_size := mload(returndata) revert(add(32, returndata), returndata_size) } } else { revert(errorMessage); } } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.9.0) (proxy/utils/Initializable.sol) pragma solidity ^0.8.2; import "../../utils/AddressUpgradeable.sol"; /** * @dev This is a base contract to aid in writing upgradeable contracts, or any kind of contract that will be deployed * behind a proxy. Since proxied contracts do not make use of a constructor, it's common to move constructor logic to an * external initializer function, usually called `initialize`. It then becomes necessary to protect this initializer * function so it can only be called once. The {initializer} modifier provided by this contract will have this effect. * * The initialization functions use a version number. Once a version number is used, it is consumed and cannot be * reused. This mechanism prevents re-execution of each "step" but allows the creation of new initialization steps in * case an upgrade adds a module that needs to be initialized. * * For example: * * [.hljs-theme-light.nopadding] * ```solidity * contract MyToken is ERC20Upgradeable { * function initialize() initializer public { * __ERC20_init("MyToken", "MTK"); * } * } * * contract MyTokenV2 is MyToken, ERC20PermitUpgradeable { * function initializeV2() reinitializer(2) public { * __ERC20Permit_init("MyToken"); * } * } * ``` * * TIP: To avoid leaving the proxy in an uninitialized state, the initializer function should be called as early as * possible by providing the encoded function call as the `_data` argument to {ERC1967Proxy-constructor}. * * CAUTION: When used with inheritance, manual care must be taken to not invoke a parent initializer twice, or to ensure * that all initializers are idempotent. This is not verified automatically as constructors are by Solidity. * * [CAUTION] * ==== * Avoid leaving a contract uninitialized. * * An uninitialized contract can be taken over by an attacker. This applies to both a proxy and its implementation * contract, which may impact the proxy. To prevent the implementation contract from being used, you should invoke * the {_disableInitializers} function in the constructor to automatically lock it when it is deployed: * * [.hljs-theme-light.nopadding] * ``` * /// @custom:oz-upgrades-unsafe-allow constructor * constructor() { * _disableInitializers(); * } * ``` * ==== */ abstract contract Initializable { /** * @dev Indicates that the contract has been initialized. * @custom:oz-retyped-from bool */ uint8 private _initialized; /** * @dev Indicates that the contract is in the process of being initialized. */ bool private _initializing; /** * @dev Triggered when the contract has been initialized or reinitialized. */ event Initialized(uint8 version); /** * @dev A modifier that defines a protected initializer function that can be invoked at most once. In its scope, * `onlyInitializing` functions can be used to initialize parent contracts. * * Similar to `reinitializer(1)`, except that functions marked with `initializer` can be nested in the context of a * constructor. * * Emits an {Initialized} event. */ modifier initializer() { bool isTopLevelCall = !_initializing; require( (isTopLevelCall && _initialized < 1) || (!AddressUpgradeable.isContract(address(this)) && _initialized == 1), "Initializable: contract is already initialized" ); _initialized = 1; if (isTopLevelCall) { _initializing = true; } _; if (isTopLevelCall) { _initializing = false; emit Initialized(1); } } /** * @dev A modifier that defines a protected reinitializer function that can be invoked at most once, and only if the * contract hasn't been initialized to a greater version before. In its scope, `onlyInitializing` functions can be * used to initialize parent contracts. * * A reinitializer may be used after the original initialization step. This is essential to configure modules that * are added through upgrades and that require initialization. * * When `version` is 1, this modifier is similar to `initializer`, except that functions marked with `reinitializer` * cannot be nested. If one is invoked in the context of another, execution will revert. * * Note that versions can jump in increments greater than 1; this implies that if multiple reinitializers coexist in * a contract, executing them in the right order is up to the developer or operator. * * WARNING: setting the version to 255 will prevent any future reinitialization. * * Emits an {Initialized} event. */ modifier reinitializer(uint8 version) { require(!_initializing && _initialized < version, "Initializable: contract is already initialized"); _initialized = version; _initializing = true; _; _initializing = false; emit Initialized(version); } /** * @dev Modifier to protect an initialization function so that it can only be invoked by functions with the * {initializer} and {reinitializer} modifiers, directly or indirectly. */ modifier onlyInitializing() { require(_initializing, "Initializable: contract is not initializing"); _; } /** * @dev Locks the contract, preventing any future reinitialization. This cannot be part of an initializer call. * Calling this in the constructor of a contract will prevent that contract from being initialized or reinitialized * to any version. It is recommended to use this to lock implementation contracts that are designed to be called * through proxies. * * Emits an {Initialized} event the first time it is successfully executed. */ function _disableInitializers() internal virtual { require(!_initializing, "Initializable: contract is initializing"); if (_initialized != type(uint8).max) { _initialized = type(uint8).max; emit Initialized(type(uint8).max); } } /** * @dev Returns the highest version that has been initialized. See {reinitializer}. */ function _getInitializedVersion() internal view returns (uint8) { return _initialized; } /** * @dev Returns `true` if the contract is currently initializing. See {onlyInitializing}. */ function _isInitializing() internal view returns (bool) { return _initializing; } }
{ "remappings": [ "ds-test/=lib/forge-std/lib/ds-test/src/", "forge-std/=lib/forge-std/src/", "@openzeppelin/=node_modules/@openzeppelin/", "fx-portal/=lib/contracts/contracts/", "@routerprotocol/=node_modules/@routerprotocol/" ], "optimizer": { "enabled": true, "runs": 999999 }, "metadata": { "useLiteralContent": false, "bytecodeHash": "ipfs", "appendCBOR": true }, "outputSelection": { "*": { "*": [ "evm.bytecode", "evm.deployedBytecode", "devdoc", "userdoc", "metadata", "abi" ] } }, "evmVersion": "paris", "viaIR": false, "libraries": {} }
Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
[{"inputs":[{"internalType":"address","name":"_assetForwarderAddress","type":"address"},{"internalType":"address","name":"_native","type":"address"},{"internalType":"address","name":"_wrappedNative","type":"address"},{"internalType":"address","name":"_univ2SkimAddress","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"AlreadyFactorySetter","type":"error"},{"inputs":[],"name":"AmountTooLow","type":"error"},{"inputs":[],"name":"ExcecutionFailed","type":"error"},{"inputs":[],"name":"InvalidCaller","type":"error"},{"inputs":[],"name":"InvalidDepositType","type":"error"},{"inputs":[],"name":"InvalidPool","type":"error"},{"inputs":[],"name":"RestrictNativeToken","type":"error"},{"inputs":[],"name":"WrongDataLength","type":"error"},{"inputs":[],"name":"WrongTokenSent","type":"error"},{"inputs":[],"name":"ZeroAddress","type":"error"},{"inputs":[],"name":"ZeroFlag","type":"error"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"newOwner","type":"address"}],"name":"ClaimOwnership","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"bytes32","name":"previousAdminRole","type":"bytes32"},{"indexed":true,"internalType":"bytes32","name":"newAdminRole","type":"bytes32"}],"name":"RoleAdminChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":true,"internalType":"address","name":"sender","type":"address"}],"name":"RoleGranted","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":true,"internalType":"address","name":"sender","type":"address"}],"name":"RoleRevoked","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"assetBridge","type":"address"},{"indexed":false,"internalType":"address","name":"admin","type":"address"}],"name":"SetAssetBridge","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"assetForwarder","type":"address"},{"indexed":false,"internalType":"address","name":"admin","type":"address"}],"name":"SetAssetForwarder","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"factorySetter","type":"address"}],"name":"SetFactorySetter","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"flag","type":"uint256"},{"indexed":false,"internalType":"address","name":"factoryAddress","type":"address"}],"name":"SetFlagToFactory","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"wrappedNative","type":"address"}],"name":"SetWNativeAddresses","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"string","name":"funcName","type":"string"},{"indexed":false,"internalType":"contract IERC20Upgradeable[]","name":"tokenPath","type":"address[]"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"},{"indexed":true,"internalType":"address","name":"sender","type":"address"},{"indexed":true,"internalType":"address","name":"receiver","type":"address"},{"indexed":false,"internalType":"uint256","name":"finalAmt","type":"uint256"},{"indexed":false,"internalType":"uint256[]","name":"flags","type":"uint256[]"},{"indexed":false,"internalType":"uint256","name":"widgetID","type":"uint256"}],"name":"Swap","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"contract IERC20Upgradeable","name":"fromToken","type":"address"},{"indexed":false,"internalType":"contract IERC20Upgradeable","name":"destToken","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"},{"indexed":false,"internalType":"bytes","name":"_data","type":"bytes"},{"indexed":false,"internalType":"uint256","name":"flags","type":"uint256"}],"name":"SwapOnSameChain","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"string","name":"funcName","type":"string"},{"indexed":false,"internalType":"contract IERC20Upgradeable[]","name":"tokenPath","type":"address[]"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"},{"indexed":true,"internalType":"address","name":"sender","type":"address"},{"indexed":true,"internalType":"address","name":"receiver","type":"address"},{"indexed":false,"internalType":"uint256","name":"finalAmt","type":"uint256"},{"indexed":false,"internalType":"uint256[]","name":"flags","type":"uint256[]"},{"indexed":false,"internalType":"uint256","name":"widgetID","type":"uint256"}],"name":"SwapWithRecipient","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"newOwner","type":"address"}],"name":"TransferOwnership","type":"event"},{"inputs":[],"name":"DEFAULT_ADMIN_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"DEXES_COUNT_UPDATED","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"FACTORY_SETTER_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"assetBridge","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"assetForwarder","outputs":[{"internalType":"contract IAssetForwarder","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"claimOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"flagToAddress","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"}],"name":"getRoleAdmin","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"grantRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_tokenSent","type":"address"},{"internalType":"uint256","name":"_amount","type":"uint256"},{"internalType":"bytes","name":"message","type":"bytes"}],"name":"handleMessage","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"hasRole","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes[]","name":"data","type":"bytes[]"}],"name":"multicall","outputs":[{"internalType":"bytes[]","name":"results","type":"bytes[]"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"nativeAddress","outputs":[{"internalType":"contract IERC20Upgradeable","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"newOwner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"renounceRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"revokeRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_assetBridge","type":"address"}],"name":"setAssetBridge","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_forwarder","type":"address"}],"name":"setAssetForwarder","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_factorySetter","type":"address"}],"name":"setFactorySetter","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_flagCode","type":"uint256"},{"internalType":"address","name":"_factoryAddress","type":"address"}],"name":"setFlagToFactoryAddress","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_native","type":"address"},{"internalType":"address","name":"_wrappedNative","type":"address"}],"name":"setWNativeAddresses","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes4","name":"interfaceId","type":"bytes4"}],"name":"supportsInterface","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"partnerId","type":"uint256"},{"internalType":"bytes32","name":"destChainIdBytes","type":"bytes32"},{"internalType":"bytes","name":"recipient","type":"bytes"},{"internalType":"uint8","name":"depositType","type":"uint8"},{"internalType":"uint256","name":"destAmount","type":"uint256"},{"internalType":"bytes","name":"message","type":"bytes"},{"components":[{"internalType":"contract IERC20Upgradeable[]","name":"tokens","type":"address[]"},{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"uint256","name":"minReturn","type":"uint256"},{"internalType":"uint256[]","name":"flags","type":"uint256[]"},{"internalType":"bytes[]","name":"dataTx","type":"bytes[]"},{"internalType":"bool","name":"isWrapper","type":"bool"},{"internalType":"address","name":"recipient","type":"address"},{"internalType":"bytes","name":"destToken","type":"bytes"}],"internalType":"struct DexSpan.SwapParams","name":"swapData","type":"tuple"},{"internalType":"address","name":"refundRecipient","type":"address"}],"name":"swapAndDeposit","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"contract IERC20Upgradeable[]","name":"tokens","type":"address[]"},{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"uint256","name":"minReturn","type":"uint256"},{"internalType":"uint256[]","name":"flags","type":"uint256[]"},{"internalType":"bytes[]","name":"dataTx","type":"bytes[]"},{"internalType":"bool","name":"isWrapper","type":"bool"},{"internalType":"address","name":"recipient","type":"address"},{"internalType":"uint256","name":"widgetID","type":"uint256"}],"name":"swapInSameChain","outputs":[{"internalType":"uint256","name":"returnAmount","type":"uint256"}],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"contract IERC20Upgradeable[]","name":"tokens","type":"address[]"},{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"uint256","name":"minReturn","type":"uint256"},{"internalType":"uint256[]","name":"flags","type":"uint256[]"},{"internalType":"bytes[]","name":"dataTx","type":"bytes[]"},{"internalType":"bool","name":"isWrapper","type":"bool"},{"internalType":"address","name":"recipient","type":"address"}],"name":"swapMultiWithRecipient","outputs":[{"internalType":"uint256","name":"returnAmount","type":"uint256"}],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"_newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"univ2SkimAddress","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"wnativeAddress","outputs":[{"internalType":"contract IWETH","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"stateMutability":"payable","type":"receive"}]
Contract Creation Code
60806040523480156200001157600080fd5b5060405162004e4638038062004e46833981016040819052620000349162000206565b6001600160a01b0384166200005c5760405163d92e233d60e01b815260040160405180910390fd5b6001600160a01b038316620000845760405163d92e233d60e01b815260040160405180910390fd5b6001600160a01b038216620000ac5760405163d92e233d60e01b815260040160405180910390fd5b6001600160a01b038116620000d45760405163d92e233d60e01b815260040160405180910390fd5b620000e160003362000135565b600480546001600160a01b039586166001600160a01b031991821617909155600280549486169482169490941790935560018054928516928416929092179091556006805491909316911617905562000263565b62000141828262000145565b5050565b60008281526003602090815260408083206001600160a01b038516845290915290205460ff16620001415760008281526003602090815260408083206001600160a01b03851684529091529020805460ff19166001179055620001a53390565b6001600160a01b0316816001600160a01b0316837f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d60405160405180910390a45050565b80516001600160a01b03811681146200020157600080fd5b919050565b600080600080608085870312156200021d57600080fd5b6200022885620001e9565b93506200023860208601620001e9565b92506200024860408601620001e9565b91506200025860608601620001e9565b905092959194509250565b614bd380620002736000396000f3fe6080604052600436106101bb5760003560e01c80639e99ec39116100ec578063d4ee1d901161008a578063e2a4ac2d11610064578063e2a4ac2d146105a9578063e738aa8d146105d6578063f2fde38b146105e9578063f9636f301461060957600080fd5b8063d4ee1d901461053c578063d547741f14610569578063da6689f01461058957600080fd5b8063ac9650d8116100c6578063ac9650d81461048c578063adb88982146104b9578063c75a57e4146104d9578063d00a2d5f1461051c57600080fd5b80639e99ec391461042a578063a217fddf1461044a578063a2625efc1461045f57600080fd5b8063285f94a01161015957806336568abe1161013357806336568abe146103755780634e71e0c8146103955780637fe68917146103aa57806391d14854146103d757600080fd5b8063285f94a0146102d65780632e476337146103285780632f2ff15d1461035557600080fd5b80631696516011610195578063169651601461025357806318137a4114610273578063183d9c9514610293578063248a9ca3146102a657600080fd5b806301ffc9a7146101c757806306135b7c146101fc578063086efdc41461021157600080fd5b366101c257005b600080fd5b3480156101d357600080fd5b506101e76101e236600461393c565b61061e565b60405190151581526020015b60405180910390f35b61020f61020a366004613dc5565b6106b7565b005b34801561021d57600080fd5b506102457fafffb39e42e2a1496bc4305c8783f904fa76641e3895205b6002a03336ee097581565b6040519081526020016101f3565b34801561025f57600080fd5b5061020f61026e366004613e94565b610a27565b34801561027f57600080fd5b5061020f61028e366004613ec4565b610b65565b6102456102a1366004613ee1565b610c3d565b3480156102b257600080fd5b506102456102c1366004613fa8565b60009081526003602052604090206001015490565b3480156102e257600080fd5b506005546103039073ffffffffffffffffffffffffffffffffffffffff1681565b60405173ffffffffffffffffffffffffffffffffffffffff90911681526020016101f3565b34801561033457600080fd5b506002546103039073ffffffffffffffffffffffffffffffffffffffff1681565b34801561036157600080fd5b5061020f610370366004613e94565b610ce7565b34801561038157600080fd5b5061020f610390366004613e94565b610d11565b3480156103a157600080fd5b5061020f610dc9565b3480156103b657600080fd5b506004546103039073ffffffffffffffffffffffffffffffffffffffff1681565b3480156103e357600080fd5b506101e76103f2366004613e94565b600091825260036020908152604080842073ffffffffffffffffffffffffffffffffffffffff93909316845291905290205460ff1690565b34801561043657600080fd5b5061020f610445366004613ec4565b610e5a565b34801561045657600080fd5b50610245600081565b34801561046b57600080fd5b506006546103039073ffffffffffffffffffffffffffffffffffffffff1681565b34801561049857600080fd5b506104ac6104a7366004613fc1565b610f2a565b6040516101f391906140f9565b3480156104c557600080fd5b5061020f6104d4366004613ec4565b61101f565b3480156104e557600080fd5b506103036104f4366004613fa8565b60086020526000908152604090205473ffffffffffffffffffffffffffffffffffffffff1681565b34801561052857600080fd5b5061020f61053736600461410c565b611166565b34801561054857600080fd5b506007546103039073ffffffffffffffffffffffffffffffffffffffff1681565b34801561057557600080fd5b5061020f610584366004613e94565b6111e8565b34801561059557600080fd5b5061020f6105a4366004614165565b61120d565b3480156105b557600080fd5b506001546103039073ffffffffffffffffffffffffffffffffffffffff1681565b6102456105e4366004614193565b611335565b3480156105f557600080fd5b5061020f610604366004613ec4565b6113df565b34801561061557600080fd5b50610245600181565b60007fffffffff0000000000000000000000000000000000000000000000000000000082167f7965db0b0000000000000000000000000000000000000000000000000000000014806106b157507f01ffc9a7000000000000000000000000000000000000000000000000000000007fffffffff000000000000000000000000000000000000000000000000000000008316145b92915050565b6106de826000015183602001518460400151856060015186608001518760a00151306114aa565b5081518051600091906106f390600190614285565b8151811061070357610703614298565b602002602001015190508560ff1660000361085657600061073a73ffffffffffffffffffffffffffffffffffffffff8316306119c0565b6004549091506107649073ffffffffffffffffffffffffffffffffffffffff848116911683611a85565b60045473ffffffffffffffffffffffffffffffffffffffff9081169063f452ed4d90610791908516611aa9565b61079c57600061079e565b825b6040518060c001604052808f81526020018581526020018a81526020018673ffffffffffffffffffffffffffffffffffffffff1681526020018773ffffffffffffffffffffffffffffffffffffffff1681526020018e8152508760e001518d8d6040518663ffffffff1660e01b815260040161081d9493929190614310565b6000604051808303818588803b15801561083657600080fd5b505af115801561084a573d6000803e3d6000fd5b50505050505050610a1c565b8560ff166001036109ea57600061088373ffffffffffffffffffffffffffffffffffffffff8316306119c0565b60045460408601519192506108b29173ffffffffffffffffffffffffffffffffffffffff858116921690611a85565b60045473ffffffffffffffffffffffffffffffffffffffff90811690630421caf0906108df908516611aa9565b6108ea5760006108ec565b825b6040518060c001604052808f8152602001886040015181526020018a81526020018673ffffffffffffffffffffffffffffffffffffffff1681526020018773ffffffffffffffffffffffffffffffffffffffff1681526020018e8152508760e001518d8d8b6040518763ffffffff1660e01b8152600401610971959493929190614397565b6000604051808303818588803b15801561098a57600080fd5b505af115801561099e573d6000803e3d6000fd5b505050505083604001518111156109e3576109e1838560400151836109c39190614285565b73ffffffffffffffffffffffffffffffffffffffff85169190611afc565b505b5050610a1c565b6040517f26667fc400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b505050505050505050565b7fafffb39e42e2a1496bc4305c8783f904fa76641e3895205b6002a03336ee0975610a5181611bae565b82600003610a8b576040517f196de28b00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b73ffffffffffffffffffffffffffffffffffffffff8216610ad8576040517fd92e233d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60008381526008602090815260409182902080547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff86169081179091558251868152918201527f11f5b5361c420666dc3452b8107601e1702f94b951f15bd93c26262c8147874e91015b60405180910390a1505050565b6000610b7081611bae565b73ffffffffffffffffffffffffffffffffffffffff8216610bbd576040517fd92e233d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600480547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff8416908117909155604080519182523360208301527f61b6fe2922f0180b98d305419bf3dcf432f5d8df894388c61c1f599c2194ec1d91015b60405180910390a15050565b6000610c4e89898989898989611335565b6040517f73776170496e53616d65436861696e0000000000000000000000000000000000815290915073ffffffffffffffffffffffffffffffffffffffff8416903390600f0160405180910390207fe3716b48e7d01d727d68472c873c69c2c4407365e4f68b2b6c8dd4569cd16dc78c8c868c89604051610cd39594939291906144c0565b60405180910390a498975050505050505050565b600082815260036020526040902060010154610d0281611bae565b610d0c8383611bbb565b505050565b73ffffffffffffffffffffffffffffffffffffffff81163314610dbb576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602f60248201527f416363657373436f6e74726f6c3a2063616e206f6e6c792072656e6f756e636560448201527f20726f6c657320666f722073656c66000000000000000000000000000000000060648201526084015b60405180910390fd5b610dc58282611caf565b5050565b60075473ffffffffffffffffffffffffffffffffffffffff163314610e1a576040517f48f5c3ed00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b610e25600033611d6a565b6040513381527f85a8c8100c1d48466310240af79644f50cdae7d09cb4820d60dfc5b2462f0fd09060200160405180910390a1565b6000610e6581611bae565b73ffffffffffffffffffffffffffffffffffffffff8216610eb2576040517fd92e233d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600580547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff8416908117909155604080519182523360208301527f45085069ced50a4d2e82656a82ba8f5a1a28694489d8ea262252e40899a930a29101610c31565b60608167ffffffffffffffff811115610f4557610f456139dd565b604051908082528060200260200182016040528015610f7857816020015b6060815260200190600190039081610f635790505b50905060005b8281101561101857610fe830858584818110610f9c57610f9c614298565b9050602002810190610fae9190614504565b8080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250611d7492505050565b828281518110610ffa57610ffa614298565b6020026020010181905250808061101090614569565b915050610f7e565b5092915050565b600061102a81611bae565b73ffffffffffffffffffffffffffffffffffffffff8216611077576040517fd92e233d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b73ffffffffffffffffffffffffffffffffffffffff821660009081527f3ab9add546f7e3b43565da9bc7e65e47b969d3856bb01a7dcac7bc8ff5080cbd602052604090205460ff16156110f6576040517fe4e970d000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6111207fafffb39e42e2a1496bc4305c8783f904fa76641e3895205b6002a03336ee097583611d6a565b60405173ffffffffffffffffffffffffffffffffffffffff831681527fd2b69bde5a989d23ef605a0dd4e0edf7662105058ab69f2559e482857b599ed890602001610c31565b60045473ffffffffffffffffffffffffffffffffffffffff1633148015906111a6575060055473ffffffffffffffffffffffffffffffffffffffff163314155b156111dd576040517f48f5c3ed00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b610d0c838383611d99565b60008281526003602052604090206001015461120381611bae565b610d0c8383611caf565b600061121881611bae565b73ffffffffffffffffffffffffffffffffffffffff8316611265576040517fd92e233d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b73ffffffffffffffffffffffffffffffffffffffff82166112b2576040517fd92e233d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6002805473ffffffffffffffffffffffffffffffffffffffff8581167fffffffffffffffffffffffff0000000000000000000000000000000000000000928316179092556001805492851692909116821790556040519081527fcc4166d40cf68104cdf710f65ce022efd296742868a22b42e4695f89b886363690602001610b58565b6000611346888888888888886114aa565b6040517f737761704d756c746957697468526563697069656e7400000000000000000000815290915073ffffffffffffffffffffffffffffffffffffffff831690339060160160405180910390207fc40fae9d5f584875c393ac222c6f88b6c9dced1e9cc6251483648ac2e902c8b08b8b868b60006040516113cc9594939291906144c0565b60405180910390a4979650505050505050565b60006113ea81611bae565b73ffffffffffffffffffffffffffffffffffffffff8216611437576040517fd92e233d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600780547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff84169081179091556040519081527fcfaaa26691e16e66e73290fc725eee1a6b4e0e693a1640484937aac25ffb55a490602001610c31565b600073ffffffffffffffffffffffffffffffffffffffff82166114f9576040517fd92e233d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8451600189516115099190614285565b14611540576040517fcc513c7200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b826116085761157e8860008151811061155b5761155b614298565b602002602001015173ffffffffffffffffffffffffffffffffffffffff16611aa9565b15801561158a57503415155b156115c1576040517f694b150300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6116083330898b6000815181106115da576115da614298565b602002602001015173ffffffffffffffffffffffffffffffffffffffff1661210c909392919063ffffffff16565b61164b308960008151811061161f5761161f614298565b602002602001015173ffffffffffffffffffffffffffffffffffffffff166119c090919063ffffffff16565b905060008860018a5161165e9190614285565b8151811061166e5761166e614298565b602002602001015190506000600190505b89518110156117a45789818151811061169a5761169a614298565b602002602001015173ffffffffffffffffffffffffffffffffffffffff168a6001836116c69190614285565b815181106116d6576116d6614298565b602002602001015173ffffffffffffffffffffffffffffffffffffffff1603156117925761178f8a611709600184614285565b8151811061171957611719614298565b60200260200101518b838151811061173357611733614298565b60200260200101518560008b60018761174c9190614285565b8151811061175c5761175c614298565b60200260200101518b6001886117729190614285565b8151811061178257611782614298565b60200260200101516122ec565b92505b8061179c81614569565b91505061167f565b506117c48173ffffffffffffffffffffffffffffffffffffffff16611aa9565b156118e1576001546040517f70a0823100000000000000000000000000000000000000000000000000000000815230600482015273ffffffffffffffffffffffffffffffffffffffff909116906370a0823190602401602060405180830381865afa158015611837573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061185b91906145a1565b6001546040517f2e1a7d4d0000000000000000000000000000000000000000000000000000000081526004810183905291935073ffffffffffffffffffffffffffffffffffffffff1690632e1a7d4d90602401600060405180830381600087803b1580156118c857600080fd5b505af11580156118dc573d6000803e3d6000fd5b505050505b73ffffffffffffffffffffffffffffffffffffffff831630146119b457600061192073ffffffffffffffffffffffffffffffffffffffff8316856119c0565b905061194373ffffffffffffffffffffffffffffffffffffffff83168585611afc565b50600061196673ffffffffffffffffffffffffffffffffffffffff8416866119c0565b905060006119748383614285565b90508981116119af576040517f1fbaba3500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b935050505b50979650505050505050565b60006119cb83611aa9565b156119ee575073ffffffffffffffffffffffffffffffffffffffff8116316106b1565b6040517f70a0823100000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff83811660048301528416906370a0823190602401602060405180830381865afa158015611a5a573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611a7e91906145a1565b90506106b1565b611a8e83611aa9565b610d0c57611a9e83836000612307565b610d0c838383612307565b600073ffffffffffffffffffffffffffffffffffffffff821615806106b1575073ffffffffffffffffffffffffffffffffffffffff821673eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee1492915050565b600081600003611b0e57506001611ba7565b611b1784611aa9565b15611b985760008373ffffffffffffffffffffffffffffffffffffffff168360405160006040518083038185875af1925050503d8060008114611b76576040519150601f19603f3d011682016040523d82523d6000602084013e611b7b565b606091505b5090915050600181151514611b9257611b926145ba565b50611ba7565b611ba384848461249d565b5060015b9392505050565b611bb8813361262c565b50565b600082815260036020908152604080832073ffffffffffffffffffffffffffffffffffffffff8516845290915290205460ff16610dc557600082815260036020908152604080832073ffffffffffffffffffffffffffffffffffffffff85168452909152902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00166001179055611c513390565b73ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff16837f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d60405160405180910390a45050565b600082815260036020908152604080832073ffffffffffffffffffffffffffffffffffffffff8516845290915290205460ff1615610dc557600082815260036020908152604080832073ffffffffffffffffffffffffffffffffffffffff8516808552925280832080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0016905551339285917ff6391f5c32d9c69d2a47ea670b442974b53935d1edc7fd64eb21e047a839171b9190a45050565b610dc58282611bbb565b6060611ba78383604051806060016040528060278152602001614b77602791396126e6565b600080600080600080600087806020019051810190611db89190614783565b965096509650965096509650965086600081518110611dd957611dd9614298565b602002602001015173ffffffffffffffffffffffffffffffffffffffff168a73ffffffffffffffffffffffffffffffffffffffff1614611e45576040517f198b098900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b606060003073ffffffffffffffffffffffffffffffffffffffff1663e738aa8d60e01b8a8d8b8a8c60018c604051602401611e86979695949392919061485b565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529181526020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fffffffff00000000000000000000000000000000000000000000000000000000909416939093179092529051611f0f91906148d2565b6000604051808303816000865af19150503d8060008114611f4c576040519150601f19603f3d011682016040523d82523d6000602084013e611f51565b606091505b509250905080611fa257611fa0858c8b600081518110611f7357611f73614298565b602002602001015173ffffffffffffffffffffffffffffffffffffffff16611afc9092919063ffffffff16565b505b83156120fe57600081611fb5578b611fbe565b611fbe836148ee565b9050600082611fcd578d611ff5565b8a60018c51611fdc9190614285565b81518110611fec57611fec614298565b60200260200101515b90508673ffffffffffffffffffffffffffffffffffffffff1663d00a2d5f60e01b82848860405160240161202b93929190614933565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529181526020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fffffffff000000000000000000000000000000000000000000000000000000009094169390931790925290516120b491906148d2565b6000604051808303816000865af19150503d80600081146120f1576040519150601f19603f3d011682016040523d82523d6000602084013e6120f6565b606091505b509450925050505b505050505050505050505050565b80156122e65761211b84611aa9565b156122da5773ffffffffffffffffffffffffffffffffffffffff8316331480156121455750803410155b6121d1576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602a60248201527f57726f6e67207573616765206f66204554482e756e6976657273616c5472616e60448201527f7366657246726f6d2829000000000000000000000000000000000000000000006064820152608401610db2565b73ffffffffffffffffffffffffffffffffffffffff821630146122665760008273ffffffffffffffffffffffffffffffffffffffff168260405160006040518083038185875af1925050503d8060008114612248576040519150601f19603f3d011682016040523d82523d6000602084013e61224d565b606091505b5090915050600181151514612264576122646145ba565b505b803411156122d55760003361227b348461276b565b604051600081818185875af1925050503d80600081146122b7576040519150601f19603f3d011682016040523d82523d6000602084013e6122bc565b606091505b50909150506001811515146122d3576122d36145ba565b505b6122e6565b6122e684848484612777565b50505050565b60006122fc878787878787612916565b979650505050505050565b6040805173ffffffffffffffffffffffffffffffffffffffff8481166024830152604480830185905283518084039091018152606490920183526020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167f095ea7b300000000000000000000000000000000000000000000000000000000179052915160009283929087169161239e91906148d2565b6000604051808303816000865af19150503d80600081146123db576040519150601f19603f3d011682016040523d82523d6000602084013e6123e0565b606091505b509150915081801561240a57508051158061240a57508080602001905181019061240a9190614971565b612496576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602b60248201527f5472616e7366657248656c7065723a3a73616665417070726f76653a2061707060448201527f726f7665206661696c65640000000000000000000000000000000000000000006064820152608401610db2565b5050505050565b6040805173ffffffffffffffffffffffffffffffffffffffff8481166024830152604480830185905283518084039091018152606490920183526020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fa9059cbb00000000000000000000000000000000000000000000000000000000179052915160009283929087169161253491906148d2565b6000604051808303816000865af19150503d8060008114612571576040519150601f19603f3d011682016040523d82523d6000602084013e612576565b606091505b50915091508180156125a05750805115806125a05750808060200190518101906125a09190614971565b612496576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602d60248201527f5472616e7366657248656c7065723a3a736166655472616e736665723a20747260448201527f616e73666572206661696c6564000000000000000000000000000000000000006064820152608401610db2565b600082815260036020908152604080832073ffffffffffffffffffffffffffffffffffffffff8516845290915290205460ff16610dc55761266c816129c2565b6126778360206129e1565b60405160200161268892919061498e565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0818403018152908290527f08c379a0000000000000000000000000000000000000000000000000000000008252610db291600401614a0f565b60606000808573ffffffffffffffffffffffffffffffffffffffff168560405161271091906148d2565b600060405180830381855af49150503d806000811461274b576040519150601f19603f3d011682016040523d82523d6000602084013e612750565b606091505b509150915061276186838387612c24565b9695505050505050565b6000611ba78284614285565b6040805173ffffffffffffffffffffffffffffffffffffffff85811660248301528481166044830152606480830185905283518084039091018152608490920183526020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167f23b872dd00000000000000000000000000000000000000000000000000000000179052915160009283929088169161281691906148d2565b6000604051808303816000865af19150503d8060008114612853576040519150601f19603f3d011682016040523d82523d6000602084013e612858565b606091505b50915091508180156128825750805115806128825750808060200190518101906128829190614971565b61290e576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152603160248201527f5472616e7366657248656c7065723a3a7472616e7366657246726f6d3a20747260448201527f616e7366657246726f6d206661696c65640000000000000000000000000000006064820152608401610db2565b505050505050565b60008573ffffffffffffffffffffffffffffffffffffffff168773ffffffffffffffffffffffffffffffffffffffff1603612952575083612761565b61393261295e84612ccc565b9050600061298273ffffffffffffffffffffffffffffffffffffffff8a16306119c0565b905061299589898387898763ffffffff16565b6129b573ffffffffffffffffffffffffffffffffffffffff8916306119c0565b9998505050505050505050565b60606106b173ffffffffffffffffffffffffffffffffffffffff831660145b606060006129f0836002614a22565b6129fb906002614a39565b67ffffffffffffffff811115612a1357612a136139dd565b6040519080825280601f01601f191660200182016040528015612a3d576020820181803683370190505b5090507f300000000000000000000000000000000000000000000000000000000000000081600081518110612a7457612a74614298565b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a9053507f780000000000000000000000000000000000000000000000000000000000000081600181518110612ad757612ad7614298565b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a9053506000612b13846002614a22565b612b1e906001614a39565b90505b6001811115612bbb577f303132333435363738396162636465660000000000000000000000000000000085600f1660108110612b5f57612b5f614298565b1a60f81b828281518110612b7557612b75614298565b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a90535060049490941c93612bb481614a4c565b9050612b21565b508315611ba7576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820181905260248201527f537472696e67733a20686578206c656e67746820696e73756666696369656e746044820152606401610db2565b60608315612cba578251600003612cb35773ffffffffffffffffffffffffffffffffffffffff85163b612cb3576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000006044820152606401610db2565b5081612cc4565b612cc48383612d0a565b949350505050565b6139326103e982108015612ce1575060018210155b15612cef5750612d4e919050565b816107d203612d015750612d5a919050565b50612fe3919050565b815115612d1a5781518083602001fd5b806040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610db29190614a0f565b61290e8585858461314f565b60008181526008602052604090205473ffffffffffffffffffffffffffffffffffffffff1680612db6576040517fd92e233d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b612dd58673ffffffffffffffffffffffffffffffffffffffff16611aa9565b15612e5e57600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663d0e30db0856040518263ffffffff1660e01b81526004016000604051808303818588803b158015612e4457600080fd5b505af1158015612e58573d6000803e3d6000fd5b50505050505b6000612e7f8773ffffffffffffffffffffffffffffffffffffffff16611aa9565b612e895786612ea3565b60015473ffffffffffffffffffffffffffffffffffffffff165b9050612f358273ffffffffffffffffffffffffffffffffffffffff1663d2c4b5986040518163ffffffff1660e01b8152600401602060405180830381865afa158015612ef3573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612f179190614a81565b73ffffffffffffffffffffffffffffffffffffffff83169087611a85565b60008273ffffffffffffffffffffffffffffffffffffffff1685604051612f5c91906148d2565b6000604051808303816000865af19150503d8060008114612f99576040519150601f19603f3d011682016040523d82523d6000602084013e612f9e565b606091505b5050905080612fd9576040517f5987947500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5050505050505050565b60008181526008602052604090205473ffffffffffffffffffffffffffffffffffffffff168061303f576040517fd92e233d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b61305e8673ffffffffffffffffffffffffffffffffffffffff16611aa9565b156130e757600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663d0e30db0856040518263ffffffff1660e01b81526004016000604051808303818588803b1580156130cd57600080fd5b505af11580156130e1573d6000803e3d6000fd5b50505050505b60006131088773ffffffffffffffffffffffffffffffffffffffff16611aa9565b613112578661312c565b60015473ffffffffffffffffffffffffffffffffffffffff165b9050612f3573ffffffffffffffffffffffffffffffffffffffff82168387611a85565b60006131708573ffffffffffffffffffffffffffffffffffffffff16611aa9565b156131f957600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663d0e30db0846040518263ffffffff1660e01b81526004016000604051808303818588803b1580156131df57600080fd5b505af11580156131f3573d6000803e3d6000fd5b50505050505b60008281526008602052604090205473ffffffffffffffffffffffffffffffffffffffff1680613285576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f52413a2045786368616e6765206e6f7420666f756e64000000000000000000006044820152606401610db2565b8060006132a773ffffffffffffffffffffffffffffffffffffffff8916611aa9565b6132b157876132cb565b60015473ffffffffffffffffffffffffffffffffffffffff165b905060006132ee8873ffffffffffffffffffffffffffffffffffffffff16611aa9565b6132f85787613312565b60015473ffffffffffffffffffffffffffffffffffffffff165b90508073ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff16036133535786945050505050612cc4565b6040517fe6a4390500000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff838116600483015282811660248301526000919085169063e6a4390590604401602060405180830381865afa1580156133cb573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906133ef9190614a81565b905073ffffffffffffffffffffffffffffffffffffffff811661343e576040517f2083cd4000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60008061346373ffffffffffffffffffffffffffffffffffffffff841686868d613702565b9199509250905081156134d5578273ffffffffffffffffffffffffffffffffffffffff1663fff6cae96040518163ffffffff1660e01b8152600401600060405180830381600087803b1580156134b857600080fd5b505af11580156134cc573d6000803e3d6000fd5b50505050613561565b8015613561576006546040517fbc25cf7700000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff91821660048201529084169063bc25cf7790602401600060405180830381600087803b15801561354857600080fd5b505af115801561355c573d6000803e3d6000fd5b505050505b61358273ffffffffffffffffffffffffffffffffffffffff8616848c611afc565b508373ffffffffffffffffffffffffffffffffffffffff168573ffffffffffffffffffffffffffffffffffffffff161015613657576040517f022c0d9f000000000000000000000000000000000000000000000000000000008152600060048201819052602482018a905230604483015260806064830152608482015273ffffffffffffffffffffffffffffffffffffffff84169063022c0d9f9060a401600060405180830381600087803b15801561363a57600080fd5b505af115801561364e573d6000803e3d6000fd5b505050506136f3565b6040517f022c0d9f0000000000000000000000000000000000000000000000000000000081526004810189905260006024820181905230604483015260806064830152608482015273ffffffffffffffffffffffffffffffffffffffff84169063022c0d9f9060a401600060405180830381600087803b1580156136da57600080fd5b505af11580156136ee573d6000803e3d6000fd5b505050505b50505050505050949350505050565b600080808061372773ffffffffffffffffffffffffffffffffffffffff8816896119c0565b9050600061374b73ffffffffffffffffffffffffffffffffffffffff88168a6119c0565b90506000808a73ffffffffffffffffffffffffffffffffffffffff16630902f1ac6040518163ffffffff1660e01b8152600401606060405180830381865afa15801561379b573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906137bf9190614abc565b50915091508873ffffffffffffffffffffffffffffffffffffffff168a73ffffffffffffffffffffffffffffffffffffffff1611156137fa57905b816dffffffffffffffffffffffffffff168410806138275750806dffffffffffffffffffffffffffff1683105b95508515801561385f5750816dffffffffffffffffffffffffffff1684118061385f5750806dffffffffffffffffffffffffffff1683115b9450600061386f896103e56138f8565b9050600061389761389086856dffffffffffffffffffffffffffff16613904565b83906138f8565b905060006138cb836138c56103e86138bf8b8a6dffffffffffffffffffffffffffff16613904565b906138f8565b9061391a565b905080156138e2576138dd8282613926565b6138e5565b60005b9950505050505050509450945094915050565b6000611ba78284614a22565b60008183106139135781611ba7565b5090919050565b6000611ba78284614a39565b6000611ba78284614b0c565b61393a614b47565b565b60006020828403121561394e57600080fd5b81357fffffffff0000000000000000000000000000000000000000000000000000000081168114611ba757600080fd5b60008083601f84011261399057600080fd5b50813567ffffffffffffffff8111156139a857600080fd5b6020830191508360208285010111156139c057600080fd5b9250929050565b803560ff811681146139d857600080fd5b919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b604051610100810167ffffffffffffffff81118282101715613a3057613a306139dd565b60405290565b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016810167ffffffffffffffff81118282101715613a7d57613a7d6139dd565b604052919050565b600067ffffffffffffffff821115613a9f57613a9f6139dd565b50601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe01660200190565b600082601f830112613adc57600080fd5b8135613aef613aea82613a85565b613a36565b818152846020838601011115613b0457600080fd5b816020850160208301376000918101602001919091529392505050565b600067ffffffffffffffff821115613b3b57613b3b6139dd565b5060051b60200190565b73ffffffffffffffffffffffffffffffffffffffff81168114611bb857600080fd5b600082601f830112613b7857600080fd5b81356020613b88613aea83613b21565b82815260059290921b84018101918181019086841115613ba757600080fd5b8286015b84811015613bcb578035613bbe81613b45565b8352918301918301613bab565b509695505050505050565b600082601f830112613be757600080fd5b81356020613bf7613aea83613b21565b82815260059290921b84018101918181019086841115613c1657600080fd5b8286015b84811015613bcb5780358352918301918301613c1a565b600082601f830112613c4257600080fd5b81356020613c52613aea83613b21565b82815260059290921b84018101918181019086841115613c7157600080fd5b8286015b84811015613bcb57803567ffffffffffffffff811115613c955760008081fd5b613ca38986838b0101613acb565b845250918301918301613c75565b8015158114611bb857600080fd5b80356139d881613cb1565b80356139d881613b45565b60006101008284031215613ce857600080fd5b613cf0613a0c565b9050813567ffffffffffffffff80821115613d0a57600080fd5b613d1685838601613b67565b835260208401356020840152604084013560408401526060840135915080821115613d4057600080fd5b613d4c85838601613bd6565b60608401526080840135915080821115613d6557600080fd5b613d7185838601613c31565b6080840152613d8260a08501613cbf565b60a0840152613d9360c08501613cca565b60c084015260e0840135915080821115613dac57600080fd5b50613db984828501613acb565b60e08301525092915050565b60008060008060008060008060006101008a8c031215613de457600080fd5b8935985060208a0135975060408a013567ffffffffffffffff80821115613e0a57600080fd5b613e168d838e0161397e565b9099509750879150613e2a60608d016139c7565b965060808c0135955060a08c0135915080821115613e4757600080fd5b613e538d838e01613acb565b945060c08c0135915080821115613e6957600080fd5b50613e768c828d01613cd5565b925050613e8560e08b01613cca565b90509295985092959850929598565b60008060408385031215613ea757600080fd5b823591506020830135613eb981613b45565b809150509250929050565b600060208284031215613ed657600080fd5b8135611ba781613b45565b600080600080600080600080610100898b031215613efe57600080fd5b883567ffffffffffffffff80821115613f1657600080fd5b613f228c838d01613b67565b995060208b0135985060408b0135975060608b0135915080821115613f4657600080fd5b613f528c838d01613bd6565b965060808b0135915080821115613f6857600080fd5b50613f758b828c01613c31565b945050613f8460a08a01613cbf565b9250613f9260c08a01613cca565b915060e089013590509295985092959890939650565b600060208284031215613fba57600080fd5b5035919050565b60008060208385031215613fd457600080fd5b823567ffffffffffffffff80821115613fec57600080fd5b818501915085601f83011261400057600080fd5b81358181111561400f57600080fd5b8660208260051b850101111561402457600080fd5b60209290920196919550909350505050565b60005b83811015614051578181015183820152602001614039565b50506000910152565b60008151808452614072816020860160208601614036565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169290920160200192915050565b600081518084526020808501808196508360051b8101915082860160005b858110156140ec5782840389526140da84835161405a565b988501989350908401906001016140c2565b5091979650505050505050565b602081526000611ba760208301846140a4565b60008060006060848603121561412157600080fd5b833561412c81613b45565b925060208401359150604084013567ffffffffffffffff81111561414f57600080fd5b61415b86828701613acb565b9150509250925092565b6000806040838503121561417857600080fd5b823561418381613b45565b91506020830135613eb981613b45565b600080600080600080600060e0888a0312156141ae57600080fd5b873567ffffffffffffffff808211156141c657600080fd5b6141d28b838c01613b67565b985060208a0135975060408a0135965060608a01359150808211156141f657600080fd5b6142028b838c01613bd6565b955060808a013591508082111561421857600080fd5b506142258a828b01613c31565b93505060a088013561423681613cb1565b915060c088013561424681613b45565b8091505092959891949750929550565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b818103818111156106b1576106b1614256565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b8183528181602085013750600060208284010152600060207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f840116840101905092915050565b60006101006143708388805182526020810151602083015260408101516040830152606081015173ffffffffffffffffffffffffffffffffffffffff8082166060850152806080840151166080850152505060a081015160a08301525050565b8060c08401526143828184018761405a565b905082810360e08401526122fc8185876142c7565b60006101206143f78389805182526020810151602083015260408101516040830152606081015173ffffffffffffffffffffffffffffffffffffffff8082166060850152806080840151166080850152505060a081015160a08301525050565b8060c08401526144098184018861405a565b905082810360e084015261441e8186886142c7565b9050828103610100840152614433818561405a565b98975050505050505050565b600081518084526020808501945080840160005b8381101561448557815173ffffffffffffffffffffffffffffffffffffffff1687529582019590820190600101614453565b509495945050505050565b600081518084526020808501945080840160005b83811015614485578151875295820195908201906001016144a4565b60a0815260006144d360a083018861443f565b86602084015285604084015282810360608401526144f18186614490565b9150508260808301529695505050505050565b60008083357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe184360301811261453957600080fd5b83018035915067ffffffffffffffff82111561455457600080fd5b6020019150368190038213156139c057600080fd5b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff820361459a5761459a614256565b5060010190565b6000602082840312156145b357600080fd5b5051919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052600160045260246000fd5b600082601f8301126145fa57600080fd5b8151602061460a613aea83613b21565b82815260059290921b8401810191818101908684111561462957600080fd5b8286015b84811015613bcb57805161464081613b45565b835291830191830161462d565b600082601f83011261465e57600080fd5b815161466c613aea82613a85565b81815284602083860101111561468157600080fd5b612cc4826020830160208701614036565b600082601f8301126146a357600080fd5b815160206146b3613aea83613b21565b82815260059290921b840181019181810190868411156146d257600080fd5b8286015b84811015613bcb57805167ffffffffffffffff8111156146f65760008081fd5b6147048986838b010161464d565b8452509183019183016146d6565b600082601f83011261472357600080fd5b81516020614733613aea83613b21565b82815260059290921b8401810191818101908684111561475257600080fd5b8286015b84811015613bcb5780518352918301918301614756565b80516139d881613b45565b80516139d881613cb1565b600080600080600080600060e0888a03121561479e57600080fd5b875167ffffffffffffffff808211156147b657600080fd5b6147c28b838c016145e9565b985060208a0151975060408a01519150808211156147df57600080fd5b6147eb8b838c01614692565b965060608a015191508082111561480157600080fd5b61480d8b838c01614712565b955061481b60808b0161476d565b945061482960a08b01614778565b935060c08a015191508082111561483f57600080fd5b5061484c8a828b0161464d565b91505092959891949750929550565b60e08152600061486e60e083018a61443f565b886020840152876040840152828103606084015261488c8188614490565b905082810360808401526148a081876140a4565b94151560a0840152505073ffffffffffffffffffffffffffffffffffffffff9190911660c09091015295945050505050565b600082516148e4818460208701614036565b9190910192915050565b8051602080830151919081101561492d577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8160200360031b1b821691505b50919050565b73ffffffffffffffffffffffffffffffffffffffff84168152826020820152606060408201526000614968606083018461405a565b95945050505050565b60006020828403121561498357600080fd5b8151611ba781613cb1565b7f416363657373436f6e74726f6c3a206163636f756e74200000000000000000008152600083516149c6816017850160208801614036565b7f206973206d697373696e6720726f6c65200000000000000000000000000000006017918401918201528351614a03816028840160208801614036565b01602801949350505050565b602081526000611ba7602083018461405a565b80820281158282048414176106b1576106b1614256565b808201808211156106b1576106b1614256565b600081614a5b57614a5b614256565b507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0190565b600060208284031215614a9357600080fd5b8151611ba781613b45565b80516dffffffffffffffffffffffffffff811681146139d857600080fd5b600080600060608486031215614ad157600080fd5b614ada84614a9e565b9250614ae860208501614a9e565b9150604084015163ffffffff81168114614b0157600080fd5b809150509250925092565b600082614b42577f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b500490565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052605160045260246000fdfe416464726573733a206c6f772d6c6576656c2064656c65676174652063616c6c206661696c6564a2646970667358221220f057570c576617372fc0a0f3470114b114723b85fcdba6d43afc0d25377818ec64736f6c63430008150033000000000000000000000000c21e4ebd1d92036cb467b53fe3258f219d909eb9000000000000000000000000eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2000000000000000000000000b1b64005b11350a94c4d069eff4215592d98f2e2
Deployed Bytecode
0x6080604052600436106101bb5760003560e01c80639e99ec39116100ec578063d4ee1d901161008a578063e2a4ac2d11610064578063e2a4ac2d146105a9578063e738aa8d146105d6578063f2fde38b146105e9578063f9636f301461060957600080fd5b8063d4ee1d901461053c578063d547741f14610569578063da6689f01461058957600080fd5b8063ac9650d8116100c6578063ac9650d81461048c578063adb88982146104b9578063c75a57e4146104d9578063d00a2d5f1461051c57600080fd5b80639e99ec391461042a578063a217fddf1461044a578063a2625efc1461045f57600080fd5b8063285f94a01161015957806336568abe1161013357806336568abe146103755780634e71e0c8146103955780637fe68917146103aa57806391d14854146103d757600080fd5b8063285f94a0146102d65780632e476337146103285780632f2ff15d1461035557600080fd5b80631696516011610195578063169651601461025357806318137a4114610273578063183d9c9514610293578063248a9ca3146102a657600080fd5b806301ffc9a7146101c757806306135b7c146101fc578063086efdc41461021157600080fd5b366101c257005b600080fd5b3480156101d357600080fd5b506101e76101e236600461393c565b61061e565b60405190151581526020015b60405180910390f35b61020f61020a366004613dc5565b6106b7565b005b34801561021d57600080fd5b506102457fafffb39e42e2a1496bc4305c8783f904fa76641e3895205b6002a03336ee097581565b6040519081526020016101f3565b34801561025f57600080fd5b5061020f61026e366004613e94565b610a27565b34801561027f57600080fd5b5061020f61028e366004613ec4565b610b65565b6102456102a1366004613ee1565b610c3d565b3480156102b257600080fd5b506102456102c1366004613fa8565b60009081526003602052604090206001015490565b3480156102e257600080fd5b506005546103039073ffffffffffffffffffffffffffffffffffffffff1681565b60405173ffffffffffffffffffffffffffffffffffffffff90911681526020016101f3565b34801561033457600080fd5b506002546103039073ffffffffffffffffffffffffffffffffffffffff1681565b34801561036157600080fd5b5061020f610370366004613e94565b610ce7565b34801561038157600080fd5b5061020f610390366004613e94565b610d11565b3480156103a157600080fd5b5061020f610dc9565b3480156103b657600080fd5b506004546103039073ffffffffffffffffffffffffffffffffffffffff1681565b3480156103e357600080fd5b506101e76103f2366004613e94565b600091825260036020908152604080842073ffffffffffffffffffffffffffffffffffffffff93909316845291905290205460ff1690565b34801561043657600080fd5b5061020f610445366004613ec4565b610e5a565b34801561045657600080fd5b50610245600081565b34801561046b57600080fd5b506006546103039073ffffffffffffffffffffffffffffffffffffffff1681565b34801561049857600080fd5b506104ac6104a7366004613fc1565b610f2a565b6040516101f391906140f9565b3480156104c557600080fd5b5061020f6104d4366004613ec4565b61101f565b3480156104e557600080fd5b506103036104f4366004613fa8565b60086020526000908152604090205473ffffffffffffffffffffffffffffffffffffffff1681565b34801561052857600080fd5b5061020f61053736600461410c565b611166565b34801561054857600080fd5b506007546103039073ffffffffffffffffffffffffffffffffffffffff1681565b34801561057557600080fd5b5061020f610584366004613e94565b6111e8565b34801561059557600080fd5b5061020f6105a4366004614165565b61120d565b3480156105b557600080fd5b506001546103039073ffffffffffffffffffffffffffffffffffffffff1681565b6102456105e4366004614193565b611335565b3480156105f557600080fd5b5061020f610604366004613ec4565b6113df565b34801561061557600080fd5b50610245600181565b60007fffffffff0000000000000000000000000000000000000000000000000000000082167f7965db0b0000000000000000000000000000000000000000000000000000000014806106b157507f01ffc9a7000000000000000000000000000000000000000000000000000000007fffffffff000000000000000000000000000000000000000000000000000000008316145b92915050565b6106de826000015183602001518460400151856060015186608001518760a00151306114aa565b5081518051600091906106f390600190614285565b8151811061070357610703614298565b602002602001015190508560ff1660000361085657600061073a73ffffffffffffffffffffffffffffffffffffffff8316306119c0565b6004549091506107649073ffffffffffffffffffffffffffffffffffffffff848116911683611a85565b60045473ffffffffffffffffffffffffffffffffffffffff9081169063f452ed4d90610791908516611aa9565b61079c57600061079e565b825b6040518060c001604052808f81526020018581526020018a81526020018673ffffffffffffffffffffffffffffffffffffffff1681526020018773ffffffffffffffffffffffffffffffffffffffff1681526020018e8152508760e001518d8d6040518663ffffffff1660e01b815260040161081d9493929190614310565b6000604051808303818588803b15801561083657600080fd5b505af115801561084a573d6000803e3d6000fd5b50505050505050610a1c565b8560ff166001036109ea57600061088373ffffffffffffffffffffffffffffffffffffffff8316306119c0565b60045460408601519192506108b29173ffffffffffffffffffffffffffffffffffffffff858116921690611a85565b60045473ffffffffffffffffffffffffffffffffffffffff90811690630421caf0906108df908516611aa9565b6108ea5760006108ec565b825b6040518060c001604052808f8152602001886040015181526020018a81526020018673ffffffffffffffffffffffffffffffffffffffff1681526020018773ffffffffffffffffffffffffffffffffffffffff1681526020018e8152508760e001518d8d8b6040518763ffffffff1660e01b8152600401610971959493929190614397565b6000604051808303818588803b15801561098a57600080fd5b505af115801561099e573d6000803e3d6000fd5b505050505083604001518111156109e3576109e1838560400151836109c39190614285565b73ffffffffffffffffffffffffffffffffffffffff85169190611afc565b505b5050610a1c565b6040517f26667fc400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b505050505050505050565b7fafffb39e42e2a1496bc4305c8783f904fa76641e3895205b6002a03336ee0975610a5181611bae565b82600003610a8b576040517f196de28b00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b73ffffffffffffffffffffffffffffffffffffffff8216610ad8576040517fd92e233d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60008381526008602090815260409182902080547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff86169081179091558251868152918201527f11f5b5361c420666dc3452b8107601e1702f94b951f15bd93c26262c8147874e91015b60405180910390a1505050565b6000610b7081611bae565b73ffffffffffffffffffffffffffffffffffffffff8216610bbd576040517fd92e233d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600480547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff8416908117909155604080519182523360208301527f61b6fe2922f0180b98d305419bf3dcf432f5d8df894388c61c1f599c2194ec1d91015b60405180910390a15050565b6000610c4e89898989898989611335565b6040517f73776170496e53616d65436861696e0000000000000000000000000000000000815290915073ffffffffffffffffffffffffffffffffffffffff8416903390600f0160405180910390207fe3716b48e7d01d727d68472c873c69c2c4407365e4f68b2b6c8dd4569cd16dc78c8c868c89604051610cd39594939291906144c0565b60405180910390a498975050505050505050565b600082815260036020526040902060010154610d0281611bae565b610d0c8383611bbb565b505050565b73ffffffffffffffffffffffffffffffffffffffff81163314610dbb576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602f60248201527f416363657373436f6e74726f6c3a2063616e206f6e6c792072656e6f756e636560448201527f20726f6c657320666f722073656c66000000000000000000000000000000000060648201526084015b60405180910390fd5b610dc58282611caf565b5050565b60075473ffffffffffffffffffffffffffffffffffffffff163314610e1a576040517f48f5c3ed00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b610e25600033611d6a565b6040513381527f85a8c8100c1d48466310240af79644f50cdae7d09cb4820d60dfc5b2462f0fd09060200160405180910390a1565b6000610e6581611bae565b73ffffffffffffffffffffffffffffffffffffffff8216610eb2576040517fd92e233d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600580547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff8416908117909155604080519182523360208301527f45085069ced50a4d2e82656a82ba8f5a1a28694489d8ea262252e40899a930a29101610c31565b60608167ffffffffffffffff811115610f4557610f456139dd565b604051908082528060200260200182016040528015610f7857816020015b6060815260200190600190039081610f635790505b50905060005b8281101561101857610fe830858584818110610f9c57610f9c614298565b9050602002810190610fae9190614504565b8080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250611d7492505050565b828281518110610ffa57610ffa614298565b6020026020010181905250808061101090614569565b915050610f7e565b5092915050565b600061102a81611bae565b73ffffffffffffffffffffffffffffffffffffffff8216611077576040517fd92e233d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b73ffffffffffffffffffffffffffffffffffffffff821660009081527f3ab9add546f7e3b43565da9bc7e65e47b969d3856bb01a7dcac7bc8ff5080cbd602052604090205460ff16156110f6576040517fe4e970d000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6111207fafffb39e42e2a1496bc4305c8783f904fa76641e3895205b6002a03336ee097583611d6a565b60405173ffffffffffffffffffffffffffffffffffffffff831681527fd2b69bde5a989d23ef605a0dd4e0edf7662105058ab69f2559e482857b599ed890602001610c31565b60045473ffffffffffffffffffffffffffffffffffffffff1633148015906111a6575060055473ffffffffffffffffffffffffffffffffffffffff163314155b156111dd576040517f48f5c3ed00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b610d0c838383611d99565b60008281526003602052604090206001015461120381611bae565b610d0c8383611caf565b600061121881611bae565b73ffffffffffffffffffffffffffffffffffffffff8316611265576040517fd92e233d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b73ffffffffffffffffffffffffffffffffffffffff82166112b2576040517fd92e233d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6002805473ffffffffffffffffffffffffffffffffffffffff8581167fffffffffffffffffffffffff0000000000000000000000000000000000000000928316179092556001805492851692909116821790556040519081527fcc4166d40cf68104cdf710f65ce022efd296742868a22b42e4695f89b886363690602001610b58565b6000611346888888888888886114aa565b6040517f737761704d756c746957697468526563697069656e7400000000000000000000815290915073ffffffffffffffffffffffffffffffffffffffff831690339060160160405180910390207fc40fae9d5f584875c393ac222c6f88b6c9dced1e9cc6251483648ac2e902c8b08b8b868b60006040516113cc9594939291906144c0565b60405180910390a4979650505050505050565b60006113ea81611bae565b73ffffffffffffffffffffffffffffffffffffffff8216611437576040517fd92e233d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600780547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff84169081179091556040519081527fcfaaa26691e16e66e73290fc725eee1a6b4e0e693a1640484937aac25ffb55a490602001610c31565b600073ffffffffffffffffffffffffffffffffffffffff82166114f9576040517fd92e233d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8451600189516115099190614285565b14611540576040517fcc513c7200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b826116085761157e8860008151811061155b5761155b614298565b602002602001015173ffffffffffffffffffffffffffffffffffffffff16611aa9565b15801561158a57503415155b156115c1576040517f694b150300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6116083330898b6000815181106115da576115da614298565b602002602001015173ffffffffffffffffffffffffffffffffffffffff1661210c909392919063ffffffff16565b61164b308960008151811061161f5761161f614298565b602002602001015173ffffffffffffffffffffffffffffffffffffffff166119c090919063ffffffff16565b905060008860018a5161165e9190614285565b8151811061166e5761166e614298565b602002602001015190506000600190505b89518110156117a45789818151811061169a5761169a614298565b602002602001015173ffffffffffffffffffffffffffffffffffffffff168a6001836116c69190614285565b815181106116d6576116d6614298565b602002602001015173ffffffffffffffffffffffffffffffffffffffff1603156117925761178f8a611709600184614285565b8151811061171957611719614298565b60200260200101518b838151811061173357611733614298565b60200260200101518560008b60018761174c9190614285565b8151811061175c5761175c614298565b60200260200101518b6001886117729190614285565b8151811061178257611782614298565b60200260200101516122ec565b92505b8061179c81614569565b91505061167f565b506117c48173ffffffffffffffffffffffffffffffffffffffff16611aa9565b156118e1576001546040517f70a0823100000000000000000000000000000000000000000000000000000000815230600482015273ffffffffffffffffffffffffffffffffffffffff909116906370a0823190602401602060405180830381865afa158015611837573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061185b91906145a1565b6001546040517f2e1a7d4d0000000000000000000000000000000000000000000000000000000081526004810183905291935073ffffffffffffffffffffffffffffffffffffffff1690632e1a7d4d90602401600060405180830381600087803b1580156118c857600080fd5b505af11580156118dc573d6000803e3d6000fd5b505050505b73ffffffffffffffffffffffffffffffffffffffff831630146119b457600061192073ffffffffffffffffffffffffffffffffffffffff8316856119c0565b905061194373ffffffffffffffffffffffffffffffffffffffff83168585611afc565b50600061196673ffffffffffffffffffffffffffffffffffffffff8416866119c0565b905060006119748383614285565b90508981116119af576040517f1fbaba3500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b935050505b50979650505050505050565b60006119cb83611aa9565b156119ee575073ffffffffffffffffffffffffffffffffffffffff8116316106b1565b6040517f70a0823100000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff83811660048301528416906370a0823190602401602060405180830381865afa158015611a5a573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611a7e91906145a1565b90506106b1565b611a8e83611aa9565b610d0c57611a9e83836000612307565b610d0c838383612307565b600073ffffffffffffffffffffffffffffffffffffffff821615806106b1575073ffffffffffffffffffffffffffffffffffffffff821673eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee1492915050565b600081600003611b0e57506001611ba7565b611b1784611aa9565b15611b985760008373ffffffffffffffffffffffffffffffffffffffff168360405160006040518083038185875af1925050503d8060008114611b76576040519150601f19603f3d011682016040523d82523d6000602084013e611b7b565b606091505b5090915050600181151514611b9257611b926145ba565b50611ba7565b611ba384848461249d565b5060015b9392505050565b611bb8813361262c565b50565b600082815260036020908152604080832073ffffffffffffffffffffffffffffffffffffffff8516845290915290205460ff16610dc557600082815260036020908152604080832073ffffffffffffffffffffffffffffffffffffffff85168452909152902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00166001179055611c513390565b73ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff16837f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d60405160405180910390a45050565b600082815260036020908152604080832073ffffffffffffffffffffffffffffffffffffffff8516845290915290205460ff1615610dc557600082815260036020908152604080832073ffffffffffffffffffffffffffffffffffffffff8516808552925280832080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0016905551339285917ff6391f5c32d9c69d2a47ea670b442974b53935d1edc7fd64eb21e047a839171b9190a45050565b610dc58282611bbb565b6060611ba78383604051806060016040528060278152602001614b77602791396126e6565b600080600080600080600087806020019051810190611db89190614783565b965096509650965096509650965086600081518110611dd957611dd9614298565b602002602001015173ffffffffffffffffffffffffffffffffffffffff168a73ffffffffffffffffffffffffffffffffffffffff1614611e45576040517f198b098900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b606060003073ffffffffffffffffffffffffffffffffffffffff1663e738aa8d60e01b8a8d8b8a8c60018c604051602401611e86979695949392919061485b565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529181526020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fffffffff00000000000000000000000000000000000000000000000000000000909416939093179092529051611f0f91906148d2565b6000604051808303816000865af19150503d8060008114611f4c576040519150601f19603f3d011682016040523d82523d6000602084013e611f51565b606091505b509250905080611fa257611fa0858c8b600081518110611f7357611f73614298565b602002602001015173ffffffffffffffffffffffffffffffffffffffff16611afc9092919063ffffffff16565b505b83156120fe57600081611fb5578b611fbe565b611fbe836148ee565b9050600082611fcd578d611ff5565b8a60018c51611fdc9190614285565b81518110611fec57611fec614298565b60200260200101515b90508673ffffffffffffffffffffffffffffffffffffffff1663d00a2d5f60e01b82848860405160240161202b93929190614933565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529181526020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fffffffff000000000000000000000000000000000000000000000000000000009094169390931790925290516120b491906148d2565b6000604051808303816000865af19150503d80600081146120f1576040519150601f19603f3d011682016040523d82523d6000602084013e6120f6565b606091505b509450925050505b505050505050505050505050565b80156122e65761211b84611aa9565b156122da5773ffffffffffffffffffffffffffffffffffffffff8316331480156121455750803410155b6121d1576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602a60248201527f57726f6e67207573616765206f66204554482e756e6976657273616c5472616e60448201527f7366657246726f6d2829000000000000000000000000000000000000000000006064820152608401610db2565b73ffffffffffffffffffffffffffffffffffffffff821630146122665760008273ffffffffffffffffffffffffffffffffffffffff168260405160006040518083038185875af1925050503d8060008114612248576040519150601f19603f3d011682016040523d82523d6000602084013e61224d565b606091505b5090915050600181151514612264576122646145ba565b505b803411156122d55760003361227b348461276b565b604051600081818185875af1925050503d80600081146122b7576040519150601f19603f3d011682016040523d82523d6000602084013e6122bc565b606091505b50909150506001811515146122d3576122d36145ba565b505b6122e6565b6122e684848484612777565b50505050565b60006122fc878787878787612916565b979650505050505050565b6040805173ffffffffffffffffffffffffffffffffffffffff8481166024830152604480830185905283518084039091018152606490920183526020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167f095ea7b300000000000000000000000000000000000000000000000000000000179052915160009283929087169161239e91906148d2565b6000604051808303816000865af19150503d80600081146123db576040519150601f19603f3d011682016040523d82523d6000602084013e6123e0565b606091505b509150915081801561240a57508051158061240a57508080602001905181019061240a9190614971565b612496576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602b60248201527f5472616e7366657248656c7065723a3a73616665417070726f76653a2061707060448201527f726f7665206661696c65640000000000000000000000000000000000000000006064820152608401610db2565b5050505050565b6040805173ffffffffffffffffffffffffffffffffffffffff8481166024830152604480830185905283518084039091018152606490920183526020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fa9059cbb00000000000000000000000000000000000000000000000000000000179052915160009283929087169161253491906148d2565b6000604051808303816000865af19150503d8060008114612571576040519150601f19603f3d011682016040523d82523d6000602084013e612576565b606091505b50915091508180156125a05750805115806125a05750808060200190518101906125a09190614971565b612496576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602d60248201527f5472616e7366657248656c7065723a3a736166655472616e736665723a20747260448201527f616e73666572206661696c6564000000000000000000000000000000000000006064820152608401610db2565b600082815260036020908152604080832073ffffffffffffffffffffffffffffffffffffffff8516845290915290205460ff16610dc55761266c816129c2565b6126778360206129e1565b60405160200161268892919061498e565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0818403018152908290527f08c379a0000000000000000000000000000000000000000000000000000000008252610db291600401614a0f565b60606000808573ffffffffffffffffffffffffffffffffffffffff168560405161271091906148d2565b600060405180830381855af49150503d806000811461274b576040519150601f19603f3d011682016040523d82523d6000602084013e612750565b606091505b509150915061276186838387612c24565b9695505050505050565b6000611ba78284614285565b6040805173ffffffffffffffffffffffffffffffffffffffff85811660248301528481166044830152606480830185905283518084039091018152608490920183526020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167f23b872dd00000000000000000000000000000000000000000000000000000000179052915160009283929088169161281691906148d2565b6000604051808303816000865af19150503d8060008114612853576040519150601f19603f3d011682016040523d82523d6000602084013e612858565b606091505b50915091508180156128825750805115806128825750808060200190518101906128829190614971565b61290e576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152603160248201527f5472616e7366657248656c7065723a3a7472616e7366657246726f6d3a20747260448201527f616e7366657246726f6d206661696c65640000000000000000000000000000006064820152608401610db2565b505050505050565b60008573ffffffffffffffffffffffffffffffffffffffff168773ffffffffffffffffffffffffffffffffffffffff1603612952575083612761565b61393261295e84612ccc565b9050600061298273ffffffffffffffffffffffffffffffffffffffff8a16306119c0565b905061299589898387898763ffffffff16565b6129b573ffffffffffffffffffffffffffffffffffffffff8916306119c0565b9998505050505050505050565b60606106b173ffffffffffffffffffffffffffffffffffffffff831660145b606060006129f0836002614a22565b6129fb906002614a39565b67ffffffffffffffff811115612a1357612a136139dd565b6040519080825280601f01601f191660200182016040528015612a3d576020820181803683370190505b5090507f300000000000000000000000000000000000000000000000000000000000000081600081518110612a7457612a74614298565b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a9053507f780000000000000000000000000000000000000000000000000000000000000081600181518110612ad757612ad7614298565b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a9053506000612b13846002614a22565b612b1e906001614a39565b90505b6001811115612bbb577f303132333435363738396162636465660000000000000000000000000000000085600f1660108110612b5f57612b5f614298565b1a60f81b828281518110612b7557612b75614298565b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a90535060049490941c93612bb481614a4c565b9050612b21565b508315611ba7576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820181905260248201527f537472696e67733a20686578206c656e67746820696e73756666696369656e746044820152606401610db2565b60608315612cba578251600003612cb35773ffffffffffffffffffffffffffffffffffffffff85163b612cb3576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000006044820152606401610db2565b5081612cc4565b612cc48383612d0a565b949350505050565b6139326103e982108015612ce1575060018210155b15612cef5750612d4e919050565b816107d203612d015750612d5a919050565b50612fe3919050565b815115612d1a5781518083602001fd5b806040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610db29190614a0f565b61290e8585858461314f565b60008181526008602052604090205473ffffffffffffffffffffffffffffffffffffffff1680612db6576040517fd92e233d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b612dd58673ffffffffffffffffffffffffffffffffffffffff16611aa9565b15612e5e57600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663d0e30db0856040518263ffffffff1660e01b81526004016000604051808303818588803b158015612e4457600080fd5b505af1158015612e58573d6000803e3d6000fd5b50505050505b6000612e7f8773ffffffffffffffffffffffffffffffffffffffff16611aa9565b612e895786612ea3565b60015473ffffffffffffffffffffffffffffffffffffffff165b9050612f358273ffffffffffffffffffffffffffffffffffffffff1663d2c4b5986040518163ffffffff1660e01b8152600401602060405180830381865afa158015612ef3573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612f179190614a81565b73ffffffffffffffffffffffffffffffffffffffff83169087611a85565b60008273ffffffffffffffffffffffffffffffffffffffff1685604051612f5c91906148d2565b6000604051808303816000865af19150503d8060008114612f99576040519150601f19603f3d011682016040523d82523d6000602084013e612f9e565b606091505b5050905080612fd9576040517f5987947500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5050505050505050565b60008181526008602052604090205473ffffffffffffffffffffffffffffffffffffffff168061303f576040517fd92e233d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b61305e8673ffffffffffffffffffffffffffffffffffffffff16611aa9565b156130e757600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663d0e30db0856040518263ffffffff1660e01b81526004016000604051808303818588803b1580156130cd57600080fd5b505af11580156130e1573d6000803e3d6000fd5b50505050505b60006131088773ffffffffffffffffffffffffffffffffffffffff16611aa9565b613112578661312c565b60015473ffffffffffffffffffffffffffffffffffffffff165b9050612f3573ffffffffffffffffffffffffffffffffffffffff82168387611a85565b60006131708573ffffffffffffffffffffffffffffffffffffffff16611aa9565b156131f957600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663d0e30db0846040518263ffffffff1660e01b81526004016000604051808303818588803b1580156131df57600080fd5b505af11580156131f3573d6000803e3d6000fd5b50505050505b60008281526008602052604090205473ffffffffffffffffffffffffffffffffffffffff1680613285576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f52413a2045786368616e6765206e6f7420666f756e64000000000000000000006044820152606401610db2565b8060006132a773ffffffffffffffffffffffffffffffffffffffff8916611aa9565b6132b157876132cb565b60015473ffffffffffffffffffffffffffffffffffffffff165b905060006132ee8873ffffffffffffffffffffffffffffffffffffffff16611aa9565b6132f85787613312565b60015473ffffffffffffffffffffffffffffffffffffffff165b90508073ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff16036133535786945050505050612cc4565b6040517fe6a4390500000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff838116600483015282811660248301526000919085169063e6a4390590604401602060405180830381865afa1580156133cb573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906133ef9190614a81565b905073ffffffffffffffffffffffffffffffffffffffff811661343e576040517f2083cd4000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60008061346373ffffffffffffffffffffffffffffffffffffffff841686868d613702565b9199509250905081156134d5578273ffffffffffffffffffffffffffffffffffffffff1663fff6cae96040518163ffffffff1660e01b8152600401600060405180830381600087803b1580156134b857600080fd5b505af11580156134cc573d6000803e3d6000fd5b50505050613561565b8015613561576006546040517fbc25cf7700000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff91821660048201529084169063bc25cf7790602401600060405180830381600087803b15801561354857600080fd5b505af115801561355c573d6000803e3d6000fd5b505050505b61358273ffffffffffffffffffffffffffffffffffffffff8616848c611afc565b508373ffffffffffffffffffffffffffffffffffffffff168573ffffffffffffffffffffffffffffffffffffffff161015613657576040517f022c0d9f000000000000000000000000000000000000000000000000000000008152600060048201819052602482018a905230604483015260806064830152608482015273ffffffffffffffffffffffffffffffffffffffff84169063022c0d9f9060a401600060405180830381600087803b15801561363a57600080fd5b505af115801561364e573d6000803e3d6000fd5b505050506136f3565b6040517f022c0d9f0000000000000000000000000000000000000000000000000000000081526004810189905260006024820181905230604483015260806064830152608482015273ffffffffffffffffffffffffffffffffffffffff84169063022c0d9f9060a401600060405180830381600087803b1580156136da57600080fd5b505af11580156136ee573d6000803e3d6000fd5b505050505b50505050505050949350505050565b600080808061372773ffffffffffffffffffffffffffffffffffffffff8816896119c0565b9050600061374b73ffffffffffffffffffffffffffffffffffffffff88168a6119c0565b90506000808a73ffffffffffffffffffffffffffffffffffffffff16630902f1ac6040518163ffffffff1660e01b8152600401606060405180830381865afa15801561379b573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906137bf9190614abc565b50915091508873ffffffffffffffffffffffffffffffffffffffff168a73ffffffffffffffffffffffffffffffffffffffff1611156137fa57905b816dffffffffffffffffffffffffffff168410806138275750806dffffffffffffffffffffffffffff1683105b95508515801561385f5750816dffffffffffffffffffffffffffff1684118061385f5750806dffffffffffffffffffffffffffff1683115b9450600061386f896103e56138f8565b9050600061389761389086856dffffffffffffffffffffffffffff16613904565b83906138f8565b905060006138cb836138c56103e86138bf8b8a6dffffffffffffffffffffffffffff16613904565b906138f8565b9061391a565b905080156138e2576138dd8282613926565b6138e5565b60005b9950505050505050509450945094915050565b6000611ba78284614a22565b60008183106139135781611ba7565b5090919050565b6000611ba78284614a39565b6000611ba78284614b0c565b61393a614b47565b565b60006020828403121561394e57600080fd5b81357fffffffff0000000000000000000000000000000000000000000000000000000081168114611ba757600080fd5b60008083601f84011261399057600080fd5b50813567ffffffffffffffff8111156139a857600080fd5b6020830191508360208285010111156139c057600080fd5b9250929050565b803560ff811681146139d857600080fd5b919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b604051610100810167ffffffffffffffff81118282101715613a3057613a306139dd565b60405290565b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016810167ffffffffffffffff81118282101715613a7d57613a7d6139dd565b604052919050565b600067ffffffffffffffff821115613a9f57613a9f6139dd565b50601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe01660200190565b600082601f830112613adc57600080fd5b8135613aef613aea82613a85565b613a36565b818152846020838601011115613b0457600080fd5b816020850160208301376000918101602001919091529392505050565b600067ffffffffffffffff821115613b3b57613b3b6139dd565b5060051b60200190565b73ffffffffffffffffffffffffffffffffffffffff81168114611bb857600080fd5b600082601f830112613b7857600080fd5b81356020613b88613aea83613b21565b82815260059290921b84018101918181019086841115613ba757600080fd5b8286015b84811015613bcb578035613bbe81613b45565b8352918301918301613bab565b509695505050505050565b600082601f830112613be757600080fd5b81356020613bf7613aea83613b21565b82815260059290921b84018101918181019086841115613c1657600080fd5b8286015b84811015613bcb5780358352918301918301613c1a565b600082601f830112613c4257600080fd5b81356020613c52613aea83613b21565b82815260059290921b84018101918181019086841115613c7157600080fd5b8286015b84811015613bcb57803567ffffffffffffffff811115613c955760008081fd5b613ca38986838b0101613acb565b845250918301918301613c75565b8015158114611bb857600080fd5b80356139d881613cb1565b80356139d881613b45565b60006101008284031215613ce857600080fd5b613cf0613a0c565b9050813567ffffffffffffffff80821115613d0a57600080fd5b613d1685838601613b67565b835260208401356020840152604084013560408401526060840135915080821115613d4057600080fd5b613d4c85838601613bd6565b60608401526080840135915080821115613d6557600080fd5b613d7185838601613c31565b6080840152613d8260a08501613cbf565b60a0840152613d9360c08501613cca565b60c084015260e0840135915080821115613dac57600080fd5b50613db984828501613acb565b60e08301525092915050565b60008060008060008060008060006101008a8c031215613de457600080fd5b8935985060208a0135975060408a013567ffffffffffffffff80821115613e0a57600080fd5b613e168d838e0161397e565b9099509750879150613e2a60608d016139c7565b965060808c0135955060a08c0135915080821115613e4757600080fd5b613e538d838e01613acb565b945060c08c0135915080821115613e6957600080fd5b50613e768c828d01613cd5565b925050613e8560e08b01613cca565b90509295985092959850929598565b60008060408385031215613ea757600080fd5b823591506020830135613eb981613b45565b809150509250929050565b600060208284031215613ed657600080fd5b8135611ba781613b45565b600080600080600080600080610100898b031215613efe57600080fd5b883567ffffffffffffffff80821115613f1657600080fd5b613f228c838d01613b67565b995060208b0135985060408b0135975060608b0135915080821115613f4657600080fd5b613f528c838d01613bd6565b965060808b0135915080821115613f6857600080fd5b50613f758b828c01613c31565b945050613f8460a08a01613cbf565b9250613f9260c08a01613cca565b915060e089013590509295985092959890939650565b600060208284031215613fba57600080fd5b5035919050565b60008060208385031215613fd457600080fd5b823567ffffffffffffffff80821115613fec57600080fd5b818501915085601f83011261400057600080fd5b81358181111561400f57600080fd5b8660208260051b850101111561402457600080fd5b60209290920196919550909350505050565b60005b83811015614051578181015183820152602001614039565b50506000910152565b60008151808452614072816020860160208601614036565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169290920160200192915050565b600081518084526020808501808196508360051b8101915082860160005b858110156140ec5782840389526140da84835161405a565b988501989350908401906001016140c2565b5091979650505050505050565b602081526000611ba760208301846140a4565b60008060006060848603121561412157600080fd5b833561412c81613b45565b925060208401359150604084013567ffffffffffffffff81111561414f57600080fd5b61415b86828701613acb565b9150509250925092565b6000806040838503121561417857600080fd5b823561418381613b45565b91506020830135613eb981613b45565b600080600080600080600060e0888a0312156141ae57600080fd5b873567ffffffffffffffff808211156141c657600080fd5b6141d28b838c01613b67565b985060208a0135975060408a0135965060608a01359150808211156141f657600080fd5b6142028b838c01613bd6565b955060808a013591508082111561421857600080fd5b506142258a828b01613c31565b93505060a088013561423681613cb1565b915060c088013561424681613b45565b8091505092959891949750929550565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b818103818111156106b1576106b1614256565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b8183528181602085013750600060208284010152600060207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f840116840101905092915050565b60006101006143708388805182526020810151602083015260408101516040830152606081015173ffffffffffffffffffffffffffffffffffffffff8082166060850152806080840151166080850152505060a081015160a08301525050565b8060c08401526143828184018761405a565b905082810360e08401526122fc8185876142c7565b60006101206143f78389805182526020810151602083015260408101516040830152606081015173ffffffffffffffffffffffffffffffffffffffff8082166060850152806080840151166080850152505060a081015160a08301525050565b8060c08401526144098184018861405a565b905082810360e084015261441e8186886142c7565b9050828103610100840152614433818561405a565b98975050505050505050565b600081518084526020808501945080840160005b8381101561448557815173ffffffffffffffffffffffffffffffffffffffff1687529582019590820190600101614453565b509495945050505050565b600081518084526020808501945080840160005b83811015614485578151875295820195908201906001016144a4565b60a0815260006144d360a083018861443f565b86602084015285604084015282810360608401526144f18186614490565b9150508260808301529695505050505050565b60008083357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe184360301811261453957600080fd5b83018035915067ffffffffffffffff82111561455457600080fd5b6020019150368190038213156139c057600080fd5b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff820361459a5761459a614256565b5060010190565b6000602082840312156145b357600080fd5b5051919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052600160045260246000fd5b600082601f8301126145fa57600080fd5b8151602061460a613aea83613b21565b82815260059290921b8401810191818101908684111561462957600080fd5b8286015b84811015613bcb57805161464081613b45565b835291830191830161462d565b600082601f83011261465e57600080fd5b815161466c613aea82613a85565b81815284602083860101111561468157600080fd5b612cc4826020830160208701614036565b600082601f8301126146a357600080fd5b815160206146b3613aea83613b21565b82815260059290921b840181019181810190868411156146d257600080fd5b8286015b84811015613bcb57805167ffffffffffffffff8111156146f65760008081fd5b6147048986838b010161464d565b8452509183019183016146d6565b600082601f83011261472357600080fd5b81516020614733613aea83613b21565b82815260059290921b8401810191818101908684111561475257600080fd5b8286015b84811015613bcb5780518352918301918301614756565b80516139d881613b45565b80516139d881613cb1565b600080600080600080600060e0888a03121561479e57600080fd5b875167ffffffffffffffff808211156147b657600080fd5b6147c28b838c016145e9565b985060208a0151975060408a01519150808211156147df57600080fd5b6147eb8b838c01614692565b965060608a015191508082111561480157600080fd5b61480d8b838c01614712565b955061481b60808b0161476d565b945061482960a08b01614778565b935060c08a015191508082111561483f57600080fd5b5061484c8a828b0161464d565b91505092959891949750929550565b60e08152600061486e60e083018a61443f565b886020840152876040840152828103606084015261488c8188614490565b905082810360808401526148a081876140a4565b94151560a0840152505073ffffffffffffffffffffffffffffffffffffffff9190911660c09091015295945050505050565b600082516148e4818460208701614036565b9190910192915050565b8051602080830151919081101561492d577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8160200360031b1b821691505b50919050565b73ffffffffffffffffffffffffffffffffffffffff84168152826020820152606060408201526000614968606083018461405a565b95945050505050565b60006020828403121561498357600080fd5b8151611ba781613cb1565b7f416363657373436f6e74726f6c3a206163636f756e74200000000000000000008152600083516149c6816017850160208801614036565b7f206973206d697373696e6720726f6c65200000000000000000000000000000006017918401918201528351614a03816028840160208801614036565b01602801949350505050565b602081526000611ba7602083018461405a565b80820281158282048414176106b1576106b1614256565b808201808211156106b1576106b1614256565b600081614a5b57614a5b614256565b507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0190565b600060208284031215614a9357600080fd5b8151611ba781613b45565b80516dffffffffffffffffffffffffffff811681146139d857600080fd5b600080600060608486031215614ad157600080fd5b614ada84614a9e565b9250614ae860208501614a9e565b9150604084015163ffffffff81168114614b0157600080fd5b809150509250925092565b600082614b42577f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b500490565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052605160045260246000fdfe416464726573733a206c6f772d6c6576656c2064656c65676174652063616c6c206661696c6564a2646970667358221220f057570c576617372fc0a0f3470114b114723b85fcdba6d43afc0d25377818ec64736f6c63430008150033
Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)
000000000000000000000000c21e4ebd1d92036cb467b53fe3258f219d909eb9000000000000000000000000eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2000000000000000000000000b1b64005b11350a94c4d069eff4215592d98f2e2
-----Decoded View---------------
Arg [0] : _assetForwarderAddress (address): 0xC21e4ebD1d92036Cb467b53fE3258F219d909Eb9
Arg [1] : _native (address): 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE
Arg [2] : _wrappedNative (address): 0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2
Arg [3] : _univ2SkimAddress (address): 0xB1b64005B11350a94c4D069eff4215592d98F2E2
-----Encoded View---------------
4 Constructor Arguments found :
Arg [0] : 000000000000000000000000c21e4ebd1d92036cb467b53fe3258f219d909eb9
Arg [1] : 000000000000000000000000eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee
Arg [2] : 000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2
Arg [3] : 000000000000000000000000b1b64005b11350a94c4d069eff4215592d98f2e2
Loading...
Loading
Loading...
Loading
Multichain Portfolio | 30 Chains
Chain | Token | Portfolio % | Price | Amount | Value |
---|---|---|---|---|---|
ETH | 100.00% | $0.999928 | 7.7022 | $7.7 |
Loading...
Loading
[ Download: CSV Export ]
[ 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.