Contract
0x094cab67fbb074b7797ab0975c69a341b7a40641
1
Contract Overview
My Name Tag:
Not Available
[ Download CSV Export ]
Latest 25 internal transaction
[ Download CSV Export ]
Contract Name:
ZigZagExchange
Compiler Version
v0.8.10+commit.fc410830
Optimization Enabled:
Yes with 1000 runs
Other Settings:
default evmVersion
Contract Source Code (Solidity Standard Json-Input format)
//SPDX-License-Identifier: MIT pragma solidity ^0.8.0; import './LibOrder.sol'; import { IERC20 } from '@openzeppelin/contracts/token/ERC20/IERC20.sol'; import { EIP712 } from '@openzeppelin/contracts/utils/cryptography/EIP712.sol'; import { SignatureChecker } from '@openzeppelin/contracts/utils/cryptography/SignatureChecker.sol'; // import "hardhat/console.sol"; interface IWETH9 { function depositTo(address) external payable; function withdrawTo(address, uint256) external; function balanceOf(address) external view returns (uint256); } contract ZigZagExchange is EIP712 { event Swap( address maker, address indexed taker, address indexed makerSellToken, address indexed takerSellToken, uint256 makerSellAmount, uint256 takerSellAmount, uint256 makerVolumeFee, uint256 takerVolumeFee ); event CancelOrder(bytes32 indexed orderHash); event OrderStatus(bytes32 indexed orderHash, uint filled, uint remaining); mapping(bytes32 => uint256) public filled; mapping(bytes32 => bool) public cancelled; // fees address immutable FEE_ADDRESS; address immutable WETH_ADDRESS; address immutable EXCHANGE_ADDRESS; address constant ETH_ADDRESS = address(0); uint256 maker_fee_numerator = 0; uint256 maker_fee_denominator = 10000; uint256 taker_fee_numerator = 5; uint256 taker_fee_denominator = 10000; // initialize fee address constructor(string memory name, string memory version, address fee_address, address weth_address) EIP712(name, version) { FEE_ADDRESS = fee_address; WETH_ADDRESS = weth_address; EXCHANGE_ADDRESS = address(this); } receive() external payable {} /// @notice Cancel an order so it can no longer be filled /// @param order order that should get cancelled function cancelOrder(LibOrder.Order calldata order) public { require(msg.sender == order.user, 'only user may cancel order'); bytes32 orderHash = LibOrder.getOrderHash(order); require(filled[orderHash] < order.sellAmount, 'order already filled'); cancelled[orderHash] = true; emit CancelOrder(orderHash); } function fillOrderRouteETH( LibOrder.Order[] calldata makerOrder, bytes[] calldata makerSignature, uint takerAmount, bool fillAvailable ) public payable returns (bool) { require(makerOrder.length == makerSignature.length, 'Length of makerOrders and makerSignatures does not match'); require(makerOrder.length > 0, 'Length of makerOrders can not be 0'); if (makerOrder.length == 1) { return fillOrderExactInputETH(makerOrder[0], makerSignature[0], takerAmount, fillAvailable); } uint256 n = makerOrder.length - 1; for (uint i = 0; i <= n; i++) { require(i == 0 || makerOrder[i - 1].sellToken == makerOrder[i].buyToken, 'Tokens on route do not match'); // takerAmountOut = takerAmountIn * price takerAmount = (takerAmount * makerOrder[i].sellAmount) / makerOrder[i].buyAmount; // first or last tx might need to (un-)wrap ETH if (i == 0 && makerOrder[0].buyToken == WETH_ADDRESS) { _fillOrderETH(makerOrder[0], makerSignature[0], msg.sender, EXCHANGE_ADDRESS, takerAmount, fillAvailable); } else if (i == n && makerOrder[n].sellToken == WETH_ADDRESS) { _fillOrderETH(makerOrder[n], makerSignature[n], EXCHANGE_ADDRESS, msg.sender, takerAmount, fillAvailable); } else { _fillOrder( makerOrder[i], makerSignature[i], i == 0 ? msg.sender : EXCHANGE_ADDRESS, i == n ? msg.sender : EXCHANGE_ADDRESS, makerOrder[i].sellToken, makerOrder[i].buyToken, takerAmount, fillAvailable ); } // adjust the takerAmountOut by the tx fee paid by the taker takerAmount = takerAmount - (takerAmount * taker_fee_numerator) / taker_fee_denominator; } _refundETH(); return true; } function fillOrderRoute( LibOrder.Order[] calldata makerOrder, bytes[] calldata makerSignature, uint takerAmount, bool fillAvailable ) public payable returns (bool) { require(makerOrder.length == makerSignature.length, 'Length of makerOrders and makerSignatures does not match'); require(makerOrder.length > 0, 'Length of makerOrders can not be 0'); if (makerOrder.length == 1) { return fillOrderExactInput(makerOrder[0], makerSignature[0], takerAmount, fillAvailable); } uint256 n = makerOrder.length - 1; for (uint i = 0; i <= n; i++) { require(i == 0 || makerOrder[i - 1].sellToken == makerOrder[i].buyToken, 'Tokens on route do not match'); // takerAmountOut = takerAmountIn * price takerAmount = (takerAmount * makerOrder[i].sellAmount) / makerOrder[i].buyAmount; _fillOrder( makerOrder[i], makerSignature[i], i == 0 ? msg.sender : EXCHANGE_ADDRESS, i == n ? msg.sender : EXCHANGE_ADDRESS, makerOrder[i].sellToken, makerOrder[i].buyToken, takerAmount, fillAvailable ); // adjust the takerAmountOut by the tx fee paid by the taker takerAmount = takerAmount - (takerAmount * taker_fee_numerator) / taker_fee_denominator; } return true; } /// @notice Fills an order with an exact amount to sell, taking or returning ETH /// @param makerOrder Order that will be used to make this swap, buyToken or sellToken must be WETH /// @param makerSignature Signature for the order used /// @param takerSellAmount amount send from the sender to the maker /// @return returns true if successfull function fillOrderExactInputETH( LibOrder.Order calldata makerOrder, bytes calldata makerSignature, uint takerSellAmount, bool fillAvailable ) public payable returns (bool) { uint takerBuyAmount = (takerSellAmount * makerOrder.sellAmount) / makerOrder.buyAmount; _fillOrderETH(makerOrder, makerSignature, msg.sender, msg.sender, takerBuyAmount, fillAvailable); _refundETH(); return true; } /// @notice Fills an order with an exact amount to buy, taking or returning ETH /// @param makerOrder Order that will be used to make this swap, buyToken or sellToken must be WETH /// @param makerSignature Signature for the order used /// @param takerBuyAmount amount send to the sender from the maker /// @param fillAvailable Should the maximum buyAmount possible be used /// @return returns true if successfull function fillOrderExactOutputETH( LibOrder.Order calldata makerOrder, bytes calldata makerSignature, uint takerBuyAmount, bool fillAvailable ) public payable returns (bool) { // add the takerFee to the buy amount to recive the exact amount after fees takerBuyAmount = (takerBuyAmount * taker_fee_denominator) / (taker_fee_denominator - taker_fee_numerator); _fillOrderETH(makerOrder, makerSignature, msg.sender, msg.sender, takerBuyAmount, fillAvailable); _refundETH(); return true; } function _fillOrderETH( LibOrder.Order calldata makerOrder, bytes calldata makerSignature, address taker, address takerReciver, uint takerBuyAmountAdjusted, bool fillAvailable ) internal { require(makerOrder.buyToken == WETH_ADDRESS || makerOrder.sellToken == WETH_ADDRESS, 'Either buy or sell token should be WETH'); if (makerOrder.buyToken == WETH_ADDRESS) { _fillOrder(makerOrder, makerSignature, taker, takerReciver, makerOrder.sellToken, ETH_ADDRESS, takerBuyAmountAdjusted, fillAvailable); } else { _fillOrder(makerOrder, makerSignature, taker, takerReciver, ETH_ADDRESS, makerOrder.buyToken, takerBuyAmountAdjusted, fillAvailable); } } /// @notice Fills an order with an exact amount to sell /// @param makerOrder Order that will be used to make this swap /// @param makerSignature Signature for the order used /// @param takerSellAmount amount send from the sender to the maker /// @return returns true if successfull function fillOrderExactInput( LibOrder.Order calldata makerOrder, bytes calldata makerSignature, uint takerSellAmount, bool fillAvailable ) public returns (bool) { uint takerBuyAmount = (takerSellAmount * makerOrder.sellAmount) / makerOrder.buyAmount; _fillOrder( makerOrder, makerSignature, msg.sender, msg.sender, makerOrder.sellToken, makerOrder.buyToken, takerBuyAmount, fillAvailable ); return true; } /// @notice Fills an order with an exact amount to buy /// @param makerOrder Order that will be used to make this swap /// @param makerSignature Signature for the order used /// @param takerBuyAmount amount send to the sender from the maker /// @param fillAvailable Should the maximum buyAmount possible be used /// @return returns true if successfull function fillOrderExactOutput( LibOrder.Order calldata makerOrder, bytes calldata makerSignature, uint takerBuyAmount, bool fillAvailable ) public returns (bool) { // add the takerFee to the buy amount to recive the exact amount after fees takerBuyAmount = (takerBuyAmount * taker_fee_denominator) / (taker_fee_denominator - taker_fee_numerator); _fillOrder( makerOrder, makerSignature, msg.sender, msg.sender, makerOrder.sellToken, makerOrder.buyToken, takerBuyAmount, fillAvailable ); return true; } function _fillOrder( LibOrder.Order calldata makerOrder, bytes calldata makerSignature, address taker, address takerReciver, address sellToken, address buyToken, uint takerBuyAmountAdjusted, bool fillAvailable ) internal { require(takerReciver != ETH_ADDRESS, "Can't recive to zero address"); //validate signature LibOrder.OrderInfo memory makerOrderInfo = getOpenOrder(makerOrder); require(_isValidSignatureHash(makerOrder.user, makerOrderInfo.orderHash, makerSignature), 'invalid maker signature'); uint takerSellAmount; { // prevent Stack too deep uint availableTakerSellSize = makerOrder.sellAmount - makerOrderInfo.orderSellFilledAmount; if (fillAvailable && availableTakerSellSize < takerBuyAmountAdjusted) takerBuyAmountAdjusted = availableTakerSellSize; takerSellAmount = (takerBuyAmountAdjusted * makerOrder.buyAmount) / makerOrder.sellAmount; require(takerBuyAmountAdjusted <= availableTakerSellSize, 'amount exceeds available size'); } // mark fills in storage uint makerOrderFilled = makerOrderInfo.orderSellFilledAmount + takerBuyAmountAdjusted; filled[makerOrderInfo.orderHash] = makerOrderFilled; // The fee gets subtracted from the buy amounts so they deduct from the total instead of adding on to it // The maker fee comes out of the taker sell quantity, so the maker ends up with less // The taker fee comes out of the maker sell quantity, so the taker ends up with less // makerFee = (takerSellAmount * maker_fee_numerator) / maker_fee_denominator // takerFee = (takerBuyAmountAdjusted * taker_fee_numerator) / taker_fee_denominator _settleMatchedOrders( makerOrder.user, taker, takerReciver, sellToken, buyToken, takerBuyAmountAdjusted, takerSellAmount, (takerSellAmount * maker_fee_numerator) / maker_fee_denominator, (takerBuyAmountAdjusted * taker_fee_numerator) / taker_fee_denominator ); emit OrderStatus(makerOrderInfo.orderHash, makerOrderFilled, makerOrder.sellAmount - makerOrderFilled); } function _settleMatchedOrders( address maker, address taker, address takerReciver, address makerSellToken, address takerSellToken, uint makerSellAmount, uint takerSellAmount, uint makerFee, uint takerFee ) internal { if (takerSellToken == ETH_ADDRESS) { require(msg.value >= takerSellAmount, 'msg value not high enough'); } else if (taker != EXCHANGE_ADDRESS) { require(IERC20(takerSellToken).balanceOf(taker) >= takerSellAmount, 'taker order not enough balance'); require(IERC20(takerSellToken).allowance(taker, EXCHANGE_ADDRESS) >= takerSellAmount, 'taker order not enough allowance'); } if (makerSellToken == ETH_ADDRESS) { require(IERC20(WETH_ADDRESS).balanceOf(maker) >= makerSellAmount, 'maker order not enough balance'); require(IERC20(WETH_ADDRESS).allowance(maker, EXCHANGE_ADDRESS) >= makerSellAmount, 'maker order not enough allowance'); } else { require(IERC20(makerSellToken).balanceOf(maker) >= makerSellAmount, 'maker order not enough balance'); require(IERC20(makerSellToken).allowance(maker, EXCHANGE_ADDRESS) >= makerSellAmount, 'maker order not enough allowance'); } // Taker fee -> fee recipient // taker fee is collected in takerBuyToken if (takerFee > 0) { if (makerSellToken == ETH_ADDRESS) { IERC20(WETH_ADDRESS).transferFrom(maker, FEE_ADDRESS, takerFee); } else { IERC20(makerSellToken).transferFrom(maker, FEE_ADDRESS, takerFee); } } // Maker fee -> fee recipient // Maker fee is collected in makerBuyToken if (makerFee > 0) { if (takerSellToken == ETH_ADDRESS) { IWETH9(WETH_ADDRESS).depositTo{ value: makerFee }(FEE_ADDRESS); } else if (taker == EXCHANGE_ADDRESS) { IERC20(takerSellToken).transfer(FEE_ADDRESS, makerFee); } else { IERC20(takerSellToken).transferFrom(taker, FEE_ADDRESS, makerFee); } } // taker -> maker if (takerSellToken == ETH_ADDRESS) { IWETH9(WETH_ADDRESS).depositTo{ value: takerSellAmount - makerFee }(maker); } else if (taker == EXCHANGE_ADDRESS) { IERC20(takerSellToken).transfer(maker, takerSellAmount - makerFee); } else { IERC20(takerSellToken).transferFrom(taker, maker, takerSellAmount - makerFee); } // maker -> taker if (makerSellToken == ETH_ADDRESS) { IERC20(WETH_ADDRESS).transferFrom(maker, EXCHANGE_ADDRESS, makerSellAmount - takerFee); IWETH9(WETH_ADDRESS).withdrawTo(takerReciver, makerSellAmount - takerFee); } else { IERC20(makerSellToken).transferFrom(maker, takerReciver, makerSellAmount - takerFee); } emit Swap(maker, taker, makerSellToken, takerSellToken, makerSellAmount, takerSellAmount, makerFee, takerFee); } function getOpenOrder(LibOrder.Order calldata order) public view returns (LibOrder.OrderInfo memory orderInfo) { orderInfo.orderHash = LibOrder.getOrderHash(order); orderInfo.orderSellFilledAmount = filled[orderInfo.orderHash]; require(orderInfo.orderSellFilledAmount < order.sellAmount, 'order is filled'); require(block.timestamp <= order.expirationTimeSeconds, 'order expired'); require(!cancelled[orderInfo.orderHash], 'order canceled'); } function isValidOrderSignature(LibOrder.Order calldata order, bytes calldata signature) public view returns (bool) { bytes32 orderHash = LibOrder.getOrderHash(order); return _isValidSignatureHash(order.user, orderHash, signature); } // hash can be an order hash or a cancel order hash function _isValidSignatureHash(address user, bytes32 hash, bytes calldata signature) private view returns (bool) { bytes32 digest = _hashTypedDataV4(hash); return SignatureChecker.isValidSignatureNow(user, digest, signature); } function _refundETH() internal { if (address(this).balance > 0) { (bool success, ) = msg.sender.call{ value: address(this).balance }(new bytes(0)); require(success, 'ETH transfer failed'); } } }
//SPDX-License-Identifier: MIT pragma solidity ^0.8.0; library LibOrder { //keccak256("Order(address user,address sellToken,address buyToken,uint256 sellAmount,uint256 buyAmount,uint256 expirationTimeSeconds)") bytes32 internal constant _EIP712_ORDER_SCHEMA_HASH = 0x68d868c8698fc31da3a36bb7a184a4af099797794701bae97bea3de7ebe6e399; struct Order { address user; //address of the Order Creator making the sale address sellToken; // address of the Token the Order Creator wants to sell address buyToken; // address of the Token the Order Creator wants to receive in return uint256 sellAmount; // amount of Token that the Order Creator wants to sell uint256 buyAmount; // amount of Token that the Order Creator wants to receive in return uint256 expirationTimeSeconds; //time after which the order is no longer valid } struct OrderInfo { bytes32 orderHash; // EIP712 typed data hash of the order (see LibOrder.getTypedDataHash). uint256 orderSellFilledAmount; // Amount of order that has already been filled. } // https://eips.ethereum.org/EIPS/eip-712#definition-of-hashstruct function getOrderHash(Order memory order) internal pure returns (bytes32 orderHash) { orderHash = keccak256( abi.encode(_EIP712_ORDER_SCHEMA_HASH, order.user, order.sellToken, order.buyToken, order.sellAmount, order.buyAmount, order.expirationTimeSeconds) ); } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.6.0) (token/ERC20/IERC20.sol) pragma solidity ^0.8.0; /** * @dev Interface of the ERC20 standard as defined in the EIP. */ interface IERC20 { /** * @dev Emitted when `value` tokens are moved from one account (`from`) to * another (`to`). * * Note that `value` may be zero. */ event Transfer(address indexed from, address indexed to, uint256 value); /** * @dev Emitted when the allowance of a `spender` for an `owner` is set by * a call to {approve}. `value` is the new allowance. */ event Approval(address indexed owner, address indexed spender, uint256 value); /** * @dev Returns the amount of tokens in existence. */ function totalSupply() external view returns (uint256); /** * @dev Returns the amount of tokens owned by `account`. */ function balanceOf(address account) external view returns (uint256); /** * @dev Moves `amount` tokens from the caller's account to `to`. * * Returns a boolean value indicating whether the operation succeeded. * * Emits a {Transfer} event. */ function transfer(address to, uint256 amount) external returns (bool); /** * @dev Returns the remaining number of tokens that `spender` will be * allowed to spend on behalf of `owner` through {transferFrom}. This is * zero by default. * * This value changes when {approve} or {transferFrom} are called. */ function allowance(address owner, address spender) external view returns (uint256); /** * @dev Sets `amount` as the allowance of `spender` over the caller's tokens. * * Returns a boolean value indicating whether the operation succeeded. * * IMPORTANT: Beware that changing an allowance with this method brings the risk * that someone may use both the old and the new allowance by unfortunate * transaction ordering. One possible solution to mitigate this race * condition is to first reduce the spender's allowance to 0 and set the * desired value afterwards: * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729 * * Emits an {Approval} event. */ function approve(address spender, uint256 amount) external returns (bool); /** * @dev Moves `amount` tokens from `from` to `to` using the * allowance mechanism. `amount` is then deducted from the caller's * allowance. * * Returns a boolean value indicating whether the operation succeeded. * * Emits a {Transfer} event. */ function transferFrom( address from, address to, uint256 amount ) external returns (bool); }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.8.0-rc.2) (utils/cryptography/EIP712.sol) pragma solidity ^0.8.0; import "./ECDSA.sol"; /** * @dev https://eips.ethereum.org/EIPS/eip-712[EIP 712] is a standard for hashing and signing of typed structured data. * * The encoding specified in the EIP is very generic, and such a generic implementation in Solidity is not feasible, * thus this contract does not implement the encoding itself. Protocols need to implement the type-specific encoding * they need in their contracts using a combination of `abi.encode` and `keccak256`. * * This contract implements the EIP 712 domain separator ({_domainSeparatorV4}) that is used as part of the encoding * scheme, and the final step of the encoding to obtain the message digest that is then signed via ECDSA * ({_hashTypedDataV4}). * * The implementation of the domain separator was designed to be as efficient as possible while still properly updating * the chain id to protect against replay attacks on an eventual fork of the chain. * * NOTE: This contract implements the version of the encoding known as "v4", as implemented by the JSON RPC method * https://docs.metamask.io/guide/signing-data.html[`eth_signTypedDataV4` in MetaMask]. * * _Available since v3.4._ */ abstract contract EIP712 { /* solhint-disable var-name-mixedcase */ // Cache the domain separator as an immutable value, but also store the chain id that it corresponds to, in order to // invalidate the cached domain separator if the chain id changes. bytes32 private immutable _CACHED_DOMAIN_SEPARATOR; uint256 private immutable _CACHED_CHAIN_ID; address private immutable _CACHED_THIS; bytes32 private immutable _HASHED_NAME; bytes32 private immutable _HASHED_VERSION; bytes32 private immutable _TYPE_HASH; /* solhint-enable var-name-mixedcase */ /** * @dev Initializes the domain separator and parameter caches. * * The meaning of `name` and `version` is specified in * https://eips.ethereum.org/EIPS/eip-712#definition-of-domainseparator[EIP 712]: * * - `name`: the user readable name of the signing domain, i.e. the name of the DApp or the protocol. * - `version`: the current major version of the signing domain. * * NOTE: These parameters cannot be changed except through a xref:learn::upgrading-smart-contracts.adoc[smart * contract upgrade]. */ constructor(string memory name, string memory version) { bytes32 hashedName = keccak256(bytes(name)); bytes32 hashedVersion = keccak256(bytes(version)); bytes32 typeHash = keccak256( "EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)" ); _HASHED_NAME = hashedName; _HASHED_VERSION = hashedVersion; _CACHED_CHAIN_ID = block.chainid; _CACHED_DOMAIN_SEPARATOR = _buildDomainSeparator(typeHash, hashedName, hashedVersion); _CACHED_THIS = address(this); _TYPE_HASH = typeHash; } /** * @dev Returns the domain separator for the current chain. */ function _domainSeparatorV4() internal view returns (bytes32) { if (address(this) == _CACHED_THIS && block.chainid == _CACHED_CHAIN_ID) { return _CACHED_DOMAIN_SEPARATOR; } else { return _buildDomainSeparator(_TYPE_HASH, _HASHED_NAME, _HASHED_VERSION); } } function _buildDomainSeparator( bytes32 typeHash, bytes32 nameHash, bytes32 versionHash ) private view returns (bytes32) { return keccak256(abi.encode(typeHash, nameHash, versionHash, block.chainid, address(this))); } /** * @dev Given an already https://eips.ethereum.org/EIPS/eip-712#definition-of-hashstruct[hashed struct], this * function returns the hash of the fully encoded EIP712 message for this domain. * * This hash can be used together with {ECDSA-recover} to obtain the signer of a message. For example: * * ```solidity * bytes32 digest = _hashTypedDataV4(keccak256(abi.encode( * keccak256("Mail(address to,string contents)"), * mailTo, * keccak256(bytes(mailContents)) * ))); * address signer = ECDSA.recover(digest, signature); * ``` */ function _hashTypedDataV4(bytes32 structHash) internal view virtual returns (bytes32) { return ECDSA.toTypedDataHash(_domainSeparatorV4(), structHash); } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.8.0-rc.2) (utils/cryptography/SignatureChecker.sol) pragma solidity ^0.8.0; import "./ECDSA.sol"; import "../Address.sol"; import "../../interfaces/IERC1271.sol"; /** * @dev Signature verification helper that can be used instead of `ECDSA.recover` to seamlessly support both ECDSA * signatures from externally owned accounts (EOAs) as well as ERC1271 signatures from smart contract wallets like * Argent and Gnosis Safe. * * _Available since v4.1._ */ library SignatureChecker { /** * @dev Checks if a signature is valid for a given signer and data hash. If the signer is a smart contract, the * signature is validated against that smart contract using ERC1271, otherwise it's validated using `ECDSA.recover`. * * NOTE: Unlike ECDSA signatures, contract signatures are revocable, and the outcome of this function can thus * change through time. It could return true at block N and false at block N+1 (or the opposite). */ function isValidSignatureNow( address signer, bytes32 hash, bytes memory signature ) internal view returns (bool) { (address recovered, ECDSA.RecoverError error) = ECDSA.tryRecover(hash, signature); if (error == ECDSA.RecoverError.NoError && recovered == signer) { return true; } (bool success, bytes memory result) = signer.staticcall( abi.encodeWithSelector(IERC1271.isValidSignature.selector, hash, signature) ); return (success && result.length == 32 && abi.decode(result, (bytes32)) == bytes32(IERC1271.isValidSignature.selector)); } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.8.0-rc.2) (utils/cryptography/ECDSA.sol) pragma solidity ^0.8.0; import "../Strings.sol"; /** * @dev Elliptic Curve Digital Signature Algorithm (ECDSA) operations. * * These functions can be used to verify that a message was signed by the holder * of the private keys of a given address. */ library ECDSA { enum RecoverError { NoError, InvalidSignature, InvalidSignatureLength, InvalidSignatureS, InvalidSignatureV // Deprecated in v4.8 } function _throwError(RecoverError error) private pure { if (error == RecoverError.NoError) { return; // no error: do nothing } else if (error == RecoverError.InvalidSignature) { revert("ECDSA: invalid signature"); } else if (error == RecoverError.InvalidSignatureLength) { revert("ECDSA: invalid signature length"); } else if (error == RecoverError.InvalidSignatureS) { revert("ECDSA: invalid signature 's' value"); } } /** * @dev Returns the address that signed a hashed message (`hash`) with * `signature` or error string. This address can then be used for verification purposes. * * The `ecrecover` EVM opcode allows for malleable (non-unique) signatures: * this function rejects them by requiring the `s` value to be in the lower * half order, and the `v` value to be either 27 or 28. * * IMPORTANT: `hash` _must_ be the result of a hash operation for the * verification to be secure: it is possible to craft signatures that * recover to arbitrary addresses for non-hashed data. A safe way to ensure * this is by receiving a hash of the original message (which may otherwise * be too long), and then calling {toEthSignedMessageHash} on it. * * Documentation for signature generation: * - with https://web3js.readthedocs.io/en/v1.3.4/web3-eth-accounts.html#sign[Web3.js] * - with https://docs.ethers.io/v5/api/signer/#Signer-signMessage[ethers] * * _Available since v4.3._ */ function tryRecover(bytes32 hash, bytes memory signature) internal pure returns (address, RecoverError) { if (signature.length == 65) { bytes32 r; bytes32 s; uint8 v; // ecrecover takes the signature parameters, and the only way to get them // currently is to use assembly. /// @solidity memory-safe-assembly assembly { r := mload(add(signature, 0x20)) s := mload(add(signature, 0x40)) v := byte(0, mload(add(signature, 0x60))) } return tryRecover(hash, v, r, s); } else { return (address(0), RecoverError.InvalidSignatureLength); } } /** * @dev Returns the address that signed a hashed message (`hash`) with * `signature`. This address can then be used for verification purposes. * * The `ecrecover` EVM opcode allows for malleable (non-unique) signatures: * this function rejects them by requiring the `s` value to be in the lower * half order, and the `v` value to be either 27 or 28. * * IMPORTANT: `hash` _must_ be the result of a hash operation for the * verification to be secure: it is possible to craft signatures that * recover to arbitrary addresses for non-hashed data. A safe way to ensure * this is by receiving a hash of the original message (which may otherwise * be too long), and then calling {toEthSignedMessageHash} on it. */ function recover(bytes32 hash, bytes memory signature) internal pure returns (address) { (address recovered, RecoverError error) = tryRecover(hash, signature); _throwError(error); return recovered; } /** * @dev Overload of {ECDSA-tryRecover} that receives the `r` and `vs` short-signature fields separately. * * See https://eips.ethereum.org/EIPS/eip-2098[EIP-2098 short signatures] * * _Available since v4.3._ */ function tryRecover( bytes32 hash, bytes32 r, bytes32 vs ) internal pure returns (address, RecoverError) { bytes32 s = vs & bytes32(0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff); uint8 v = uint8((uint256(vs) >> 255) + 27); return tryRecover(hash, v, r, s); } /** * @dev Overload of {ECDSA-recover} that receives the `r and `vs` short-signature fields separately. * * _Available since v4.2._ */ function recover( bytes32 hash, bytes32 r, bytes32 vs ) internal pure returns (address) { (address recovered, RecoverError error) = tryRecover(hash, r, vs); _throwError(error); return recovered; } /** * @dev Overload of {ECDSA-tryRecover} that receives the `v`, * `r` and `s` signature fields separately. * * _Available since v4.3._ */ function tryRecover( bytes32 hash, uint8 v, bytes32 r, bytes32 s ) internal pure returns (address, RecoverError) { // EIP-2 still allows signature malleability for ecrecover(). Remove this possibility and make the signature // unique. Appendix F in the Ethereum Yellow paper (https://ethereum.github.io/yellowpaper/paper.pdf), defines // the valid range for s in (301): 0 < s < secp256k1n ÷ 2 + 1, and for v in (302): v ∈ {27, 28}. Most // signatures from current libraries generate a unique signature with an s-value in the lower half order. // // If your library generates malleable signatures, such as s-values in the upper range, calculate a new s-value // with 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141 - s1 and flip v from 27 to 28 or // vice versa. If your library also generates signatures with 0/1 for v instead 27/28, add 27 to v to accept // these malleable signatures as well. if (uint256(s) > 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5D576E7357A4501DDFE92F46681B20A0) { return (address(0), RecoverError.InvalidSignatureS); } // If the signature is valid (and not malleable), return the signer address address signer = ecrecover(hash, v, r, s); if (signer == address(0)) { return (address(0), RecoverError.InvalidSignature); } return (signer, RecoverError.NoError); } /** * @dev Overload of {ECDSA-recover} that receives the `v`, * `r` and `s` signature fields separately. */ function recover( bytes32 hash, uint8 v, bytes32 r, bytes32 s ) internal pure returns (address) { (address recovered, RecoverError error) = tryRecover(hash, v, r, s); _throwError(error); return recovered; } /** * @dev Returns an Ethereum Signed Message, created from a `hash`. This * produces hash corresponding to the one signed with the * https://eth.wiki/json-rpc/API#eth_sign[`eth_sign`] * JSON-RPC method as part of EIP-191. * * See {recover}. */ function toEthSignedMessageHash(bytes32 hash) internal pure returns (bytes32) { // 32 is the length in bytes of hash, // enforced by the type signature above return keccak256(abi.encodePacked("\x19Ethereum Signed Message:\n32", hash)); } /** * @dev Returns an Ethereum Signed Message, created from `s`. This * produces hash corresponding to the one signed with the * https://eth.wiki/json-rpc/API#eth_sign[`eth_sign`] * JSON-RPC method as part of EIP-191. * * See {recover}. */ function toEthSignedMessageHash(bytes memory s) internal pure returns (bytes32) { return keccak256(abi.encodePacked("\x19Ethereum Signed Message:\n", Strings.toString(s.length), s)); } /** * @dev Returns an Ethereum Signed Typed Data, created from a * `domainSeparator` and a `structHash`. This produces hash corresponding * to the one signed with the * https://eips.ethereum.org/EIPS/eip-712[`eth_signTypedData`] * JSON-RPC method as part of EIP-712. * * See {recover}. */ function toTypedDataHash(bytes32 domainSeparator, bytes32 structHash) internal pure returns (bytes32) { return keccak256(abi.encodePacked("\x19\x01", domainSeparator, structHash)); } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.8.0-rc.2) (utils/Strings.sol) pragma solidity ^0.8.0; import "./math/Math.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 `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); } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.8.0-rc.2) (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) { return prod0 / denominator; } // Make sure the result is less than 2^256. Also prevents denominator == 0. require(denominator > prod1); /////////////////////////////////////////////// // 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 10, 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 * 8) < value ? 1 : 0); } } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.8.0-rc.2) (utils/Address.sol) pragma solidity ^0.8.1; /** * @dev Collection of functions related to the address type */ library Address { /** * @dev Returns true if `account` is a contract. * * [IMPORTANT] * ==== * It is unsafe to assume that an address for which this function returns * false is an externally-owned account (EOA) and not a contract. * * Among others, `isContract` will return false for the following * types of addresses: * * - an externally-owned account * - a contract in construction * - an address where a contract will be created * - an address where a contract lived, but was destroyed * ==== * * [IMPORTANT] * ==== * You shouldn't rely on `isContract` to protect against flash loan attacks! * * Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets * like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract * constructor. * ==== */ function isContract(address account) internal view returns (bool) { // This method relies on extcodesize/address.code.length, which returns 0 // for contracts in construction, since the code is only stored at the end // of the constructor execution. return account.code.length > 0; } /** * @dev Replacement for Solidity's `transfer`: sends `amount` wei to * `recipient`, forwarding all available gas and reverting on errors. * * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost * of certain opcodes, possibly making contracts go over the 2300 gas limit * imposed by `transfer`, making them unable to receive funds via * `transfer`. {sendValue} removes this limitation. * * https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more]. * * IMPORTANT: because control is transferred to `recipient`, care must be * taken to not create reentrancy vulnerabilities. Consider using * {ReentrancyGuard} or the * https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern]. */ function sendValue(address payable recipient, uint256 amount) internal { require(address(this).balance >= amount, "Address: insufficient balance"); (bool success, ) = recipient.call{value: amount}(""); require(success, "Address: unable to send value, recipient may have reverted"); } /** * @dev Performs a Solidity function call using a low level `call`. A * plain `call` is an unsafe replacement for a function call: use this * function instead. * * If `target` reverts with a revert reason, it is bubbled up by this * function (like regular Solidity function calls). * * Returns the raw returned data. To convert to the expected return value, * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`]. * * Requirements: * * - `target` must be a contract. * - calling `target` with `data` must not revert. * * _Available since v3.1._ */ function functionCall(address target, bytes memory data) internal returns (bytes memory) { return 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 (interfaces/IERC1271.sol) pragma solidity ^0.8.0; /** * @dev Interface of the ERC1271 standard signature validation method for * contracts as defined in https://eips.ethereum.org/EIPS/eip-1271[ERC-1271]. * * _Available since v4.1._ */ interface IERC1271 { /** * @dev Should return whether the signature provided is valid for the provided data * @param hash Hash of the data to be signed * @param signature Signature byte array associated with _data */ function isValidSignature(bytes32 hash, bytes memory signature) external view returns (bytes4 magicValue); }
{ "optimizer": { "enabled": true, "runs": 1000 }, "outputSelection": { "*": { "*": [ "evm.bytecode", "evm.deployedBytecode", "devdoc", "userdoc", "metadata", "abi" ] } }, "libraries": {} }
[{"inputs":[{"internalType":"string","name":"name","type":"string"},{"internalType":"string","name":"version","type":"string"},{"internalType":"address","name":"fee_address","type":"address"},{"internalType":"address","name":"weth_address","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"orderHash","type":"bytes32"}],"name":"CancelOrder","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"orderHash","type":"bytes32"},{"indexed":false,"internalType":"uint256","name":"filled","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"remaining","type":"uint256"}],"name":"OrderStatus","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"maker","type":"address"},{"indexed":true,"internalType":"address","name":"taker","type":"address"},{"indexed":true,"internalType":"address","name":"makerSellToken","type":"address"},{"indexed":true,"internalType":"address","name":"takerSellToken","type":"address"},{"indexed":false,"internalType":"uint256","name":"makerSellAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"takerSellAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"makerVolumeFee","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"takerVolumeFee","type":"uint256"}],"name":"Swap","type":"event"},{"inputs":[{"components":[{"internalType":"address","name":"user","type":"address"},{"internalType":"address","name":"sellToken","type":"address"},{"internalType":"address","name":"buyToken","type":"address"},{"internalType":"uint256","name":"sellAmount","type":"uint256"},{"internalType":"uint256","name":"buyAmount","type":"uint256"},{"internalType":"uint256","name":"expirationTimeSeconds","type":"uint256"}],"internalType":"struct LibOrder.Order","name":"order","type":"tuple"}],"name":"cancelOrder","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"name":"cancelled","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"components":[{"internalType":"address","name":"user","type":"address"},{"internalType":"address","name":"sellToken","type":"address"},{"internalType":"address","name":"buyToken","type":"address"},{"internalType":"uint256","name":"sellAmount","type":"uint256"},{"internalType":"uint256","name":"buyAmount","type":"uint256"},{"internalType":"uint256","name":"expirationTimeSeconds","type":"uint256"}],"internalType":"struct LibOrder.Order","name":"makerOrder","type":"tuple"},{"internalType":"bytes","name":"makerSignature","type":"bytes"},{"internalType":"uint256","name":"takerSellAmount","type":"uint256"},{"internalType":"bool","name":"fillAvailable","type":"bool"}],"name":"fillOrderExactInput","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"components":[{"internalType":"address","name":"user","type":"address"},{"internalType":"address","name":"sellToken","type":"address"},{"internalType":"address","name":"buyToken","type":"address"},{"internalType":"uint256","name":"sellAmount","type":"uint256"},{"internalType":"uint256","name":"buyAmount","type":"uint256"},{"internalType":"uint256","name":"expirationTimeSeconds","type":"uint256"}],"internalType":"struct LibOrder.Order","name":"makerOrder","type":"tuple"},{"internalType":"bytes","name":"makerSignature","type":"bytes"},{"internalType":"uint256","name":"takerSellAmount","type":"uint256"},{"internalType":"bool","name":"fillAvailable","type":"bool"}],"name":"fillOrderExactInputETH","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"payable","type":"function"},{"inputs":[{"components":[{"internalType":"address","name":"user","type":"address"},{"internalType":"address","name":"sellToken","type":"address"},{"internalType":"address","name":"buyToken","type":"address"},{"internalType":"uint256","name":"sellAmount","type":"uint256"},{"internalType":"uint256","name":"buyAmount","type":"uint256"},{"internalType":"uint256","name":"expirationTimeSeconds","type":"uint256"}],"internalType":"struct LibOrder.Order","name":"makerOrder","type":"tuple"},{"internalType":"bytes","name":"makerSignature","type":"bytes"},{"internalType":"uint256","name":"takerBuyAmount","type":"uint256"},{"internalType":"bool","name":"fillAvailable","type":"bool"}],"name":"fillOrderExactOutput","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"components":[{"internalType":"address","name":"user","type":"address"},{"internalType":"address","name":"sellToken","type":"address"},{"internalType":"address","name":"buyToken","type":"address"},{"internalType":"uint256","name":"sellAmount","type":"uint256"},{"internalType":"uint256","name":"buyAmount","type":"uint256"},{"internalType":"uint256","name":"expirationTimeSeconds","type":"uint256"}],"internalType":"struct LibOrder.Order","name":"makerOrder","type":"tuple"},{"internalType":"bytes","name":"makerSignature","type":"bytes"},{"internalType":"uint256","name":"takerBuyAmount","type":"uint256"},{"internalType":"bool","name":"fillAvailable","type":"bool"}],"name":"fillOrderExactOutputETH","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"payable","type":"function"},{"inputs":[{"components":[{"internalType":"address","name":"user","type":"address"},{"internalType":"address","name":"sellToken","type":"address"},{"internalType":"address","name":"buyToken","type":"address"},{"internalType":"uint256","name":"sellAmount","type":"uint256"},{"internalType":"uint256","name":"buyAmount","type":"uint256"},{"internalType":"uint256","name":"expirationTimeSeconds","type":"uint256"}],"internalType":"struct LibOrder.Order[]","name":"makerOrder","type":"tuple[]"},{"internalType":"bytes[]","name":"makerSignature","type":"bytes[]"},{"internalType":"uint256","name":"takerAmount","type":"uint256"},{"internalType":"bool","name":"fillAvailable","type":"bool"}],"name":"fillOrderRoute","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"payable","type":"function"},{"inputs":[{"components":[{"internalType":"address","name":"user","type":"address"},{"internalType":"address","name":"sellToken","type":"address"},{"internalType":"address","name":"buyToken","type":"address"},{"internalType":"uint256","name":"sellAmount","type":"uint256"},{"internalType":"uint256","name":"buyAmount","type":"uint256"},{"internalType":"uint256","name":"expirationTimeSeconds","type":"uint256"}],"internalType":"struct LibOrder.Order[]","name":"makerOrder","type":"tuple[]"},{"internalType":"bytes[]","name":"makerSignature","type":"bytes[]"},{"internalType":"uint256","name":"takerAmount","type":"uint256"},{"internalType":"bool","name":"fillAvailable","type":"bool"}],"name":"fillOrderRouteETH","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"name":"filled","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"components":[{"internalType":"address","name":"user","type":"address"},{"internalType":"address","name":"sellToken","type":"address"},{"internalType":"address","name":"buyToken","type":"address"},{"internalType":"uint256","name":"sellAmount","type":"uint256"},{"internalType":"uint256","name":"buyAmount","type":"uint256"},{"internalType":"uint256","name":"expirationTimeSeconds","type":"uint256"}],"internalType":"struct LibOrder.Order","name":"order","type":"tuple"}],"name":"getOpenOrder","outputs":[{"components":[{"internalType":"bytes32","name":"orderHash","type":"bytes32"},{"internalType":"uint256","name":"orderSellFilledAmount","type":"uint256"}],"internalType":"struct LibOrder.OrderInfo","name":"orderInfo","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"components":[{"internalType":"address","name":"user","type":"address"},{"internalType":"address","name":"sellToken","type":"address"},{"internalType":"address","name":"buyToken","type":"address"},{"internalType":"uint256","name":"sellAmount","type":"uint256"},{"internalType":"uint256","name":"buyAmount","type":"uint256"},{"internalType":"uint256","name":"expirationTimeSeconds","type":"uint256"}],"internalType":"struct LibOrder.Order","name":"order","type":"tuple"},{"internalType":"bytes","name":"signature","type":"bytes"}],"name":"isValidOrderSignature","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"stateMutability":"payable","type":"receive"}]
Contract Creation Code
6101a0604052600060025561271060035560056004556127106005553480156200002857600080fd5b5060405162002ed938038062002ed98339810160408190526200004b91620001e4565b835160209485012083519385019390932060e08490526101008190524660a0818152604080517f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f818a01819052818301989098526060810194909452608080850193909352308483018190528151808603909301835260c0948501909152815191909701209052849052610120929092526001600160a01b039081166101405216610160526101805262000273565b634e487b7160e01b600052604160045260246000fd5b600082601f8301126200012257600080fd5b81516001600160401b03808211156200013f576200013f620000fa565b604051601f8301601f19908116603f011681019082821181831017156200016a576200016a620000fa565b816040528381526020925086838588010111156200018757600080fd5b600091505b83821015620001ab57858201830151818301840152908201906200018c565b83821115620001bd5760008385830101525b9695505050505050565b80516001600160a01b0381168114620001df57600080fd5b919050565b60008060008060808587031215620001fb57600080fd5b84516001600160401b03808211156200021357600080fd5b620002218883890162000110565b955060208701519150808211156200023857600080fd5b50620002478782880162000110565b9350506200025860408601620001c7565b91506200026860608601620001c7565b905092959194509250565b60805160a05160c05160e0516101005161012051610140516101605161018051612b466200039360003960008181610894015281816108c301528181610ce701528181610dc101528181611441015281816115520152818161171f015281816118e301528181611bea01528181611e170152611fb3015260008181610c4001528181610d1e01528181610f0201528181610f4c01528181611003015281816116450152818161174901528181611a0901528181611b8501528181611d8901528181611f8b015261205f0152600081816119da01528181611a9b01528181611b5d01528181611c520152611cf301526000612460015260006124af0152600061248a015260006123e30152600061240d015260006124370152612b466000f3fe6080604052600436106100c05760003560e01c80637334798f11610074578063cc43f94e1161004e578063cc43f94e1461020f578063efbdebce14610222578063feb31ca11461024257600080fd5b80637334798f146101ad578063acdf5718146101cd578063c50e7b6e146101ed57600080fd5b80632ac12622116100a55780632ac1262214610147578063427c59131461018757806359e656ef1461019a57600080fd5b80631e9c8a6c146100cc578063288cdc911461010c57600080fd5b366100c757005b600080fd5b3480156100d857600080fd5b506100ec6100e736600461261f565b610255565b604080518251815260209283015192810192909252015b60405180910390f35b34801561011857600080fd5b5061013961012736600461263b565b60006020819052908152604090205481565b604051908152602001610103565b34801561015357600080fd5b5061017761016236600461263b565b60016020526000908152604090205460ff1681565b6040519015158152602001610103565b6101776101953660046126af565b6103aa565b6101776101a83660046126af565b6103f0565b3480156101b957600080fd5b506101776101c83660046126af565b61043e565b3480156101d957600080fd5b506101776101e8366004612724565b610492565b3480156101f957600080fd5b5061020d61020836600461261f565b6104cc565b005b61017761021d3660046127bd565b6105f8565b34801561022e57600080fd5b5061017761023d3660046126af565b61098d565b6101776102503660046127bd565b6109e7565b604080518082019091526000808252602082015261028061027b3684900384018461288a565b610e4c565b808252600090815260208181526040909120549082018190526060830135116102f05760405162461bcd60e51b815260206004820152600f60248201527f6f726465722069732066696c6c6564000000000000000000000000000000000060448201526064015b60405180910390fd5b8160a001354211156103445760405162461bcd60e51b815260206004820152600d60248201527f6f7264657220657870697265640000000000000000000000000000000000000060448201526064016102e7565b805160009081526001602052604090205460ff16156103a55760405162461bcd60e51b815260206004820152600e60248201527f6f726465722063616e63656c656400000000000000000000000000000000000060448201526064016102e7565b919050565b60008060808701356103c060608901358661293b565b6103ca919061295a565b90506103db87878733338689610ef8565b6103e3611092565b5060019695505050505050565b6000600454600554610402919061297c565b60055461040f908561293b565b610419919061295a565b925061042a86868633338888610ef8565b610432611092565b50600195945050505050565b600080608087013561045460608901358661293b565b61045e919061295a565b90506103e387878733806104786040860160208701612993565b8d604001602081019061048b9190612993565b888b611150565b6000806104a761027b3687900387018761288a565b90506104c16104b96020870187612993565b82868661138d565b9150505b9392505050565b6104d96020820182612993565b6001600160a01b0316336001600160a01b0316146105395760405162461bcd60e51b815260206004820152601a60248201527f6f6e6c792075736572206d61792063616e63656c206f7264657200000000000060448201526064016102e7565b600061054d61027b3684900384018461288a565b6000818152602081905260409020549091506060830135116105b15760405162461bcd60e51b815260206004820152601460248201527f6f7264657220616c72656164792066696c6c656400000000000000000000000060448201526064016102e7565b6000818152600160208190526040808320805460ff19169092179091555182917f42c76c81a7cba1b9c861353909a184e20747ab960332628dabcbb5852fc5cbb591a25050565b600085841461066f5760405162461bcd60e51b815260206004820152603860248201527f4c656e677468206f66206d616b65724f726465727320616e64206d616b65725360448201527f69676e61747572657320646f6573206e6f74206d61746368000000000000000060648201526084016102e7565b856106c75760405162461bcd60e51b815260206004820152602260248201527f4c656e677468206f66206d616b65724f72646572732063616e206e6f74206265604482015261020360f41b60648201526084016102e7565b600186141561071f57610718878760008181106106e6576106e66129ae565b905060c00201868660008181106106ff576106ff6129ae565b905060200281019061071191906129c4565b868661043e565b9050610983565b600061072c60018861297c565b905060005b81811161097c578015806107b25750888882818110610752576107526129ae565b905060c00201604001602081019061076a9190612993565b6001600160a01b0316898961078060018561297c565b81811061078f5761078f6129ae565b905060c0020160200160208101906107a79190612993565b6001600160a01b0316145b6107fe5760405162461bcd60e51b815260206004820152601c60248201527f546f6b656e73206f6e20726f75746520646f206e6f74206d617463680000000060448201526064016102e7565b888882818110610810576108106129ae565b905060c002016080013589898381811061082c5761082c6129ae565b905060c002016060013586610841919061293b565b61084b919061295a565b9450610944898983818110610862576108626129ae565b905060c0020188888481811061087a5761087a6129ae565b905060200281019061088c91906129c4565b84156108b8577f00000000000000000000000000000000000000000000000000000000000000006108ba565b335b8686146108e7577f00000000000000000000000000000000000000000000000000000000000000006108e9565b335b8e8e888181106108fb576108fb6129ae565b905060c0020160200160208101906109139190612993565b8f8f89818110610925576109256129ae565b905060c00201604001602081019061093d9190612993565b8c8c611150565b600554600454610954908761293b565b61095e919061295a565b610968908661297c565b94508061097481612a0b565b915050610731565b5060019150505b9695505050505050565b600060045460055461099f919061297c565b6005546109ac908561293b565b6109b6919061295a565b925061043286868633806109d06040860160208701612993565b6109e060608e0160408f01612993565b8a8a611150565b6000858414610a5e5760405162461bcd60e51b815260206004820152603860248201527f4c656e677468206f66206d616b65724f726465727320616e64206d616b65725360448201527f69676e61747572657320646f6573206e6f74206d61746368000000000000000060648201526084016102e7565b85610ab65760405162461bcd60e51b815260206004820152602260248201527f4c656e677468206f66206d616b65724f72646572732063616e206e6f74206265604482015261020360f41b60648201526084016102e7565b6001861415610b075761071887876000818110610ad557610ad56129ae565b905060c0020186866000818110610aee57610aee6129ae565b9050602002810190610b0091906129c4565b86866103aa565b6000610b1460018861297c565b905060005b818111610e3557801580610b9a5750888882818110610b3a57610b3a6129ae565b905060c002016040016020810190610b529190612993565b6001600160a01b03168989610b6860018561297c565b818110610b7757610b776129ae565b905060c002016020016020810190610b8f9190612993565b6001600160a01b0316145b610be65760405162461bcd60e51b815260206004820152601c60248201527f546f6b656e73206f6e20726f75746520646f206e6f74206d617463680000000060448201526064016102e7565b888882818110610bf857610bf86129ae565b905060c0020160800135898983818110610c1457610c146129ae565b905060c002016060013586610c29919061293b565b610c33919061295a565b945080158015610c9e57507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031689896000818110610c7b57610c7b6129ae565b905060c002016040016020810190610c939190612993565b6001600160a01b0316145b15610d1257610d0d89896000818110610cb957610cb96129ae565b905060c0020188886000818110610cd257610cd26129ae565b9050602002810190610ce491906129c4565b337f00000000000000000000000000000000000000000000000000000000000000008a8a610ef8565b610dfd565b8181148015610d7b57507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316898984818110610d5857610d586129ae565b905060c002016020016020810190610d709190612993565b6001600160a01b0316145b15610de857610d0d898984818110610d9557610d956129ae565b905060c00201888885818110610dad57610dad6129ae565b9050602002810190610dbf91906129c4565b7f0000000000000000000000000000000000000000000000000000000000000000338a8a610ef8565b610dfd898983818110610862576108626129ae565b600554600454610e0d908761293b565b610e17919061295a565b610e21908661297c565b945080610e2d81612a0b565b915050610b19565b50610e3e611092565b506001979650505050505050565b80516020808301516040808501516060860151608087015160a08801519351600097610edb977f68d868c8698fc31da3a36bb7a184a4af099797794701bae97bea3de7ebe6e3999791969195949392019687526001600160a01b0395861660208801529385166040870152919093166060850152608084019290925260a083019190915260c082015260e00190565b604051602081830303815290604052805190602001209050919050565b6001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016610f326060890160408a01612993565b6001600160a01b03161480610f8757506001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016610f7c6040890160208a01612993565b6001600160a01b0316145b610ff95760405162461bcd60e51b815260206004820152602760248201527f45697468657220627579206f722073656c6c20746f6b656e2073686f756c642060448201527f626520574554480000000000000000000000000000000000000000000000000060648201526084016102e7565b6001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000166110336060890160408a01612993565b6001600160a01b0316141561106857611063878787878761105a6040860160208701612993565b60008989611150565b611089565b611089878787878760006110826060870160408801612993565b8989611150565b50505050505050565b471561114e5760408051600080825260208201909252339047906040516110b99190612a56565b60006040518083038185875af1925050503d80600081146110f6576040519150601f19603f3d011682016040523d82523d6000602084013e6110fb565b606091505b505090508061114c5760405162461bcd60e51b815260206004820152601360248201527f455448207472616e73666572206661696c65640000000000000000000000000060448201526064016102e7565b505b565b6001600160a01b0385166111a65760405162461bcd60e51b815260206004820152601c60248201527f43616e27742072656369766520746f207a65726f20616464726573730000000060448201526064016102e7565b60006111b18a610255565b90506111cc6111c360208c018c612993565b82518b8b61138d565b6112185760405162461bcd60e51b815260206004820152601760248201527f696e76616c6964206d616b6572207369676e617475726500000000000000000060448201526064016102e7565b60008082602001518c6060013561122f919061297c565b905083801561123d57508481105b15611246578094505b60608c013561125960808e01358761293b565b611263919061295a565b9150808511156112b55760405162461bcd60e51b815260206004820152601d60248201527f616d6f756e74206578636565647320617661696c61626c652073697a6500000060448201526064016102e7565b5060008483602001516112c89190612a72565b8351600090815260208181526040909120829055909150611330906112ef908e018e612993565b8a8a8a8a8a886003546002548b611306919061293b565b611310919061295a565b6005546004548f611321919061293b565b61132b919061295a565b6113dc565b82600001517ff56da1ef5eb4658fc8a117e0749fb8d158d65790babdb91264a19c3c2fad622c82838f60600135611367919061297c565b6040805192835260208301919091520160405180910390a2505050505050505050505050565b600080611399856121f7565b9050610983868286868080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525061226692505050565b6001600160a01b03851661143f578234101561143a5760405162461bcd60e51b815260206004820152601960248201527f6d73672076616c7565206e6f74206869676820656e6f7567680000000000000060448201526064016102e7565b611616565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316886001600160a01b031614611616576040516370a0823160e01b81526001600160a01b0389811660048301528491908716906370a0823190602401602060405180830381865afa1580156114c1573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906114e59190612a8a565b10156115335760405162461bcd60e51b815260206004820152601e60248201527f74616b6572206f72646572206e6f7420656e6f7567682062616c616e6365000060448201526064016102e7565b604051636eb1769f60e11b81526001600160a01b0389811660048301527f00000000000000000000000000000000000000000000000000000000000000008116602483015284919087169063dd62ed3e90604401602060405180830381865afa1580156115a4573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906115c89190612a8a565b10156116165760405162461bcd60e51b815260206004820181905260248201527f74616b6572206f72646572206e6f7420656e6f75676820616c6c6f77616e636560448201526064016102e7565b6001600160a01b038616611809576040516370a0823160e01b81526001600160a01b038a8116600483015285917f0000000000000000000000000000000000000000000000000000000000000000909116906370a0823190602401602060405180830381865afa15801561168e573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906116b29190612a8a565b10156117005760405162461bcd60e51b815260206004820152601e60248201527f6d616b6572206f72646572206e6f7420656e6f7567682062616c616e6365000060448201526064016102e7565b604051636eb1769f60e11b81526001600160a01b038a811660048301527f00000000000000000000000000000000000000000000000000000000000000008116602483015285917f00000000000000000000000000000000000000000000000000000000000000009091169063dd62ed3e90604401602060405180830381865afa158015611792573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906117b69190612a8a565b10156118045760405162461bcd60e51b815260206004820181905260248201527f6d616b6572206f72646572206e6f7420656e6f75676820616c6c6f77616e636560448201526064016102e7565b6119a7565b6040516370a0823160e01b81526001600160a01b038a811660048301528591908816906370a0823190602401602060405180830381865afa158015611852573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906118769190612a8a565b10156118c45760405162461bcd60e51b815260206004820152601e60248201527f6d616b6572206f72646572206e6f7420656e6f7567682062616c616e6365000060448201526064016102e7565b604051636eb1769f60e11b81526001600160a01b038a811660048301527f00000000000000000000000000000000000000000000000000000000000000008116602483015285919088169063dd62ed3e90604401602060405180830381865afa158015611935573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906119599190612a8a565b10156119a75760405162461bcd60e51b815260206004820181905260248201527f6d616b6572206f72646572206e6f7420656e6f75676820616c6c6f77616e636560448201526064016102e7565b8015611b19576001600160a01b038616611a7c576040516323b872dd60e01b81526001600160a01b038a811660048301527f000000000000000000000000000000000000000000000000000000000000000081166024830152604482018390527f000000000000000000000000000000000000000000000000000000000000000016906323b872dd906064016020604051808303816000875af1158015611a52573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611a769190612aa3565b50611b19565b6040516323b872dd60e01b81526001600160a01b038a811660048301527f000000000000000000000000000000000000000000000000000000000000000081166024830152604482018390528716906323b872dd906064016020604051808303816000875af1158015611af3573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611b179190612aa3565b505b8115611d71576001600160a01b038516611be8576040517fb760faf90000000000000000000000000000000000000000000000000000000081526001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000811660048301527f0000000000000000000000000000000000000000000000000000000000000000169063b760faf99084906024016000604051808303818588803b158015611bca57600080fd5b505af1158015611bde573d6000803e3d6000fd5b5050505050611d71565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316886001600160a01b03161415611cd4576040517fa9059cbb0000000000000000000000000000000000000000000000000000000081526001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000811660048301526024820184905286169063a9059cbb906044016020604051808303816000875af1158015611caa573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611cce9190612aa3565b50611d71565b6040516323b872dd60e01b81526001600160a01b0389811660048301527f000000000000000000000000000000000000000000000000000000000000000081166024830152604482018490528616906323b872dd906064016020604051808303816000875af1158015611d4b573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611d6f9190612aa3565b505b6001600160a01b038516611e15576001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001663b760faf9611db8848661297c565b6040516001600160e01b031960e084901b1681526001600160a01b038d1660048201526024016000604051808303818588803b158015611df757600080fd5b505af1158015611e0b573d6000803e3d6000fd5b5050505050611f73565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316886001600160a01b03161415611ede576001600160a01b03851663a9059cbb8a611e69858761297c565b6040516001600160e01b031960e085901b1681526001600160a01b03909216600483015260248201526044016020604051808303816000875af1158015611eb4573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611ed89190612aa3565b50611f73565b6001600160a01b0385166323b872dd898b611ef9868861297c565b6040516001600160e01b031960e086901b1681526001600160a01b03938416600482015292909116602483015260448201526064016020604051808303816000875af1158015611f4d573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611f719190612aa3565b505b6001600160a01b0386166120f2576001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000166323b872dd8a7f0000000000000000000000000000000000000000000000000000000000000000611fdc858961297c565b6040516001600160e01b031960e086901b1681526001600160a01b03938416600482015292909116602483015260448201526064016020604051808303816000875af1158015612030573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906120549190612aa3565b506001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001663205c28788861208f848861297c565b6040516001600160e01b031960e085901b1681526001600160a01b0390921660048301526024820152604401600060405180830381600087803b1580156120d557600080fd5b505af11580156120e9573d6000803e3d6000fd5b50505050612187565b6001600160a01b0386166323b872dd8a8961210d858961297c565b6040516001600160e01b031960e086901b1681526001600160a01b03938416600482015292909116602483015260448201526064016020604051808303816000875af1158015612161573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906121859190612aa3565b505b604080516001600160a01b038b811682526020820187905291810185905260608101849052608081018390528187169188811691908b16907f6950339c7661cca450281e53722525cc136590e622b011d5be7e4c4993685a6c9060a00160405180910390a4505050505050505050565b60006122606122046123d6565b836040517f19010000000000000000000000000000000000000000000000000000000000006020820152602281018390526042810182905260009060620160405160208183030381529060405280519060200120905092915050565b92915050565b600080600061227585856124fd565b9092509050600081600481111561228e5761228e612ac0565b1480156122ac5750856001600160a01b0316826001600160a01b0316145b156122bc576001925050506104c5565b600080876001600160a01b0316631626ba7e60e01b88886040516024016122e4929190612ad6565b60408051601f198184030181529181526020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff166001600160e01b03199094169390931790925290516123379190612a56565b600060405180830381855afa9150503d8060008114612372576040519150601f19603f3d011682016040523d82523d6000602084013e612377565b606091505b509150915081801561238a575080516020145b80156123ca575080517f1626ba7e00000000000000000000000000000000000000000000000000000000906123c89083016020908101908401612a8a565b145b98975050505050505050565b6000306001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001614801561242f57507f000000000000000000000000000000000000000000000000000000000000000046145b1561245957507f000000000000000000000000000000000000000000000000000000000000000090565b50604080517f00000000000000000000000000000000000000000000000000000000000000006020808301919091527f0000000000000000000000000000000000000000000000000000000000000000828401527f000000000000000000000000000000000000000000000000000000000000000060608301524660808301523060a0808401919091528351808403909101815260c0909201909252805191012090565b6000808251604114156125345760208301516040840151606085015160001a61252887828585612543565b9450945050505061253c565b506000905060025b9250929050565b6000807f7fffffffffffffffffffffffffffffff5d576e7357a4501ddfe92f46681b20a083111561257a57506000905060036125fe565b6040805160008082526020820180845289905260ff881692820192909252606081018690526080810185905260019060a0016020604051602081039080840390855afa1580156125ce573d6000803e3d6000fd5b5050604051601f1901519150506001600160a01b0381166125f7576000600192509250506125fe565b9150600090505b94509492505050565b600060c0828403121561261957600080fd5b50919050565b600060c0828403121561263157600080fd5b6104c58383612607565b60006020828403121561264d57600080fd5b5035919050565b60008083601f84011261266657600080fd5b50813567ffffffffffffffff81111561267e57600080fd5b60208301915083602082850101111561253c57600080fd5b801515811461114c57600080fd5b80356103a581612696565b600080600080600061012086880312156126c857600080fd5b6126d28787612607565b945060c086013567ffffffffffffffff8111156126ee57600080fd5b6126fa88828901612654565b90955093505060e0860135915061010086013561271681612696565b809150509295509295909350565b600080600060e0848603121561273957600080fd5b6127438585612607565b925060c084013567ffffffffffffffff81111561275f57600080fd5b61276b86828701612654565b9497909650939450505050565b60008083601f84011261278a57600080fd5b50813567ffffffffffffffff8111156127a257600080fd5b6020830191508360208260051b850101111561253c57600080fd5b600080600080600080608087890312156127d657600080fd5b863567ffffffffffffffff808211156127ee57600080fd5b818901915089601f83011261280257600080fd5b81358181111561281157600080fd5b8a602060c08302850101111561282657600080fd5b60209283019850965090880135908082111561284157600080fd5b5061284e89828a01612778565b90955093505060408701359150612867606088016126a4565b90509295509295509295565b80356001600160a01b03811681146103a557600080fd5b600060c0828403121561289c57600080fd5b60405160c0810181811067ffffffffffffffff821117156128cd57634e487b7160e01b600052604160045260246000fd5b6040526128d983612873565b81526128e760208401612873565b60208201526128f860408401612873565b6040820152606083013560608201526080830135608082015260a083013560a08201528091505092915050565b634e487b7160e01b600052601160045260246000fd5b600081600019048311821515161561295557612955612925565b500290565b60008261297757634e487b7160e01b600052601260045260246000fd5b500490565b60008282101561298e5761298e612925565b500390565b6000602082840312156129a557600080fd5b6104c582612873565b634e487b7160e01b600052603260045260246000fd5b6000808335601e198436030181126129db57600080fd5b83018035915067ffffffffffffffff8211156129f657600080fd5b60200191503681900382131561253c57600080fd5b6000600019821415612a1f57612a1f612925565b5060010190565b60005b83811015612a41578181015183820152602001612a29565b83811115612a50576000848401525b50505050565b60008251612a68818460208701612a26565b9190910192915050565b60008219821115612a8557612a85612925565b500190565b600060208284031215612a9c57600080fd5b5051919050565b600060208284031215612ab557600080fd5b81516104c581612696565b634e487b7160e01b600052602160045260246000fd5b8281526040602082015260008251806040840152612afb816060850160208701612a26565b601f01601f191691909101606001939250505056fea2646970667358221220c64a05be1d920912d76f4e16673a97c069685991556f977187c31f26f9add3ee64736f6c634300080a0033000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000c0000000000000000000000000f4bba1e2a5024a2754225b981e9a0db7d2c33ee900000000000000000000000082af49447d8a07e3bd95bd0d56f35241523fbab100000000000000000000000000000000000000000000000000000000000000065a69675a616700000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003322e310000000000000000000000000000000000000000000000000000000000
Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)
000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000c0000000000000000000000000f4bba1e2a5024a2754225b981e9a0db7d2c33ee900000000000000000000000082af49447d8a07e3bd95bd0d56f35241523fbab100000000000000000000000000000000000000000000000000000000000000065a69675a616700000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003322e310000000000000000000000000000000000000000000000000000000000
-----Decoded View---------------
Arg [0] : name (string): ZigZag
Arg [1] : version (string): 2.1
Arg [2] : fee_address (address): 0xf4bba1e2a5024a2754225b981e9a0db7d2c33ee9
Arg [3] : weth_address (address): 0x82af49447d8a07e3bd95bd0d56f35241523fbab1
-----Encoded View---------------
8 Constructor Arguments found :
Arg [0] : 0000000000000000000000000000000000000000000000000000000000000080
Arg [1] : 00000000000000000000000000000000000000000000000000000000000000c0
Arg [2] : 000000000000000000000000f4bba1e2a5024a2754225b981e9a0db7d2c33ee9
Arg [3] : 00000000000000000000000082af49447d8a07e3bd95bd0d56f35241523fbab1
Arg [4] : 0000000000000000000000000000000000000000000000000000000000000006
Arg [5] : 5a69675a61670000000000000000000000000000000000000000000000000000
Arg [6] : 0000000000000000000000000000000000000000000000000000000000000003
Arg [7] : 322e310000000000000000000000000000000000000000000000000000000000
Age | Block | Fee Address | BC Fee Address | Voting Power | Jailed | Incoming |
---|
Make sure to use the "Vote Down" button for any spammy posts, and the "Vote Up" for interesting conversations.