Overview
ETH Balance
0 ETH
Eth Value
$0.00More Info
Private Name Tags
ContractCreator
Latest 25 from a total of 5,214 transactions
Transaction Hash |
Method
|
Block
|
From
|
To
|
|||||
---|---|---|---|---|---|---|---|---|---|
Take Order | 15246609 | 881 days ago | IN | 0 ETH | 0.0005927 | ||||
Take Order | 15246609 | 881 days ago | IN | 0 ETH | 0.00042674 | ||||
Take Order | 15246609 | 881 days ago | IN | 0 ETH | 0.00042674 | ||||
Cancel Orders | 14315057 | 1031 days ago | IN | 0 ETH | 0.01631679 | ||||
Cancel Orders | 14315056 | 1031 days ago | IN | 0 ETH | 0.02096825 | ||||
Cancel Orders | 14315052 | 1031 days ago | IN | 0 ETH | 0.01888683 | ||||
Cancel Orders | 14295991 | 1033 days ago | IN | 0 ETH | 0.02606502 | ||||
Cancel Orders | 14295980 | 1034 days ago | IN | 0 ETH | 0.06096203 | ||||
Activate Kill Sw... | 14295967 | 1034 days ago | IN | 0 ETH | 0.00386301 | ||||
Make Order | 14288719 | 1035 days ago | IN | 0 ETH | 0.0049426 | ||||
Make Order | 14288708 | 1035 days ago | IN | 0 ETH | 0.00510136 | ||||
Cancel Order | 14288698 | 1035 days ago | IN | 0 ETH | 0.00234163 | ||||
Cancel Order | 14275991 | 1037 days ago | IN | 0 ETH | 0.00474037 | ||||
Cancel Order | 14273585 | 1037 days ago | IN | 0 ETH | 0.00245585 | ||||
Make Order | 14273577 | 1037 days ago | IN | 0 ETH | 0.00568022 | ||||
Cancel Order | 14271497 | 1037 days ago | IN | 0 ETH | 0.00633954 | ||||
Take Orders | 14270255 | 1037 days ago | IN | 2.41868467 ETH | 0.00903871 | ||||
Take Order | 14269527 | 1038 days ago | IN | 0.213 ETH | 0.00742437 | ||||
Make Order | 14267406 | 1038 days ago | IN | 0 ETH | 0.00672112 | ||||
Take Order | 14267052 | 1038 days ago | IN | 0.5 ETH | 0.01289143 | ||||
Make Order | 14263394 | 1039 days ago | IN | 0 ETH | 0.00899662 | ||||
Take Order | 14253987 | 1040 days ago | IN | 0.17 ETH | 0.00568333 | ||||
Take Orders | 14253636 | 1040 days ago | IN | 0.0038478 ETH | 0.01140077 | ||||
Make Order | 14253198 | 1040 days ago | IN | 0 ETH | 0.00665458 | ||||
Make Order | 14252543 | 1040 days ago | IN | 0 ETH | 0.01217496 |
Latest 25 internal transactions (View All)
Advanced mode:
Parent Transaction Hash | Block |
From
|
To
|
|||
---|---|---|---|---|---|---|
14315057 | 1031 days ago | 1 wei | ||||
14315057 | 1031 days ago | 0.01 ETH | ||||
14315057 | 1031 days ago | 0.29 ETH | ||||
14315057 | 1031 days ago | 0.67002714 ETH | ||||
14315057 | 1031 days ago | 0.121788 ETH | ||||
14315057 | 1031 days ago | 0.05 ETH | ||||
14315057 | 1031 days ago | 0.005 ETH | ||||
14315056 | 1031 days ago | 0.001 ETH | ||||
14315056 | 1031 days ago | 1 wei | ||||
14315056 | 1031 days ago | 0.19251554 ETH | ||||
14315056 | 1031 days ago | 0.15 ETH | ||||
14315056 | 1031 days ago | 0.005 ETH | ||||
14315056 | 1031 days ago | 0.005 ETH | ||||
14315056 | 1031 days ago | 0.001 ETH | ||||
14315056 | 1031 days ago | 0.1902 ETH | ||||
14315056 | 1031 days ago | 0.005 ETH | ||||
14315052 | 1031 days ago | 0.005 ETH | ||||
14315052 | 1031 days ago | 0.001 ETH | ||||
14315052 | 1031 days ago | 0.0018 ETH | ||||
14315052 | 1031 days ago | 1 wei | ||||
14315052 | 1031 days ago | 0.0018 ETH | ||||
14315052 | 1031 days ago | 0.1615412 ETH | ||||
14315052 | 1031 days ago | 0.0052 ETH | ||||
14315052 | 1031 days ago | 0.013 ETH | ||||
14315052 | 1031 days ago | 1.168608 ETH |
Loading...
Loading
Contract Name:
Dubiex
Compiler Version
v0.6.12+commit.27d51765
Optimization Enabled:
Yes with 200 runs
Other Settings:
default evmVersion
Contract Source Code (Solidity Standard Json-Input format)
// SPDX-License-Identifier: MIT pragma solidity 0.6.12; pragma experimental ABIEncoderV2; import "@openzeppelin/contracts/token/ERC20/IERC20.sol"; import "@openzeppelin/contracts/token/ERC20/SafeERC20.sol"; import "@openzeppelin/contracts/token/ERC721/IERC721.sol"; import "@openzeppelin/contracts/token/ERC721/ERC721Holder.sol"; import "@openzeppelin/contracts/introspection/ERC165.sol"; import "@openzeppelin/contracts/introspection/IERC1820Registry.sol"; import "@openzeppelin/contracts/utils/ReentrancyGuard.sol"; import "@prps/solidity/contracts/IBoostableERC20.sol"; import "./DubiexLib.sol"; import "./Boostable.sol"; /** * @dev The Dubiex contract * * Supported currencies: * - ETH * - ERC20 * - BoostedERC20 * - ERC721 * * Any owner of ERC721 tokens may wish to approve Dubiex for all his/her tokens, * by calling `setApprovalForAll()`. Then approval for subsequent trades isn't required either. * * ERC20 can be approved once with an practically-infinite amount, then Dubiex requires * approval only once as well. * * BoostedERC20 tokens are designed to work without any explicit approval for Dubiex. * * External functions: * - makeOrder(s) * - takeOrder(s) * - cancelOrder(s) * - getOrder() * - boostedMakeOrder(Batch) * - boostedTakeOrder(Batch) * - boostedCanceleOrder(Batch) * */ contract Dubiex is ReentrancyGuard, ERC721Holder, Boostable { using SafeERC20 for IERC20; bytes32 private constant _BOOSTABLE_ERC20_TOKEN_HASH = keccak256( "BoostableERC20Token" ); // https://github.com/OpenZeppelin/openzeppelin-contracts/blob/v3.1.0/contracts/token/ERC721/ERC721.sol#L68 bytes4 private constant _ERC721_INTERFACE_HASH = 0x80ac58cd; IERC1820Registry private constant _ERC1820_REGISTRY = IERC1820Registry( 0x1820a4B7618BdE71Dce8cdc73aAB6C95905faD24 ); // This is a empty order to workaround: // "This variable is of storage pointer type and can be accessed without prior assignment, which would lead to undefined behaviour" // In places where we need to return a zero-initialized storage order. DubiexLib.PackedOrderBookItem private emptyOrder; // Only required for burning fuel address private immutable _prps; address private immutable _dubi; // Security mechanism which anyone can enable if the total supply of PRPS or DUBI should ever go >= 1 billion bool private _killSwitchOn; function activateKillSwitch() public { require(!_killSwitchOn, "Dubiex: kill switch already on"); uint256 oneBillion = 1000000000 * 1 ether; uint256 totalPrpsSupply = IERC20(_prps).totalSupply(); uint256 totalDubiSupply = IERC20(_dubi).totalSupply(); require( totalPrpsSupply >= oneBillion || totalDubiSupply >= oneBillion, "Dubiex: insufficient total supply for kill switch" ); _killSwitchOn = true; } constructor( address optIn, address prps, address dubi ) public ReentrancyGuard() Boostable(optIn) { _prps = prps; _dubi = dubi; } event MadeOrder( uint32 id, address maker, // uint96 makerValue, uint96 takerValue, uint32 orderPairAlias, uint32 padding uint256 packedData ); event TookOrder( uint32 id, address maker, address taker, // uint96 makerValue, uint96 takerValue, uint32 orderPairAlias, uint32 padding uint256 packedData ); event CanceledOrder(address maker, uint32 id); event UpdatedOrder(address maker, uint32 id); /** * @dev Order pair aliases are generated by incrementing a number. Although the counter * is using 32 bits, we do not support more than 2**28 = 268_435_456 pairs for technical reasons. */ uint32 private _orderPairAliasCounter; /** * @dev A mapping of order pair alias to a packed order pair. */ mapping(uint32 => DubiexLib.PackedOrderPair) private _orderPairsByAlias; /** * @dev A reverse mapping of order pair hash to an order pair alias. Required to check if * a given pair already exists when creating an order where the full pair information are * provided instead of an alias. I.e. * MakeOrder { * ... * makerCurrencyType: ..., * takerCurrencyType: ..., * makerContractAddress: ..., * takerContractAddress: ..., * } * * The hash of these four fields is used as the key of the mapping. */ mapping(bytes32 => uint32) private _orderPairAliasesByHash; /** * @dev Mapping of address to a counter for order ids. */ mapping(address => uint32) private _counters; /** * @dev Mapping of address to packed order book items. */ mapping(address => DubiexLib.PackedOrderBookItem[]) private _ordersByAddress; /** * @dev Get an order by id. If the id doesn't exist (e.g. got cancelled / filled), a default order is returned. * The caller should therefore check the id of the returned item. Any non-zero value means the order exists. */ function getOrder(address maker, uint64 id) public view returns (DubiexLib.PrettyOrderBookItem memory) { DubiexLib.PackedOrderBookItem[] storage orders = _ordersByAddress[maker]; for (uint256 i = 0; i < orders.length; i++) { DubiexLib.PackedOrderBookItem storage _packed = orders[i]; DubiexLib.UnpackedOrderBookItem memory _unpacked = DubiexLib .unpackOrderBookItem(_packed.packedData); if (_unpacked.id == id) { DubiexLib.PrettyOrderBookItem memory pretty; pretty.id = _unpacked.id; pretty.makerValue = _unpacked.makerValue; pretty.takerValue = _unpacked.takerValue; pretty.orderPairAlias = _unpacked.orderPairAlias; pretty.pair = getOrderPairByAlias(_unpacked.orderPairAlias); pretty.flags = _unpacked.flags; pretty.successorOrderId = _packed.successorOrderId; pretty.ancestorOrderId = _packed.ancestorOrderId; return pretty; } } DubiexLib.PrettyOrderBookItem memory empty; return empty; } /** * @dev Get an order pair by alias. */ function getOrderPairByAlias(uint32 orderPairAlias) public view returns (DubiexLib.OrderPair memory) { DubiexLib.OrderPair memory orderPair; DubiexLib.PackedOrderPair storage packedOrderPair = _orderPairsByAlias[orderPairAlias]; ( address makerContractAddress, DubiexLib.CurrencyType makerCurrencyType ) = DubiexLib.unpackOrderPairAddressType(packedOrderPair.makerPair); ( address takerContractAddress, DubiexLib.CurrencyType takerCurrencyType ) = DubiexLib.unpackOrderPairAddressType(packedOrderPair.takerPair); orderPair.makerContractAddress = makerContractAddress; orderPair.makerCurrencyType = makerCurrencyType; orderPair.takerContractAddress = takerContractAddress; orderPair.takerCurrencyType = takerCurrencyType; return orderPair; } /** * @dev Get an order pair by it's hash. */ function getOrderPairByHash(bytes32 orderPairHash) public view returns (DubiexLib.OrderPair memory) { uint32 orderPairAlias = _orderPairAliasesByHash[orderPairHash]; return getOrderPairByAlias(orderPairAlias); } /** * @dev Get an order pair alias by it's hash. */ function getOrderPairAliasByHash(bytes32 orderPairHash) public view returns (uint32) { return _orderPairAliasesByHash[orderPairHash]; } /** * @dev Make a single order. Reverts on failure. * * If an `orderId` is provided, an already existing order will be updated * according to `updatedWeiRatio`. For efficiency reasons, the id of the updated order * remains the same. Taker orders provide a minimum ratio to protect themselves against * front-running by the maker. * * Returns the assigned order id. */ function makeOrder(DubiexLib.MakeOrderInput memory input) external payable nonReentrant returns (uint32) { require(!_killSwitchOn, "Dubiex: make order prevented by kill switch"); uint256 excessEth = msg.value; uint32 orderId; (orderId, excessEth) = _makeOrderInternal({ input: input, maker: msg.sender, excessEthAndIntrinsicFuel: excessEth, isBoosted: false, revertOnUpdateError: true }); _refundExcessEth(excessEth); return orderId; } /** * @dev Create multiple orders at once. The transaction won't revert if any make order fails, but * silently ignore it. Returns an array of order ids where each item corresponds to an input * at the same index and non-zero values indicate success. */ function makeOrders(DubiexLib.MakeOrderInput[] memory inputs) external payable nonReentrant returns (uint32[] memory) { require(!_killSwitchOn, "Dubiex: make order prevented by kill switch"); require(inputs.length > 0, "Dubiex: empty inputs"); uint32[] memory orderIds = new uint32[](inputs.length); uint256 excessEth = msg.value; for (uint256 i = 0; i < inputs.length; i++) { uint32 orderId; (orderId, excessEth) = _makeOrderInternal({ input: inputs[i], maker: msg.sender, excessEthAndIntrinsicFuel: excessEth, isBoosted: false, revertOnUpdateError: false }); orderIds[i] = orderId; } _refundExcessEth(excessEth); return orderIds; } /** * @dev Take a single order. Reverts on failure. */ function takeOrder(DubiexLib.TakeOrderInput calldata input) external payable nonReentrant { require(!_killSwitchOn, "Dubiex: take order prevented by kill switch"); uint256 excessEth = msg.value; (, excessEth, ) = _takeOrderInternal({ input: input, taker: msg.sender, excessEthAndIntrinsicFuel: excessEth, revertOnError: true, isBoosted: false }); _refundExcessEth(excessEth); } /** * @dev Take multiple orders at once. The transaction won't revert if any take order fails, but * silently ignore it. Check the logs in the receipt to see if any failed. * * See `takeOrder` for more information about the opt-in. * * @param inputs the take order inputs */ function takeOrders(DubiexLib.TakeOrderInput[] calldata inputs) external payable nonReentrant returns (bool[] memory) { require(!_killSwitchOn, "Dubiex: take order prevented by kill switch"); require(inputs.length > 0, "Dubiex: empty inputs"); bool[] memory result = new bool[](inputs.length); uint256 excessEth = msg.value; for (uint256 i = 0; i < inputs.length; i++) { bool success; (success, excessEth, ) = _takeOrderInternal({ input: inputs[i], taker: msg.sender, excessEthAndIntrinsicFuel: uint96(excessEth), revertOnError: false, isBoosted: false }); result[i] = success; } _refundExcessEth(excessEth); return result; } /** * @dev Cancel a single order. */ function cancelOrder(DubiexLib.CancelOrderInput memory input) external nonReentrant { _cancelOrderInternal({ maker: input.maker, id: input.id, intrinsicFuel: 0, isBoosted: false, revertOnError: true, isKillSwitchOn: _killSwitchOn }); } /** * @dev Cancel multiple orders at once. It will not revert on error, but ignore failed * orders silently. Check the logs in the receipt to see if any failed. * * @return Array of booleans with `ids.length` items where each item corresponds to an id * at the same index and `true` indicate success. */ function cancelOrders(DubiexLib.CancelOrderInput[] calldata inputs) external nonReentrant returns (bool[] memory) { require(inputs.length > 0, "Dubiex: empty inputs"); bool[] memory result = new bool[](inputs.length); bool isKillSwitchOn = _killSwitchOn; for (uint256 i = 0; i < inputs.length; i++) { result[i] = _cancelOrderInternal({ maker: inputs[i].maker, id: inputs[i].id, intrinsicFuel: 0, isBoosted: false, revertOnError: false, isKillSwitchOn: isKillSwitchOn }); } return result; } /** * @dev Create an order for the signer of `signature`. */ function boostedMakeOrder( BoostedMakeOrder memory order, Signature memory signature ) public payable nonReentrant returns (uint32) { require(!_killSwitchOn, "Dubiex: make order prevented by kill switch"); uint32 orderId; uint256 excessEth = msg.value; (orderId, excessEth) = _boostedMakeOrderInternal( order, signature, excessEth, true ); _refundExcessEth(excessEth); return orderId; } function _boostedMakeOrderInternal( BoostedMakeOrder memory order, Signature memory signature, uint256 excessEth, bool revertOnUpdateError ) private returns (uint32, uint256) { uint96 intrinsicFuel = _burnFuel(order.maker, order.fuel); // We optimize ERC721 sell orders by not increasing the // nonce, because every ERC721 is unique - trying to replay the // transaction while the signature hasn't expired yet is almost // guaranteed to always fail. The only scenarios where it would be // possible is: // - if the order gets cancelled // - the order is filled by the maker OR the taker sends it back to the maker // // But this all has to happen in a very short timeframe, so the chance of this happening // is really low. // if ( order.input.pair.makerCurrencyType == DubiexLib.CurrencyType.ERC721 ) { _verifyBoostWithoutNonce( order.maker, hashBoostedMakeOrder(order, msg.sender), order.boosterPayload, signature ); } else { verifyBoost( order.maker, hashBoostedMakeOrder(order, msg.sender), order.boosterPayload, signature ); } uint32 orderId; // Encode the intrinsic fuel in the upper bits of the excess eth, // because we are hitting 'CompilerError: Stack too deep'. uint256 excessEthAndIntrinsicFuel = excessEth; excessEthAndIntrinsicFuel |= uint256(intrinsicFuel) << 96; (orderId, excessEth) = _makeOrderInternal({ maker: order.maker, input: order.input, excessEthAndIntrinsicFuel: excessEthAndIntrinsicFuel, isBoosted: true, revertOnUpdateError: revertOnUpdateError }); return (orderId, excessEth); } /** * @dev Take an order for the signer of `signature`. */ function boostedTakeOrder( BoostedTakeOrder memory order, Signature memory signature ) public payable nonReentrant { require(!_killSwitchOn, "Dubiex: take order prevented by kill switch"); uint256 excessEth = _boostedTakeOrderInternal({ order: order, signature: signature, excessEth: msg.value, revertOnError: true }); _refundExcessEth(excessEth); } function _boostedTakeOrderInternal( BoostedTakeOrder memory order, Signature memory signature, uint256 excessEth, bool revertOnError ) private returns (uint256) { uint96 intrinsicFuel = _burnFuel(order.taker, order.fuel); // Encode the intrinsic fuel in the upper bits of the excess eth, // because we are hitting 'CompilerError: Stack too deep'. uint256 excessEthAndIntrinsicFuel = excessEth; excessEthAndIntrinsicFuel |= uint256(intrinsicFuel) << 96; DubiexLib.CurrencyType takerCurrencyType; (, excessEth, takerCurrencyType) = _takeOrderInternal({ input: order.input, taker: order.taker, excessEthAndIntrinsicFuel: excessEthAndIntrinsicFuel, revertOnError: revertOnError, isBoosted: true }); // We optimize ERC721 take orders by not increasing the // nonce, because every ERC721 is unique - trying to replay the // transaction will always fail, since once taken - the target order doesn't // exist anymore and thus cannot be filled ever again. if (takerCurrencyType == DubiexLib.CurrencyType.ERC721) { _verifyBoostWithoutNonce( order.taker, hashBoostedTakeOrder(order, msg.sender), order.boosterPayload, signature ); } else { verifyBoost( // The signer of the boosted message order.taker, hashBoostedTakeOrder(order, msg.sender), order.boosterPayload, signature ); } return excessEth; } /** * @dev Cancel an order for the signer of `signature`. */ function boostedCancelOrder( BoostedCancelOrder memory order, Signature memory signature ) public payable nonReentrant { bool isKillSwitchOn = _killSwitchOn; _boostedCancelOrderInternal(order, signature, true, isKillSwitchOn); } function _boostedCancelOrderInternal( BoostedCancelOrder memory order, Signature memory signature, bool reverOnError, bool isKillSwitchOn ) private { uint96 intrinsicFuel = _burnFuel(order.input.maker, order.fuel); // We do not need a nonce, since once cancelled the order id can never be re-used again _verifyBoostWithoutNonce( order.input.maker, hashBoostedCancelOrder(order, msg.sender), order.boosterPayload, signature ); // Encode the intrinsic fuel in the upper bits of the excess eth, // (which for cancel order is always 0), because we are hitting 'CompilerError: Stack too deep'. uint256 excessEthAndIntrinsicFuel; excessEthAndIntrinsicFuel |= uint256(intrinsicFuel) << 96; _cancelOrderInternal({ maker: order.input.maker, id: order.input.id, isBoosted: true, intrinsicFuel: excessEthAndIntrinsicFuel, revertOnError: reverOnError, isKillSwitchOn: isKillSwitchOn }); } /** * @dev Perform multiple `boostedMakeOrder` calls in a single transaction. */ function boostedMakeOrderBatch( BoostedMakeOrder[] calldata orders, Signature[] calldata signatures ) external payable nonReentrant { require(!_killSwitchOn, "Dubiex: make order prevented by kill switch"); require( orders.length > 0 && orders.length == signatures.length, "Dubiex: invalid input lengths" ); uint256 excessEth = msg.value; for (uint256 i = 0; i < orders.length; i++) { (, excessEth) = _boostedMakeOrderInternal( orders[i], signatures[i], uint96(excessEth), false ); } } /** * @dev Perform multiple `boostedTakeOrder` calls in a single transaction. */ function boostedTakeOrderBatch( BoostedTakeOrder[] memory boostedTakeOrders, Signature[] calldata signatures ) external payable nonReentrant { require(!_killSwitchOn, "Dubiex: take order prevented by kill switch"); require( boostedTakeOrders.length > 0 && boostedTakeOrders.length == signatures.length, "Dubiex: invalid input lengths" ); uint256 excessEth = msg.value; for (uint256 i = 0; i < boostedTakeOrders.length; i++) { excessEth = _boostedTakeOrderInternal( boostedTakeOrders[i], signatures[i], uint96(excessEth), false ); } _refundExcessEth(excessEth); } /** * @dev Perform multiple `boostedCancelOrder` calls in a single transaction. */ function boostedCancelOrderBatch( BoostedCancelOrder[] memory orders, Signature[] calldata signatures ) external payable nonReentrant returns (uint32) { require( orders.length > 0 && orders.length == signatures.length, "Dubiex: invalid input lengths" ); bool isKillSwitchOn = _killSwitchOn; for (uint256 i = 0; i < orders.length; i++) { _boostedCancelOrderInternal( orders[i], signatures[i], false, isKillSwitchOn ); } } /** * @dev Create a new single order. * * @return the assigned order id */ function _makeOrderInternal( DubiexLib.MakeOrderInput memory input, address payable maker, uint256 excessEthAndIntrinsicFuel, bool isBoosted, bool revertOnUpdateError ) private returns (uint32, uint256) { require( maker != address(this) && maker != address(0), "Dubiex: unexpected maker" ); // An explicit id means an existing order should be updated. if (input.orderId > 0) { return ( _updateOrder( maker, input.orderId, input.updatedRatioWei, revertOnUpdateError ), // Update order never uses eth, so we refund everything in case something was mistakenly sent uint96(excessEthAndIntrinsicFuel) ); } // Reverts if the input is invalid require(input.makerValue > 0, "Dubiex: makerValue must be greater 0"); require(input.takerValue > 0, "Dubiex: takerValue must be greater 0"); // Reverts if the order pair is incompatible uint32 orderPairAlias = _getOrCreateOrderPairAlias(input.pair); // Deposit the makerValue, which will fail if no approval has been given // or the maker hasn't enough funds. // NOTE(reentrancy): safe, because we are using `nonReentrant` for makeOrder(s). // NOTE2: _transfer returns the *excessEth* only, but we reuse the 'excessEthAndIntrinsicFuel' variable // to work around 'CompilerError: Stack too deep'. bool deposited; (deposited, excessEthAndIntrinsicFuel) = _transfer({ from: maker, to: payable(address(this)), value: input.makerValue, valueContractAddress: input.pair.makerContractAddress, valueCurrencyType: input.pair.makerCurrencyType, excessEthAndIntrinsicFuel: excessEthAndIntrinsicFuel, isBoosted: isBoosted }); require(deposited, "Dubiex: failed to deposit. not enough funds?"); // Create the orderbook item DubiexLib.PackedOrderBookItem memory _packed; DubiexLib.UnpackedOrderBookItem memory _unpacked; _unpacked.id = _getNextOrderId(maker); _unpacked.makerValue = input.makerValue; _unpacked.takerValue = input.takerValue; _unpacked.orderPairAlias = orderPairAlias; _unpacked.flags.isMakerERC721 = input.pair.makerCurrencyType == DubiexLib.CurrencyType.ERC721; _unpacked.flags.isTakerERC721 = input.pair.takerCurrencyType == DubiexLib.CurrencyType.ERC721; // Update ancestor order if any _updateOrderAncestorIfAny(input, maker, _unpacked, _packed); // Pack unpacked data and write to storage _packed.packedData = DubiexLib.packOrderBookItem(_unpacked); _ordersByAddress[maker].push(_packed); // Emit event and done uint256 packedData; packedData |= input.makerValue; packedData |= uint256(input.takerValue) << 96; packedData |= uint256(orderPairAlias) << (96 + 96); emit MadeOrder(_unpacked.id, maker, packedData); return (_unpacked.id, excessEthAndIntrinsicFuel); } function _updateOrderAncestorIfAny( DubiexLib.MakeOrderInput memory input, address maker, DubiexLib.UnpackedOrderBookItem memory unpacked, DubiexLib.PackedOrderBookItem memory packed ) private { // If an ancestor is provided, we check if it exists and try to make this order // an successor of it. If it succeeds, then this order ends up being hidden. if (input.ancestorOrderId > 0) { packed.ancestorOrderId = input.ancestorOrderId; bool success = _setSuccessorOfAncestor( maker, input.ancestorOrderId, unpacked.id ); // New successor order must be hidden if it has an existing ancestor now unpacked.flags.isHidden = success; } } /** * @dev Take a make order. * @param input the take order input. * @param taker address of the taker * @param revertOnError whether to revert on errors or not. True, when taking a single order. * */ function _takeOrderInternal( address payable taker, DubiexLib.TakeOrderInput memory input, uint256 excessEthAndIntrinsicFuel, bool revertOnError, bool isBoosted ) private returns ( bool, uint256, DubiexLib.CurrencyType ) { ( DubiexLib.PackedOrderBookItem storage _packed, DubiexLib.UnpackedOrderBookItem memory _unpacked, uint256 index ) = _assertTakeOrderInput(input, revertOnError); // Order doesn't exist or input is invalid. if (_unpacked.id == 0) { // Only gets here if 'revertOnError' is false return ( false, uint96(excessEthAndIntrinsicFuel), DubiexLib.CurrencyType.NULL ); } // Get the actual makerValue, which might just be a fraction of the total // `takerValue` of the `_makeOrder`. (uint96 _makerValue, uint96 _takerValue) = _calculateMakerAndTakerValue( _unpacked, input.takerValue, input.maxTakerMakerRatio ); if (_makerValue == 0 || _takerValue == 0) { if (revertOnError) { revert("Dubiex: invalid takerValue"); } return ( false, uint96(excessEthAndIntrinsicFuel), DubiexLib.CurrencyType.NULL ); } // Transfer from taker to maker // NOTE(reentrancy): `takeOrder(s)` is marked nonReentrant // NOTE2: _transferFromTakerToMaker returns the *excessEth* only, but we reuse the 'excessEthAndIntrinsicFuel' variable // to work around 'CompilerError: Stack too deep'. excessEthAndIntrinsicFuel = _transferFromTakerToMaker( taker, input.maker, _takerValue, _unpacked.pair, excessEthAndIntrinsicFuel, isBoosted ); // Transfer from maker to taker // NOTE(reentrancy): `takeOrder(s)` is marked nonReentrant if ( !_transferFromContractToTaker( taker, _makerValue, _unpacked.pair, false, 0 ) ) { if (revertOnError) { revert("Dubiex: failed to transfer value to taker"); } return ( false, excessEthAndIntrinsicFuel, DubiexLib.CurrencyType.NULL ); } // If filled, the order can be deleted (without having to update the maker/taker value) if (_unpacked.makerValue - _makerValue == 0) { // Make successor of filled order visible if any. if (_unpacked.flags.hasSuccessor) { _setOrderVisible(input.maker, _packed.successorOrderId); } // Delete the filled order _deleteOrder({maker: input.maker, index: index}); } else { // Not filled yet, so update original make order _unpacked.makerValue -= _makerValue; _unpacked.takerValue -= _takerValue; // Write updated item to storage _packed.packedData = DubiexLib.packOrderBookItem(_unpacked); } // NOTE: We write the new taker/maker value to the in-memory struct // and pass it to a function that emits 'TookOrder' to avoid the 'Stack too deep' error _unpacked.makerValue = _makerValue; _unpacked.takerValue = _takerValue; return _emitTookOrder( input.maker, taker, _unpacked, excessEthAndIntrinsicFuel ); } /** * @dev Emit 'TookOrder' in a separate function to avoid the 'Stack too deep' error */ function _emitTookOrder( address maker, address taker, DubiexLib.UnpackedOrderBookItem memory unpacked, uint256 excessEthAndIntrinsicFuel ) private returns ( bool, uint256, DubiexLib.CurrencyType ) { uint256 packedData; packedData |= unpacked.makerValue; packedData |= uint256(unpacked.takerValue) << 96; packedData |= uint256(unpacked.orderPairAlias) << (96 + 96); emit TookOrder(unpacked.id, maker, taker, packedData); return ( true, excessEthAndIntrinsicFuel, unpacked.pair.takerCurrencyType ); } /** * @dev Cancel an order * @param maker the maker of the order * @param id the id of the order to cancel * @param revertOnError whether to revert on errors or not */ function _cancelOrderInternal( address payable maker, uint32 id, uint256 intrinsicFuel, bool isBoosted, bool revertOnError, bool isKillSwitchOn ) private returns (bool) { // Anyone can cancel any order if the kill switch is on. // For efficiency, we do not need to check the kill switch if this is a boosted cancel order, // because in that case we already have the explicit consent of the maker. // If it's neither a boosted cancel nor a post-kill switch cancel, the msg.sender must be the maker. if (!isBoosted && !isKillSwitchOn) { require(maker == msg.sender, "Dubiex: msg.sender must be maker"); } if (!revertOnError && !_orderExists(maker, id)) { return false; } // Get the make order (reverts if order doesn't exist) ( , DubiexLib.UnpackedOrderBookItem memory unpacked, uint256 index ) = _safeGetOrder(maker, id, DubiexLib.OrderPairReadStrategy.MAKER); // Transfer remaining `makerValue` back to maker, by assuming the taker role with the maker. // NOTE(reentrancy): `cancelOrder(s)` is marked nonReentrant if ( !_transferFromContractToTaker({ taker: maker, makerValue: unpacked.makerValue, pair: unpacked.pair, isBoosted: isBoosted, excessEthAndIntrinsicFuel: intrinsicFuel }) ) { return false; } // Delete the cancelled order _deleteOrder({maker: maker, index: index}); emit CanceledOrder(maker, id); return true; } /** * @dev Update the `takerValue` of an order using the given `updatedRatioWei` * @param maker the maker of the order to update * @param orderId the id of the existing order * @param updatedRatioWei the new ratio in wei */ function _updateOrder( address maker, uint32 orderId, uint128 updatedRatioWei, bool revertOnUpdateError ) private returns (uint32) { ( DubiexLib.PackedOrderBookItem storage _packed, DubiexLib.UnpackedOrderBookItem memory _unpacked, ) = _getOrder(maker, orderId, DubiexLib.OrderPairReadStrategy.SKIP); // Order doesn't exist if (_unpacked.id == 0) { if (revertOnUpdateError) { revert("Dubiex: order does not exist"); } return 0; } // We don't prevent reverts here, even if `revertOnUpdateError` is false since // they are user errors unlike a non-existing order which a user has no control over. require(updatedRatioWei > 0, "Dubiex: ratio is 0"); require( !_unpacked.flags.isMakerERC721 && !_unpacked.flags.isTakerERC721, "Dubiex: cannot update ERC721 value" ); // Update the existing order with the new ratio to the takerValue. // The makerValue stays untouched. uint256 updatedTakerValue = (uint256(_unpacked.makerValue) * uint256(updatedRatioWei)) / 1 ether; require(updatedTakerValue < 2**96, "Dubiex: takerValue overflow"); _unpacked.takerValue = uint96(updatedTakerValue); _packed.packedData = DubiexLib.packOrderBookItem(_unpacked); emit UpdatedOrder(maker, orderId); return orderId; } // If both returned values are > 0, then the provided `takerValue` and `maxTakerMakerRatio` are valid. function _calculateMakerAndTakerValue( DubiexLib.UnpackedOrderBookItem memory _unpacked, uint96 takerValue, uint256 maxTakerMakerRatio ) private pure returns (uint96, uint96) { uint256 calculatedMakerValue = _unpacked.makerValue; uint256 calculatedTakerValue = takerValue; // ERC721 cannot be bought/sold partially, therefore the `takerValue` must match the requested // value exactly. if ( _unpacked.pair.makerCurrencyType == DubiexLib.CurrencyType.ERC721 || _unpacked.pair.takerCurrencyType == DubiexLib.CurrencyType.ERC721 ) { if (takerValue != _unpacked.takerValue) { return (0, 0); } // The order gets filled completely, so we use the values as is. } else { // Calculate the current takerMakerValue ratio and compare it to `maxTakerMakerRatio`. // If it is higher then the order will not be taken. uint256 takerMakerRatio = (uint256(_unpacked.takerValue) * 1 ether) / calculatedMakerValue; if (maxTakerMakerRatio < takerMakerRatio) { return (0, 0); } if (calculatedTakerValue > _unpacked.takerValue) { calculatedTakerValue = _unpacked.takerValue; } // Calculate actual makerValue for ETH/ERC20 trades which might only get partially filled by the // takerValue. Since we don't have decimals, we need to multiply by 10^18 and divide by it again at the end // to not lose any information. calculatedMakerValue *= 1 ether; calculatedMakerValue *= calculatedTakerValue; calculatedMakerValue /= _unpacked.takerValue; calculatedMakerValue /= 1 ether; } // Sanity checks assert( calculatedMakerValue < 2**96 && calculatedMakerValue <= _unpacked.makerValue ); assert( calculatedTakerValue < 2**96 && calculatedTakerValue <= _unpacked.takerValue ); return (uint96(calculatedMakerValue), uint96(calculatedTakerValue)); } /** * @dev Assert a take order input and return the order. If a zero-order is returned, * then it does not exist and it is up to the caller how to handle it. */ function _assertTakeOrderInput( DubiexLib.TakeOrderInput memory input, bool revertOnError ) private view returns ( DubiexLib.PackedOrderBookItem storage, DubiexLib.UnpackedOrderBookItem memory, uint256 // index ) { ( DubiexLib.PackedOrderBookItem storage packed, DubiexLib.UnpackedOrderBookItem memory unpacked, uint256 index ) = _getOrder( input.maker, input.id, DubiexLib.OrderPairReadStrategy.FULL ); bool validTakerValue = input.takerValue > 0; bool orderExistsAndNotHidden = unpacked.id > 0 && !unpacked.flags.isHidden; if (revertOnError) { require(validTakerValue, "Dubiex: takerValue must be greater 0"); require(orderExistsAndNotHidden, "Dubiex: order does not exist"); } else { if (!validTakerValue || !orderExistsAndNotHidden) { DubiexLib.UnpackedOrderBookItem memory emptyUnpacked; return (emptyOrder, emptyUnpacked, 0); } } return (packed, unpacked, index); } function _orderExists(address maker, uint32 id) private view returns (bool) { // Since we don't want to revert for cancelOrders, we have to check that the order // (maker, id) exists by looping over the orders of the maker and comparing the id. DubiexLib.PackedOrderBookItem[] storage orders = _ordersByAddress[maker]; uint256 length = orders.length; for (uint256 i = 0; i < length; i++) { // The first 32 bits of the packed data corresponds to the id. By casting to uint32, // we can compare the id without having to unpack the entire thing. uint32 orderId = uint32(orders[i].packedData); if (orderId == id) { // Found order return true; } } // Doesn't exist return false; } function _refundExcessEth(uint256 excessEth) private { // Casting to uint96 to get rid off any of the higher utility bits excessEth = uint96(excessEth); // Sanity check assert(msg.value >= excessEth); if (excessEth > 0) { msg.sender.transfer(excessEth); } } // Transfer `takerValue` to `maker`. function _transferFromTakerToMaker( address payable taker, address payable maker, uint96 takerValue, DubiexLib.OrderPair memory pair, uint256 excessEthAndIntrinsicFuel, bool isBoosted ) private returns (uint256) { (bool success, uint256 excessEth) = _transfer( taker, maker, takerValue, pair.takerContractAddress, pair.takerCurrencyType, excessEthAndIntrinsicFuel, isBoosted ); require(success, "Dubiex: failed to transfer value to maker"); return excessEth; } // Transfer `makerValue` to `taker` function _transferFromContractToTaker( address payable taker, uint96 makerValue, DubiexLib.OrderPair memory pair, bool isBoosted, uint256 excessEthAndIntrinsicFuel ) private returns (bool) { (bool success, ) = _transfer( payable(address(this)), taker, makerValue, pair.makerContractAddress, pair.makerCurrencyType, excessEthAndIntrinsicFuel, isBoosted ); return success; } function _transfer( address payable from, address payable to, uint256 value, address valueContractAddress, DubiexLib.CurrencyType valueCurrencyType, uint256 excessEthAndIntrinsicFuel, bool isBoosted ) private returns (bool, uint256) { uint256 excessEth = uint96(excessEthAndIntrinsicFuel); if (valueCurrencyType == DubiexLib.CurrencyType.ETH) { // Eth is a bit special, because it's not a token. Therefore we need to ensure // that the taker/maker sent enough eth (`excessEth` >= `value`) and also that // he is refunded at the end of the transaction properly. if (from != address(this)) { if (excessEth < value) { return (false, excessEth); } // Got enough eth, but maybe too much, so we subtract the value from the excessEth. This is important // to refund the sender correctly e.g. he mistakenly sent too much or the order // was partially filled while his transaction was pending. excessEth -= value; } // Not a deposit, so transfer eth owned by this contract to maker or taker if (to != address(this)) { to.transfer(value); } return (true, excessEth); } if (valueCurrencyType == DubiexLib.CurrencyType.ERC20) { IERC20 erc20 = IERC20(valueContractAddress); uint256 recipientBalanceBefore = erc20.balanceOf(to); if (from == address(this)) { // If sending own tokens, use `safeTransfer` because Dubiex doesn't have any allowance // for itself which would cause `safeTransferFrom` to fail. erc20.safeTransfer(to, value); } else { erc20.safeTransferFrom(from, to, value); } uint256 recipientBalanceAfter = erc20.balanceOf(to); // Safe guard to minimize the risk of getting buggy orders if the contract // deviates from the ERC20 standard. require( recipientBalanceAfter == recipientBalanceBefore + value, "Dubiex: failed to transfer ERC20 token" ); return (true, excessEth); } if (valueCurrencyType == DubiexLib.CurrencyType.BOOSTABLE_ERC20) { IBoostableERC20 erc20 = IBoostableERC20(valueContractAddress); if (from == address(this)) { // If sending own tokens, use `safeTransfer`, because Dubiex doesn't have any allowance // for itself which would cause `permissionSend` to fail. IERC20(address(erc20)).safeTransfer(to, value); } else { bool success = erc20.boostedTransferFrom( from, to, value, abi.encodePacked(isBoosted) ); require( success, "Dubiex: failed to transfer boosted ERC20 token" ); } return (true, excessEth); } if (valueCurrencyType == DubiexLib.CurrencyType.ERC721) { IERC721 erc721 = IERC721(valueContractAddress); // Pass isBoosted flag + fuel if any erc721.safeTransferFrom( from, to, value, abi.encodePacked( isBoosted, uint96(excessEthAndIntrinsicFuel >> 96) ) ); // Safe guard to minimize the risk of getting buggy orders if the contract // deviates from the ERC721 standard. require( erc721.ownerOf(value) == to, "Dubiex: failed to transfer ERC721 token" ); return (true, excessEth); } revert("Dubiex: unexpected currency type"); } /** * @dev Validates that the given contract address and currency type are compatible. * @param currencyType type of the currency * @param contractAddress the contract address associated with currency */ function _validateCurrencyType( DubiexLib.CurrencyType currencyType, address contractAddress ) private returns (bool) { if (currencyType == DubiexLib.CurrencyType.ETH) { require( contractAddress == address(0), "Dubiex: expected zero address" ); return true; } if (currencyType == DubiexLib.CurrencyType.ERC721) { // https://github.com/ethereum/EIPs/blob/master/EIPS/eip-721.md // // `contractAddress` must implement the ERC721 standard. According to the ERC721 standard // every compliant token is also expected to use ERC165 for that. require( IERC165(contractAddress).supportsInterface( _ERC721_INTERFACE_HASH ), "Dubiex: not ERC721 compliant" ); return true; } if (currencyType == DubiexLib.CurrencyType.BOOSTABLE_ERC20) { // The contract must implement the BOOSTABLE_ERC20 interface address implementer = _ERC1820_REGISTRY.getInterfaceImplementer( contractAddress, _BOOSTABLE_ERC20_TOKEN_HASH ); require( implementer != address(0), "Dubiex: not BoostableERC20 compliant" ); return true; } if (currencyType == DubiexLib.CurrencyType.ERC20) { // Using `call` is our last-resort to check if the given contract implements // ERC721, since we can't just call `supportsInterface` directly without reverting // if `contractAddress` doesn't implement it. Unlike above, where we want an ERC721, // so reverting is fine for non-ERC721 contracts. // // NOTE: bytes4(keccak256(supportsInterface(bytes4))) => 0x01ffc9a7 // solhint-disable-next-line avoid-low-level-calls (bool success, bytes memory result) = contractAddress.call( abi.encodeWithSelector(0x01ffc9a7, _ERC721_INTERFACE_HASH) ); // The call above must either fail (success = false) or if it succeeds, // return false. bool isERC721 = false; if (result.length > 0) { isERC721 = abi.decode(result, (bool)); } require(!success || !isERC721, "Dubiex: ERC20 implements ERC721"); // Lastly, we heuristically check if it responds to `balanceOf`. // If it succeeds, we assume it is an ERC20. // NOTE: bytes4(keccak256(balanceOf(address))) => 0x70a08231 result = Address.functionCall( contractAddress, abi.encodeWithSelector(0x70a08231, contractAddress) ); require(result.length > 0, "Dubiex: not ERC20 compliant"); return true; } return false; } /** * @dev Increment the order id counter and return the new id. */ function _getNextOrderId(address account) private returns (uint32) { uint32 currentId = _counters[account]; assert(currentId < 2**32); uint32 nextId = currentId + 1; _counters[account] = nextId; return nextId; } /** * @dev Get or create order pair alias from the given order pair. */ function _getOrCreateOrderPairAlias(DubiexLib.OrderPair memory pair) private returns (uint32) { bytes32 orderPairHash = keccak256( abi.encode( pair.makerContractAddress, pair.takerContractAddress, pair.makerCurrencyType, pair.takerCurrencyType ) ); uint32 orderPairAlias = _orderPairAliasesByHash[orderPairHash]; // If it doesn't exist yet, we create it (which makes the make order for the caller a bit more expensive). if (orderPairAlias == 0) { require( _validateCurrencyType( pair.makerCurrencyType, pair.makerContractAddress ), "Dubiex: makerContractAddress and currencyType mismatch" ); require( _validateCurrencyType( pair.takerCurrencyType, pair.takerContractAddress ), "Dubiex: takerContractAddress and currencyType mismatch" ); uint32 orderPairAliasCounter = _orderPairAliasCounter; orderPairAliasCounter++; orderPairAlias = orderPairAliasCounter; _orderPairAliasCounter = orderPairAliasCounter; // Write mappings _orderPairAliasesByHash[orderPairHash] = orderPairAlias; _orderPairsByAlias[orderPairAlias] = DubiexLib.packOrderPair(pair); } return orderPairAlias; } function _safeGetOrderPairByAlias( uint32 orderPairAlias, DubiexLib.OrderPairReadStrategy strategy ) private view returns (DubiexLib.OrderPair memory) { DubiexLib.OrderPair memory _unpackedOrderPair; if (strategy == DubiexLib.OrderPairReadStrategy.SKIP) { return _unpackedOrderPair; } DubiexLib.PackedOrderPair storage _pairStorage = _orderPairsByAlias[orderPairAlias]; // Read only maker info if requested if ( strategy == DubiexLib.OrderPairReadStrategy.MAKER || strategy == DubiexLib.OrderPairReadStrategy.FULL ) { ( address makerContractAddress, DubiexLib.CurrencyType makerCurrencyType ) = DubiexLib.unpackOrderPairAddressType(_pairStorage.makerPair); _unpackedOrderPair.makerContractAddress = makerContractAddress; _unpackedOrderPair.makerCurrencyType = makerCurrencyType; require( _unpackedOrderPair.makerCurrencyType != DubiexLib.CurrencyType.NULL, "Dubiex: maker order pair not found" ); } // Read only taker info if requested if ( strategy == DubiexLib.OrderPairReadStrategy.TAKER || strategy == DubiexLib.OrderPairReadStrategy.FULL ) { ( address takerContractAddress, DubiexLib.CurrencyType takerCurrencyType ) = DubiexLib.unpackOrderPairAddressType(_pairStorage.takerPair); _unpackedOrderPair.takerContractAddress = takerContractAddress; _unpackedOrderPair.takerCurrencyType = takerCurrencyType; require( _unpackedOrderPair.takerCurrencyType != DubiexLib.CurrencyType.NULL, "Dubiex: taker order pair not found" ); } return _unpackedOrderPair; } /** * @dev Tries to set the successor of the order with `ancestorOrderId`. * * - Reverts, if the ancestor exists and already has a successor. * - Returns false, if the ancestor doesn't exist. * - If it succeeds, then it implies that the ancestor hasn't been filled yet and thus * the caller has to ensure that the successor gets hidden. */ function _setSuccessorOfAncestor( address account, uint32 ancestorOrderId, uint32 successorOrderId ) private returns (bool) { DubiexLib.PackedOrderBookItem[] storage orders = _ordersByAddress[account]; uint256 length = orders.length; for (uint256 i = 0; i < length; i++) { DubiexLib.PackedOrderBookItem storage _packed = orders[i]; uint256 packedData = _packed.packedData; // The first 32 bits of the packed data corresponds to the id. By casting to uint32, // we can compare the id without having to unpack the entire thing. uint32 orderId = uint32(packedData); if (orderId == ancestorOrderId) { DubiexLib.UnpackedOrderBookItem memory _unpacked = DubiexLib .unpackOrderBookItem(packedData); // Set successor if none yet if (!_unpacked.flags.hasSuccessor) { _unpacked.flags.hasSuccessor = true; _packed.successorOrderId = successorOrderId; // Pack data again and update storage _packed.packedData = DubiexLib.packOrderBookItem(_unpacked); return true; } // Ancestor exists, but has already a successor revert("Dubiex: ancestor order already has a successor"); } } // Ancestor doesn't exist - so it got filled/cancelled or was never created to begin with. return false; } /** * @dev Makes the given successor order visible if it exists. */ function _setOrderVisible(address account, uint32 successorOrderId) private { DubiexLib.PackedOrderBookItem[] storage orders = _ordersByAddress[account]; uint256 length = orders.length; for (uint256 i = 0; i < length; i++) { DubiexLib.PackedOrderBookItem storage _packed = orders[i]; uint256 packedData = _packed.packedData; // The first 32 bits of the packed data corresponds to the id. By casting to uint32, // we can compare the id without having to unpack the entire thing. uint32 orderId = uint32(packedData); if (orderId == successorOrderId) { DubiexLib.UnpackedOrderBookItem memory _unpacked = DubiexLib .unpackOrderBookItem(packedData); _unpacked.flags.isHidden = false; // Write updated data _packed.packedData = DubiexLib.packOrderBookItem(_unpacked); break; } } } /** * @dev Returns the order from `account` with the given id from storage * plus the index of it. * * If it cannot be found, then this function reverts, because we expect the * caller to operate on existing orders. */ function _safeGetOrder( address account, uint32 id, DubiexLib.OrderPairReadStrategy strategy ) private view returns ( DubiexLib.PackedOrderBookItem storage, DubiexLib.UnpackedOrderBookItem memory, uint256 ) { DubiexLib.PackedOrderBookItem[] storage orders = _ordersByAddress[account]; uint256 length = orders.length; for (uint256 i = 0; i < length; i++) { DubiexLib.PackedOrderBookItem storage _packed = orders[i]; uint256 packedData = _packed.packedData; // The first 32 bits of the packed data corresponds to the id. By casting to uint32, // we can compare the id without having to unpack the entire thing. uint32 orderId = uint32(packedData); if (orderId == id) { DubiexLib.UnpackedOrderBookItem memory _unpacked = DubiexLib .unpackOrderBookItem(packedData); // Read the order pair with the given strategy _unpacked.pair = _safeGetOrderPairByAlias( _unpacked.orderPairAlias, strategy ); return (_packed, _unpacked, i); } } revert("Dubiex: order does not exist"); } /** * @dev Returns the order from `account` with the given id from storage * plus the index of it. * * If it cannot be found, then this function does not revert and it's up to the * caller to decide. */ function _getOrder( address account, uint32 id, DubiexLib.OrderPairReadStrategy strategy ) private view returns ( DubiexLib.PackedOrderBookItem storage, DubiexLib.UnpackedOrderBookItem memory, uint256 ) { DubiexLib.PackedOrderBookItem[] storage orders = _ordersByAddress[account]; uint256 length = orders.length; for (uint256 i = 0; i < length; i++) { DubiexLib.PackedOrderBookItem storage _packed = orders[i]; uint256 packedData = _packed.packedData; // The first 32 bits of the packed data corresponds to the id. By casting to uint32, // we can compare the id without having to unpack the entire thing. uint32 orderId = uint32(packedData); if (orderId == id) { DubiexLib.UnpackedOrderBookItem memory _unpacked = DubiexLib .unpackOrderBookItem(packedData); // Read the order pair with the given strategy // NOTE: This cannot revert when the order exists. _unpacked.pair = _safeGetOrderPairByAlias( _unpacked.orderPairAlias, strategy ); return (_packed, _unpacked, i); } } DubiexLib.UnpackedOrderBookItem memory _unpacked; return (emptyOrder, _unpacked, 0); } /** * @dev Delete an order of `maker` by index in O(1). */ function _deleteOrder(address maker, uint256 index) private { DubiexLib.PackedOrderBookItem[] storage orders = _ordersByAddress[maker]; uint256 length = orders.length; // swap and pop, changes the order if (index != length - 1) { // Move last item to the position of the to-be-deleted item (`index`) orders[index] = orders[length - 1]; } orders.pop(); } //--------------------------------------------------------------- // Fuel //--------------------------------------------------------------- /** * @dev Burn `fuel` from `from`. */ function _burnFuel(address from, BoosterFuel memory fuel) internal returns (uint96) { // Burn unlocked PRPS if (fuel.unlockedPrps > 0) { IBoostableERC20(address(_prps)).burnFuel( from, TokenFuel({ tokenAlias: 0, /* UNLOCKED PRPS */ amount: fuel.unlockedPrps }) ); return 0; } // Burn locked PRPS if (fuel.lockedPrps > 0) { IBoostableERC20(address(_prps)).burnFuel( from, TokenFuel({ tokenAlias: 1, /* LOCKED PRPS */ amount: fuel.lockedPrps }) ); return 0; } // Burn DUBI from balance if (fuel.dubi > 0) { IBoostableERC20(address(_dubi)).burnFuel( from, TokenFuel({ tokenAlias: 2, /* DUBI */ amount: fuel.dubi }) ); return 0; } // The intrinsic fuel is only supported for ERC721 tokens via // the 'safeTransferFrom' payload. if (fuel.intrinsicFuel > 0) { return fuel.intrinsicFuel; } // No fuel return 0; } }
// SPDX-License-Identifier: MIT pragma solidity 0.6.12; pragma experimental ABIEncoderV2; import "@prps/solidity/contracts/EIP712Boostable.sol"; import "./DubiexLib.sol"; /** * @dev Dubiex Boostable primitives following the EIP712 standard */ abstract contract Boostable is EIP712Boostable { bytes32 private constant BOOSTED_MAKE_ORDER_TYPEHASH = keccak256( "BoostedMakeOrder(MakeOrderInput input,address maker,BoosterFuel fuel,BoosterPayload boosterPayload)BoosterFuel(uint96 dubi,uint96 unlockedPrps,uint96 lockedPrps,uint96 intrinsicFuel)BoosterPayload(address booster,uint64 timestamp,uint64 nonce,bool isLegacySignature)MakeOrderInput(uint96 makerValue,uint96 takerValue,OrderPair pair,uint32 orderId,uint32 ancestorOrderId,uint128 updatedRatioWei)OrderPair(address makerContractAddress,address takerContractAddress,uint8 makerCurrencyType,uint8 takerCurrencyType)" ); bytes32 private constant BOOSTED_TAKE_ORDER_TYPEHASH = keccak256( "BoostedTakeOrder(TakeOrderInput input,address taker,BoosterFuel fuel,BoosterPayload boosterPayload)BoosterFuel(uint96 dubi,uint96 unlockedPrps,uint96 lockedPrps,uint96 intrinsicFuel)BoosterPayload(address booster,uint64 timestamp,uint64 nonce,bool isLegacySignature)TakeOrderInput(uint32 id,address maker,uint96 takerValue,uint256 maxTakerMakerRatio)" ); bytes32 private constant BOOSTED_CANCEL_ORDER_TYPEHASH = keccak256( "BoostedCancelOrder(CancelOrderInput input,BoosterFuel fuel,BoosterPayload boosterPayload)BoosterFuel(uint96 dubi,uint96 unlockedPrps,uint96 lockedPrps,uint96 intrinsicFuel)BoosterPayload(address booster,uint64 timestamp,uint64 nonce,bool isLegacySignature)CancelOrderInput(uint32 id,address maker)" ); bytes32 private constant MAKE_ORDER_INPUT_TYPEHASH = keccak256( "MakeOrderInput(uint96 makerValue,uint96 takerValue,OrderPair pair,uint32 orderId,uint32 ancestorOrderId,uint128 updatedRatioWei)OrderPair(address makerContractAddress,address takerContractAddress,uint8 makerCurrencyType,uint8 takerCurrencyType)" ); bytes32 private constant TAKE_ORDER_INPUT_TYPEHASH = keccak256( "TakeOrderInput(uint32 id,address maker,uint96 takerValue,uint256 maxTakerMakerRatio)" ); bytes32 private constant CANCEL_ORDER_INPUT_TYPEHASH = keccak256( "CancelOrderInput(uint32 id,address maker)" ); bytes32 private constant ORDER_PAIR_TYPEHASH = keccak256( "OrderPair(address makerContractAddress,address takerContractAddress,uint8 makerCurrencyType,uint8 takerCurrencyType)" ); constructor(address optIn) public EIP712Boostable( optIn, keccak256( abi.encode( EIP712_DOMAIN_TYPEHASH, keccak256("Dubiex"), keccak256("1"), _getChainId(), address(this) ) ) ) {} /** * @dev A struct representing the payload of `boostedMakeOrder`. */ struct BoostedMakeOrder { DubiexLib.MakeOrderInput input; address payable maker; BoosterFuel fuel; BoosterPayload boosterPayload; } /** * @dev A struct representing the payload of `boostedTakeOrder`. */ struct BoostedTakeOrder { DubiexLib.TakeOrderInput input; address payable taker; BoosterFuel fuel; BoosterPayload boosterPayload; } /** * @dev A struct representing the payload of `boostedCancelOrder`. */ struct BoostedCancelOrder { DubiexLib.CancelOrderInput input; BoosterFuel fuel; BoosterPayload boosterPayload; } function hashBoostedMakeOrder( BoostedMakeOrder memory boostedMakeOrder, address booster ) internal view returns (bytes32) { return BoostableLib.hashWithDomainSeparator( _DOMAIN_SEPARATOR, keccak256( abi.encode( BOOSTED_MAKE_ORDER_TYPEHASH, hashMakeOrderInput(boostedMakeOrder.input), boostedMakeOrder.maker, BoostableLib.hashBoosterFuel(boostedMakeOrder.fuel), BoostableLib.hashBoosterPayload( boostedMakeOrder.boosterPayload, booster ) ) ) ); } function hashBoostedTakeOrder( BoostedTakeOrder memory boostedTakeOrder, address booster ) internal view returns (bytes32) { return BoostableLib.hashWithDomainSeparator( _DOMAIN_SEPARATOR, keccak256( abi.encode( BOOSTED_TAKE_ORDER_TYPEHASH, hashTakeOrderInput(boostedTakeOrder.input), boostedTakeOrder.taker, BoostableLib.hashBoosterFuel(boostedTakeOrder.fuel), BoostableLib.hashBoosterPayload( boostedTakeOrder.boosterPayload, booster ) ) ) ); } function hashBoostedCancelOrder( BoostedCancelOrder memory boostedCancelOrder, address booster ) internal view returns (bytes32) { return BoostableLib.hashWithDomainSeparator( _DOMAIN_SEPARATOR, keccak256( abi.encode( BOOSTED_CANCEL_ORDER_TYPEHASH, hashCancelOrderInput(boostedCancelOrder.input), BoostableLib.hashBoosterFuel(boostedCancelOrder.fuel), BoostableLib.hashBoosterPayload( boostedCancelOrder.boosterPayload, booster ) ) ) ); } function hashMakeOrderInput(DubiexLib.MakeOrderInput memory input) private pure returns (bytes32) { return keccak256( abi.encode( MAKE_ORDER_INPUT_TYPEHASH, input.makerValue, input.takerValue, hashOrderPair(input.pair), input.orderId, input.ancestorOrderId, input.updatedRatioWei ) ); } function hashOrderPair(DubiexLib.OrderPair memory pair) private pure returns (bytes32) { return keccak256( abi.encode( ORDER_PAIR_TYPEHASH, pair.makerContractAddress, pair.takerContractAddress, pair.makerCurrencyType, pair.takerCurrencyType ) ); } function hashTakeOrderInput(DubiexLib.TakeOrderInput memory input) private pure returns (bytes32) { return keccak256( abi.encode( TAKE_ORDER_INPUT_TYPEHASH, input.id, input.maker, input.takerValue, input.maxTakerMakerRatio ) ); } function hashCancelOrderInput(DubiexLib.CancelOrderInput memory input) private pure returns (bytes32) { return keccak256( abi.encode(CANCEL_ORDER_INPUT_TYPEHASH, input.id, input.maker) ); } }
// SPDX-License-Identifier: MIT pragma solidity 0.6.12; pragma experimental ABIEncoderV2; import "@openzeppelin/contracts/cryptography/ECDSA.sol"; import "./IOptIn.sol"; import "./BoostableLib.sol"; import "./IBoostableERC20.sol"; /** * @dev Boostable base contract * * All deriving contracts are expected to implement EIP712 for the message signing. * */ abstract contract EIP712Boostable { using ECDSA for bytes32; // solhint-disable-next-line var-name-mixedcase IOptIn internal immutable _OPT_IN; // solhint-disable-next-line var-name-mixedcase bytes32 internal immutable _DOMAIN_SEPARATOR; bytes32 internal constant EIP712_DOMAIN_TYPEHASH = keccak256( "EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)" ); bytes32 private constant BOOSTER_PAYLOAD_TYPEHASH = keccak256( "BoosterPayload(address booster,uint64 timestamp,uint64 nonce,bool isLegacySignature)" ); bytes32 internal constant BOOSTER_FUEL_TYPEHASH = keccak256( "BoosterFuel(uint96 dubi,uint96 unlockedPrps,uint96 lockedPrps,uint96 intrinsicFuel)" ); // The boost fuel is capped to 10 of the respective token that will be used for payment. uint96 internal constant MAX_BOOSTER_FUEL = 10 ether; // A magic booster permission prefix bytes6 private constant MAGIC_BOOSTER_PERMISSION_PREFIX = "BOOST-"; constructor(address optIn, bytes32 domainSeparator) public { _OPT_IN = IOptIn(optIn); _DOMAIN_SEPARATOR = domainSeparator; } // A mapping of mappings to keep track of used nonces by address to // protect against replays. Each 'Boostable' contract maintains it's own // state for nonces. mapping(address => uint64) private _nonces; //--------------------------------------------------------------- function getNonce(address account) external virtual view returns (uint64) { return _nonces[account]; } function getOptInStatus(address account) internal view returns (IOptIn.OptInStatus memory) { return _OPT_IN.getOptInStatus(account); } /** * @dev Called by every 'boosted'-function to ensure that `msg.sender` (i.e. a booster) is * allowed to perform the call for `from` (the origin) by verifying that `messageHash` * has been signed by `from`. Additionally, `from` provides a nonce to prevent * replays. Boosts cannot be verified out of order. * * @param from the address that the boost is made for * @param messageHash the reconstructed message hash based on the function input * @param payload the booster payload * @param signature the signature of `from` */ function verifyBoost( address from, bytes32 messageHash, BoosterPayload memory payload, Signature memory signature ) internal { uint64 currentNonce = _nonces[from]; require(currentNonce == payload.nonce - 1, "AB-1"); _nonces[from] = currentNonce + 1; _verifyBoostWithoutNonce(from, messageHash, payload, signature); } /** * @dev Verify a boost without verifying the nonce. */ function _verifyBoostWithoutNonce( address from, bytes32 messageHash, BoosterPayload memory payload, Signature memory signature ) internal view { // The sender must be the booster specified in the payload require(msg.sender == payload.booster, "AB-2"); (bool isOptedInToSender, uint256 optOutPeriod) = _OPT_IN.isOptedInBy( msg.sender, from ); // `from` must be opted-in to booster require(isOptedInToSender, "AB-3"); // The given timestamp must not be greater than `block.timestamp + 1 hour` // and at most `optOutPeriod(booster)` seconds old. uint64 _now = uint64(block.timestamp); uint64 _optOutPeriod = uint64(optOutPeriod); bool notTooFarInFuture = payload.timestamp <= _now + 1 hours; bool belowMaxAge = true; // Calculate the absolute difference. Because of the small tolerance, `payload.timestamp` // may be greater than `_now`: if (payload.timestamp <= _now) { belowMaxAge = _now - payload.timestamp <= _optOutPeriod; } // Signature must not be expired require(notTooFarInFuture && belowMaxAge, "AB-4"); // NOTE: Currently, hardware wallets (e.g. Ledger, Trezor) do not support EIP712 signing (specifically `signTypedData_v4`). // However, a user can still sign the EIP712 hash with the caveat that it's signed using `personal_sign` which prepends // the prefix '"\x19Ethereum Signed Message:\n" + len(message)'. // // To still support that, we add the prefix to the hash if `isLegacySignature` is true. if (payload.isLegacySignature) { messageHash = messageHash.toEthSignedMessageHash(); } // Valid, if the recovered address from `messageHash` with the given `signature` matches `from`. address signer = ecrecover( messageHash, signature.v, signature.r, signature.s ); if (!payload.isLegacySignature && signer != from) { // As a last resort we try anyway, in case the caller simply forgot the `isLegacySignature` flag. signer = ecrecover( messageHash.toEthSignedMessageHash(), signature.v, signature.r, signature.s ); } require(from == signer, "AB-5"); } /** * @dev Returns the hash of `payload` using the provided booster (i.e. `msg.sender`). */ function hashBoosterPayload(BoosterPayload memory payload, address booster) internal pure returns (bytes32) { return keccak256( abi.encode( BOOSTER_PAYLOAD_TYPEHASH, booster, payload.timestamp, payload.nonce ) ); } function _getChainId() internal pure returns (uint256) { uint256 chainId; assembly { chainId := chainid() } return chainId; } }
// SPDX-License-Identifier: MIT pragma solidity 0.6.12; library DubiexLib { enum CurrencyType {NULL, ETH, ERC20, BOOSTABLE_ERC20, ERC721} // Enum is used to read only a specific part of the order pair from // storage, since it is a bad idea to always perform 4 SLOADs. enum OrderPairReadStrategy {SKIP, MAKER, TAKER, FULL} struct OrderPair { address makerContractAddress; CurrencyType makerCurrencyType; address takerContractAddress; CurrencyType takerCurrencyType; } // To reduce the number of reads, the order pairs // are stored packed and on read unpacked as required. // Also see `OrderPair` and `OrderPairReadStrategy`. struct PackedOrderPair { // 20 bytes address + 1 byte currency type uint168 makerPair; // 20 bytes address + 1 byte currency type uint168 takerPair; } struct PackedOrderBookItem { // Serialized `UnpackedOrderBookItem` uint256 packedData; // // Mostly zero // uint32 successorOrderId; uint32 ancestorOrderId; } struct UnpackedOrderBookItem { uint32 id; uint96 makerValue; uint96 takerValue; uint32 orderPairAlias; // The resolved pair based on the order pair alias OrderPair pair; OrderFlags flags; } // Struct that contains all unpacked data and the additional almost-always zero fields from // the packed order bookt item - returned from `getOrder()` to be more user-friendly to consume. struct PrettyOrderBookItem { uint32 id; uint96 makerValue; uint96 takerValue; uint32 orderPairAlias; OrderPair pair; OrderFlags flags; uint32 successorOrderId; uint32 ancestorOrderId; } struct OrderFlags { bool isMakerERC721; bool isTakerERC721; bool isHidden; bool hasSuccessor; } function packOrderBookItem(UnpackedOrderBookItem memory _unpacked) internal pure returns (uint256) { // Bitpacking saves gas on read/write: // 61287 gas // struct Item1 { // uint256 word1; // uint256 word2; // } // // 62198 gas // struct Item2 { // uint256 word1; // uint128 a; // uint128 b; // } // // 62374 gas // struct Item3 { // uint256 word1; // uint64 a; // uint64 b; // uint64 c; // uint64 d; // } uint256 packedData; uint256 offset; // 1) Set first 32 bits to id uint32 id = _unpacked.id; packedData |= id; offset += 32; // 2) Set next 96 bits to maker value uint96 makerValue = _unpacked.makerValue; packedData |= uint256(makerValue) << offset; offset += 96; // 3) Set next 96 bits to taker value uint96 takerValue = _unpacked.takerValue; packedData |= uint256(takerValue) << offset; offset += 96; // 4) Set next 28 bits to order pair alias // Since it is stored in a uint32 AND it with a bitmask where the first 28 bits are 1 uint32 orderPairAlias = _unpacked.orderPairAlias; uint32 orderPairAliasMask = (1 << 28) - 1; packedData |= uint256(orderPairAlias & orderPairAliasMask) << offset; offset += 28; // 5) Set remaining bits to flags OrderFlags memory flags = _unpacked.flags; if (flags.isMakerERC721) { // Maker currency type is ERC721 packedData |= 1 << (offset + 0); } if (flags.isTakerERC721) { // Taker currency type is ERC721 packedData |= 1 << (offset + 1); } if (flags.isHidden) { // Order is hidden packedData |= 1 << (offset + 2); } if (flags.hasSuccessor) { // Order has a successor packedData |= 1 << (offset + 3); } offset += 4; assert(offset == 256); return packedData; } function unpackOrderBookItem(uint256 packedData) internal pure returns (UnpackedOrderBookItem memory) { UnpackedOrderBookItem memory _unpacked; uint256 offset; // 1) Read id from the first 32 bits _unpacked.id = uint32(packedData >> offset); offset += 32; // 2) Read maker value from next 96 bits _unpacked.makerValue = uint96(packedData >> offset); offset += 96; // 3) Read taker value from next 96 bits _unpacked.takerValue = uint96(packedData >> offset); offset += 96; // 4) Read order pair alias from next 28 bits uint32 orderPairAlias = uint32(packedData >> offset); uint32 orderPairAliasMask = (1 << 28) - 1; _unpacked.orderPairAlias = orderPairAlias & orderPairAliasMask; offset += 28; // NOTE: the caller still needs to read the order pair from storage // with the unpacked alias // 5) Read order flags from remaining bits OrderFlags memory flags = _unpacked.flags; flags.isMakerERC721 = (packedData >> (offset + 0)) & 1 == 1; flags.isTakerERC721 = (packedData >> (offset + 1)) & 1 == 1; flags.isHidden = (packedData >> (offset + 2)) & 1 == 1; flags.hasSuccessor = (packedData >> (offset + 3)) & 1 == 1; offset += 4; assert(offset == 256); return _unpacked; } function packOrderPair(OrderPair memory unpacked) internal pure returns (PackedOrderPair memory) { uint168 packedMaker = uint160(unpacked.makerContractAddress); packedMaker |= uint168(unpacked.makerCurrencyType) << 160; uint168 packedTaker = uint160(unpacked.takerContractAddress); packedTaker |= uint168(unpacked.takerCurrencyType) << 160; return PackedOrderPair(packedMaker, packedTaker); } function unpackOrderPairAddressType(uint168 packed) internal pure returns (address, CurrencyType) { // The first 20 bytes of order pair are used for the maker address address unpackedAddress = address(packed); // The next 8 bits for the maker currency type CurrencyType unpackedCurrencyType = CurrencyType(uint8(packed >> 160)); return (unpackedAddress, unpackedCurrencyType); } /** * @dev A struct representing the payload of `makeOrder`. */ struct MakeOrderInput { uint96 makerValue; uint96 takerValue; OrderPair pair; // An id of an existing order can be optionally provided to // update the makerValue-takerValue ratio with a single call as opposed to cancel-then-make-new-order. uint32 orderId; // If specified, this order becomes a successor for the ancestor order and will be hidden until // the ancestor has been filled. uint32 ancestorOrderId; // When calling make order using an existing order id, the `updatedRatio` will be applied on // the `makerValue` to calculate the new `takerValue`. uint128 updatedRatioWei; } /** * @dev A struct representing the payload of `takeOrder`. */ struct TakeOrderInput { uint32 id; address payable maker; uint96 takerValue; // The expected max taker maker ratio of the order to take. uint256 maxTakerMakerRatio; } /** * @dev A struct representing the payload of `cancelOrder`. */ struct CancelOrderInput { uint32 id; address payable maker; } }
// SPDX-License-Identifier: MIT pragma solidity ^0.6.0; /** * @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 { /** * @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) { // Check the signature length if (signature.length != 65) { revert("ECDSA: invalid signature length"); } // Divide the signature in r, s and v variables bytes32 r; bytes32 s; uint8 v; // ecrecover takes the signature parameters, and the only way to get them // currently is to use assembly. // solhint-disable-next-line no-inline-assembly assembly { r := mload(add(signature, 0x20)) s := mload(add(signature, 0x40)) v := byte(0, mload(add(signature, 0x60))) } // 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 (281): 0 < s < secp256k1n ÷ 2 + 1, and for v in (282): 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) { revert("ECDSA: invalid signature 's' value"); } if (v != 27 && v != 28) { revert("ECDSA: invalid signature 'v' value"); } // If the signature is valid (and not malleable), return the signer address address signer = ecrecover(hash, v, r, s); require(signer != address(0), "ECDSA: invalid signature"); return signer; } /** * @dev Returns an Ethereum Signed Message, created from a `hash`. This * replicates the behavior of the * https://github.com/ethereum/wiki/wiki/JSON-RPC#eth_sign[`eth_sign`] * JSON-RPC method. * * 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)); } }
// SPDX-License-Identifier: MIT pragma solidity 0.6.12; pragma experimental ABIEncoderV2; struct Signature { bytes32 r; bytes32 s; uint8 v; } interface IOptIn { struct OptInStatus { bool isOptedIn; bool permaBoostActive; address optedInTo; uint32 optOutPeriod; } function getOptInStatusPair(address accountA, address accountB) external view returns (OptInStatus memory, OptInStatus memory); function getOptInStatus(address account) external view returns (OptInStatus memory); function isOptedInBy(address _sender, address _account) external view returns (bool, uint256); }
// SPDX-License-Identifier: MIT pragma solidity 0.6.12; pragma experimental ABIEncoderV2; struct BoosterFuel { uint96 dubi; uint96 unlockedPrps; uint96 lockedPrps; uint96 intrinsicFuel; } struct BoosterPayload { address booster; uint64 timestamp; uint64 nonce; // Fallback for 'personal_sign' when e.g. using hardware wallets that don't support // EIP712 signing (yet). bool isLegacySignature; } // Library for Boostable hash functions that are completely inlined. library BoostableLib { bytes32 private constant BOOSTER_PAYLOAD_TYPEHASH = keccak256( "BoosterPayload(address booster,uint64 timestamp,uint64 nonce,bool isLegacySignature)" ); bytes32 internal constant BOOSTER_FUEL_TYPEHASH = keccak256( "BoosterFuel(uint96 dubi,uint96 unlockedPrps,uint96 lockedPrps,uint96 intrinsicFuel)" ); /** * @dev Returns the hash of the packed DOMAIN_SEPARATOR and `messageHash` and is used for verifying * a signature. */ function hashWithDomainSeparator( bytes32 domainSeparator, bytes32 messageHash ) internal pure returns (bytes32) { return keccak256( abi.encodePacked("\x19\x01", domainSeparator, messageHash) ); } /** * @dev Returns the hash of `payload` using the provided booster (i.e. `msg.sender`). */ function hashBoosterPayload(BoosterPayload memory payload, address booster) internal pure returns (bytes32) { return keccak256( abi.encode( BOOSTER_PAYLOAD_TYPEHASH, booster, payload.timestamp, payload.nonce, payload.isLegacySignature ) ); } function hashBoosterFuel(BoosterFuel memory fuel) internal pure returns (bytes32) { return keccak256( abi.encode( BOOSTER_FUEL_TYPEHASH, fuel.dubi, fuel.unlockedPrps, fuel.lockedPrps, fuel.intrinsicFuel ) ); } /** * @dev Returns the tag found in the given `boosterMessage`. */ function _readBoosterTag(bytes memory boosterMessage) internal pure returns (uint8) { // The tag is either the 32th byte or the 64th byte depending on whether // the booster message contains dynamic bytes or not. // // If it contains a dynamic byte array, then the first word points to the first // data location. // // Therefore, we read the 32th byte and check if it's >= 32 and if so, // simply read the (32 + first word)th byte to get the tag. // // This imposes a limit on the number of tags we can support (<32), but // given that it is very unlikely for so many tags to exist it is fine. // // Read the 32th byte to get the tag, because it is a uint8 padded to 32 bytes. // i.e. // -----------------------------------------------------------------v // 0x0000000000000000000000000000000000000000000000000000000000000001 // ... // uint8 tag = uint8(boosterMessage[31]); if (tag >= 32) { // Read the (32 + tag) byte. E.g. if tag is 32, then we read the 64th: // -------------------------------------------------------------------- // 0x0000000000000000000000000000000000000000000000000000000000000020 | // 0000000000000000000000000000000000000000000000000000000000000001 < // ... // tag = uint8(boosterMessage[31 + tag]); } return tag; } }
// SPDX-License-Identifier: MIT pragma solidity 0.6.12; pragma experimental ABIEncoderV2; // Token agnostic fuel struct that is passed around when the fuel is burned by a different (token) contract. // The contract has to explicitely support the desired token that should be burned. struct TokenFuel { // A token alias that must be understood by the target contract uint8 tokenAlias; uint96 amount; } /** * @dev Extends the interface of the ERC20 standard as defined in the EIP with * `boostedTransferFrom` to perform transfers without having to rely on an allowance. */ interface IBoostableERC20 { // ERC20 function totalSupply() external view returns (uint256); function balanceOf(address account) external view returns (uint256); function transfer(address recipient, uint256 amount) external returns (bool); function allowance(address owner, address spender) external view returns (uint256); function approve(address spender, uint256 amount) external returns (bool); function transferFrom( address sender, address recipient, uint256 amount ) external returns (bool); event Transfer(address indexed from, address indexed to, uint256 value); event Approval( address indexed owner, address indexed spender, uint256 value ); // Extension /** * @dev Moves `amount` tokens from `sender` to `recipient`. * * If the caller is known by the callee, then the implementation should skip approval checks. * Also accepts a data payload, similar to ERC721's `safeTransferFrom` to pass arbitrary data. * */ function boostedTransferFrom( address sender, address recipient, uint256 amount, bytes calldata data ) external returns (bool); /** * @dev Burns `fuel` from `from`. */ function burnFuel(address from, TokenFuel memory fuel) external; }
// SPDX-License-Identifier: MIT pragma solidity ^0.6.0; /** * @dev Interface of the ERC20 standard as defined in the EIP. */ interface IERC20 { /** * @dev Returns the amount of tokens in existence. */ function totalSupply() external view returns (uint256); /** * @dev Returns the amount of tokens owned by `account`. */ function balanceOf(address account) external view returns (uint256); /** * @dev Moves `amount` tokens from the caller's account to `recipient`. * * Returns a boolean value indicating whether the operation succeeded. * * Emits a {Transfer} event. */ function transfer(address recipient, 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 `sender` to `recipient` 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 sender, address recipient, uint256 amount) external returns (bool); /** * @dev Emitted when `value` tokens are moved from one account (`from`) to * another (`to`). * * Note that `value` may be zero. */ event Transfer(address indexed from, address indexed to, uint256 value); /** * @dev Emitted when the allowance of a `spender` for an `owner` is set by * a call to {approve}. `value` is the new allowance. */ event Approval(address indexed owner, address indexed spender, uint256 value); }
// SPDX-License-Identifier: MIT pragma solidity ^0.6.0; import "./IERC20.sol"; import "../../math/SafeMath.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 SafeMath for uint256; using Address for address; function safeTransfer(IERC20 token, address to, uint256 value) internal { _callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value)); } function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal { _callOptionalReturn(token, abi.encodeWithSelector(token.transferFrom.selector, from, to, value)); } /** * @dev Deprecated. This function has issues similar to the ones found in * {IERC20-approve}, and its usage is discouraged. * * Whenever possible, use {safeIncreaseAllowance} and * {safeDecreaseAllowance} instead. */ function safeApprove(IERC20 token, address spender, uint256 value) internal { // safeApprove should only be called when setting an initial allowance, // or when resetting it to zero. To increase and decrease it, use // 'safeIncreaseAllowance' and 'safeDecreaseAllowance' // solhint-disable-next-line max-line-length require((value == 0) || (token.allowance(address(this), spender) == 0), "SafeERC20: approve from non-zero to non-zero allowance" ); _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, value)); } function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal { uint256 newAllowance = token.allowance(address(this), spender).add(value); _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance)); } function safeDecreaseAllowance(IERC20 token, address spender, uint256 value) internal { uint256 newAllowance = token.allowance(address(this), spender).sub(value, "SafeERC20: decreased allowance below zero"); _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance)); } /** * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement * on the return value: the return value is optional (but if data is returned, it must not be false). * @param token The token targeted by the call. * @param data The call data (encoded using abi.encode or one of its variants). */ function _callOptionalReturn(IERC20 token, bytes memory data) private { // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since // we're implementing it ourselves. We use {Address.functionCall} to perform this call, which verifies that // the target address contains contract code and also asserts for success in the low-level call. bytes memory returndata = address(token).functionCall(data, "SafeERC20: low-level call failed"); if (returndata.length > 0) { // Return data is optional // solhint-disable-next-line max-line-length require(abi.decode(returndata, (bool)), "SafeERC20: ERC20 operation did not succeed"); } } }
// SPDX-License-Identifier: MIT pragma solidity ^0.6.2; import "../../introspection/IERC165.sol"; /** * @dev Required interface of an ERC721 compliant contract. */ interface IERC721 is IERC165 { /** * @dev Emitted when `tokenId` token is transfered from `from` to `to`. */ event Transfer(address indexed from, address indexed to, uint256 indexed tokenId); /** * @dev Emitted when `owner` enables `approved` to manage the `tokenId` token. */ event Approval(address indexed owner, address indexed approved, uint256 indexed tokenId); /** * @dev Emitted when `owner` enables or disables (`approved`) `operator` to manage all of its assets. */ event ApprovalForAll(address indexed owner, address indexed operator, bool approved); /** * @dev Returns the number of tokens in ``owner``'s account. */ function balanceOf(address owner) external view returns (uint256 balance); /** * @dev Returns the owner of the `tokenId` token. * * Requirements: * * - `tokenId` must exist. */ function ownerOf(uint256 tokenId) external view returns (address owner); /** * @dev Safely transfers `tokenId` token from `from` to `to`, checking first that contract recipients * are aware of the ERC721 protocol to prevent tokens from being forever locked. * * Requirements: * * - `from` cannot be the zero address. * - `to` cannot be the zero address. * - `tokenId` token must exist and be owned by `from`. * - If the caller is not `from`, it must be have been allowed to move this token by either {approve} or {setApprovalForAll}. * - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon a safe transfer. * * Emits a {Transfer} event. */ function safeTransferFrom(address from, address to, uint256 tokenId) external; /** * @dev Transfers `tokenId` token from `from` to `to`. * * WARNING: Usage of this method is discouraged, use {safeTransferFrom} whenever possible. * * Requirements: * * - `from` cannot be the zero address. * - `to` cannot be the zero address. * - `tokenId` token must be owned by `from`. * - If the caller is not `from`, it must be approved to move this token by either {approve} or {setApprovalForAll}. * * Emits a {Transfer} event. */ function transferFrom(address from, address to, uint256 tokenId) external; /** * @dev Gives permission to `to` to transfer `tokenId` token to another account. * The approval is cleared when the token is transferred. * * Only a single account can be approved at a time, so approving the zero address clears previous approvals. * * Requirements: * * - The caller must own the token or be an approved operator. * - `tokenId` must exist. * * Emits an {Approval} event. */ function approve(address to, uint256 tokenId) external; /** * @dev Returns the account approved for `tokenId` token. * * Requirements: * * - `tokenId` must exist. */ function getApproved(uint256 tokenId) external view returns (address operator); /** * @dev Approve or remove `operator` as an operator for the caller. * Operators can call {transferFrom} or {safeTransferFrom} for any token owned by the caller. * * Requirements: * * - The `operator` cannot be the caller. * * Emits an {ApprovalForAll} event. */ function setApprovalForAll(address operator, bool _approved) external; /** * @dev Returns if the `operator` is allowed to manage all of the assets of `owner`. * * See {setApprovalForAll} */ function isApprovedForAll(address owner, address operator) external view returns (bool); /** * @dev Safely transfers `tokenId` token from `from` to `to`. * * Requirements: * * - `from` cannot be the zero address. * - `to` cannot be the zero address. * - `tokenId` token must exist and be owned by `from`. * - If the caller is not `from`, it must be approved to move this token by either {approve} or {setApprovalForAll}. * - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon a safe transfer. * * Emits a {Transfer} event. */ function safeTransferFrom(address from, address to, uint256 tokenId, bytes calldata data) external; }
// SPDX-License-Identifier: MIT pragma solidity ^0.6.0; import "./IERC721Receiver.sol"; /** * @dev Implementation of the {IERC721Receiver} interface. * * Accepts all token transfers. * Make sure the contract is able to use its token with {IERC721-safeTransferFrom}, {IERC721-approve} or {IERC721-setApprovalForAll}. */ contract ERC721Holder is IERC721Receiver { /** * @dev See {IERC721Receiver-onERC721Received}. * * Always returns `IERC721Receiver.onERC721Received.selector`. */ function onERC721Received(address, address, uint256, bytes memory) public virtual override returns (bytes4) { return this.onERC721Received.selector; } }
// SPDX-License-Identifier: MIT pragma solidity ^0.6.0; import "./IERC165.sol"; /** * @dev Implementation of the {IERC165} interface. * * Contracts may inherit from this and call {_registerInterface} to declare * their support of an interface. */ contract ERC165 is IERC165 { /* * bytes4(keccak256('supportsInterface(bytes4)')) == 0x01ffc9a7 */ bytes4 private constant _INTERFACE_ID_ERC165 = 0x01ffc9a7; /** * @dev Mapping of interface ids to whether or not it's supported. */ mapping(bytes4 => bool) private _supportedInterfaces; constructor () internal { // Derived contracts need only register support for their own interfaces, // we register support for ERC165 itself here _registerInterface(_INTERFACE_ID_ERC165); } /** * @dev See {IERC165-supportsInterface}. * * Time complexity O(1), guaranteed to always use less than 30 000 gas. */ function supportsInterface(bytes4 interfaceId) public view override returns (bool) { return _supportedInterfaces[interfaceId]; } /** * @dev Registers the contract as an implementer of the interface defined by * `interfaceId`. Support of the actual ERC165 interface is automatic and * registering its interface id is not required. * * See {IERC165-supportsInterface}. * * Requirements: * * - `interfaceId` cannot be the ERC165 invalid interface (`0xffffffff`). */ function _registerInterface(bytes4 interfaceId) internal virtual { require(interfaceId != 0xffffffff, "ERC165: invalid interface id"); _supportedInterfaces[interfaceId] = true; } }
// SPDX-License-Identifier: MIT pragma solidity ^0.6.0; /** * @dev Interface of the global ERC1820 Registry, as defined in the * https://eips.ethereum.org/EIPS/eip-1820[EIP]. Accounts may register * implementers for interfaces in this registry, as well as query support. * * Implementers may be shared by multiple accounts, and can also implement more * than a single interface for each account. Contracts can implement interfaces * for themselves, but externally-owned accounts (EOA) must delegate this to a * contract. * * {IERC165} interfaces can also be queried via the registry. * * For an in-depth explanation and source code analysis, see the EIP text. */ interface IERC1820Registry { /** * @dev Sets `newManager` as the manager for `account`. A manager of an * account is able to set interface implementers for it. * * By default, each account is its own manager. Passing a value of `0x0` in * `newManager` will reset the manager to this initial state. * * Emits a {ManagerChanged} event. * * Requirements: * * - the caller must be the current manager for `account`. */ function setManager(address account, address newManager) external; /** * @dev Returns the manager for `account`. * * See {setManager}. */ function getManager(address account) external view returns (address); /** * @dev Sets the `implementer` contract as ``account``'s implementer for * `interfaceHash`. * * `account` being the zero address is an alias for the caller's address. * The zero address can also be used in `implementer` to remove an old one. * * See {interfaceHash} to learn how these are created. * * Emits an {InterfaceImplementerSet} event. * * Requirements: * * - the caller must be the current manager for `account`. * - `interfaceHash` must not be an {IERC165} interface id (i.e. it must not * end in 28 zeroes). * - `implementer` must implement {IERC1820Implementer} and return true when * queried for support, unless `implementer` is the caller. See * {IERC1820Implementer-canImplementInterfaceForAddress}. */ function setInterfaceImplementer(address account, bytes32 interfaceHash, address implementer) external; /** * @dev Returns the implementer of `interfaceHash` for `account`. If no such * implementer is registered, returns the zero address. * * If `interfaceHash` is an {IERC165} interface id (i.e. it ends with 28 * zeroes), `account` will be queried for support of it. * * `account` being the zero address is an alias for the caller's address. */ function getInterfaceImplementer(address account, bytes32 interfaceHash) external view returns (address); /** * @dev Returns the interface hash for an `interfaceName`, as defined in the * corresponding * https://eips.ethereum.org/EIPS/eip-1820#interface-name[section of the EIP]. */ function interfaceHash(string calldata interfaceName) external pure returns (bytes32); /** * @notice Updates the cache with whether the contract implements an ERC165 interface or not. * @param account Address of the contract for which to update the cache. * @param interfaceId ERC165 interface for which to update the cache. */ function updateERC165Cache(address account, bytes4 interfaceId) external; /** * @notice Checks whether a contract implements an ERC165 interface or not. * If the result is not cached a direct lookup on the contract address is performed. * If the result is not cached or the cached value is out-of-date, the cache MUST be updated manually by calling * {updateERC165Cache} with the contract address. * @param account Address of the contract to check. * @param interfaceId ERC165 interface to check. * @return True if `account` implements `interfaceId`, false otherwise. */ function implementsERC165Interface(address account, bytes4 interfaceId) external view returns (bool); /** * @notice Checks whether a contract implements an ERC165 interface or not without using nor updating the cache. * @param account Address of the contract to check. * @param interfaceId ERC165 interface to check. * @return True if `account` implements `interfaceId`, false otherwise. */ function implementsERC165InterfaceNoCache(address account, bytes4 interfaceId) external view returns (bool); event InterfaceImplementerSet(address indexed account, bytes32 indexed interfaceHash, address indexed implementer); event ManagerChanged(address indexed account, address indexed newManager); }
// SPDX-License-Identifier: MIT pragma solidity ^0.6.0; /** * @dev Contract module that helps prevent reentrant calls to a function. * * Inheriting from `ReentrancyGuard` will make the {nonReentrant} modifier * available, which can be applied to functions to make sure there are no nested * (reentrant) calls to them. * * Note that because there is a single `nonReentrant` guard, functions marked as * `nonReentrant` may not call one another. This can be worked around by making * those functions `private`, and then adding `external` `nonReentrant` entry * points to them. * * TIP: If you would like to learn more about reentrancy and alternative ways * to protect against it, check out our blog post * https://blog.openzeppelin.com/reentrancy-after-istanbul/[Reentrancy After Istanbul]. */ contract ReentrancyGuard { // Booleans are more expensive than uint256 or any type that takes up a full // word because each write operation emits an extra SLOAD to first read the // slot's contents, replace the bits taken up by the boolean, and then write // back. This is the compiler's defense against contract upgrades and // pointer aliasing, and it cannot be disabled. // The values being non-zero value makes deployment a bit more expensive, // but in exchange the refund on every call to nonReentrant will be lower in // amount. Since refunds are capped to a percentage of the total // transaction's gas, it is best to keep them low in cases like this one, to // increase the likelihood of the full refund coming into effect. uint256 private constant _NOT_ENTERED = 1; uint256 private constant _ENTERED = 2; uint256 private _status; constructor () internal { _status = _NOT_ENTERED; } /** * @dev Prevents a contract from calling itself, directly or indirectly. * Calling a `nonReentrant` function from another `nonReentrant` * function is not supported. It is possible to prevent this from happening * by making the `nonReentrant` function external, and make it call a * `private` function that does the actual work. */ modifier nonReentrant() { // On the first call to nonReentrant, _notEntered will be true require(_status != _ENTERED, "ReentrancyGuard: reentrant call"); // Any calls to nonReentrant after this point will fail _status = _ENTERED; _; // By storing the original value once again, a refund is triggered (see // https://eips.ethereum.org/EIPS/eip-2200) _status = _NOT_ENTERED; } }
// SPDX-License-Identifier: MIT pragma solidity ^0.6.0; /** * @dev Wrappers over Solidity's arithmetic operations with added overflow * checks. * * Arithmetic operations in Solidity wrap on overflow. This can easily result * in bugs, because programmers usually assume that an overflow raises an * error, which is the standard behavior in high level programming languages. * `SafeMath` restores this intuition by reverting the transaction when an * operation overflows. * * Using this library instead of the unchecked operations eliminates an entire * class of bugs, so it's recommended to use it always. */ library SafeMath { /** * @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) { uint256 c = a + b; require(c >= a, "SafeMath: addition overflow"); return c; } /** * @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 sub(a, b, "SafeMath: subtraction overflow"); } /** * @dev Returns the subtraction of two unsigned integers, reverting with custom message on * overflow (when the result is negative). * * Counterpart to Solidity's `-` operator. * * Requirements: * * - Subtraction cannot overflow. */ function sub(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) { require(b <= a, errorMessage); uint256 c = a - b; return c; } /** * @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) { // 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 0; } uint256 c = a * b; require(c / a == b, "SafeMath: multiplication overflow"); return c; } /** * @dev Returns the integer division of two unsigned integers. Reverts 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) internal pure returns (uint256) { return div(a, b, "SafeMath: division by zero"); } /** * @dev Returns the integer division of two unsigned integers. Reverts 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) { require(b > 0, errorMessage); uint256 c = a / b; // assert(a == b * c + a % b); // There is no case in which this doesn't hold return c; } /** * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo), * Reverts 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 mod(a, b, "SafeMath: modulo by zero"); } /** * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo), * Reverts with custom message 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, string memory errorMessage) internal pure returns (uint256) { require(b != 0, errorMessage); return a % b; } }
// SPDX-License-Identifier: MIT pragma solidity ^0.6.2; /** * @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 * ==== */ function isContract(address account) internal view returns (bool) { // According to EIP-1052, 0x0 is the value returned for not-yet created accounts // and 0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470 is returned // for accounts without code, i.e. `keccak256('')` bytes32 codehash; bytes32 accountHash = 0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470; // solhint-disable-next-line no-inline-assembly assembly { codehash := extcodehash(account) } return (codehash != accountHash && codehash != 0x0); } /** * @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"); // solhint-disable-next-line avoid-low-level-calls, avoid-call-value (bool success, ) = recipient.call{ value: amount }(""); require(success, "Address: unable to send value, recipient may have reverted"); } /** * @dev Performs a Solidity function call using a low level `call`. A * plain`call` is an unsafe replacement for a function call: use this * function instead. * * If `target` reverts with a revert reason, it is bubbled up by this * function (like regular Solidity function calls). * * Returns the raw returned data. To convert to the expected return value, * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`]. * * Requirements: * * - `target` must be a contract. * - calling `target` with `data` must not revert. * * _Available since v3.1._ */ function functionCall(address target, bytes memory data) internal returns (bytes memory) { return functionCall(target, data, "Address: low-level call failed"); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with * `errorMessage` as a fallback revert reason when `target` reverts. * * _Available since v3.1._ */ function functionCall(address target, bytes memory data, string memory errorMessage) internal returns (bytes memory) { return _functionCallWithValue(target, data, 0, errorMessage); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], * but also transferring `value` wei to `target`. * * Requirements: * * - the calling contract must have an ETH balance of at least `value`. * - the called Solidity function must be `payable`. * * _Available since v3.1._ */ function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) { return functionCallWithValue(target, data, value, "Address: low-level call with value failed"); } /** * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but * with `errorMessage` as a fallback revert reason when `target` reverts. * * _Available since v3.1._ */ function functionCallWithValue(address target, bytes memory data, uint256 value, string memory errorMessage) internal returns (bytes memory) { require(address(this).balance >= value, "Address: insufficient balance for call"); return _functionCallWithValue(target, data, value, errorMessage); } function _functionCallWithValue(address target, bytes memory data, uint256 weiValue, string memory errorMessage) private returns (bytes memory) { require(isContract(target), "Address: call to non-contract"); // solhint-disable-next-line avoid-low-level-calls (bool success, bytes memory returndata) = target.call{ value: weiValue }(data); if (success) { return returndata; } else { // Look for revert reason and bubble it up if present if (returndata.length > 0) { // The easiest way to bubble the revert reason is using memory via assembly // solhint-disable-next-line no-inline-assembly assembly { let returndata_size := mload(returndata) revert(add(32, returndata), returndata_size) } } else { revert(errorMessage); } } } }
// SPDX-License-Identifier: MIT pragma solidity ^0.6.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 pragma solidity ^0.6.0; /** * @title ERC721 token receiver interface * @dev Interface for any contract that wants to support safeTransfers * from ERC721 asset contracts. */ interface IERC721Receiver { /** * @dev Whenever an {IERC721} `tokenId` token is transferred to this contract via {IERC721-safeTransferFrom} * by `operator` from `from`, this function is called. * * It must return its Solidity selector to confirm the token transfer. * If any other value is returned or the interface is not implemented by the recipient, the transfer will be reverted. * * The selector can be obtained in Solidity with `IERC721.onERC721Received.selector`. */ function onERC721Received(address operator, address from, uint256 tokenId, bytes calldata data) external returns (bytes4); }
// SPDX-License-Identifier: MIT pragma solidity ^0.6.0; import "../../GSN/Context.sol"; import "./IERC721.sol"; import "./IERC721Metadata.sol"; import "./IERC721Enumerable.sol"; import "./IERC721Receiver.sol"; import "../../introspection/ERC165.sol"; import "../../math/SafeMath.sol"; import "../../utils/Address.sol"; import "../../utils/EnumerableSet.sol"; import "../../utils/EnumerableMap.sol"; import "../../utils/Strings.sol"; /** * @title ERC721 Non-Fungible Token Standard basic implementation * @dev see https://eips.ethereum.org/EIPS/eip-721 */ contract ERC721 is Context, ERC165, IERC721, IERC721Metadata, IERC721Enumerable { using SafeMath for uint256; using Address for address; using EnumerableSet for EnumerableSet.UintSet; using EnumerableMap for EnumerableMap.UintToAddressMap; using Strings for uint256; // Equals to `bytes4(keccak256("onERC721Received(address,address,uint256,bytes)"))` // which can be also obtained as `IERC721Receiver(0).onERC721Received.selector` bytes4 private constant _ERC721_RECEIVED = 0x150b7a02; // Mapping from holder address to their (enumerable) set of owned tokens mapping (address => EnumerableSet.UintSet) private _holderTokens; // Enumerable mapping from token ids to their owners EnumerableMap.UintToAddressMap private _tokenOwners; // Mapping from token ID to approved address mapping (uint256 => address) private _tokenApprovals; // Mapping from owner to operator approvals mapping (address => mapping (address => bool)) private _operatorApprovals; // Token name string private _name; // Token symbol string private _symbol; // Optional mapping for token URIs mapping(uint256 => string) private _tokenURIs; // Base URI string private _baseURI; /* * bytes4(keccak256('balanceOf(address)')) == 0x70a08231 * bytes4(keccak256('ownerOf(uint256)')) == 0x6352211e * bytes4(keccak256('approve(address,uint256)')) == 0x095ea7b3 * bytes4(keccak256('getApproved(uint256)')) == 0x081812fc * bytes4(keccak256('setApprovalForAll(address,bool)')) == 0xa22cb465 * bytes4(keccak256('isApprovedForAll(address,address)')) == 0xe985e9c5 * bytes4(keccak256('transferFrom(address,address,uint256)')) == 0x23b872dd * bytes4(keccak256('safeTransferFrom(address,address,uint256)')) == 0x42842e0e * bytes4(keccak256('safeTransferFrom(address,address,uint256,bytes)')) == 0xb88d4fde * * => 0x70a08231 ^ 0x6352211e ^ 0x095ea7b3 ^ 0x081812fc ^ * 0xa22cb465 ^ 0xe985e9c ^ 0x23b872dd ^ 0x42842e0e ^ 0xb88d4fde == 0x80ac58cd */ bytes4 private constant _INTERFACE_ID_ERC721 = 0x80ac58cd; /* * bytes4(keccak256('name()')) == 0x06fdde03 * bytes4(keccak256('symbol()')) == 0x95d89b41 * bytes4(keccak256('tokenURI(uint256)')) == 0xc87b56dd * * => 0x06fdde03 ^ 0x95d89b41 ^ 0xc87b56dd == 0x5b5e139f */ bytes4 private constant _INTERFACE_ID_ERC721_METADATA = 0x5b5e139f; /* * bytes4(keccak256('totalSupply()')) == 0x18160ddd * bytes4(keccak256('tokenOfOwnerByIndex(address,uint256)')) == 0x2f745c59 * bytes4(keccak256('tokenByIndex(uint256)')) == 0x4f6ccce7 * * => 0x18160ddd ^ 0x2f745c59 ^ 0x4f6ccce7 == 0x780e9d63 */ bytes4 private constant _INTERFACE_ID_ERC721_ENUMERABLE = 0x780e9d63; /** * @dev Initializes the contract by setting a `name` and a `symbol` to the token collection. */ constructor (string memory name, string memory symbol) public { _name = name; _symbol = symbol; // register the supported interfaces to conform to ERC721 via ERC165 _registerInterface(_INTERFACE_ID_ERC721); _registerInterface(_INTERFACE_ID_ERC721_METADATA); _registerInterface(_INTERFACE_ID_ERC721_ENUMERABLE); } /** * @dev See {IERC721-balanceOf}. */ function balanceOf(address owner) public view override returns (uint256) { require(owner != address(0), "ERC721: balance query for the zero address"); return _holderTokens[owner].length(); } /** * @dev See {IERC721-ownerOf}. */ function ownerOf(uint256 tokenId) public view override returns (address) { return _tokenOwners.get(tokenId, "ERC721: owner query for nonexistent token"); } /** * @dev See {IERC721Metadata-name}. */ function name() public view override returns (string memory) { return _name; } /** * @dev See {IERC721Metadata-symbol}. */ function symbol() public view override returns (string memory) { return _symbol; } /** * @dev See {IERC721Metadata-tokenURI}. */ function tokenURI(uint256 tokenId) public view override returns (string memory) { require(_exists(tokenId), "ERC721Metadata: URI query for nonexistent token"); string memory _tokenURI = _tokenURIs[tokenId]; // If there is no base URI, return the token URI. if (bytes(_baseURI).length == 0) { return _tokenURI; } // If both are set, concatenate the baseURI and tokenURI (via abi.encodePacked). if (bytes(_tokenURI).length > 0) { return string(abi.encodePacked(_baseURI, _tokenURI)); } // If there is a baseURI but no tokenURI, concatenate the tokenID to the baseURI. return string(abi.encodePacked(_baseURI, tokenId.toString())); } /** * @dev Returns the base URI set via {_setBaseURI}. This will be * automatically added as a prefix in {tokenURI} to each token's URI, or * to the token ID if no specific URI is set for that token ID. */ function baseURI() public view returns (string memory) { return _baseURI; } /** * @dev See {IERC721Enumerable-tokenOfOwnerByIndex}. */ function tokenOfOwnerByIndex(address owner, uint256 index) public view override returns (uint256) { return _holderTokens[owner].at(index); } /** * @dev See {IERC721Enumerable-totalSupply}. */ function totalSupply() public view override returns (uint256) { // _tokenOwners are indexed by tokenIds, so .length() returns the number of tokenIds return _tokenOwners.length(); } /** * @dev See {IERC721Enumerable-tokenByIndex}. */ function tokenByIndex(uint256 index) public view override returns (uint256) { (uint256 tokenId, ) = _tokenOwners.at(index); return tokenId; } /** * @dev See {IERC721-approve}. */ function approve(address to, uint256 tokenId) public virtual override { address owner = ownerOf(tokenId); require(to != owner, "ERC721: approval to current owner"); require(_msgSender() == owner || isApprovedForAll(owner, _msgSender()), "ERC721: approve caller is not owner nor approved for all" ); _approve(to, tokenId); } /** * @dev See {IERC721-getApproved}. */ function getApproved(uint256 tokenId) public view override returns (address) { require(_exists(tokenId), "ERC721: approved query for nonexistent token"); return _tokenApprovals[tokenId]; } /** * @dev See {IERC721-setApprovalForAll}. */ function setApprovalForAll(address operator, bool approved) public virtual override { require(operator != _msgSender(), "ERC721: approve to caller"); _operatorApprovals[_msgSender()][operator] = approved; emit ApprovalForAll(_msgSender(), operator, approved); } /** * @dev See {IERC721-isApprovedForAll}. */ function isApprovedForAll(address owner, address operator) public view override returns (bool) { return _operatorApprovals[owner][operator]; } /** * @dev See {IERC721-transferFrom}. */ function transferFrom(address from, address to, uint256 tokenId) public virtual override { //solhint-disable-next-line max-line-length require(_isApprovedOrOwner(_msgSender(), tokenId), "ERC721: transfer caller is not owner nor approved"); _transfer(from, to, tokenId); } /** * @dev See {IERC721-safeTransferFrom}. */ function safeTransferFrom(address from, address to, uint256 tokenId) public virtual override { safeTransferFrom(from, to, tokenId, ""); } /** * @dev See {IERC721-safeTransferFrom}. */ function safeTransferFrom(address from, address to, uint256 tokenId, bytes memory _data) public virtual override { require(_isApprovedOrOwner(_msgSender(), tokenId), "ERC721: transfer caller is not owner nor approved"); _safeTransfer(from, to, tokenId, _data); } /** * @dev Safely transfers `tokenId` token from `from` to `to`, checking first that contract recipients * are aware of the ERC721 protocol to prevent tokens from being forever locked. * * `_data` is additional data, it has no specified format and it is sent in call to `to`. * * This internal function is equivalent to {safeTransferFrom}, and can be used to e.g. * implement alternative mecanisms to perform token transfer, such as signature-based. * * Requirements: * * - `from` cannot be the zero address. * - `to` cannot be the zero address. * - `tokenId` token must exist and be owned by `from`. * - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon a safe transfer. * * Emits a {Transfer} event. */ function _safeTransfer(address from, address to, uint256 tokenId, bytes memory _data) internal virtual { _transfer(from, to, tokenId); require(_checkOnERC721Received(from, to, tokenId, _data), "ERC721: transfer to non ERC721Receiver implementer"); } /** * @dev Returns whether `tokenId` exists. * * Tokens can be managed by their owner or approved accounts via {approve} or {setApprovalForAll}. * * Tokens start existing when they are minted (`_mint`), * and stop existing when they are burned (`_burn`). */ function _exists(uint256 tokenId) internal view returns (bool) { return _tokenOwners.contains(tokenId); } /** * @dev Returns whether `spender` is allowed to manage `tokenId`. * * Requirements: * * - `tokenId` must exist. */ function _isApprovedOrOwner(address spender, uint256 tokenId) internal view returns (bool) { require(_exists(tokenId), "ERC721: operator query for nonexistent token"); address owner = ownerOf(tokenId); return (spender == owner || getApproved(tokenId) == spender || isApprovedForAll(owner, spender)); } /** * @dev Safely mints `tokenId` and transfers it to `to`. * * Requirements: d* * - `tokenId` must not exist. * - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon a safe transfer. * * Emits a {Transfer} event. */ function _safeMint(address to, uint256 tokenId) internal virtual { _safeMint(to, tokenId, ""); } /** * @dev Same as {xref-ERC721-_safeMint-address-uint256-}[`_safeMint`], with an additional `data` parameter which is * forwarded in {IERC721Receiver-onERC721Received} to contract recipients. */ function _safeMint(address to, uint256 tokenId, bytes memory _data) internal virtual { _mint(to, tokenId); require(_checkOnERC721Received(address(0), to, tokenId, _data), "ERC721: transfer to non ERC721Receiver implementer"); } /** * @dev Mints `tokenId` and transfers it to `to`. * * WARNING: Usage of this method is discouraged, use {_safeMint} whenever possible * * Requirements: * * - `tokenId` must not exist. * - `to` cannot be the zero address. * * Emits a {Transfer} event. */ function _mint(address to, uint256 tokenId) internal virtual { require(to != address(0), "ERC721: mint to the zero address"); require(!_exists(tokenId), "ERC721: token already minted"); _beforeTokenTransfer(address(0), to, tokenId); _holderTokens[to].add(tokenId); _tokenOwners.set(tokenId, to); emit Transfer(address(0), to, tokenId); } /** * @dev Destroys `tokenId`. * The approval is cleared when the token is burned. * * Requirements: * * - `tokenId` must exist. * * Emits a {Transfer} event. */ function _burn(uint256 tokenId) internal virtual { address owner = ownerOf(tokenId); _beforeTokenTransfer(owner, address(0), tokenId); // Clear approvals _approve(address(0), tokenId); // Clear metadata (if any) if (bytes(_tokenURIs[tokenId]).length != 0) { delete _tokenURIs[tokenId]; } _holderTokens[owner].remove(tokenId); _tokenOwners.remove(tokenId); emit Transfer(owner, address(0), tokenId); } /** * @dev Transfers `tokenId` from `from` to `to`. * As opposed to {transferFrom}, this imposes no restrictions on msg.sender. * * Requirements: * * - `to` cannot be the zero address. * - `tokenId` token must be owned by `from`. * * Emits a {Transfer} event. */ function _transfer(address from, address to, uint256 tokenId) internal virtual { require(ownerOf(tokenId) == from, "ERC721: transfer of token that is not own"); require(to != address(0), "ERC721: transfer to the zero address"); _beforeTokenTransfer(from, to, tokenId); // Clear approvals from the previous owner _approve(address(0), tokenId); _holderTokens[from].remove(tokenId); _holderTokens[to].add(tokenId); _tokenOwners.set(tokenId, to); emit Transfer(from, to, tokenId); } /** * @dev Sets `_tokenURI` as the tokenURI of `tokenId`. * * Requirements: * * - `tokenId` must exist. */ function _setTokenURI(uint256 tokenId, string memory _tokenURI) internal virtual { require(_exists(tokenId), "ERC721Metadata: URI set of nonexistent token"); _tokenURIs[tokenId] = _tokenURI; } /** * @dev Internal function to set the base URI for all token IDs. It is * automatically added as a prefix to the value returned in {tokenURI}, * or to the token ID if {tokenURI} is empty. */ function _setBaseURI(string memory baseURI_) internal virtual { _baseURI = baseURI_; } /** * @dev Internal function to invoke {IERC721Receiver-onERC721Received} on a target address. * The call is not executed if the target address is not a contract. * * @param from address representing the previous owner of the given token ID * @param to target address that will receive the tokens * @param tokenId uint256 ID of the token to be transferred * @param _data bytes optional data to send along with the call * @return bool whether the call correctly returned the expected magic value */ function _checkOnERC721Received(address from, address to, uint256 tokenId, bytes memory _data) private returns (bool) { if (!to.isContract()) { return true; } bytes memory returndata = to.functionCall(abi.encodeWithSelector( IERC721Receiver(to).onERC721Received.selector, _msgSender(), from, tokenId, _data ), "ERC721: transfer to non ERC721Receiver implementer"); bytes4 retval = abi.decode(returndata, (bytes4)); return (retval == _ERC721_RECEIVED); } function _approve(address to, uint256 tokenId) private { _tokenApprovals[tokenId] = to; emit Approval(ownerOf(tokenId), to, tokenId); } /** * @dev Hook that is called before any token transfer. This includes minting * and burning. * * Calling conditions: * * - When `from` and `to` are both non-zero, ``from``'s `tokenId` will be * transferred to `to`. * - When `from` is zero, `tokenId` will be minted for `to`. * - When `to` is zero, ``from``'s `tokenId` will be burned. * - `from` cannot be the zero address. * - `to` cannot be the zero address. * * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks]. */ function _beforeTokenTransfer(address from, address to, uint256 tokenId) internal virtual { } }
// SPDX-License-Identifier: MIT pragma solidity ^0.6.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 GSN 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 payable) { return msg.sender; } function _msgData() internal view virtual returns (bytes memory) { this; // silence state mutability warning without generating bytecode - see https://github.com/ethereum/solidity/issues/2691 return msg.data; } }
// SPDX-License-Identifier: MIT pragma solidity ^0.6.2; import "./IERC721.sol"; /** * @title ERC-721 Non-Fungible Token Standard, optional metadata extension * @dev See https://eips.ethereum.org/EIPS/eip-721 */ interface IERC721Metadata is IERC721 { /** * @dev Returns the token collection name. */ function name() external view returns (string memory); /** * @dev Returns the token collection symbol. */ function symbol() external view returns (string memory); /** * @dev Returns the Uniform Resource Identifier (URI) for `tokenId` token. */ function tokenURI(uint256 tokenId) external view returns (string memory); }
// SPDX-License-Identifier: MIT pragma solidity ^0.6.2; import "./IERC721.sol"; /** * @title ERC-721 Non-Fungible Token Standard, optional enumeration extension * @dev See https://eips.ethereum.org/EIPS/eip-721 */ interface IERC721Enumerable is IERC721 { /** * @dev Returns the total amount of tokens stored by the contract. */ function totalSupply() external view returns (uint256); /** * @dev Returns a token ID owned by `owner` at a given `index` of its token list. * Use along with {balanceOf} to enumerate all of ``owner``'s tokens. */ function tokenOfOwnerByIndex(address owner, uint256 index) external view returns (uint256 tokenId); /** * @dev Returns a token ID at a given `index` of all the tokens stored by the contract. * Use along with {totalSupply} to enumerate all tokens. */ function tokenByIndex(uint256 index) external view returns (uint256); }
// SPDX-License-Identifier: MIT pragma solidity ^0.6.0; /** * @dev Library for managing * https://en.wikipedia.org/wiki/Set_(abstract_data_type)[sets] of primitive * types. * * Sets have the following properties: * * - Elements are added, removed, and checked for existence in constant time * (O(1)). * - Elements are enumerated in O(n). No guarantees are made on the ordering. * * ``` * contract Example { * // Add the library methods * using EnumerableSet for EnumerableSet.AddressSet; * * // Declare a set state variable * EnumerableSet.AddressSet private mySet; * } * ``` * * As of v3.0.0, only sets of type `address` (`AddressSet`) and `uint256` * (`UintSet`) are supported. */ library EnumerableSet { // To implement this library for multiple types with as little code // repetition as possible, we write it in terms of a generic Set type with // bytes32 values. // The Set implementation uses private functions, and user-facing // implementations (such as AddressSet) are just wrappers around the // underlying Set. // This means that we can only create new EnumerableSets for types that fit // in bytes32. struct Set { // Storage of set values bytes32[] _values; // Position of the value in the `values` array, plus 1 because index 0 // means a value is not in the set. mapping (bytes32 => uint256) _indexes; } /** * @dev Add a value to a set. O(1). * * Returns true if the value was added to the set, that is if it was not * already present. */ function _add(Set storage set, bytes32 value) private returns (bool) { if (!_contains(set, value)) { set._values.push(value); // The value is stored at length-1, but we add 1 to all indexes // and use 0 as a sentinel value set._indexes[value] = set._values.length; return true; } else { return false; } } /** * @dev Removes a value from a set. O(1). * * Returns true if the value was removed from the set, that is if it was * present. */ function _remove(Set storage set, bytes32 value) private returns (bool) { // We read and store the value's index to prevent multiple reads from the same storage slot uint256 valueIndex = set._indexes[value]; if (valueIndex != 0) { // Equivalent to contains(set, value) // To delete an element from the _values array in O(1), we swap the element to delete with the last one in // the array, and then remove the last element (sometimes called as 'swap and pop'). // This modifies the order of the array, as noted in {at}. uint256 toDeleteIndex = valueIndex - 1; uint256 lastIndex = set._values.length - 1; // When the value to delete is the last one, the swap operation is unnecessary. However, since this occurs // so rarely, we still do the swap anyway to avoid the gas cost of adding an 'if' statement. bytes32 lastvalue = set._values[lastIndex]; // Move the last value to the index where the value to delete is set._values[toDeleteIndex] = lastvalue; // Update the index for the moved value set._indexes[lastvalue] = toDeleteIndex + 1; // All indexes are 1-based // Delete the slot where the moved value was stored set._values.pop(); // Delete the index for the deleted slot delete set._indexes[value]; return true; } else { return false; } } /** * @dev Returns true if the value is in the set. O(1). */ function _contains(Set storage set, bytes32 value) private view returns (bool) { return set._indexes[value] != 0; } /** * @dev Returns the number of values on the set. O(1). */ function _length(Set storage set) private view returns (uint256) { return set._values.length; } /** * @dev Returns the value stored at position `index` in the set. O(1). * * Note that there are no guarantees on the ordering of values inside the * array, and it may change when more values are added or removed. * * Requirements: * * - `index` must be strictly less than {length}. */ function _at(Set storage set, uint256 index) private view returns (bytes32) { require(set._values.length > index, "EnumerableSet: index out of bounds"); return set._values[index]; } // AddressSet struct AddressSet { Set _inner; } /** * @dev Add a value to a set. O(1). * * Returns true if the value was added to the set, that is if it was not * already present. */ function add(AddressSet storage set, address value) internal returns (bool) { return _add(set._inner, bytes32(uint256(value))); } /** * @dev Removes a value from a set. O(1). * * Returns true if the value was removed from the set, that is if it was * present. */ function remove(AddressSet storage set, address value) internal returns (bool) { return _remove(set._inner, bytes32(uint256(value))); } /** * @dev Returns true if the value is in the set. O(1). */ function contains(AddressSet storage set, address value) internal view returns (bool) { return _contains(set._inner, bytes32(uint256(value))); } /** * @dev Returns the number of values in the set. O(1). */ function length(AddressSet storage set) internal view returns (uint256) { return _length(set._inner); } /** * @dev Returns the value stored at position `index` in the set. O(1). * * Note that there are no guarantees on the ordering of values inside the * array, and it may change when more values are added or removed. * * Requirements: * * - `index` must be strictly less than {length}. */ function at(AddressSet storage set, uint256 index) internal view returns (address) { return address(uint256(_at(set._inner, index))); } // UintSet struct UintSet { Set _inner; } /** * @dev Add a value to a set. O(1). * * Returns true if the value was added to the set, that is if it was not * already present. */ function add(UintSet storage set, uint256 value) internal returns (bool) { return _add(set._inner, bytes32(value)); } /** * @dev Removes a value from a set. O(1). * * Returns true if the value was removed from the set, that is if it was * present. */ function remove(UintSet storage set, uint256 value) internal returns (bool) { return _remove(set._inner, bytes32(value)); } /** * @dev Returns true if the value is in the set. O(1). */ function contains(UintSet storage set, uint256 value) internal view returns (bool) { return _contains(set._inner, bytes32(value)); } /** * @dev Returns the number of values on the set. O(1). */ function length(UintSet storage set) internal view returns (uint256) { return _length(set._inner); } /** * @dev Returns the value stored at position `index` in the set. O(1). * * Note that there are no guarantees on the ordering of values inside the * array, and it may change when more values are added or removed. * * Requirements: * * - `index` must be strictly less than {length}. */ function at(UintSet storage set, uint256 index) internal view returns (uint256) { return uint256(_at(set._inner, index)); } }
// SPDX-License-Identifier: MIT pragma solidity ^0.6.0; /** * @dev Library for managing an enumerable variant of Solidity's * https://solidity.readthedocs.io/en/latest/types.html#mapping-types[`mapping`] * type. * * Maps have the following properties: * * - Entries are added, removed, and checked for existence in constant time * (O(1)). * - Entries are enumerated in O(n). No guarantees are made on the ordering. * * ``` * contract Example { * // Add the library methods * using EnumerableMap for EnumerableMap.UintToAddressMap; * * // Declare a set state variable * EnumerableMap.UintToAddressMap private myMap; * } * ``` * * As of v3.0.0, only maps of type `uint256 -> address` (`UintToAddressMap`) are * supported. */ library EnumerableMap { // To implement this library for multiple types with as little code // repetition as possible, we write it in terms of a generic Map type with // bytes32 keys and values. // The Map implementation uses private functions, and user-facing // implementations (such as Uint256ToAddressMap) are just wrappers around // the underlying Map. // This means that we can only create new EnumerableMaps for types that fit // in bytes32. struct MapEntry { bytes32 _key; bytes32 _value; } struct Map { // Storage of map keys and values MapEntry[] _entries; // Position of the entry defined by a key in the `entries` array, plus 1 // because index 0 means a key is not in the map. mapping (bytes32 => uint256) _indexes; } /** * @dev Adds a key-value pair to a map, or updates the value for an existing * key. O(1). * * Returns true if the key was added to the map, that is if it was not * already present. */ function _set(Map storage map, bytes32 key, bytes32 value) private returns (bool) { // We read and store the key's index to prevent multiple reads from the same storage slot uint256 keyIndex = map._indexes[key]; if (keyIndex == 0) { // Equivalent to !contains(map, key) map._entries.push(MapEntry({ _key: key, _value: value })); // The entry is stored at length-1, but we add 1 to all indexes // and use 0 as a sentinel value map._indexes[key] = map._entries.length; return true; } else { map._entries[keyIndex - 1]._value = value; return false; } } /** * @dev Removes a key-value pair from a map. O(1). * * Returns true if the key was removed from the map, that is if it was present. */ function _remove(Map storage map, bytes32 key) private returns (bool) { // We read and store the key's index to prevent multiple reads from the same storage slot uint256 keyIndex = map._indexes[key]; if (keyIndex != 0) { // Equivalent to contains(map, key) // To delete a key-value pair from the _entries array in O(1), we swap the entry to delete with the last one // in the array, and then remove the last entry (sometimes called as 'swap and pop'). // This modifies the order of the array, as noted in {at}. uint256 toDeleteIndex = keyIndex - 1; uint256 lastIndex = map._entries.length - 1; // When the entry to delete is the last one, the swap operation is unnecessary. However, since this occurs // so rarely, we still do the swap anyway to avoid the gas cost of adding an 'if' statement. MapEntry storage lastEntry = map._entries[lastIndex]; // Move the last entry to the index where the entry to delete is map._entries[toDeleteIndex] = lastEntry; // Update the index for the moved entry map._indexes[lastEntry._key] = toDeleteIndex + 1; // All indexes are 1-based // Delete the slot where the moved entry was stored map._entries.pop(); // Delete the index for the deleted slot delete map._indexes[key]; return true; } else { return false; } } /** * @dev Returns true if the key is in the map. O(1). */ function _contains(Map storage map, bytes32 key) private view returns (bool) { return map._indexes[key] != 0; } /** * @dev Returns the number of key-value pairs in the map. O(1). */ function _length(Map storage map) private view returns (uint256) { return map._entries.length; } /** * @dev Returns the key-value pair stored at position `index` in the map. O(1). * * Note that there are no guarantees on the ordering of entries inside the * array, and it may change when more entries are added or removed. * * Requirements: * * - `index` must be strictly less than {length}. */ function _at(Map storage map, uint256 index) private view returns (bytes32, bytes32) { require(map._entries.length > index, "EnumerableMap: index out of bounds"); MapEntry storage entry = map._entries[index]; return (entry._key, entry._value); } /** * @dev Returns the value associated with `key`. O(1). * * Requirements: * * - `key` must be in the map. */ function _get(Map storage map, bytes32 key) private view returns (bytes32) { return _get(map, key, "EnumerableMap: nonexistent key"); } /** * @dev Same as {_get}, with a custom error message when `key` is not in the map. */ function _get(Map storage map, bytes32 key, string memory errorMessage) private view returns (bytes32) { uint256 keyIndex = map._indexes[key]; require(keyIndex != 0, errorMessage); // Equivalent to contains(map, key) return map._entries[keyIndex - 1]._value; // All indexes are 1-based } // UintToAddressMap struct UintToAddressMap { Map _inner; } /** * @dev Adds a key-value pair to a map, or updates the value for an existing * key. O(1). * * Returns true if the key was added to the map, that is if it was not * already present. */ function set(UintToAddressMap storage map, uint256 key, address value) internal returns (bool) { return _set(map._inner, bytes32(key), bytes32(uint256(value))); } /** * @dev Removes a value from a set. O(1). * * Returns true if the key was removed from the map, that is if it was present. */ function remove(UintToAddressMap storage map, uint256 key) internal returns (bool) { return _remove(map._inner, bytes32(key)); } /** * @dev Returns true if the key is in the map. O(1). */ function contains(UintToAddressMap storage map, uint256 key) internal view returns (bool) { return _contains(map._inner, bytes32(key)); } /** * @dev Returns the number of elements in the map. O(1). */ function length(UintToAddressMap storage map) internal view returns (uint256) { return _length(map._inner); } /** * @dev Returns the element stored at position `index` in the set. O(1). * Note that there are no guarantees on the ordering of values inside the * array, and it may change when more values are added or removed. * * Requirements: * * - `index` must be strictly less than {length}. */ function at(UintToAddressMap storage map, uint256 index) internal view returns (uint256, address) { (bytes32 key, bytes32 value) = _at(map._inner, index); return (uint256(key), address(uint256(value))); } /** * @dev Returns the value associated with `key`. O(1). * * Requirements: * * - `key` must be in the map. */ function get(UintToAddressMap storage map, uint256 key) internal view returns (address) { return address(uint256(_get(map._inner, bytes32(key)))); } /** * @dev Same as {get}, with a custom error message when `key` is not in the map. */ function get(UintToAddressMap storage map, uint256 key, string memory errorMessage) internal view returns (address) { return address(uint256(_get(map._inner, bytes32(key), errorMessage))); } }
// SPDX-License-Identifier: MIT pragma solidity ^0.6.0; /** * @dev String operations. */ library Strings { /** * @dev Converts a `uint256` to its ASCII `string` representation. */ function toString(uint256 value) internal pure returns (string memory) { // Inspired by OraclizeAPI's implementation - MIT licence // https://github.com/oraclize/ethereum-api/blob/b42146b063c7d6ee1358846c198246239e9360e8/oraclizeAPI_0.4.25.sol if (value == 0) { return "0"; } uint256 temp = value; uint256 digits; while (temp != 0) { digits++; temp /= 10; } bytes memory buffer = new bytes(digits); uint256 index = digits - 1; temp = value; while (temp != 0) { buffer[index--] = byte(uint8(48 + temp % 10)); temp /= 10; } return string(buffer); } }
// SPDX-License-Identifier: MIT pragma solidity ^0.6.0; import "../../GSN/Context.sol"; import "./IERC20.sol"; import "../../math/SafeMath.sol"; import "../../utils/Address.sol"; /** * @dev Implementation of the {IERC20} interface. * * This implementation is agnostic to the way tokens are created. This means * that a supply mechanism has to be added in a derived contract using {_mint}. * For a generic mechanism see {ERC20PresetMinterPauser}. * * TIP: For a detailed writeup see our guide * https://forum.zeppelin.solutions/t/how-to-implement-erc20-supply-mechanisms/226[How * to implement supply mechanisms]. * * We have followed general OpenZeppelin guidelines: functions revert instead * of returning `false` on failure. This behavior is nonetheless conventional * and does not conflict with the expectations of ERC20 applications. * * Additionally, an {Approval} event is emitted on calls to {transferFrom}. * This allows applications to reconstruct the allowance for all accounts just * by listening to said events. Other implementations of the EIP may not emit * these events, as it isn't required by the specification. * * Finally, the non-standard {decreaseAllowance} and {increaseAllowance} * functions have been added to mitigate the well-known issues around setting * allowances. See {IERC20-approve}. */ contract ERC20 is Context, IERC20 { using SafeMath for uint256; using Address for address; mapping (address => uint256) private _balances; mapping (address => mapping (address => uint256)) private _allowances; uint256 private _totalSupply; string private _name; string private _symbol; uint8 private _decimals; /** * @dev Sets the values for {name} and {symbol}, initializes {decimals} with * a default value of 18. * * To select a different value for {decimals}, use {_setupDecimals}. * * All three of these values are immutable: they can only be set once during * construction. */ constructor (string memory name, string memory symbol) public { _name = name; _symbol = symbol; _decimals = 18; } /** * @dev Returns the name of the token. */ function name() public view returns (string memory) { return _name; } /** * @dev Returns the symbol of the token, usually a shorter version of the * name. */ function symbol() public view returns (string memory) { return _symbol; } /** * @dev Returns the number of decimals used to get its user representation. * For example, if `decimals` equals `2`, a balance of `505` tokens should * be displayed to a user as `5,05` (`505 / 10 ** 2`). * * Tokens usually opt for a value of 18, imitating the relationship between * Ether and Wei. This is the value {ERC20} uses, unless {_setupDecimals} is * called. * * NOTE: This information is only used for _display_ purposes: it in * no way affects any of the arithmetic of the contract, including * {IERC20-balanceOf} and {IERC20-transfer}. */ function decimals() public view returns (uint8) { return _decimals; } /** * @dev See {IERC20-totalSupply}. */ function totalSupply() public view override returns (uint256) { return _totalSupply; } /** * @dev See {IERC20-balanceOf}. */ function balanceOf(address account) public view override returns (uint256) { return _balances[account]; } /** * @dev See {IERC20-transfer}. * * Requirements: * * - `recipient` cannot be the zero address. * - the caller must have a balance of at least `amount`. */ function transfer(address recipient, uint256 amount) public virtual override returns (bool) { _transfer(_msgSender(), recipient, amount); return true; } /** * @dev See {IERC20-allowance}. */ function allowance(address owner, address spender) public view virtual override returns (uint256) { return _allowances[owner][spender]; } /** * @dev See {IERC20-approve}. * * Requirements: * * - `spender` cannot be the zero address. */ function approve(address spender, uint256 amount) public virtual override returns (bool) { _approve(_msgSender(), spender, amount); return true; } /** * @dev See {IERC20-transferFrom}. * * Emits an {Approval} event indicating the updated allowance. This is not * required by the EIP. See the note at the beginning of {ERC20}; * * Requirements: * - `sender` and `recipient` cannot be the zero address. * - `sender` must have a balance of at least `amount`. * - the caller must have allowance for ``sender``'s tokens of at least * `amount`. */ function transferFrom(address sender, address recipient, uint256 amount) public virtual override returns (bool) { _transfer(sender, recipient, amount); _approve(sender, _msgSender(), _allowances[sender][_msgSender()].sub(amount, "ERC20: transfer amount exceeds allowance")); return true; } /** * @dev Atomically increases the allowance granted to `spender` by the caller. * * This is an alternative to {approve} that can be used as a mitigation for * problems described in {IERC20-approve}. * * Emits an {Approval} event indicating the updated allowance. * * Requirements: * * - `spender` cannot be the zero address. */ function increaseAllowance(address spender, uint256 addedValue) public virtual returns (bool) { _approve(_msgSender(), spender, _allowances[_msgSender()][spender].add(addedValue)); return true; } /** * @dev Atomically decreases the allowance granted to `spender` by the caller. * * This is an alternative to {approve} that can be used as a mitigation for * problems described in {IERC20-approve}. * * Emits an {Approval} event indicating the updated allowance. * * Requirements: * * - `spender` cannot be the zero address. * - `spender` must have allowance for the caller of at least * `subtractedValue`. */ function decreaseAllowance(address spender, uint256 subtractedValue) public virtual returns (bool) { _approve(_msgSender(), spender, _allowances[_msgSender()][spender].sub(subtractedValue, "ERC20: decreased allowance below zero")); return true; } /** * @dev Moves tokens `amount` from `sender` to `recipient`. * * This is internal function is equivalent to {transfer}, and can be used to * e.g. implement automatic token fees, slashing mechanisms, etc. * * Emits a {Transfer} event. * * Requirements: * * - `sender` cannot be the zero address. * - `recipient` cannot be the zero address. * - `sender` must have a balance of at least `amount`. */ function _transfer(address sender, address recipient, uint256 amount) internal virtual { require(sender != address(0), "ERC20: transfer from the zero address"); require(recipient != address(0), "ERC20: transfer to the zero address"); _beforeTokenTransfer(sender, recipient, amount); _balances[sender] = _balances[sender].sub(amount, "ERC20: transfer amount exceeds balance"); _balances[recipient] = _balances[recipient].add(amount); emit Transfer(sender, recipient, amount); } /** @dev Creates `amount` tokens and assigns them to `account`, increasing * the total supply. * * Emits a {Transfer} event with `from` set to the zero address. * * Requirements * * - `to` cannot be the zero address. */ function _mint(address account, uint256 amount) internal virtual { require(account != address(0), "ERC20: mint to the zero address"); _beforeTokenTransfer(address(0), account, amount); _totalSupply = _totalSupply.add(amount); _balances[account] = _balances[account].add(amount); emit Transfer(address(0), account, amount); } /** * @dev Destroys `amount` tokens from `account`, reducing the * total supply. * * Emits a {Transfer} event with `to` set to the zero address. * * Requirements * * - `account` cannot be the zero address. * - `account` must have at least `amount` tokens. */ function _burn(address account, uint256 amount) internal virtual { require(account != address(0), "ERC20: burn from the zero address"); _beforeTokenTransfer(account, address(0), amount); _balances[account] = _balances[account].sub(amount, "ERC20: burn amount exceeds balance"); _totalSupply = _totalSupply.sub(amount); emit Transfer(account, address(0), amount); } /** * @dev Sets `amount` as the allowance of `spender` over the `owner`s tokens. * * This is internal function is equivalent to `approve`, and can be used to * e.g. set automatic allowances for certain subsystems, etc. * * Emits an {Approval} event. * * Requirements: * * - `owner` cannot be the zero address. * - `spender` cannot be the zero address. */ function _approve(address owner, address spender, uint256 amount) internal virtual { require(owner != address(0), "ERC20: approve from the zero address"); require(spender != address(0), "ERC20: approve to the zero address"); _allowances[owner][spender] = amount; emit Approval(owner, spender, amount); } /** * @dev Sets {decimals} to a value other than the default one of 18. * * WARNING: This function should only be called from the constructor. Most * applications that interact with token contracts will not expect * {decimals} to ever change, and may work incorrectly if it does. */ function _setupDecimals(uint8 decimals_) internal { _decimals = decimals_; } /** * @dev Hook that is called before any transfer of tokens. This includes * minting and burning. * * Calling conditions: * * - when `from` and `to` are both non-zero, `amount` of ``from``'s tokens * will be to transferred to `to`. * - when `from` is zero, `amount` tokens will be minted for `to`. * - when `to` is zero, `amount` of ``from``'s tokens will be burned. * - `from` and `to` are never both zero. * * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks]. */ function _beforeTokenTransfer(address from, address to, uint256 amount) internal virtual { } }
// SPDX-License-Identifier: MIT pragma solidity ^0.6.0; import "../GSN/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. */ 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 () internal { address msgSender = _msgSender(); _owner = msgSender; emit OwnershipTransferred(address(0), msgSender); } /** * @dev Returns the address of the current owner. */ function owner() public view returns (address) { return _owner; } /** * @dev Throws if called by any account other than the owner. */ modifier onlyOwner() { require(_owner == _msgSender(), "Ownable: caller is not the owner"); _; } /** * @dev Leaves the contract without owner. It will not be possible to call * `onlyOwner` functions anymore. Can only be called by the current owner. * * NOTE: Renouncing ownership will leave the contract without an owner, * thereby removing any functionality that is only available to the owner. */ function renounceOwnership() public virtual onlyOwner { emit OwnershipTransferred(_owner, address(0)); _owner = 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"); emit OwnershipTransferred(_owner, newOwner); _owner = newOwner; } }
// SPDX-License-Identifier: MIT pragma solidity 0.6.12; import "@openzeppelin/contracts/token/ERC20/ERC20.sol"; import "@openzeppelin/contracts/access/Ownable.sol"; // Only used for testing Dubiex contract DummyVanillaERC20 is ERC20, Ownable { string public constant NAME = "Dummy"; string public constant SYMBOL = "DUMMY"; constructor() public ERC20(NAME, SYMBOL) Ownable() {} function mint(address to, uint256 amount) public onlyOwner { _mint(to, amount); } }
// SPDX-License-Identifier: MIT pragma solidity 0.6.12; import "@openzeppelin/contracts/token/ERC721/ERC721.sol"; contract DummyVanillaERC721 is ERC721 { string public constant NAME = "Vanilla ERC721"; string public constant SYMBOL = "VANILLA-"; constructor() public ERC721(NAME, SYMBOL) {} function mint(address to, uint256 tokenId) public { _mint(to, tokenId); } }
{ "optimizer": { "enabled": true, "runs": 200 }, "outputSelection": { "*": { "*": [ "evm.bytecode", "evm.deployedBytecode", "abi" ] } }, "libraries": {} }
Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
[{"inputs":[{"internalType":"address","name":"optIn","type":"address"},{"internalType":"address","name":"prps","type":"address"},{"internalType":"address","name":"dubi","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"maker","type":"address"},{"indexed":false,"internalType":"uint32","name":"id","type":"uint32"}],"name":"CanceledOrder","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint32","name":"id","type":"uint32"},{"indexed":false,"internalType":"address","name":"maker","type":"address"},{"indexed":false,"internalType":"uint256","name":"packedData","type":"uint256"}],"name":"MadeOrder","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint32","name":"id","type":"uint32"},{"indexed":false,"internalType":"address","name":"maker","type":"address"},{"indexed":false,"internalType":"address","name":"taker","type":"address"},{"indexed":false,"internalType":"uint256","name":"packedData","type":"uint256"}],"name":"TookOrder","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"maker","type":"address"},{"indexed":false,"internalType":"uint32","name":"id","type":"uint32"}],"name":"UpdatedOrder","type":"event"},{"inputs":[],"name":"activateKillSwitch","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"components":[{"components":[{"internalType":"uint32","name":"id","type":"uint32"},{"internalType":"address payable","name":"maker","type":"address"}],"internalType":"struct DubiexLib.CancelOrderInput","name":"input","type":"tuple"},{"components":[{"internalType":"uint96","name":"dubi","type":"uint96"},{"internalType":"uint96","name":"unlockedPrps","type":"uint96"},{"internalType":"uint96","name":"lockedPrps","type":"uint96"},{"internalType":"uint96","name":"intrinsicFuel","type":"uint96"}],"internalType":"struct BoosterFuel","name":"fuel","type":"tuple"},{"components":[{"internalType":"address","name":"booster","type":"address"},{"internalType":"uint64","name":"timestamp","type":"uint64"},{"internalType":"uint64","name":"nonce","type":"uint64"},{"internalType":"bool","name":"isLegacySignature","type":"bool"}],"internalType":"struct BoosterPayload","name":"boosterPayload","type":"tuple"}],"internalType":"struct Boostable.BoostedCancelOrder","name":"order","type":"tuple"},{"components":[{"internalType":"bytes32","name":"r","type":"bytes32"},{"internalType":"bytes32","name":"s","type":"bytes32"},{"internalType":"uint8","name":"v","type":"uint8"}],"internalType":"struct Signature","name":"signature","type":"tuple"}],"name":"boostedCancelOrder","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"components":[{"components":[{"internalType":"uint32","name":"id","type":"uint32"},{"internalType":"address payable","name":"maker","type":"address"}],"internalType":"struct DubiexLib.CancelOrderInput","name":"input","type":"tuple"},{"components":[{"internalType":"uint96","name":"dubi","type":"uint96"},{"internalType":"uint96","name":"unlockedPrps","type":"uint96"},{"internalType":"uint96","name":"lockedPrps","type":"uint96"},{"internalType":"uint96","name":"intrinsicFuel","type":"uint96"}],"internalType":"struct BoosterFuel","name":"fuel","type":"tuple"},{"components":[{"internalType":"address","name":"booster","type":"address"},{"internalType":"uint64","name":"timestamp","type":"uint64"},{"internalType":"uint64","name":"nonce","type":"uint64"},{"internalType":"bool","name":"isLegacySignature","type":"bool"}],"internalType":"struct BoosterPayload","name":"boosterPayload","type":"tuple"}],"internalType":"struct Boostable.BoostedCancelOrder[]","name":"orders","type":"tuple[]"},{"components":[{"internalType":"bytes32","name":"r","type":"bytes32"},{"internalType":"bytes32","name":"s","type":"bytes32"},{"internalType":"uint8","name":"v","type":"uint8"}],"internalType":"struct Signature[]","name":"signatures","type":"tuple[]"}],"name":"boostedCancelOrderBatch","outputs":[{"internalType":"uint32","name":"","type":"uint32"}],"stateMutability":"payable","type":"function"},{"inputs":[{"components":[{"components":[{"internalType":"uint96","name":"makerValue","type":"uint96"},{"internalType":"uint96","name":"takerValue","type":"uint96"},{"components":[{"internalType":"address","name":"makerContractAddress","type":"address"},{"internalType":"enum DubiexLib.CurrencyType","name":"makerCurrencyType","type":"uint8"},{"internalType":"address","name":"takerContractAddress","type":"address"},{"internalType":"enum DubiexLib.CurrencyType","name":"takerCurrencyType","type":"uint8"}],"internalType":"struct DubiexLib.OrderPair","name":"pair","type":"tuple"},{"internalType":"uint32","name":"orderId","type":"uint32"},{"internalType":"uint32","name":"ancestorOrderId","type":"uint32"},{"internalType":"uint128","name":"updatedRatioWei","type":"uint128"}],"internalType":"struct DubiexLib.MakeOrderInput","name":"input","type":"tuple"},{"internalType":"address payable","name":"maker","type":"address"},{"components":[{"internalType":"uint96","name":"dubi","type":"uint96"},{"internalType":"uint96","name":"unlockedPrps","type":"uint96"},{"internalType":"uint96","name":"lockedPrps","type":"uint96"},{"internalType":"uint96","name":"intrinsicFuel","type":"uint96"}],"internalType":"struct BoosterFuel","name":"fuel","type":"tuple"},{"components":[{"internalType":"address","name":"booster","type":"address"},{"internalType":"uint64","name":"timestamp","type":"uint64"},{"internalType":"uint64","name":"nonce","type":"uint64"},{"internalType":"bool","name":"isLegacySignature","type":"bool"}],"internalType":"struct BoosterPayload","name":"boosterPayload","type":"tuple"}],"internalType":"struct Boostable.BoostedMakeOrder","name":"order","type":"tuple"},{"components":[{"internalType":"bytes32","name":"r","type":"bytes32"},{"internalType":"bytes32","name":"s","type":"bytes32"},{"internalType":"uint8","name":"v","type":"uint8"}],"internalType":"struct Signature","name":"signature","type":"tuple"}],"name":"boostedMakeOrder","outputs":[{"internalType":"uint32","name":"","type":"uint32"}],"stateMutability":"payable","type":"function"},{"inputs":[{"components":[{"components":[{"internalType":"uint96","name":"makerValue","type":"uint96"},{"internalType":"uint96","name":"takerValue","type":"uint96"},{"components":[{"internalType":"address","name":"makerContractAddress","type":"address"},{"internalType":"enum DubiexLib.CurrencyType","name":"makerCurrencyType","type":"uint8"},{"internalType":"address","name":"takerContractAddress","type":"address"},{"internalType":"enum DubiexLib.CurrencyType","name":"takerCurrencyType","type":"uint8"}],"internalType":"struct DubiexLib.OrderPair","name":"pair","type":"tuple"},{"internalType":"uint32","name":"orderId","type":"uint32"},{"internalType":"uint32","name":"ancestorOrderId","type":"uint32"},{"internalType":"uint128","name":"updatedRatioWei","type":"uint128"}],"internalType":"struct DubiexLib.MakeOrderInput","name":"input","type":"tuple"},{"internalType":"address payable","name":"maker","type":"address"},{"components":[{"internalType":"uint96","name":"dubi","type":"uint96"},{"internalType":"uint96","name":"unlockedPrps","type":"uint96"},{"internalType":"uint96","name":"lockedPrps","type":"uint96"},{"internalType":"uint96","name":"intrinsicFuel","type":"uint96"}],"internalType":"struct BoosterFuel","name":"fuel","type":"tuple"},{"components":[{"internalType":"address","name":"booster","type":"address"},{"internalType":"uint64","name":"timestamp","type":"uint64"},{"internalType":"uint64","name":"nonce","type":"uint64"},{"internalType":"bool","name":"isLegacySignature","type":"bool"}],"internalType":"struct BoosterPayload","name":"boosterPayload","type":"tuple"}],"internalType":"struct Boostable.BoostedMakeOrder[]","name":"orders","type":"tuple[]"},{"components":[{"internalType":"bytes32","name":"r","type":"bytes32"},{"internalType":"bytes32","name":"s","type":"bytes32"},{"internalType":"uint8","name":"v","type":"uint8"}],"internalType":"struct Signature[]","name":"signatures","type":"tuple[]"}],"name":"boostedMakeOrderBatch","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"components":[{"components":[{"internalType":"uint32","name":"id","type":"uint32"},{"internalType":"address payable","name":"maker","type":"address"},{"internalType":"uint96","name":"takerValue","type":"uint96"},{"internalType":"uint256","name":"maxTakerMakerRatio","type":"uint256"}],"internalType":"struct DubiexLib.TakeOrderInput","name":"input","type":"tuple"},{"internalType":"address payable","name":"taker","type":"address"},{"components":[{"internalType":"uint96","name":"dubi","type":"uint96"},{"internalType":"uint96","name":"unlockedPrps","type":"uint96"},{"internalType":"uint96","name":"lockedPrps","type":"uint96"},{"internalType":"uint96","name":"intrinsicFuel","type":"uint96"}],"internalType":"struct BoosterFuel","name":"fuel","type":"tuple"},{"components":[{"internalType":"address","name":"booster","type":"address"},{"internalType":"uint64","name":"timestamp","type":"uint64"},{"internalType":"uint64","name":"nonce","type":"uint64"},{"internalType":"bool","name":"isLegacySignature","type":"bool"}],"internalType":"struct BoosterPayload","name":"boosterPayload","type":"tuple"}],"internalType":"struct Boostable.BoostedTakeOrder","name":"order","type":"tuple"},{"components":[{"internalType":"bytes32","name":"r","type":"bytes32"},{"internalType":"bytes32","name":"s","type":"bytes32"},{"internalType":"uint8","name":"v","type":"uint8"}],"internalType":"struct Signature","name":"signature","type":"tuple"}],"name":"boostedTakeOrder","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"components":[{"components":[{"internalType":"uint32","name":"id","type":"uint32"},{"internalType":"address payable","name":"maker","type":"address"},{"internalType":"uint96","name":"takerValue","type":"uint96"},{"internalType":"uint256","name":"maxTakerMakerRatio","type":"uint256"}],"internalType":"struct DubiexLib.TakeOrderInput","name":"input","type":"tuple"},{"internalType":"address payable","name":"taker","type":"address"},{"components":[{"internalType":"uint96","name":"dubi","type":"uint96"},{"internalType":"uint96","name":"unlockedPrps","type":"uint96"},{"internalType":"uint96","name":"lockedPrps","type":"uint96"},{"internalType":"uint96","name":"intrinsicFuel","type":"uint96"}],"internalType":"struct BoosterFuel","name":"fuel","type":"tuple"},{"components":[{"internalType":"address","name":"booster","type":"address"},{"internalType":"uint64","name":"timestamp","type":"uint64"},{"internalType":"uint64","name":"nonce","type":"uint64"},{"internalType":"bool","name":"isLegacySignature","type":"bool"}],"internalType":"struct BoosterPayload","name":"boosterPayload","type":"tuple"}],"internalType":"struct Boostable.BoostedTakeOrder[]","name":"boostedTakeOrders","type":"tuple[]"},{"components":[{"internalType":"bytes32","name":"r","type":"bytes32"},{"internalType":"bytes32","name":"s","type":"bytes32"},{"internalType":"uint8","name":"v","type":"uint8"}],"internalType":"struct Signature[]","name":"signatures","type":"tuple[]"}],"name":"boostedTakeOrderBatch","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"components":[{"internalType":"uint32","name":"id","type":"uint32"},{"internalType":"address payable","name":"maker","type":"address"}],"internalType":"struct DubiexLib.CancelOrderInput","name":"input","type":"tuple"}],"name":"cancelOrder","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"components":[{"internalType":"uint32","name":"id","type":"uint32"},{"internalType":"address payable","name":"maker","type":"address"}],"internalType":"struct DubiexLib.CancelOrderInput[]","name":"inputs","type":"tuple[]"}],"name":"cancelOrders","outputs":[{"internalType":"bool[]","name":"","type":"bool[]"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"getNonce","outputs":[{"internalType":"uint64","name":"","type":"uint64"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"maker","type":"address"},{"internalType":"uint64","name":"id","type":"uint64"}],"name":"getOrder","outputs":[{"components":[{"internalType":"uint32","name":"id","type":"uint32"},{"internalType":"uint96","name":"makerValue","type":"uint96"},{"internalType":"uint96","name":"takerValue","type":"uint96"},{"internalType":"uint32","name":"orderPairAlias","type":"uint32"},{"components":[{"internalType":"address","name":"makerContractAddress","type":"address"},{"internalType":"enum DubiexLib.CurrencyType","name":"makerCurrencyType","type":"uint8"},{"internalType":"address","name":"takerContractAddress","type":"address"},{"internalType":"enum DubiexLib.CurrencyType","name":"takerCurrencyType","type":"uint8"}],"internalType":"struct DubiexLib.OrderPair","name":"pair","type":"tuple"},{"components":[{"internalType":"bool","name":"isMakerERC721","type":"bool"},{"internalType":"bool","name":"isTakerERC721","type":"bool"},{"internalType":"bool","name":"isHidden","type":"bool"},{"internalType":"bool","name":"hasSuccessor","type":"bool"}],"internalType":"struct DubiexLib.OrderFlags","name":"flags","type":"tuple"},{"internalType":"uint32","name":"successorOrderId","type":"uint32"},{"internalType":"uint32","name":"ancestorOrderId","type":"uint32"}],"internalType":"struct DubiexLib.PrettyOrderBookItem","name":"","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"orderPairHash","type":"bytes32"}],"name":"getOrderPairAliasByHash","outputs":[{"internalType":"uint32","name":"","type":"uint32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint32","name":"orderPairAlias","type":"uint32"}],"name":"getOrderPairByAlias","outputs":[{"components":[{"internalType":"address","name":"makerContractAddress","type":"address"},{"internalType":"enum DubiexLib.CurrencyType","name":"makerCurrencyType","type":"uint8"},{"internalType":"address","name":"takerContractAddress","type":"address"},{"internalType":"enum DubiexLib.CurrencyType","name":"takerCurrencyType","type":"uint8"}],"internalType":"struct DubiexLib.OrderPair","name":"","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"orderPairHash","type":"bytes32"}],"name":"getOrderPairByHash","outputs":[{"components":[{"internalType":"address","name":"makerContractAddress","type":"address"},{"internalType":"enum DubiexLib.CurrencyType","name":"makerCurrencyType","type":"uint8"},{"internalType":"address","name":"takerContractAddress","type":"address"},{"internalType":"enum DubiexLib.CurrencyType","name":"takerCurrencyType","type":"uint8"}],"internalType":"struct DubiexLib.OrderPair","name":"","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"components":[{"internalType":"uint96","name":"makerValue","type":"uint96"},{"internalType":"uint96","name":"takerValue","type":"uint96"},{"components":[{"internalType":"address","name":"makerContractAddress","type":"address"},{"internalType":"enum DubiexLib.CurrencyType","name":"makerCurrencyType","type":"uint8"},{"internalType":"address","name":"takerContractAddress","type":"address"},{"internalType":"enum DubiexLib.CurrencyType","name":"takerCurrencyType","type":"uint8"}],"internalType":"struct DubiexLib.OrderPair","name":"pair","type":"tuple"},{"internalType":"uint32","name":"orderId","type":"uint32"},{"internalType":"uint32","name":"ancestorOrderId","type":"uint32"},{"internalType":"uint128","name":"updatedRatioWei","type":"uint128"}],"internalType":"struct DubiexLib.MakeOrderInput","name":"input","type":"tuple"}],"name":"makeOrder","outputs":[{"internalType":"uint32","name":"","type":"uint32"}],"stateMutability":"payable","type":"function"},{"inputs":[{"components":[{"internalType":"uint96","name":"makerValue","type":"uint96"},{"internalType":"uint96","name":"takerValue","type":"uint96"},{"components":[{"internalType":"address","name":"makerContractAddress","type":"address"},{"internalType":"enum DubiexLib.CurrencyType","name":"makerCurrencyType","type":"uint8"},{"internalType":"address","name":"takerContractAddress","type":"address"},{"internalType":"enum DubiexLib.CurrencyType","name":"takerCurrencyType","type":"uint8"}],"internalType":"struct DubiexLib.OrderPair","name":"pair","type":"tuple"},{"internalType":"uint32","name":"orderId","type":"uint32"},{"internalType":"uint32","name":"ancestorOrderId","type":"uint32"},{"internalType":"uint128","name":"updatedRatioWei","type":"uint128"}],"internalType":"struct DubiexLib.MakeOrderInput[]","name":"inputs","type":"tuple[]"}],"name":"makeOrders","outputs":[{"internalType":"uint32[]","name":"","type":"uint32[]"}],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"address","name":"","type":"address"},{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"bytes","name":"","type":"bytes"}],"name":"onERC721Received","outputs":[{"internalType":"bytes4","name":"","type":"bytes4"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"components":[{"internalType":"uint32","name":"id","type":"uint32"},{"internalType":"address payable","name":"maker","type":"address"},{"internalType":"uint96","name":"takerValue","type":"uint96"},{"internalType":"uint256","name":"maxTakerMakerRatio","type":"uint256"}],"internalType":"struct DubiexLib.TakeOrderInput","name":"input","type":"tuple"}],"name":"takeOrder","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"components":[{"internalType":"uint32","name":"id","type":"uint32"},{"internalType":"address payable","name":"maker","type":"address"},{"internalType":"uint96","name":"takerValue","type":"uint96"},{"internalType":"uint256","name":"maxTakerMakerRatio","type":"uint256"}],"internalType":"struct DubiexLib.TakeOrderInput[]","name":"inputs","type":"tuple[]"}],"name":"takeOrders","outputs":[{"internalType":"bool[]","name":"","type":"bool[]"}],"stateMutability":"payable","type":"function"}]
Contract Creation Code
6101006040523480156200001257600080fd5b50604051620057b0380380620057b0833981016040819052620000359162000110565b82807f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f7ffd0a9ab201fb4f6ded13ed73b8600641f1eebb926a13f8ab819bb70e8aba60697fc89efdaa54c0f20c7adf612882df0950f5a951637e0307cdcb4c672f298b8bc6620000a46200010c565b30604051602001620000bb95949392919062000163565b60408051601f19818403018152919052805160209091012060016000556001600160601b0319606092831b811660805260a09190915293811b841660c0529190911b90911660e05250620001a89050565b4690565b60008060006060848603121562000125578283fd5b835162000132816200018f565b602085015190935062000145816200018f565b604085015190925062000158816200018f565b809150509250925092565b9485526020850193909352604084019190915260608301526001600160a01b0316608082015260a00190565b6001600160a01b0381168114620001a557600080fd5b50565b60805160601c60a05160c05160601c60e05160601c6155b06200020060003980610c8352806119d1525080610bee52806118a15280611959525080611a34528061234c5280612dbc525080611af852506155b06000f3fe6080604052600436106101145760003560e01c80636b2a4aba116100a0578063d51b97f311610064578063d51b97f3146102d7578063f24e7fd9146102f7578063f6adcd211461030c578063f744a5c71461032c578063ffc1d8181461033f57610114565b80636b2a4aba1461022a5780637cc650801461024a578063a0a7d09c1461025d578063a4d91c9a1461028a578063cccedc83146102b757610114565b80632d0335ab116100e75780632d0335ab146101a2578063348e9d63146101cf57806344f648df146101e45780636593a384146101f757806369097d7a1461021757610114565b8063084487041461011957806309bcad3e14610142578063150b7a021461016257806327762f091461018f575b600080fd5b61012c610127366004614025565b610352565b604051610139919061544d565b60405180910390f35b610155610150366004614331565b61041a565b60405161013991906147ca565b34801561016e57600080fd5b5061018261017d366004613f39565b610555565b6040516101399190614a09565b61012c61019d366004614438565b610566565b3480156101ae57600080fd5b506101c26101bd366004613f01565b6105d1565b60405161013991906154b2565b6101e26101dd3660046143ef565b6105f9565b005b61012c6101f23660046144ad565b61063e565b34801561020357600080fd5b5061012c6102123660046143d7565b6106b5565b6101e26102253660046144e4565b6106cd565b34801561023657600080fd5b506101e2610245366004614492565b61074d565b6101e26102583660046140f6565b610793565b34801561026957600080fd5b5061027d6102783660046143d7565b610885565b6040516101399190615395565b34801561029657600080fd5b506102aa6102a5366004613ff0565b6108b2565b60405161013991906153a3565b3480156102c357600080fd5b506101556102d2366004614224565b6109d5565b3480156102e357600080fd5b5061027d6102f236600461452e565b610aeb565b34801561030357600080fd5b506101e2610bb6565b61031f61031a366004614293565b610d51565b6040516101399190614810565b6101e261033a36600461418a565b610e7e565b6101e261034d366004614465565b610f6c565b6000600260005414156103805760405162461bcd60e51b815260040161037790615270565b60405180910390fd5b60026000558351158015906103955750835182145b6103b15760405162461bcd60e51b815260040161037790614f1b565b60045460ff1660005b855181101561040c576104048682815181106103d257fe5b60200260200101518686848181106103e657fe5b9050606002018036038101906103fc91906144c9565b600085610fd1565b6001016103ba565b505060016000559392505050565b60606002600054141561043f5760405162461bcd60e51b815260040161037790615270565b600260005560045460ff16156104675760405162461bcd60e51b815260040161037790614ba5565b816104845760405162461bcd60e51b815260040161037790614eab565b6060826001600160401b038111801561049c57600080fd5b506040519080825280602002602001820160405280156104c6578160200160208202803683370190505b5090503460005b8481101561053e57600061050f338888858181106104e757fe5b9050608002018036038101906104fd91906144fb565b856001600160601b031660008061103e565b5080945081925050508084838151811061052557fe5b91151560209283029190910190910152506001016104cd565b5061054881611228565b5060016000559392505050565b630a85bd0160e11b5b949350505050565b60006002600054141561058b5760405162461bcd60e51b815260040161037790615270565b600260005560045460ff16156105b35760405162461bcd60e51b815260040161037790615094565b6000346105c38585836001611273565b909250905061054881611228565b6001600160a01b0381166000908152600160205260409020546001600160401b03165b919050565b6002600054141561061c5760405162461bcd60e51b815260040161037790615270565b600260005560045460ff166106348383600184610fd1565b5050600160005550565b6000600260005414156106635760405162461bcd60e51b815260040161037790615270565b600260005560045460ff161561068b5760405162461bcd60e51b815260040161037790615094565b34600061069c843384846001611324565b925090506106a982611228565b60016000559392505050565b60009081526006602052604090205463ffffffff1690565b600260005414156106f05760405162461bcd60e51b815260040161037790615270565b600260005560045460ff16156107185760405162461bcd60e51b815260040161037790614ba5565b346107363361072c368590038501856144fb565b836001600061103e565b509150610744905081611228565b50506001600055565b600260005414156107705760405162461bcd60e51b815260040161037790615270565b60026000908155602082015182516004546107449390819060019060ff166115e9565b600260005414156107b65760405162461bcd60e51b815260040161037790615270565b600260005560045460ff16156107de5760405162461bcd60e51b815260040161037790615094565b82158015906107ec57508281145b6108085760405162461bcd60e51b815260040161037790614f1b565b3460005b848110156108785761086d86868381811061082357fe5b9050610240020180360381019061083a919061441c565b85858481811061084657fe5b90506060020180360381019061085c91906144c9565b846001600160601b03166000611273565b92505060010161080c565b5050600160005550505050565b61088d6139a1565b60008281526006602052604090205463ffffffff166108ab81610aeb565b9392505050565b6108ba6139c9565b6001600160a01b0383166000908152600860205260408120905b81548110156109c25760008282815481106108eb57fe5b90600052602060002090600202019050610903613a1b565b815461090e906116d9565b805190915063ffffffff166001600160401b03871614156109b8576109316139c9565b815163ffffffff90811682526020808401516001600160601b03908116918401919091526040808501519091169083015260608084018051909216908301525161097a90610aeb565b608082015260a0918201519181019190915260019091015463ffffffff80821660c08401526401000000009091041660e082015292506109cf915050565b50506001016108d4565b506109cb6139c9565b9150505b92915050565b6060600260005414156109fa5760405162461bcd60e51b815260040161037790615270565b600260005581610a1c5760405162461bcd60e51b815260040161037790614eab565b6060826001600160401b0381118015610a3457600080fd5b50604051908082528060200260200182016040528015610a5e578160200160208202803683370190505b5060045490915060ff1660005b8481101561040c57610ac7868683818110610a8257fe5b9050604002016020016020810190610a9a9190613f01565b878784818110610aa657fe5b610abc926020604090920201908101915061452e565b6000806000876115e9565b838281518110610ad357fe5b91151560209283029190910190910152600101610a6b565b610af36139a1565b610afb6139a1565b63ffffffff8316600090815260056020526040812080549091908190610b29906001600160a81b0316611788565b600185015491935091506000908190610b4a906001600160a81b0316611788565b6001600160a01b0386168852909250905060208601836004811115610b6b57fe5b90816004811115610b7857fe5b9052506001600160a01b038216604087015260608601816004811115610b9a57fe5b90816004811115610ba757fe5b90525094979650505050505050565b60045460ff1615610bd95760405162461bcd60e51b815260040161037790614bf0565b60006b033b2e3c9fd0803ce8000000905060007f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03166318160ddd6040518163ffffffff1660e01b815260040160206040518083038186803b158015610c4557600080fd5b505afa158015610c59573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610c7d9190614516565b905060007f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03166318160ddd6040518163ffffffff1660e01b815260040160206040518083038186803b158015610cda57600080fd5b505afa158015610cee573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610d129190614516565b90508282101580610d235750828110155b610d3f5760405162461bcd60e51b815260040161037790614e3c565b50506004805460ff1916600117905550565b606060026000541415610d765760405162461bcd60e51b815260040161037790615270565b600260005560045460ff1615610d9e5760405162461bcd60e51b815260040161037790615094565b6000825111610dbf5760405162461bcd60e51b815260040161037790614eab565b606082516001600160401b0381118015610dd857600080fd5b50604051908082528060200260200182016040528015610e02578160200160208202803683370190505b5090503460005b8451811015610e68576000610e35868381518110610e2357fe5b60200260200101513385600080611324565b809450819250505080848381518110610e4a57fe5b63ffffffff9092166020928302919091019091015250600101610e09565b50610e7281611228565b50600160005592915050565b60026000541415610ea15760405162461bcd60e51b815260040161037790615270565b600260005560045460ff1615610ec95760405162461bcd60e51b815260040161037790614ba5565b60008351118015610eda5750825181145b610ef65760405162461bcd60e51b815260040161037790614f1b565b3460005b8451811015610f5757610f4d858281518110610f1257fe5b6020026020010151858584818110610f2657fe5b905060600201803603810190610f3c91906144c9565b846001600160601b031660006117ac565b9150600101610efa565b50610f6181611228565b505060016000555050565b60026000541415610f8f5760405162461bcd60e51b815260040161037790615270565b600260005560045460ff1615610fb75760405162461bcd60e51b815260040161037790614ba5565b6000610fc683833460016117ac565b905061063481611228565b6000610fe98560000151602001518660200151611855565b905061100c8560000151602001516110018733611a2d565b876040015187611aca565b845160208101519051600160601b600160c01b03606084901b16916110359183600188886115e9565b50505050505050565b60008060008061104c613a1b565b60006110588a89611d5e565b8151929550909350915063ffffffff1661108757506000945050506001600160601b038616915082905061121d565b60008061109d848d604001518e60600151611e47565b91509150816001600160601b0316600014806110c057506001600160601b038116155b156111015789156110e35760405162461bcd60e51b815260040161037790614fb2565b5060009650506001600160601b038916945085935061121d92505050565b6111178d8d602001518387608001518f8e611fba565b9a5061112b8d83866080015160008061200c565b61116257891561114d5760405162461bcd60e51b815260040161037790614aac565b60008b6000975097509750505050505061121d565b818460200151036001600160601b0316600014156111b5578360a0015160600151156111a25760208c015160018601546111a2919063ffffffff1661203b565b6111b08c60200151846120dc565b6111e6565b6020840180516001600160601b0390849003811690915260408501805183900390911690526111e3846121be565b85555b6001600160601b0380831660208087019190915290821660408601528c0151611211908e868e6122aa565b97509750975050505050505b955095509592505050565b6001600160601b03163481111561123b57fe5b801561127057604051339082156108fc029083906000818181858888f1935050505015801561126e573d6000803e3d6000fd5b505b50565b600080600061128a87602001518860400151611855565b905060048751604001516020015160048111156112a357fe5b14156112cb576112c687602001516112bb8933612345565b896060015189611aca565b6112e8565b6112e887602001516112dd8933612345565b8960600151896123cd565b86516020880151600091600160601b600160c01b03606085901b1688179161131491908360018a611324565b909a909950975050505050505050565b6000806001600160a01b038616301480159061134857506001600160a01b03861615155b6113645760405162461bcd60e51b815260040161037790615239565b606087015163ffffffff161561139a576113888688606001518960a0015186612463565b9150506001600160601b0384166115df565b86516001600160601b03166113c15760405162461bcd60e51b815260040161037790614df8565b600087602001516001600160601b0316116113ee5760405162461bcd60e51b815260040161037790614a68565b60006113fd88604001516125c4565b9050600061142d88308b600001516001600160601b03168c60400151600001518d60400151602001518c8c612721565b975090508061144e5760405162461bcd60e51b815260040161037790614d22565b611456613a58565b61145e613a1b565b6114678a612bc0565b63ffffffff90811682528b516001600160601b039081166020808501919091528d01511660408301528416606082015260048b604001516020015160048111156114ad57fe5b60a08301519114905260048b604001516060015160048111156114cc57fe5b60a083015191146020909101526114e58b8b8385612c27565b6114ee816121be565b82526001600160a01b038a16600090815260086020908152604080832080546001808201835591855293839020865160029095020193845582860151930180548287015163ffffffff1990911663ffffffff9586161767ffffffff0000000019166401000000009590911694909402939093179092558c51908d0151835192516001600160601b0390921660609190911b600160601b600160c01b03161760c087901b63ffffffff60c01b1617917fdb2323af401323ef38d7230b256657107a493035b145c1e3eff57c8250decf5e916115cc91908e90859061545e565b60405180910390a1505194508793505050505b9550959350505050565b6000831580156115f7575081155b15611624576001600160a01b03871633146116245760405162461bcd60e51b8152600401610377906152fd565b8215801561163957506116378787612c70565b155b15611646575060006116cf565b61164e613a1b565b600061165c89896001612cec565b92509250506116768983602001518460800151898b61200c565b611685576000925050506116cf565b61168f89826120dc565b7f02091bc96053a040f6eed60a7761afa426d85bafdb7373f8cdd5b300aeb9f33589896040516116c09291906146ff565b60405180910390a16001925050505b9695505050505050565b6116e1613a1b565b6116e9613a1b565b63ffffffff831681526001600160601b03602084811c821690830152608084901c166040820152630fffffff60e084901c818116606084015260fc9161172d613a78565b5060a0840151600187851c81168114825280850188901c8116811460208301526002850188901c8116811460408301526003850188901c8116146060820152600490930192610100841461177d57fe5b509295945050505050565b600080828160ff60a083901c1660048111156117a057fe5b91935090915050915091565b6000806117c186602001518760400151611855565b60208701518751919250600160601b600160c01b03606084901b168617916000916117ef918488600161103e565b90975091506004905081600481111561180457fe5b141561182c57611827886020015161181c8a33612db5565b8a606001518a611aca565b611849565b611849886020015161183e8a33612db5565b8a606001518a6123cd565b50939695505050505050565b60208101516000906001600160601b03161561191157604080518082018252600081526020848101516001600160601b03169082015290516310b4a23d60e01b81526001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016916310b4a23d916118d6918791600401614798565b600060405180830381600087803b1580156118f057600080fd5b505af1158015611904573d6000803e3d6000fd5b50505050600090506109cf565b60408201516001600160601b03161561198e5760408051808201825260018152838201516001600160601b0316602082015290516310b4a23d60e01b81526001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016916310b4a23d916118d6918791600401614798565b81516001600160601b031615611a06576040805180820182526002815283516001600160601b0316602082015290516310b4a23d60e01b81526001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016916310b4a23d916118d6918791600401614798565b60608201516001600160601b031615611a24575060608101516109cf565b50600092915050565b60006108ab7f00000000000000000000000000000000000000000000000000000000000000007f1799a833db8e3753554dfe065e827050155c5b688581007f1ebde805a9ce822b611a818660000151612e09565b611a8e8760200151612e62565b611a9c886040015188612ead565b604051602001611aaf94939291906148f5565b60405160208183030381529060405280519060200120612f12565b81516001600160a01b03163314611af35760405162461bcd60e51b815260040161037790614d8c565b6000807f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316630296287733886040518363ffffffff1660e01b8152600401611b449291906146b2565b604080518083038186803b158015611b5b57600080fd5b505afa158015611b6f573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611b9391906143aa565b9150915081611bb45760405162461bcd60e51b815260040161037790614d6e565b6020840151429082906001600160401b03610e10840181169181169182111591600191851610611bfd57826001600160401b0316886020015185036001600160401b0316111590505b818015611c075750805b611c235760405162461bcd60e51b815260040161037790614f52565b876060015115611c3957611c3689612f27565b98505b600060018a89604001518a600001518b6020015160405160008152602001604052604051611c6a9493929190614970565b6020604051602081039080840390855afa158015611c8c573d6000803e3d6000fd5b5050506020604051035190508860600151158015611cbc57508a6001600160a01b0316816001600160a01b031614155b15611d20576001611ccc8b612f27565b6040808b01518b516020808e015184516000815290910193849052611cf19493614970565b6020604051602081039080840390855afa158015611d13573d6000803e3d6000fd5b5050506020604051035190505b806001600160a01b03168b6001600160a01b031614611d515760405162461bcd60e51b815260040161037790614e8d565b5050505050505050505050565b6000611d68613a1b565b600080611d73613a1b565b6000611d89886020015189600001516003612f3a565b60408b0151825193965091945092506001600160601b031615159060009063ffffffff1615801590611dc157508360a0015160400151155b90508815611e085781611de65760405162461bcd60e51b815260040161037790614a68565b80611e035760405162461bcd60e51b815260040161037790614c5e565b611e35565b811580611e13575080155b15611e3557611e20613a1b565b60029850965060009550611e40945050505050565b509295509093509150505b9250925092565b602083015160009081906001600160601b0390811690851660048760800151602001516004811115611e7557fe5b1480611e94575060048760800151606001516004811115611e9257fe5b145b15611ec95786604001516001600160601b0316866001600160601b031614611ec457600080935093505050611fb2565b611f60565b60008288604001516001600160601b0316670de0b6b3a76400000281611eeb57fe5b04905080861015611f055760008094509450505050611fb2565b87604001516001600160601b0316821115611f2b5787604001516001600160601b031691505b6040880151928202670de0b6b3a764000002926001600160601b03168381611f4f57fe5b670de0b6b3a7640000919004049250505b600160601b82108015611f80575086602001516001600160601b03168211155b611f8657fe5b600160601b81108015611fa6575086604001516001600160601b03168111155b611fac57fe5b90925090505b935093915050565b6000806000611fdf8989896001600160601b031689604001518a606001518a8a612721565b91509150816120005760405162461bcd60e51b815260040161037790615116565b98975050505050505050565b60008061202f3088886001600160601b031688600001518960200151888a612721565b50979650505050505050565b6001600160a01b0382166000908152600860205260408120805490915b818110156120d557600083828154811061206e57fe5b6000918252602090912060029091020180549091508063ffffffff80821690881614156120ca5761209d613a1b565b6120a6836116d9565b60a0810151600060409091015290506120be816121be565b909355506120d5915050565b505050600101612058565b5050505050565b6001600160a01b03821660009081526008602052604090208054600019810183146121825781600182038154811061211057fe5b906000526020600020906002020182848154811061212a57fe5b6000918252602090912082546002909202019081556001918201805492909101805463ffffffff191663ffffffff9384161780825591546401000000009081900490931690920267ffffffff00000000199091161790555b8180548061218c57fe5b600082815260208120600260001990930192830201908155600101805467ffffffffffffffff19169055905550505050565b80516020808301516040840151606085015160009463ffffffff81169484901b6fffffffffffffffffffffffff000000001694909417608083901b6bffffffffffffffffffffffff60801b161760e082901b630fffffff60e01b16179360fc9390929091630fffffff61222f613a78565b5060a0890151805115612246576001871b97909717965b80602001511561225d57866001016001901b881797505b80604001511561227457866002016001901b881797505b80606001511561228b57866003016001901b881797505b600487019650866101001461229c57fe5b509598975050505050505050565b60008060008085602001516001600160601b031681179050606086604001516001600160601b0316901b8117905060c0866060015163ffffffff16901b811790507f37f5657599c9ee85981aa75d21e5deb98dc1a88f0b2cd5faa9a3174e41fe7c4f86600001518989846040516123249493929190615485565b60405180910390a15050505060809190910151606001516001949193509150565b60006108ab7f00000000000000000000000000000000000000000000000000000000000000007fc11e4b33114da8b5eeb04bd5ee0a3fb507510391ed105f2af9fa87089d9d180f6123998660000151612fcc565b86602001516123ab8860400151612e62565b6123b9896060015189612ead565b604051602001611aaf9594939291906148c9565b6001600160a01b0384166000908152600160205260409081902054908301516001600160401b039182169160001990910116811461241d5760405162461bcd60e51b815260040161037790615076565b6001600160a01b0385166000908152600160208190526040909120805467ffffffffffffffff19169183016001600160401b03169190911790556120d585858585611aca565b60008061246e613a1b565b61247a87876000612f3a565b508051919350915063ffffffff166124b55783156124aa5760405162461bcd60e51b815260040161037790614c5e565b60009250505061055e565b6000856001600160801b0316116124de5760405162461bcd60e51b815260040161037790615332565b60a0810151511580156124f757508060a0015160200151155b6125135760405162461bcd60e51b815260040161037790614f70565b6000670de0b6b3a7640000866001600160801b031683602001516001600160601b0316028161253e57fe5b049050600160601b81106125645760405162461bcd60e51b81526004016103779061535e565b6001600160601b038116604083015261257c826121be565b83556040517fe2e1e85213ffa6d43a863e28337fea547c34f304d08298c76a4150fe19a79598906125b0908a908a906146ff565b60405180910390a150949695505050505050565b60008082600001518360400151846020015185606001516040516020016125ee949392919061471e565b60408051601f1981840301815291815281516020928301206000818152600690935291205490915063ffffffff16806108ab576126338460200151856000015161302b565b61264f5760405162461bcd60e51b815260040161037790614ccc565b6126618460600151856040015161302b565b61267d5760405162461bcd60e51b8152600401610377906152a7565b506004805463ffffffff610100808304821660010191821690810264ffffffff0019909316929092179092556000838152600660205260409020805463ffffffff19169091179055806126cf85613397565b63ffffffff83166000908152600560209081526040909120825181546001600160a81b03199081166001600160a81b039283161783559390920151600190910180549093169116179055509392505050565b6000806001600160601b038416600186600481111561273c57fe5b14156127bc576001600160a01b038a163014612769578781101561276557600092509050612bb4565b8790035b6001600160a01b03891630146127b1576040516001600160a01b038a169089156108fc02908a906000818181858888f193505050501580156127af573d6000803e3d6000fd5b505b600192509050612bb4565b60028660048111156127ca57fe5b1415612944576040516370a0823160e01b815287906000906001600160a01b038316906370a0823190612801908e9060040161469e565b60206040518083038186803b15801561281957600080fd5b505afa15801561282d573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906128519190614516565b90506001600160a01b038c1630141561287d576128786001600160a01b0383168c8c613432565b612892565b6128926001600160a01b0383168d8d8d61348d565b6040516370a0823160e01b81526000906001600160a01b038416906370a08231906128c1908f9060040161469e565b60206040518083038186803b1580156128d957600080fd5b505afa1580156128ed573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906129119190614516565b90508a820181146129345760405162461bcd60e51b815260040161037790615030565b6001849550955050505050612bb4565b600386600481111561295257fe5b1415612a5457866001600160a01b038b163014156129835761297e6001600160a01b0382168b8b613432565b6127af565b6000816001600160a01b03166309ee40a08d8d8d8a6040516020016129a89190614608565b6040516020818303038152906040526040518563ffffffff1660e01b81526004016129d694939291906146cc565b602060405180830381600087803b1580156129f057600080fd5b505af1158015612a04573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612a28919061438e565b905080612a475760405162461bcd60e51b815260040161037790614daa565b5050600192509050612bb4565b6004866004811115612a6257fe5b1415612b9c576000879050806001600160a01b031663b88d4fde8c8c8c8960608c901c604051602001612a96929190614616565b6040516020818303038152906040526040518563ffffffff1660e01b8152600401612ac494939291906146cc565b600060405180830381600087803b158015612ade57600080fd5b505af1158015612af2573d6000803e3d6000fd5b50506040516331a9108f60e11b81526001600160a01b03808e16935084169150636352211e90612b26908d90600401615444565b60206040518083038186803b158015612b3e57600080fd5b505afa158015612b52573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612b769190613f1d565b6001600160a01b0316146127af5760405162461bcd60e51b815260040161037790614fe9565b60405162461bcd60e51b815260040161037790614af5565b97509795505050505050565b6001600160a01b03811660009081526007602052604081205463ffffffff166401000000008110612bed57fe5b6001600160a01b0383166000908152600760205260409020805463ffffffff600190930192831663ffffffff199091161790559050919050565b608084015163ffffffff1615612c6a5760808401805163ffffffff166040830152518251600091612c5a918691906134ae565b60a0840151901515604090910152505b50505050565b6001600160a01b03821660009081526008602052604081208054825b81811015612ce0576000838281548110612ca257fe5b90600052602060002090600202016000015490508563ffffffff168163ffffffff161415612cd75760019450505050506109cf565b50600101612c8c565b50600095945050505050565b6000612cf6613a1b565b6001600160a01b03851660009081526008602052604081208054825b81811015612d93576000838281548110612d2857fe5b6000918252602090912060029091020180549091508063ffffffff808216908c161415612d8857612d57613a1b565b612d60836116d9565b9050612d7081606001518c613597565b6080820152929850919650919450612dac9350505050565b505050600101612d12565b5060405162461bcd60e51b815260040161037790614c5e565b93509350939050565b60006108ab7f00000000000000000000000000000000000000000000000000000000000000007f8d1c2f33c3caca0a1420b919fdaa6b343ae132cceddb22589ca3627a2fadf90f6123998660000151613733565b8051602080830151604051600093612e45937f8422927d64906b319ff9905ee9483f60a137efd9dc400caa8f675f48dae0b0ed93919201614910565b604051602081830303815290604052805190602001209050919050565b60007ff1f7d09b7527273cfd8370620354f0cd9a62e7bd3efaafdeca15664a7b3e045c8260000151836020015184604001518560600151604051602001612e459594939291906149db565b60007ff45b7e63030d0a046d85957a672f9a0806d76fff4cc32355d75f64eb6e83d00882846020015185604001518660600151604051602001612ef4959493929190614892565b60405160208183030381529060405280519060200120905092915050565b60008282604051602001612ef4929190614683565b600081604051602001612e459190614652565b6000612f44613a1b565b6001600160a01b03851660009081526008602052604081208054825b81811015612fb0576000838281548110612f7657fe5b6000918252602090912060029091020180549091508063ffffffff808216908c161415612fa557612d57613a1b565b505050600101612f60565b50612fb9613a1b565b6002999098506000975095505050505050565b60007f22aa64e18e438511e7911a9c6000037401f34ec1ca6db0b8ade73eaf3d72a8c582600001518360200151613006856040015161377e565b856060015186608001518760a00151604051602001612e45979695949392919061498e565b6000600183600481111561303b57fe5b1415613070576001600160a01b038216156130685760405162461bcd60e51b815260040161037790614c95565b5060016109cf565b600483600481111561307e57fe5b1415613123576040516301ffc9a760e01b81526001600160a01b038316906301ffc9a7906130b7906380ac58cd60e01b90600401614a09565b60206040518083038186803b1580156130cf57600080fd5b505afa1580156130e3573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613107919061438e565b6130685760405162461bcd60e51b815260040161037790614a31565b600383600481111561313157fe5b14156132155760405163555ddc6560e11b8152600090731820a4b7618bde71dce8cdc73aab6c95905fad249063aabbb8ca906131939086907f51d0ab336ae4fc621cb076e5c123b2236d97b9709e1ff2e304c6d727b35c6e4b9060040161477f565b60206040518083038186803b1580156131ab57600080fd5b505afa1580156131bf573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906131e39190613f1d565b90506001600160a01b03811661320b5760405162461bcd60e51b815260040161037790614b61565b60019150506109cf565b600283600481111561322357fe5b1415611a245760006060836001600160a01b03166301ffc9a76380ac58cd60e01b6040516024016132549190614a09565b6040516020818303038152906040529060e01b6020820180516001600160e01b03838183161783525050505060405161328d9190614636565b6000604051808303816000865af19150503d80600081146132ca576040519150601f19603f3d011682016040523d82523d6000602084013e6132cf565b606091505b5091509150600080825111156132f657818060200190518101906132f3919061438e565b90505b821580613301575080155b61331d5760405162461bcd60e51b815260040161037790614c27565b613368856370a0823187604051602401613337919061469e565b6040516020818303038152906040529060e01b6020820180516001600160e01b0383818316178352505050506137c9565b9150600082511161338b5760405162461bcd60e51b815260040161037790614b2a565b600193505050506109cf565b61339f613a9f565b815160208301516001600160a01b039091169060a09060048111156133c057fe5b6001600160a81b0316901b81179050600083604001516001600160a01b0316905060a0846060015160048111156133f357fe5b6001600160a81b0316901b811790506040518060400160405280836001600160a81b03168152602001826001600160a81b031681525092505050919050565b6134888363a9059cbb60e01b848460405160240161345192919061477f565b60408051601f198184030181529190526020810180516001600160e01b03166001600160e01b03199093169290921790915261380b565b505050565b612c6a846323b872dd60e01b8585856040516024016134519392919061475b565b6001600160a01b03831660009081526008602052604081208054825b8181101561358a5760008382815481106134e057fe5b6000918252602090912060029091020180549091508063ffffffff808216908a16141561357f5761350f613a1b565b613518836116d9565b90508060a00151606001516135675760a0810151600160609091018190528401805463ffffffff191663ffffffff8b16179055613554816121be565b90935550600195506108ab945050505050565b60405162461bcd60e51b81526004016103779061515f565b5050506001016134ca565b5060009695505050505050565b61359f6139a1565b6135a76139a1565b60008360038111156135b557fe5b14156135c25790506109cf565b63ffffffff8416600090815260056020526040902060018460038111156135e557fe5b14806135fc575060038460038111156135fa57fe5b145b1561367e578054600090819061361a906001600160a81b0316611788565b6001600160a01b038216865290925090506020840181600481111561363b57fe5b9081600481111561364857fe5b90525060008460200151600481111561365d57fe5b141561367b5760405162461bcd60e51b8152600401610377906151ad565b50505b600284600381111561368c57fe5b14806136a3575060038460038111156136a157fe5b145b1561372b57600181015460009081906136c4906001600160a81b0316611788565b6001600160a01b03821660408701529092509050606084018160048111156136e857fe5b908160048111156136f557fe5b90525060008460600151600481111561370a57fe5b14156137285760405162461bcd60e51b815260040161037790614ed9565b50505b509392505050565b60007fdf11d8782af28160de8c22de5ee4d2d07b0193134b891493d0a755db96ffa7f98260000151836020015184604001518560600151604051602001612e45959493929190614935565b60007fa13751d48af791cce601312c70216c412c1ab3d8c0e2b3c6a069506759d67f398260000151836040015184602001518560600151604051602001612e4595949392919061484e565b60606108ab83836040518060400160405280601e81526020017f416464726573733a206c6f772d6c6576656c2063616c6c206661696c6564000081525061389a565b6060613860826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b031661389a9092919063ffffffff16565b805190915015613488578080602001905181019061387e919061438e565b6134885760405162461bcd60e51b8152600401610377906151ef565b606061055e848460008560606138af85613968565b6138cb5760405162461bcd60e51b8152600401610377906150df565b60006060866001600160a01b031685876040516138e89190614636565b60006040518083038185875af1925050503d8060008114613925576040519150601f19603f3d011682016040523d82523d6000602084013e61392a565b606091505b5091509150811561393e57915061055e9050565b80511561394e5780518082602001fd5b8360405162461bcd60e51b81526004016103779190614a1e565b6000813f7fc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a47081811480159061055e575050151592915050565b604080516080810182526000808252602082018190529181018290529060608201905b905290565b60408051610100810182526000808252602082018190529181018290526060810191909152608081016139fa6139a1565b8152602001613a07613a78565b815260006020820181905260409091015290565b6040805160c081018252600080825260208201819052918101829052606081019190915260808101613a4b6139a1565b81526020016139c4613a78565b604080516060810182526000808252602082018190529181019190915290565b60408051608081018252600080825260208201819052918101829052606081019190915290565b604080518082019091526000808252602082015290565b80356109cf81615542565b60008083601f840112613ad2578182fd5b5081356001600160401b03811115613ae8578182fd5b602083019150836020606083028501011115613b0357600080fd5b9250929050565b8035600581106109cf57600080fd5b60006101408284031215613b2b578081fd5b613b3560606154c6565b9050613b418383613cee565b8152613b508360408401613c34565b6020820152613b628360c08401613c92565b604082015292915050565b60006102408284031215613b7f578081fd5b613b8960806154c6565b9050613b958383613d30565b8152610120820135613ba681615542565b6020820152613bb9836101408401613c34565b6040820152613bcc836101c08401613c92565b606082015292915050565b60006101a08284031215613be9578081fd5b613bf360806154c6565b9050613bff8383613e52565b81526080820135613c0f81615542565b6020820152613c218360a08401613c34565b6040820152613bcc836101208401613c92565b600060808284031215613c45578081fd5b613c4f60806154c6565b90508135613c5c81615565565b81526020820135613c6c81615565565b60208201526040820135613c7f81615565565b60408201526060820135613bcc81615565565b600060808284031215613ca3578081fd5b613cad60806154c6565b90508135613cba81615542565b8152613cc98360208401613eea565b6020820152613cdb8360408401613eea565b60408201526060820135613bcc81615557565b600060408284031215613cff578081fd5b613d0960406154c6565b9050613d158383613ed6565b81526020820135613d2581615542565b602082015292915050565b6000818303610120811215613d43578182fd5b613d4d60c06154c6565b91508235613d5a81615565565b82526020830135613d6a81615565565b60208301526080603f1982011215613d8157600080fd5b50613d8c60806154c6565b613d998460408501613ab6565b8152613da88460608501613b0a565b6020820152613dba8460808501613ab6565b6040820152613dcc8460a08501613b0a565b60608201526040820152613de38360c08401613ed6565b6060820152613df58360e08401613ed6565b6080820152613e08836101008401613ebf565b60a082015292915050565b600060608284031215613e24578081fd5b613e2e60606154c6565b90508135815260208201356020820152604082013560ff81168114613b6257600080fd5b600060808284031215613e63578081fd5b613e6d60806154c6565b9050613e798383613ed6565b81526020820135613e8981615542565b602082015260408201356001600160601b0381168114613ea857600080fd5b806040830152506060820135606082015292915050565b80356001600160801b03811681146109cf57600080fd5b803563ffffffff811681146109cf57600080fd5b80356001600160401b03811681146109cf57600080fd5b600060208284031215613f12578081fd5b81356108ab81615542565b600060208284031215613f2e578081fd5b81516108ab81615542565b60008060008060808587031215613f4e578283fd5b8435613f5981615542565b9350602085810135613f6a81615542565b93506040860135925060608601356001600160401b0380821115613f8c578384fd5b818801915088601f830112613f9f578384fd5b813581811115613fad578485fd5b613fbf601f8201601f191685016154c6565b91508082528984828501011115613fd4578485fd5b8084840185840137810190920192909252939692955090935050565b60008060408385031215614002578182fd5b823561400d81615542565b915061401c8460208501613eea565b90509250929050565b600080600060408486031215614039578081fd5b83356001600160401b038082111561404f578283fd5b818601915086601f830112614062578283fd5b8135614075614070826154ec565b6154c6565b80828252602080830192508086016101408c838288028a01011115614098578889fd5b8897505b858810156140c4576140ae8d83613b19565b855260019790970196938201939081019061409c565b509198508901359450505050808211156140dc578283fd5b506140e986828701613ac1565b9497909650939450505050565b6000806000806040858703121561410b578182fd5b84356001600160401b0380821115614121578384fd5b818701915087601f830112614134578384fd5b813581811115614142578485fd5b88602061024083028501011115614157578485fd5b602092830196509450908601359080821115614171578384fd5b5061417e87828801613ac1565b95989497509550505050565b60008060006040848603121561419e578081fd5b83356001600160401b03808211156141b4578283fd5b818601915086601f8301126141c7578283fd5b81356141d5614070826154ec565b80828252602080830192508086016101a08c838288028a010111156141f8578889fd5b8897505b858810156140c45761420e8d83613bd7565b85526001979097019693820193908101906141fc565b60008060208385031215614236578182fd5b82356001600160401b038082111561424c578384fd5b818501915085601f83011261425f578384fd5b81358181111561426d578485fd5b866020604083028501011115614281578485fd5b60209290920196919550909350505050565b600060208083850312156142a5578182fd5b82356001600160401b038111156142ba578283fd5b8301601f810185136142ca578283fd5b80356142d8614070826154ec565b81815283810190838501610120808502860187018a10156142f7578788fd5b8795505b848610156143235761430d8a83613d30565b84526001959095019492860192908101906142fb565b509098975050505050505050565b60008060208385031215614343578182fd5b82356001600160401b0380821115614359578384fd5b818501915085601f83011261436c578384fd5b81358181111561437a578485fd5b866020608083028501011115614281578485fd5b60006020828403121561439f578081fd5b81516108ab81615557565b600080604083850312156143bc578182fd5b82516143c781615557565b6020939093015192949293505050565b6000602082840312156143e8578081fd5b5035919050565b6000806101a08385031215614402578182fd5b61440c8484613b19565b915061401c846101408501613e13565b6000610240828403121561442e578081fd5b6108ab8383613b6d565b6000806102a0838503121561444b578182fd5b6144558484613b6d565b915061401c846102408501613e13565b6000806102008385031215614478578182fd5b6144828484613bd7565b915061401c846101a08501613e13565b6000604082840312156144a3578081fd5b6108ab8383613cee565b600061012082840312156144bf578081fd5b6108ab8383613d30565b6000606082840312156144da578081fd5b6108ab8383613e13565b6000608082840312156144f5578081fd5b50919050565b60006080828403121561450c578081fd5b6108ab8383613e52565b600060208284031215614527578081fd5b5051919050565b60006020828403121561453f578081fd5b813563ffffffff811681146108ab578182fd5b6000815180845261456a816020860160208601615516565b601f01601f19169290920160200192915050565b8051151582526020810151151560208301526040810151151560408301526060810151151560608301525050565b80516001600160a01b03908116835260208201516145c99061550b565b6020840152806040830151166040840152506145e8606082015161550b565b60608301525050565b63ffffffff169052565b6001600160601b03169052565b90151560f81b815260010190565b91151560f81b825260a01b6001600160a01b0319166001820152600d0190565b60008251614648818460208701615516565b9190910192915050565b7f19457468657265756d205369676e6564204d6573736167653a0a3332000000008152601c810191909152603c0190565b61190160f01b81526002810192909252602282015260420190565b6001600160a01b0391909116815260200190565b6001600160a01b0392831681529116602082015260400190565b6001600160a01b03858116825284166020820152604081018390526080606082018190526000906116cf90830184614552565b6001600160a01b0392909216825263ffffffff16602082015260400190565b6001600160a01b038581168252841660208201526080810161473f8461550b565b604083015261474d8361550b565b606083015295945050505050565b6001600160a01b039384168152919092166020820152604081019190915260600190565b6001600160a01b03929092168252602082015260400190565b6001600160a01b03929092168252805160ff1660208084019190915201516001600160601b0316604082015260600190565b6020808252825182820181905260009190848201906040850190845b818110156148045783511515835292840192918401916001016147e6565b50909695505050505050565b6020808252825182820181905260009190848201906040850190845b8181101561480457835163ffffffff168352928401929184019160010161482c565b8581526001600160a01b0385811660208301528416604082015260a081016148758461550b565b60608301526148838361550b565b60808301529695505050505050565b9485526001600160a01b039390931660208501526001600160401b0391821660408501521660608301521515608082015260a00190565b94855260208501939093526001600160a01b039190911660408401526060830152608082015260a00190565b93845260208401929092526040830152606082015260800190565b92835263ffffffff9190911660208301526001600160a01b0316604082015260600190565b94855263ffffffff9390931660208501526001600160a01b039190911660408401526001600160601b03166060830152608082015260a00190565b93845260ff9290921660208401526040830152606082015260800190565b9687526001600160601b039586166020880152939094166040860152606085019190915263ffffffff908116608085015290911660a08301526001600160801b031660c082015260e00190565b9485526001600160601b03938416602086015291831660408501528216606084015216608082015260a00190565b6001600160e01b031991909116815260200190565b6000602082526108ab6020830184614552565b6020808252601c908201527f4475626965783a206e6f742045524337323120636f6d706c69616e7400000000604082015260600190565b60208082526024908201527f4475626965783a2074616b657256616c7565206d7573742062652067726561746040820152630657220360e41b606082015260800190565b60208082526029908201527f4475626965783a206661696c656420746f207472616e736665722076616c7565604082015268103a37903a30b5b2b960b91b606082015260800190565b6020808252818101527f4475626965783a20756e65787065637465642063757272656e63792074797065604082015260600190565b6020808252601b908201527f4475626965783a206e6f7420455243323020636f6d706c69616e740000000000604082015260600190565b60208082526024908201527f4475626965783a206e6f7420426f6f737461626c65455243323020636f6d706c6040820152631a585b9d60e21b606082015260800190565b6020808252602b908201527f4475626965783a2074616b65206f726465722070726576656e7465642062792060408201526a0d6d2d8d840e6eed2e8c6d60ab1b606082015260800190565b6020808252601e908201527f4475626965783a206b696c6c2073776974636820616c7265616479206f6e0000604082015260600190565b6020808252601f908201527f4475626965783a20455243323020696d706c656d656e74732045524337323100604082015260600190565b6020808252601c908201527f4475626965783a206f7264657220646f6573206e6f7420657869737400000000604082015260600190565b6020808252601d908201527f4475626965783a206578706563746564207a65726f2061646472657373000000604082015260600190565b60208082526036908201527f4475626965783a206d616b6572436f6e74726163744164647265737320616e64604082015275040c6eae4e4cadcc6f2a8f2e0ca40dad2e6dac2e8c6d60531b606082015260800190565b6020808252602c908201527f4475626965783a206661696c656420746f206465706f7369742e206e6f74206560408201526b6e6f7567682066756e64733f60a01b606082015260800190565b60208082526004908201526341422d3360e01b604082015260600190565b60208082526004908201526320a1169960e11b604082015260600190565b6020808252602e908201527f4475626965783a206661696c656420746f207472616e7366657220626f6f737460408201526d32b21022a9219918103a37b5b2b760911b606082015260800190565b60208082526024908201527f4475626965783a206d616b657256616c7565206d7573742062652067726561746040820152630657220360e41b606082015260800190565b60208082526031908201527f4475626965783a20696e73756666696369656e7420746f74616c20737570706c6040820152700f240ccdee440d6d2d8d840e6eed2e8c6d607b1b606082015260800190565b60208082526004908201526341422d3560e01b604082015260600190565b6020808252601490820152734475626965783a20656d70747920696e7075747360601b604082015260600190565b60208082526022908201527f4475626965783a2074616b6572206f726465722070616972206e6f7420666f756040820152611b9960f21b606082015260800190565b6020808252601d908201527f4475626965783a20696e76616c696420696e707574206c656e67746873000000604082015260600190565b60208082526004908201526310508b4d60e21b604082015260600190565b60208082526022908201527f4475626965783a2063616e6e6f7420757064617465204552433732312076616c604082015261756560f01b606082015260800190565b6020808252601a908201527f4475626965783a20696e76616c69642074616b657256616c7565000000000000604082015260600190565b60208082526027908201527f4475626965783a206661696c656420746f207472616e7366657220455243373260408201526618903a37b5b2b760c91b606082015260800190565b60208082526026908201527f4475626965783a206661696c656420746f207472616e73666572204552433230604082015265103a37b5b2b760d11b606082015260800190565b60208082526004908201526341422d3160e01b604082015260600190565b6020808252602b908201527f4475626965783a206d616b65206f726465722070726576656e7465642062792060408201526a0d6d2d8d840e6eed2e8c6d60ab1b606082015260800190565b6020808252601d908201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e7472616374000000604082015260600190565b60208082526029908201527f4475626965783a206661696c656420746f207472616e736665722076616c7565604082015268103a379036b0b5b2b960b91b606082015260800190565b6020808252602e908201527f4475626965783a20616e636573746f72206f7264657220616c7265616479206860408201526d30b990309039bab1b1b2b9b9b7b960911b606082015260800190565b60208082526022908201527f4475626965783a206d616b6572206f726465722070616972206e6f7420666f756040820152611b9960f21b606082015260800190565b6020808252602a908201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e6040820152691bdd081cdd58d8d9595960b21b606082015260800190565b60208082526018908201527f4475626965783a20756e6578706563746564206d616b65720000000000000000604082015260600190565b6020808252601f908201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c00604082015260600190565b60208082526036908201527f4475626965783a2074616b6572436f6e74726163744164647265737320616e64604082015275040c6eae4e4cadcc6f2a8f2e0ca40dad2e6dac2e8c6d60531b606082015260800190565b6020808252818101527f4475626965783a206d73672e73656e646572206d757374206265206d616b6572604082015260600190565b60208082526012908201527104475626965783a20726174696f20697320360741b604082015260600190565b6020808252601b908201527f4475626965783a2074616b657256616c7565206f766572666c6f770000000000604082015260600190565b608081016109cf82846145ac565b60006101c08201905063ffffffff83511682526001600160601b03602084015116602083015260408301516153db60408401826145fb565b5060608301516153ee60608401826145f1565b50608083015161540160808401826145ac565b5060a083015161541561010084018261457e565b5060c08301516154296101808401826145f1565b5060e083015161543d6101a08401826145f1565b5092915050565b90815260200190565b63ffffffff91909116815260200190565b63ffffffff9390931683526001600160a01b03919091166020830152604082015260600190565b63ffffffff9490941684526001600160a01b03928316602085015291166040830152606082015260800190565b6001600160401b0391909116815260200190565b6040518181016001600160401b03811182821017156154e457600080fd5b604052919050565b60006001600160401b03821115615501578081fd5b5060209081020190565b80600581106105f457fe5b60005b83811015615531578181015183820152602001615519565b83811115612c6a5750506000910152565b6001600160a01b038116811461127057600080fd5b801515811461127057600080fd5b6001600160601b038116811461127057600080fdfea26469706673582212204d12dbe2e98ab63de164c0dc7ee5c680fec620f3d43b2896de851c5f4e38659364736f6c634300060c0033000000000000000000000000a916bc21d2429645585abede4ae00742a16dd1c6000000000000000000000000b628bc994e39ce264eca6f6ee1620909816a9f12000000000000000000000000f3d6af45c6dfec43216cc3347ea91fefba0849d1
Deployed Bytecode
0x6080604052600436106101145760003560e01c80636b2a4aba116100a0578063d51b97f311610064578063d51b97f3146102d7578063f24e7fd9146102f7578063f6adcd211461030c578063f744a5c71461032c578063ffc1d8181461033f57610114565b80636b2a4aba1461022a5780637cc650801461024a578063a0a7d09c1461025d578063a4d91c9a1461028a578063cccedc83146102b757610114565b80632d0335ab116100e75780632d0335ab146101a2578063348e9d63146101cf57806344f648df146101e45780636593a384146101f757806369097d7a1461021757610114565b8063084487041461011957806309bcad3e14610142578063150b7a021461016257806327762f091461018f575b600080fd5b61012c610127366004614025565b610352565b604051610139919061544d565b60405180910390f35b610155610150366004614331565b61041a565b60405161013991906147ca565b34801561016e57600080fd5b5061018261017d366004613f39565b610555565b6040516101399190614a09565b61012c61019d366004614438565b610566565b3480156101ae57600080fd5b506101c26101bd366004613f01565b6105d1565b60405161013991906154b2565b6101e26101dd3660046143ef565b6105f9565b005b61012c6101f23660046144ad565b61063e565b34801561020357600080fd5b5061012c6102123660046143d7565b6106b5565b6101e26102253660046144e4565b6106cd565b34801561023657600080fd5b506101e2610245366004614492565b61074d565b6101e26102583660046140f6565b610793565b34801561026957600080fd5b5061027d6102783660046143d7565b610885565b6040516101399190615395565b34801561029657600080fd5b506102aa6102a5366004613ff0565b6108b2565b60405161013991906153a3565b3480156102c357600080fd5b506101556102d2366004614224565b6109d5565b3480156102e357600080fd5b5061027d6102f236600461452e565b610aeb565b34801561030357600080fd5b506101e2610bb6565b61031f61031a366004614293565b610d51565b6040516101399190614810565b6101e261033a36600461418a565b610e7e565b6101e261034d366004614465565b610f6c565b6000600260005414156103805760405162461bcd60e51b815260040161037790615270565b60405180910390fd5b60026000558351158015906103955750835182145b6103b15760405162461bcd60e51b815260040161037790614f1b565b60045460ff1660005b855181101561040c576104048682815181106103d257fe5b60200260200101518686848181106103e657fe5b9050606002018036038101906103fc91906144c9565b600085610fd1565b6001016103ba565b505060016000559392505050565b60606002600054141561043f5760405162461bcd60e51b815260040161037790615270565b600260005560045460ff16156104675760405162461bcd60e51b815260040161037790614ba5565b816104845760405162461bcd60e51b815260040161037790614eab565b6060826001600160401b038111801561049c57600080fd5b506040519080825280602002602001820160405280156104c6578160200160208202803683370190505b5090503460005b8481101561053e57600061050f338888858181106104e757fe5b9050608002018036038101906104fd91906144fb565b856001600160601b031660008061103e565b5080945081925050508084838151811061052557fe5b91151560209283029190910190910152506001016104cd565b5061054881611228565b5060016000559392505050565b630a85bd0160e11b5b949350505050565b60006002600054141561058b5760405162461bcd60e51b815260040161037790615270565b600260005560045460ff16156105b35760405162461bcd60e51b815260040161037790615094565b6000346105c38585836001611273565b909250905061054881611228565b6001600160a01b0381166000908152600160205260409020546001600160401b03165b919050565b6002600054141561061c5760405162461bcd60e51b815260040161037790615270565b600260005560045460ff166106348383600184610fd1565b5050600160005550565b6000600260005414156106635760405162461bcd60e51b815260040161037790615270565b600260005560045460ff161561068b5760405162461bcd60e51b815260040161037790615094565b34600061069c843384846001611324565b925090506106a982611228565b60016000559392505050565b60009081526006602052604090205463ffffffff1690565b600260005414156106f05760405162461bcd60e51b815260040161037790615270565b600260005560045460ff16156107185760405162461bcd60e51b815260040161037790614ba5565b346107363361072c368590038501856144fb565b836001600061103e565b509150610744905081611228565b50506001600055565b600260005414156107705760405162461bcd60e51b815260040161037790615270565b60026000908155602082015182516004546107449390819060019060ff166115e9565b600260005414156107b65760405162461bcd60e51b815260040161037790615270565b600260005560045460ff16156107de5760405162461bcd60e51b815260040161037790615094565b82158015906107ec57508281145b6108085760405162461bcd60e51b815260040161037790614f1b565b3460005b848110156108785761086d86868381811061082357fe5b9050610240020180360381019061083a919061441c565b85858481811061084657fe5b90506060020180360381019061085c91906144c9565b846001600160601b03166000611273565b92505060010161080c565b5050600160005550505050565b61088d6139a1565b60008281526006602052604090205463ffffffff166108ab81610aeb565b9392505050565b6108ba6139c9565b6001600160a01b0383166000908152600860205260408120905b81548110156109c25760008282815481106108eb57fe5b90600052602060002090600202019050610903613a1b565b815461090e906116d9565b805190915063ffffffff166001600160401b03871614156109b8576109316139c9565b815163ffffffff90811682526020808401516001600160601b03908116918401919091526040808501519091169083015260608084018051909216908301525161097a90610aeb565b608082015260a0918201519181019190915260019091015463ffffffff80821660c08401526401000000009091041660e082015292506109cf915050565b50506001016108d4565b506109cb6139c9565b9150505b92915050565b6060600260005414156109fa5760405162461bcd60e51b815260040161037790615270565b600260005581610a1c5760405162461bcd60e51b815260040161037790614eab565b6060826001600160401b0381118015610a3457600080fd5b50604051908082528060200260200182016040528015610a5e578160200160208202803683370190505b5060045490915060ff1660005b8481101561040c57610ac7868683818110610a8257fe5b9050604002016020016020810190610a9a9190613f01565b878784818110610aa657fe5b610abc926020604090920201908101915061452e565b6000806000876115e9565b838281518110610ad357fe5b91151560209283029190910190910152600101610a6b565b610af36139a1565b610afb6139a1565b63ffffffff8316600090815260056020526040812080549091908190610b29906001600160a81b0316611788565b600185015491935091506000908190610b4a906001600160a81b0316611788565b6001600160a01b0386168852909250905060208601836004811115610b6b57fe5b90816004811115610b7857fe5b9052506001600160a01b038216604087015260608601816004811115610b9a57fe5b90816004811115610ba757fe5b90525094979650505050505050565b60045460ff1615610bd95760405162461bcd60e51b815260040161037790614bf0565b60006b033b2e3c9fd0803ce8000000905060007f000000000000000000000000b628bc994e39ce264eca6f6ee1620909816a9f126001600160a01b03166318160ddd6040518163ffffffff1660e01b815260040160206040518083038186803b158015610c4557600080fd5b505afa158015610c59573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610c7d9190614516565b905060007f000000000000000000000000f3d6af45c6dfec43216cc3347ea91fefba0849d16001600160a01b03166318160ddd6040518163ffffffff1660e01b815260040160206040518083038186803b158015610cda57600080fd5b505afa158015610cee573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610d129190614516565b90508282101580610d235750828110155b610d3f5760405162461bcd60e51b815260040161037790614e3c565b50506004805460ff1916600117905550565b606060026000541415610d765760405162461bcd60e51b815260040161037790615270565b600260005560045460ff1615610d9e5760405162461bcd60e51b815260040161037790615094565b6000825111610dbf5760405162461bcd60e51b815260040161037790614eab565b606082516001600160401b0381118015610dd857600080fd5b50604051908082528060200260200182016040528015610e02578160200160208202803683370190505b5090503460005b8451811015610e68576000610e35868381518110610e2357fe5b60200260200101513385600080611324565b809450819250505080848381518110610e4a57fe5b63ffffffff9092166020928302919091019091015250600101610e09565b50610e7281611228565b50600160005592915050565b60026000541415610ea15760405162461bcd60e51b815260040161037790615270565b600260005560045460ff1615610ec95760405162461bcd60e51b815260040161037790614ba5565b60008351118015610eda5750825181145b610ef65760405162461bcd60e51b815260040161037790614f1b565b3460005b8451811015610f5757610f4d858281518110610f1257fe5b6020026020010151858584818110610f2657fe5b905060600201803603810190610f3c91906144c9565b846001600160601b031660006117ac565b9150600101610efa565b50610f6181611228565b505060016000555050565b60026000541415610f8f5760405162461bcd60e51b815260040161037790615270565b600260005560045460ff1615610fb75760405162461bcd60e51b815260040161037790614ba5565b6000610fc683833460016117ac565b905061063481611228565b6000610fe98560000151602001518660200151611855565b905061100c8560000151602001516110018733611a2d565b876040015187611aca565b845160208101519051600160601b600160c01b03606084901b16916110359183600188886115e9565b50505050505050565b60008060008061104c613a1b565b60006110588a89611d5e565b8151929550909350915063ffffffff1661108757506000945050506001600160601b038616915082905061121d565b60008061109d848d604001518e60600151611e47565b91509150816001600160601b0316600014806110c057506001600160601b038116155b156111015789156110e35760405162461bcd60e51b815260040161037790614fb2565b5060009650506001600160601b038916945085935061121d92505050565b6111178d8d602001518387608001518f8e611fba565b9a5061112b8d83866080015160008061200c565b61116257891561114d5760405162461bcd60e51b815260040161037790614aac565b60008b6000975097509750505050505061121d565b818460200151036001600160601b0316600014156111b5578360a0015160600151156111a25760208c015160018601546111a2919063ffffffff1661203b565b6111b08c60200151846120dc565b6111e6565b6020840180516001600160601b0390849003811690915260408501805183900390911690526111e3846121be565b85555b6001600160601b0380831660208087019190915290821660408601528c0151611211908e868e6122aa565b97509750975050505050505b955095509592505050565b6001600160601b03163481111561123b57fe5b801561127057604051339082156108fc029083906000818181858888f1935050505015801561126e573d6000803e3d6000fd5b505b50565b600080600061128a87602001518860400151611855565b905060048751604001516020015160048111156112a357fe5b14156112cb576112c687602001516112bb8933612345565b896060015189611aca565b6112e8565b6112e887602001516112dd8933612345565b8960600151896123cd565b86516020880151600091600160601b600160c01b03606085901b1688179161131491908360018a611324565b909a909950975050505050505050565b6000806001600160a01b038616301480159061134857506001600160a01b03861615155b6113645760405162461bcd60e51b815260040161037790615239565b606087015163ffffffff161561139a576113888688606001518960a0015186612463565b9150506001600160601b0384166115df565b86516001600160601b03166113c15760405162461bcd60e51b815260040161037790614df8565b600087602001516001600160601b0316116113ee5760405162461bcd60e51b815260040161037790614a68565b60006113fd88604001516125c4565b9050600061142d88308b600001516001600160601b03168c60400151600001518d60400151602001518c8c612721565b975090508061144e5760405162461bcd60e51b815260040161037790614d22565b611456613a58565b61145e613a1b565b6114678a612bc0565b63ffffffff90811682528b516001600160601b039081166020808501919091528d01511660408301528416606082015260048b604001516020015160048111156114ad57fe5b60a08301519114905260048b604001516060015160048111156114cc57fe5b60a083015191146020909101526114e58b8b8385612c27565b6114ee816121be565b82526001600160a01b038a16600090815260086020908152604080832080546001808201835591855293839020865160029095020193845582860151930180548287015163ffffffff1990911663ffffffff9586161767ffffffff0000000019166401000000009590911694909402939093179092558c51908d0151835192516001600160601b0390921660609190911b600160601b600160c01b03161760c087901b63ffffffff60c01b1617917fdb2323af401323ef38d7230b256657107a493035b145c1e3eff57c8250decf5e916115cc91908e90859061545e565b60405180910390a1505194508793505050505b9550959350505050565b6000831580156115f7575081155b15611624576001600160a01b03871633146116245760405162461bcd60e51b8152600401610377906152fd565b8215801561163957506116378787612c70565b155b15611646575060006116cf565b61164e613a1b565b600061165c89896001612cec565b92509250506116768983602001518460800151898b61200c565b611685576000925050506116cf565b61168f89826120dc565b7f02091bc96053a040f6eed60a7761afa426d85bafdb7373f8cdd5b300aeb9f33589896040516116c09291906146ff565b60405180910390a16001925050505b9695505050505050565b6116e1613a1b565b6116e9613a1b565b63ffffffff831681526001600160601b03602084811c821690830152608084901c166040820152630fffffff60e084901c818116606084015260fc9161172d613a78565b5060a0840151600187851c81168114825280850188901c8116811460208301526002850188901c8116811460408301526003850188901c8116146060820152600490930192610100841461177d57fe5b509295945050505050565b600080828160ff60a083901c1660048111156117a057fe5b91935090915050915091565b6000806117c186602001518760400151611855565b60208701518751919250600160601b600160c01b03606084901b168617916000916117ef918488600161103e565b90975091506004905081600481111561180457fe5b141561182c57611827886020015161181c8a33612db5565b8a606001518a611aca565b611849565b611849886020015161183e8a33612db5565b8a606001518a6123cd565b50939695505050505050565b60208101516000906001600160601b03161561191157604080518082018252600081526020848101516001600160601b03169082015290516310b4a23d60e01b81526001600160a01b037f000000000000000000000000b628bc994e39ce264eca6f6ee1620909816a9f1216916310b4a23d916118d6918791600401614798565b600060405180830381600087803b1580156118f057600080fd5b505af1158015611904573d6000803e3d6000fd5b50505050600090506109cf565b60408201516001600160601b03161561198e5760408051808201825260018152838201516001600160601b0316602082015290516310b4a23d60e01b81526001600160a01b037f000000000000000000000000b628bc994e39ce264eca6f6ee1620909816a9f1216916310b4a23d916118d6918791600401614798565b81516001600160601b031615611a06576040805180820182526002815283516001600160601b0316602082015290516310b4a23d60e01b81526001600160a01b037f000000000000000000000000f3d6af45c6dfec43216cc3347ea91fefba0849d116916310b4a23d916118d6918791600401614798565b60608201516001600160601b031615611a24575060608101516109cf565b50600092915050565b60006108ab7f569bda5ba3ecc0fc23a736e68d27e7c5b75bed889794899a1981793ce1dbeac77f1799a833db8e3753554dfe065e827050155c5b688581007f1ebde805a9ce822b611a818660000151612e09565b611a8e8760200151612e62565b611a9c886040015188612ead565b604051602001611aaf94939291906148f5565b60405160208183030381529060405280519060200120612f12565b81516001600160a01b03163314611af35760405162461bcd60e51b815260040161037790614d8c565b6000807f000000000000000000000000a916bc21d2429645585abede4ae00742a16dd1c66001600160a01b0316630296287733886040518363ffffffff1660e01b8152600401611b449291906146b2565b604080518083038186803b158015611b5b57600080fd5b505afa158015611b6f573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611b9391906143aa565b9150915081611bb45760405162461bcd60e51b815260040161037790614d6e565b6020840151429082906001600160401b03610e10840181169181169182111591600191851610611bfd57826001600160401b0316886020015185036001600160401b0316111590505b818015611c075750805b611c235760405162461bcd60e51b815260040161037790614f52565b876060015115611c3957611c3689612f27565b98505b600060018a89604001518a600001518b6020015160405160008152602001604052604051611c6a9493929190614970565b6020604051602081039080840390855afa158015611c8c573d6000803e3d6000fd5b5050506020604051035190508860600151158015611cbc57508a6001600160a01b0316816001600160a01b031614155b15611d20576001611ccc8b612f27565b6040808b01518b516020808e015184516000815290910193849052611cf19493614970565b6020604051602081039080840390855afa158015611d13573d6000803e3d6000fd5b5050506020604051035190505b806001600160a01b03168b6001600160a01b031614611d515760405162461bcd60e51b815260040161037790614e8d565b5050505050505050505050565b6000611d68613a1b565b600080611d73613a1b565b6000611d89886020015189600001516003612f3a565b60408b0151825193965091945092506001600160601b031615159060009063ffffffff1615801590611dc157508360a0015160400151155b90508815611e085781611de65760405162461bcd60e51b815260040161037790614a68565b80611e035760405162461bcd60e51b815260040161037790614c5e565b611e35565b811580611e13575080155b15611e3557611e20613a1b565b60029850965060009550611e40945050505050565b509295509093509150505b9250925092565b602083015160009081906001600160601b0390811690851660048760800151602001516004811115611e7557fe5b1480611e94575060048760800151606001516004811115611e9257fe5b145b15611ec95786604001516001600160601b0316866001600160601b031614611ec457600080935093505050611fb2565b611f60565b60008288604001516001600160601b0316670de0b6b3a76400000281611eeb57fe5b04905080861015611f055760008094509450505050611fb2565b87604001516001600160601b0316821115611f2b5787604001516001600160601b031691505b6040880151928202670de0b6b3a764000002926001600160601b03168381611f4f57fe5b670de0b6b3a7640000919004049250505b600160601b82108015611f80575086602001516001600160601b03168211155b611f8657fe5b600160601b81108015611fa6575086604001516001600160601b03168111155b611fac57fe5b90925090505b935093915050565b6000806000611fdf8989896001600160601b031689604001518a606001518a8a612721565b91509150816120005760405162461bcd60e51b815260040161037790615116565b98975050505050505050565b60008061202f3088886001600160601b031688600001518960200151888a612721565b50979650505050505050565b6001600160a01b0382166000908152600860205260408120805490915b818110156120d557600083828154811061206e57fe5b6000918252602090912060029091020180549091508063ffffffff80821690881614156120ca5761209d613a1b565b6120a6836116d9565b60a0810151600060409091015290506120be816121be565b909355506120d5915050565b505050600101612058565b5050505050565b6001600160a01b03821660009081526008602052604090208054600019810183146121825781600182038154811061211057fe5b906000526020600020906002020182848154811061212a57fe5b6000918252602090912082546002909202019081556001918201805492909101805463ffffffff191663ffffffff9384161780825591546401000000009081900490931690920267ffffffff00000000199091161790555b8180548061218c57fe5b600082815260208120600260001990930192830201908155600101805467ffffffffffffffff19169055905550505050565b80516020808301516040840151606085015160009463ffffffff81169484901b6fffffffffffffffffffffffff000000001694909417608083901b6bffffffffffffffffffffffff60801b161760e082901b630fffffff60e01b16179360fc9390929091630fffffff61222f613a78565b5060a0890151805115612246576001871b97909717965b80602001511561225d57866001016001901b881797505b80604001511561227457866002016001901b881797505b80606001511561228b57866003016001901b881797505b600487019650866101001461229c57fe5b509598975050505050505050565b60008060008085602001516001600160601b031681179050606086604001516001600160601b0316901b8117905060c0866060015163ffffffff16901b811790507f37f5657599c9ee85981aa75d21e5deb98dc1a88f0b2cd5faa9a3174e41fe7c4f86600001518989846040516123249493929190615485565b60405180910390a15050505060809190910151606001516001949193509150565b60006108ab7f569bda5ba3ecc0fc23a736e68d27e7c5b75bed889794899a1981793ce1dbeac77fc11e4b33114da8b5eeb04bd5ee0a3fb507510391ed105f2af9fa87089d9d180f6123998660000151612fcc565b86602001516123ab8860400151612e62565b6123b9896060015189612ead565b604051602001611aaf9594939291906148c9565b6001600160a01b0384166000908152600160205260409081902054908301516001600160401b039182169160001990910116811461241d5760405162461bcd60e51b815260040161037790615076565b6001600160a01b0385166000908152600160208190526040909120805467ffffffffffffffff19169183016001600160401b03169190911790556120d585858585611aca565b60008061246e613a1b565b61247a87876000612f3a565b508051919350915063ffffffff166124b55783156124aa5760405162461bcd60e51b815260040161037790614c5e565b60009250505061055e565b6000856001600160801b0316116124de5760405162461bcd60e51b815260040161037790615332565b60a0810151511580156124f757508060a0015160200151155b6125135760405162461bcd60e51b815260040161037790614f70565b6000670de0b6b3a7640000866001600160801b031683602001516001600160601b0316028161253e57fe5b049050600160601b81106125645760405162461bcd60e51b81526004016103779061535e565b6001600160601b038116604083015261257c826121be565b83556040517fe2e1e85213ffa6d43a863e28337fea547c34f304d08298c76a4150fe19a79598906125b0908a908a906146ff565b60405180910390a150949695505050505050565b60008082600001518360400151846020015185606001516040516020016125ee949392919061471e565b60408051601f1981840301815291815281516020928301206000818152600690935291205490915063ffffffff16806108ab576126338460200151856000015161302b565b61264f5760405162461bcd60e51b815260040161037790614ccc565b6126618460600151856040015161302b565b61267d5760405162461bcd60e51b8152600401610377906152a7565b506004805463ffffffff610100808304821660010191821690810264ffffffff0019909316929092179092556000838152600660205260409020805463ffffffff19169091179055806126cf85613397565b63ffffffff83166000908152600560209081526040909120825181546001600160a81b03199081166001600160a81b039283161783559390920151600190910180549093169116179055509392505050565b6000806001600160601b038416600186600481111561273c57fe5b14156127bc576001600160a01b038a163014612769578781101561276557600092509050612bb4565b8790035b6001600160a01b03891630146127b1576040516001600160a01b038a169089156108fc02908a906000818181858888f193505050501580156127af573d6000803e3d6000fd5b505b600192509050612bb4565b60028660048111156127ca57fe5b1415612944576040516370a0823160e01b815287906000906001600160a01b038316906370a0823190612801908e9060040161469e565b60206040518083038186803b15801561281957600080fd5b505afa15801561282d573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906128519190614516565b90506001600160a01b038c1630141561287d576128786001600160a01b0383168c8c613432565b612892565b6128926001600160a01b0383168d8d8d61348d565b6040516370a0823160e01b81526000906001600160a01b038416906370a08231906128c1908f9060040161469e565b60206040518083038186803b1580156128d957600080fd5b505afa1580156128ed573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906129119190614516565b90508a820181146129345760405162461bcd60e51b815260040161037790615030565b6001849550955050505050612bb4565b600386600481111561295257fe5b1415612a5457866001600160a01b038b163014156129835761297e6001600160a01b0382168b8b613432565b6127af565b6000816001600160a01b03166309ee40a08d8d8d8a6040516020016129a89190614608565b6040516020818303038152906040526040518563ffffffff1660e01b81526004016129d694939291906146cc565b602060405180830381600087803b1580156129f057600080fd5b505af1158015612a04573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612a28919061438e565b905080612a475760405162461bcd60e51b815260040161037790614daa565b5050600192509050612bb4565b6004866004811115612a6257fe5b1415612b9c576000879050806001600160a01b031663b88d4fde8c8c8c8960608c901c604051602001612a96929190614616565b6040516020818303038152906040526040518563ffffffff1660e01b8152600401612ac494939291906146cc565b600060405180830381600087803b158015612ade57600080fd5b505af1158015612af2573d6000803e3d6000fd5b50506040516331a9108f60e11b81526001600160a01b03808e16935084169150636352211e90612b26908d90600401615444565b60206040518083038186803b158015612b3e57600080fd5b505afa158015612b52573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612b769190613f1d565b6001600160a01b0316146127af5760405162461bcd60e51b815260040161037790614fe9565b60405162461bcd60e51b815260040161037790614af5565b97509795505050505050565b6001600160a01b03811660009081526007602052604081205463ffffffff166401000000008110612bed57fe5b6001600160a01b0383166000908152600760205260409020805463ffffffff600190930192831663ffffffff199091161790559050919050565b608084015163ffffffff1615612c6a5760808401805163ffffffff166040830152518251600091612c5a918691906134ae565b60a0840151901515604090910152505b50505050565b6001600160a01b03821660009081526008602052604081208054825b81811015612ce0576000838281548110612ca257fe5b90600052602060002090600202016000015490508563ffffffff168163ffffffff161415612cd75760019450505050506109cf565b50600101612c8c565b50600095945050505050565b6000612cf6613a1b565b6001600160a01b03851660009081526008602052604081208054825b81811015612d93576000838281548110612d2857fe5b6000918252602090912060029091020180549091508063ffffffff808216908c161415612d8857612d57613a1b565b612d60836116d9565b9050612d7081606001518c613597565b6080820152929850919650919450612dac9350505050565b505050600101612d12565b5060405162461bcd60e51b815260040161037790614c5e565b93509350939050565b60006108ab7f569bda5ba3ecc0fc23a736e68d27e7c5b75bed889794899a1981793ce1dbeac77f8d1c2f33c3caca0a1420b919fdaa6b343ae132cceddb22589ca3627a2fadf90f6123998660000151613733565b8051602080830151604051600093612e45937f8422927d64906b319ff9905ee9483f60a137efd9dc400caa8f675f48dae0b0ed93919201614910565b604051602081830303815290604052805190602001209050919050565b60007ff1f7d09b7527273cfd8370620354f0cd9a62e7bd3efaafdeca15664a7b3e045c8260000151836020015184604001518560600151604051602001612e459594939291906149db565b60007ff45b7e63030d0a046d85957a672f9a0806d76fff4cc32355d75f64eb6e83d00882846020015185604001518660600151604051602001612ef4959493929190614892565b60405160208183030381529060405280519060200120905092915050565b60008282604051602001612ef4929190614683565b600081604051602001612e459190614652565b6000612f44613a1b565b6001600160a01b03851660009081526008602052604081208054825b81811015612fb0576000838281548110612f7657fe5b6000918252602090912060029091020180549091508063ffffffff808216908c161415612fa557612d57613a1b565b505050600101612f60565b50612fb9613a1b565b6002999098506000975095505050505050565b60007f22aa64e18e438511e7911a9c6000037401f34ec1ca6db0b8ade73eaf3d72a8c582600001518360200151613006856040015161377e565b856060015186608001518760a00151604051602001612e45979695949392919061498e565b6000600183600481111561303b57fe5b1415613070576001600160a01b038216156130685760405162461bcd60e51b815260040161037790614c95565b5060016109cf565b600483600481111561307e57fe5b1415613123576040516301ffc9a760e01b81526001600160a01b038316906301ffc9a7906130b7906380ac58cd60e01b90600401614a09565b60206040518083038186803b1580156130cf57600080fd5b505afa1580156130e3573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613107919061438e565b6130685760405162461bcd60e51b815260040161037790614a31565b600383600481111561313157fe5b14156132155760405163555ddc6560e11b8152600090731820a4b7618bde71dce8cdc73aab6c95905fad249063aabbb8ca906131939086907f51d0ab336ae4fc621cb076e5c123b2236d97b9709e1ff2e304c6d727b35c6e4b9060040161477f565b60206040518083038186803b1580156131ab57600080fd5b505afa1580156131bf573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906131e39190613f1d565b90506001600160a01b03811661320b5760405162461bcd60e51b815260040161037790614b61565b60019150506109cf565b600283600481111561322357fe5b1415611a245760006060836001600160a01b03166301ffc9a76380ac58cd60e01b6040516024016132549190614a09565b6040516020818303038152906040529060e01b6020820180516001600160e01b03838183161783525050505060405161328d9190614636565b6000604051808303816000865af19150503d80600081146132ca576040519150601f19603f3d011682016040523d82523d6000602084013e6132cf565b606091505b5091509150600080825111156132f657818060200190518101906132f3919061438e565b90505b821580613301575080155b61331d5760405162461bcd60e51b815260040161037790614c27565b613368856370a0823187604051602401613337919061469e565b6040516020818303038152906040529060e01b6020820180516001600160e01b0383818316178352505050506137c9565b9150600082511161338b5760405162461bcd60e51b815260040161037790614b2a565b600193505050506109cf565b61339f613a9f565b815160208301516001600160a01b039091169060a09060048111156133c057fe5b6001600160a81b0316901b81179050600083604001516001600160a01b0316905060a0846060015160048111156133f357fe5b6001600160a81b0316901b811790506040518060400160405280836001600160a81b03168152602001826001600160a81b031681525092505050919050565b6134888363a9059cbb60e01b848460405160240161345192919061477f565b60408051601f198184030181529190526020810180516001600160e01b03166001600160e01b03199093169290921790915261380b565b505050565b612c6a846323b872dd60e01b8585856040516024016134519392919061475b565b6001600160a01b03831660009081526008602052604081208054825b8181101561358a5760008382815481106134e057fe5b6000918252602090912060029091020180549091508063ffffffff808216908a16141561357f5761350f613a1b565b613518836116d9565b90508060a00151606001516135675760a0810151600160609091018190528401805463ffffffff191663ffffffff8b16179055613554816121be565b90935550600195506108ab945050505050565b60405162461bcd60e51b81526004016103779061515f565b5050506001016134ca565b5060009695505050505050565b61359f6139a1565b6135a76139a1565b60008360038111156135b557fe5b14156135c25790506109cf565b63ffffffff8416600090815260056020526040902060018460038111156135e557fe5b14806135fc575060038460038111156135fa57fe5b145b1561367e578054600090819061361a906001600160a81b0316611788565b6001600160a01b038216865290925090506020840181600481111561363b57fe5b9081600481111561364857fe5b90525060008460200151600481111561365d57fe5b141561367b5760405162461bcd60e51b8152600401610377906151ad565b50505b600284600381111561368c57fe5b14806136a3575060038460038111156136a157fe5b145b1561372b57600181015460009081906136c4906001600160a81b0316611788565b6001600160a01b03821660408701529092509050606084018160048111156136e857fe5b908160048111156136f557fe5b90525060008460600151600481111561370a57fe5b14156137285760405162461bcd60e51b815260040161037790614ed9565b50505b509392505050565b60007fdf11d8782af28160de8c22de5ee4d2d07b0193134b891493d0a755db96ffa7f98260000151836020015184604001518560600151604051602001612e45959493929190614935565b60007fa13751d48af791cce601312c70216c412c1ab3d8c0e2b3c6a069506759d67f398260000151836040015184602001518560600151604051602001612e4595949392919061484e565b60606108ab83836040518060400160405280601e81526020017f416464726573733a206c6f772d6c6576656c2063616c6c206661696c6564000081525061389a565b6060613860826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b031661389a9092919063ffffffff16565b805190915015613488578080602001905181019061387e919061438e565b6134885760405162461bcd60e51b8152600401610377906151ef565b606061055e848460008560606138af85613968565b6138cb5760405162461bcd60e51b8152600401610377906150df565b60006060866001600160a01b031685876040516138e89190614636565b60006040518083038185875af1925050503d8060008114613925576040519150601f19603f3d011682016040523d82523d6000602084013e61392a565b606091505b5091509150811561393e57915061055e9050565b80511561394e5780518082602001fd5b8360405162461bcd60e51b81526004016103779190614a1e565b6000813f7fc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a47081811480159061055e575050151592915050565b604080516080810182526000808252602082018190529181018290529060608201905b905290565b60408051610100810182526000808252602082018190529181018290526060810191909152608081016139fa6139a1565b8152602001613a07613a78565b815260006020820181905260409091015290565b6040805160c081018252600080825260208201819052918101829052606081019190915260808101613a4b6139a1565b81526020016139c4613a78565b604080516060810182526000808252602082018190529181019190915290565b60408051608081018252600080825260208201819052918101829052606081019190915290565b604080518082019091526000808252602082015290565b80356109cf81615542565b60008083601f840112613ad2578182fd5b5081356001600160401b03811115613ae8578182fd5b602083019150836020606083028501011115613b0357600080fd5b9250929050565b8035600581106109cf57600080fd5b60006101408284031215613b2b578081fd5b613b3560606154c6565b9050613b418383613cee565b8152613b508360408401613c34565b6020820152613b628360c08401613c92565b604082015292915050565b60006102408284031215613b7f578081fd5b613b8960806154c6565b9050613b958383613d30565b8152610120820135613ba681615542565b6020820152613bb9836101408401613c34565b6040820152613bcc836101c08401613c92565b606082015292915050565b60006101a08284031215613be9578081fd5b613bf360806154c6565b9050613bff8383613e52565b81526080820135613c0f81615542565b6020820152613c218360a08401613c34565b6040820152613bcc836101208401613c92565b600060808284031215613c45578081fd5b613c4f60806154c6565b90508135613c5c81615565565b81526020820135613c6c81615565565b60208201526040820135613c7f81615565565b60408201526060820135613bcc81615565565b600060808284031215613ca3578081fd5b613cad60806154c6565b90508135613cba81615542565b8152613cc98360208401613eea565b6020820152613cdb8360408401613eea565b60408201526060820135613bcc81615557565b600060408284031215613cff578081fd5b613d0960406154c6565b9050613d158383613ed6565b81526020820135613d2581615542565b602082015292915050565b6000818303610120811215613d43578182fd5b613d4d60c06154c6565b91508235613d5a81615565565b82526020830135613d6a81615565565b60208301526080603f1982011215613d8157600080fd5b50613d8c60806154c6565b613d998460408501613ab6565b8152613da88460608501613b0a565b6020820152613dba8460808501613ab6565b6040820152613dcc8460a08501613b0a565b60608201526040820152613de38360c08401613ed6565b6060820152613df58360e08401613ed6565b6080820152613e08836101008401613ebf565b60a082015292915050565b600060608284031215613e24578081fd5b613e2e60606154c6565b90508135815260208201356020820152604082013560ff81168114613b6257600080fd5b600060808284031215613e63578081fd5b613e6d60806154c6565b9050613e798383613ed6565b81526020820135613e8981615542565b602082015260408201356001600160601b0381168114613ea857600080fd5b806040830152506060820135606082015292915050565b80356001600160801b03811681146109cf57600080fd5b803563ffffffff811681146109cf57600080fd5b80356001600160401b03811681146109cf57600080fd5b600060208284031215613f12578081fd5b81356108ab81615542565b600060208284031215613f2e578081fd5b81516108ab81615542565b60008060008060808587031215613f4e578283fd5b8435613f5981615542565b9350602085810135613f6a81615542565b93506040860135925060608601356001600160401b0380821115613f8c578384fd5b818801915088601f830112613f9f578384fd5b813581811115613fad578485fd5b613fbf601f8201601f191685016154c6565b91508082528984828501011115613fd4578485fd5b8084840185840137810190920192909252939692955090935050565b60008060408385031215614002578182fd5b823561400d81615542565b915061401c8460208501613eea565b90509250929050565b600080600060408486031215614039578081fd5b83356001600160401b038082111561404f578283fd5b818601915086601f830112614062578283fd5b8135614075614070826154ec565b6154c6565b80828252602080830192508086016101408c838288028a01011115614098578889fd5b8897505b858810156140c4576140ae8d83613b19565b855260019790970196938201939081019061409c565b509198508901359450505050808211156140dc578283fd5b506140e986828701613ac1565b9497909650939450505050565b6000806000806040858703121561410b578182fd5b84356001600160401b0380821115614121578384fd5b818701915087601f830112614134578384fd5b813581811115614142578485fd5b88602061024083028501011115614157578485fd5b602092830196509450908601359080821115614171578384fd5b5061417e87828801613ac1565b95989497509550505050565b60008060006040848603121561419e578081fd5b83356001600160401b03808211156141b4578283fd5b818601915086601f8301126141c7578283fd5b81356141d5614070826154ec565b80828252602080830192508086016101a08c838288028a010111156141f8578889fd5b8897505b858810156140c45761420e8d83613bd7565b85526001979097019693820193908101906141fc565b60008060208385031215614236578182fd5b82356001600160401b038082111561424c578384fd5b818501915085601f83011261425f578384fd5b81358181111561426d578485fd5b866020604083028501011115614281578485fd5b60209290920196919550909350505050565b600060208083850312156142a5578182fd5b82356001600160401b038111156142ba578283fd5b8301601f810185136142ca578283fd5b80356142d8614070826154ec565b81815283810190838501610120808502860187018a10156142f7578788fd5b8795505b848610156143235761430d8a83613d30565b84526001959095019492860192908101906142fb565b509098975050505050505050565b60008060208385031215614343578182fd5b82356001600160401b0380821115614359578384fd5b818501915085601f83011261436c578384fd5b81358181111561437a578485fd5b866020608083028501011115614281578485fd5b60006020828403121561439f578081fd5b81516108ab81615557565b600080604083850312156143bc578182fd5b82516143c781615557565b6020939093015192949293505050565b6000602082840312156143e8578081fd5b5035919050565b6000806101a08385031215614402578182fd5b61440c8484613b19565b915061401c846101408501613e13565b6000610240828403121561442e578081fd5b6108ab8383613b6d565b6000806102a0838503121561444b578182fd5b6144558484613b6d565b915061401c846102408501613e13565b6000806102008385031215614478578182fd5b6144828484613bd7565b915061401c846101a08501613e13565b6000604082840312156144a3578081fd5b6108ab8383613cee565b600061012082840312156144bf578081fd5b6108ab8383613d30565b6000606082840312156144da578081fd5b6108ab8383613e13565b6000608082840312156144f5578081fd5b50919050565b60006080828403121561450c578081fd5b6108ab8383613e52565b600060208284031215614527578081fd5b5051919050565b60006020828403121561453f578081fd5b813563ffffffff811681146108ab578182fd5b6000815180845261456a816020860160208601615516565b601f01601f19169290920160200192915050565b8051151582526020810151151560208301526040810151151560408301526060810151151560608301525050565b80516001600160a01b03908116835260208201516145c99061550b565b6020840152806040830151166040840152506145e8606082015161550b565b60608301525050565b63ffffffff169052565b6001600160601b03169052565b90151560f81b815260010190565b91151560f81b825260a01b6001600160a01b0319166001820152600d0190565b60008251614648818460208701615516565b9190910192915050565b7f19457468657265756d205369676e6564204d6573736167653a0a3332000000008152601c810191909152603c0190565b61190160f01b81526002810192909252602282015260420190565b6001600160a01b0391909116815260200190565b6001600160a01b0392831681529116602082015260400190565b6001600160a01b03858116825284166020820152604081018390526080606082018190526000906116cf90830184614552565b6001600160a01b0392909216825263ffffffff16602082015260400190565b6001600160a01b038581168252841660208201526080810161473f8461550b565b604083015261474d8361550b565b606083015295945050505050565b6001600160a01b039384168152919092166020820152604081019190915260600190565b6001600160a01b03929092168252602082015260400190565b6001600160a01b03929092168252805160ff1660208084019190915201516001600160601b0316604082015260600190565b6020808252825182820181905260009190848201906040850190845b818110156148045783511515835292840192918401916001016147e6565b50909695505050505050565b6020808252825182820181905260009190848201906040850190845b8181101561480457835163ffffffff168352928401929184019160010161482c565b8581526001600160a01b0385811660208301528416604082015260a081016148758461550b565b60608301526148838361550b565b60808301529695505050505050565b9485526001600160a01b039390931660208501526001600160401b0391821660408501521660608301521515608082015260a00190565b94855260208501939093526001600160a01b039190911660408401526060830152608082015260a00190565b93845260208401929092526040830152606082015260800190565b92835263ffffffff9190911660208301526001600160a01b0316604082015260600190565b94855263ffffffff9390931660208501526001600160a01b039190911660408401526001600160601b03166060830152608082015260a00190565b93845260ff9290921660208401526040830152606082015260800190565b9687526001600160601b039586166020880152939094166040860152606085019190915263ffffffff908116608085015290911660a08301526001600160801b031660c082015260e00190565b9485526001600160601b03938416602086015291831660408501528216606084015216608082015260a00190565b6001600160e01b031991909116815260200190565b6000602082526108ab6020830184614552565b6020808252601c908201527f4475626965783a206e6f742045524337323120636f6d706c69616e7400000000604082015260600190565b60208082526024908201527f4475626965783a2074616b657256616c7565206d7573742062652067726561746040820152630657220360e41b606082015260800190565b60208082526029908201527f4475626965783a206661696c656420746f207472616e736665722076616c7565604082015268103a37903a30b5b2b960b91b606082015260800190565b6020808252818101527f4475626965783a20756e65787065637465642063757272656e63792074797065604082015260600190565b6020808252601b908201527f4475626965783a206e6f7420455243323020636f6d706c69616e740000000000604082015260600190565b60208082526024908201527f4475626965783a206e6f7420426f6f737461626c65455243323020636f6d706c6040820152631a585b9d60e21b606082015260800190565b6020808252602b908201527f4475626965783a2074616b65206f726465722070726576656e7465642062792060408201526a0d6d2d8d840e6eed2e8c6d60ab1b606082015260800190565b6020808252601e908201527f4475626965783a206b696c6c2073776974636820616c7265616479206f6e0000604082015260600190565b6020808252601f908201527f4475626965783a20455243323020696d706c656d656e74732045524337323100604082015260600190565b6020808252601c908201527f4475626965783a206f7264657220646f6573206e6f7420657869737400000000604082015260600190565b6020808252601d908201527f4475626965783a206578706563746564207a65726f2061646472657373000000604082015260600190565b60208082526036908201527f4475626965783a206d616b6572436f6e74726163744164647265737320616e64604082015275040c6eae4e4cadcc6f2a8f2e0ca40dad2e6dac2e8c6d60531b606082015260800190565b6020808252602c908201527f4475626965783a206661696c656420746f206465706f7369742e206e6f74206560408201526b6e6f7567682066756e64733f60a01b606082015260800190565b60208082526004908201526341422d3360e01b604082015260600190565b60208082526004908201526320a1169960e11b604082015260600190565b6020808252602e908201527f4475626965783a206661696c656420746f207472616e7366657220626f6f737460408201526d32b21022a9219918103a37b5b2b760911b606082015260800190565b60208082526024908201527f4475626965783a206d616b657256616c7565206d7573742062652067726561746040820152630657220360e41b606082015260800190565b60208082526031908201527f4475626965783a20696e73756666696369656e7420746f74616c20737570706c6040820152700f240ccdee440d6d2d8d840e6eed2e8c6d607b1b606082015260800190565b60208082526004908201526341422d3560e01b604082015260600190565b6020808252601490820152734475626965783a20656d70747920696e7075747360601b604082015260600190565b60208082526022908201527f4475626965783a2074616b6572206f726465722070616972206e6f7420666f756040820152611b9960f21b606082015260800190565b6020808252601d908201527f4475626965783a20696e76616c696420696e707574206c656e67746873000000604082015260600190565b60208082526004908201526310508b4d60e21b604082015260600190565b60208082526022908201527f4475626965783a2063616e6e6f7420757064617465204552433732312076616c604082015261756560f01b606082015260800190565b6020808252601a908201527f4475626965783a20696e76616c69642074616b657256616c7565000000000000604082015260600190565b60208082526027908201527f4475626965783a206661696c656420746f207472616e7366657220455243373260408201526618903a37b5b2b760c91b606082015260800190565b60208082526026908201527f4475626965783a206661696c656420746f207472616e73666572204552433230604082015265103a37b5b2b760d11b606082015260800190565b60208082526004908201526341422d3160e01b604082015260600190565b6020808252602b908201527f4475626965783a206d616b65206f726465722070726576656e7465642062792060408201526a0d6d2d8d840e6eed2e8c6d60ab1b606082015260800190565b6020808252601d908201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e7472616374000000604082015260600190565b60208082526029908201527f4475626965783a206661696c656420746f207472616e736665722076616c7565604082015268103a379036b0b5b2b960b91b606082015260800190565b6020808252602e908201527f4475626965783a20616e636573746f72206f7264657220616c7265616479206860408201526d30b990309039bab1b1b2b9b9b7b960911b606082015260800190565b60208082526022908201527f4475626965783a206d616b6572206f726465722070616972206e6f7420666f756040820152611b9960f21b606082015260800190565b6020808252602a908201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e6040820152691bdd081cdd58d8d9595960b21b606082015260800190565b60208082526018908201527f4475626965783a20756e6578706563746564206d616b65720000000000000000604082015260600190565b6020808252601f908201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c00604082015260600190565b60208082526036908201527f4475626965783a2074616b6572436f6e74726163744164647265737320616e64604082015275040c6eae4e4cadcc6f2a8f2e0ca40dad2e6dac2e8c6d60531b606082015260800190565b6020808252818101527f4475626965783a206d73672e73656e646572206d757374206265206d616b6572604082015260600190565b60208082526012908201527104475626965783a20726174696f20697320360741b604082015260600190565b6020808252601b908201527f4475626965783a2074616b657256616c7565206f766572666c6f770000000000604082015260600190565b608081016109cf82846145ac565b60006101c08201905063ffffffff83511682526001600160601b03602084015116602083015260408301516153db60408401826145fb565b5060608301516153ee60608401826145f1565b50608083015161540160808401826145ac565b5060a083015161541561010084018261457e565b5060c08301516154296101808401826145f1565b5060e083015161543d6101a08401826145f1565b5092915050565b90815260200190565b63ffffffff91909116815260200190565b63ffffffff9390931683526001600160a01b03919091166020830152604082015260600190565b63ffffffff9490941684526001600160a01b03928316602085015291166040830152606082015260800190565b6001600160401b0391909116815260200190565b6040518181016001600160401b03811182821017156154e457600080fd5b604052919050565b60006001600160401b03821115615501578081fd5b5060209081020190565b80600581106105f457fe5b60005b83811015615531578181015183820152602001615519565b83811115612c6a5750506000910152565b6001600160a01b038116811461127057600080fd5b801515811461127057600080fd5b6001600160601b038116811461127057600080fdfea26469706673582212204d12dbe2e98ab63de164c0dc7ee5c680fec620f3d43b2896de851c5f4e38659364736f6c634300060c0033
Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)
000000000000000000000000a916bc21d2429645585abede4ae00742a16dd1c6000000000000000000000000b628bc994e39ce264eca6f6ee1620909816a9f12000000000000000000000000f3d6af45c6dfec43216cc3347ea91fefba0849d1
-----Decoded View---------------
Arg [0] : optIn (address): 0xA916Bc21D2429645585aBeDe4aE00742A16DD1C6
Arg [1] : prps (address): 0xb628Bc994e39CE264ECa6f6EE1620909816A9F12
Arg [2] : dubi (address): 0xF3D6Af45C6dFeC43216CC3347Ea91fEfBa0849D1
-----Encoded View---------------
3 Constructor Arguments found :
Arg [0] : 000000000000000000000000a916bc21d2429645585abede4ae00742a16dd1c6
Arg [1] : 000000000000000000000000b628bc994e39ce264eca6f6ee1620909816a9f12
Arg [2] : 000000000000000000000000f3d6af45c6dfec43216cc3347ea91fefba0849d1
Loading...
Loading
Loading...
Loading
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.