More Info
Private Name Tags
ContractCreator
Latest 25 from a total of 52 transactions
Transaction Hash |
Method
|
Block
|
From
|
To
|
|||||
---|---|---|---|---|---|---|---|---|---|
Mint | 16662551 | 687 days ago | IN | 0.00466362 ETH | 0.00436142 | ||||
Force Emit | 16633521 | 691 days ago | IN | 0 ETH | 0.00181478 | ||||
Force Emit | 16622713 | 692 days ago | IN | 0 ETH | 0.0016718 | ||||
Mint | 16611011 | 694 days ago | IN | 0.00045787 ETH | 0.001452 | ||||
Mint | 16566316 | 700 days ago | IN | 0.00200897 ETH | 0.00191595 | ||||
Force Emit | 16555070 | 702 days ago | IN | 0 ETH | 0.00145804 | ||||
Force Emit | 16539702 | 704 days ago | IN | 0 ETH | 0.00117633 | ||||
Withdraw | 16533921 | 705 days ago | IN | 0 ETH | 0.00050041 | ||||
Mint | 16533073 | 705 days ago | IN | 0.67935476 ETH | 0.0008022 | ||||
Mint | 16531641 | 705 days ago | IN | 0.00592138 ETH | 0.00179778 | ||||
Mint | 16530154 | 705 days ago | IN | 0.01787779 ETH | 0.0011146 | ||||
Mint | 16526820 | 706 days ago | IN | 0.0049 ETH | 0.00132385 | ||||
Mint | 16526809 | 706 days ago | IN | 0.0001 ETH | 0.00189681 | ||||
Withdraw | 16522961 | 706 days ago | IN | 0 ETH | 0.00045978 | ||||
Mint | 16522704 | 706 days ago | IN | 0.06532504 ETH | 0.00164076 | ||||
Mint | 16521808 | 707 days ago | IN | 0.0069149 ETH | 0.00161236 | ||||
Mint | 16521318 | 707 days ago | IN | 0.01438629 ETH | 0.00205556 | ||||
Mint | 16520771 | 707 days ago | IN | 0.001 ETH | 0.00123975 | ||||
Withdraw | 16519120 | 707 days ago | IN | 0 ETH | 0.00042942 | ||||
Mint | 16519117 | 707 days ago | IN | 0.59574482 ETH | 0.00076437 | ||||
Withdraw | 16519112 | 707 days ago | IN | 0 ETH | 0.00046259 | ||||
Mint | 16519103 | 707 days ago | IN | 0.45543578 ETH | 0.00077981 | ||||
Mint | 16517850 | 707 days ago | IN | 0.01152915 ETH | 0.00099981 | ||||
Mint | 16516477 | 707 days ago | IN | 0.12833252 ETH | 0.00145885 | ||||
Mint | 16510782 | 708 days ago | IN | 0.01089236 ETH | 0.00106869 |
Loading...
Loading
Contract Name:
SupermassiveButterHole
Compiler Version
v0.8.17+commit.8df45f5f
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.8.17; import "@chainlink/v0.8/interfaces/VRFCoordinatorV2Interface.sol"; import "@chainlink/v0.8/VRFConsumerBaseV2.sol"; import "@openzeppelin/contracts/access/Ownable.sol"; import "@openzeppelin/contracts/proxy/utils/Initializable.sol"; import "solmate/utils/SignedWadMath.sol"; import "./extensions/LogLinearVRGDA.sol"; import "./extensions/IERC20Entity.sol"; import "./utils/MovingAverage.sol"; import "./GenesisGalaxy.sol"; import "./constants.sol"; contract SupermassiveButterHole is VRFConsumerBaseV2, Initializable, LogLinearVRGDA, Ownable { uint256 public immutable EMISSION_INTERVAL; uint256 public immutable EMISSION_SMOOTHING_INTERVAL; uint256 public immutable EMISSION_MULTIPLIER; uint256 immutable START_TIME; VRFCoordinatorV2Interface immutable COORDINATOR; bytes32 public keyHash; uint64 public subId; GenesisGalaxy public galaxy; IERC20Resource public butter; uint40 public lastEmissionTimestamp; int104 public sold; uint104 public emissionMA; uint40 public lastEmissionMAUpdateTimestamp; constructor( address vrfCoordinator, uint256 emissionInterval, uint256 emissionSmoothingInterval, uint256 emissionMultiplier ) VRFConsumerBaseV2(vrfCoordinator) LogLinearVRGDA(1e15, .5e18, 1e18) { COORDINATOR = VRFCoordinatorV2Interface(vrfCoordinator); EMISSION_INTERVAL = emissionInterval; EMISSION_SMOOTHING_INTERVAL = emissionSmoothingInterval; EMISSION_MULTIPLIER = emissionMultiplier; START_TIME = block.timestamp; } function initialize( address butter_, address galaxy_, bytes32 keyHash_, uint64 subId_ ) public initializer { butter = IERC20Resource(butter_); galaxy = GenesisGalaxy(galaxy_); keyHash = keyHash_; subId = subId_; emissionMA = 1e18 * uint104(EMISSION_MULTIPLIER); lastEmissionMAUpdateTimestamp = uint40(block.timestamp); _emit(); _transferOwnership(msg.sender); } function getPrice(uint256 amount) external view returns (uint256) { uint256 balance = butter.balanceOf(address(this)); return ((getVRGDAPrice( toDaysWadUnsafe(block.timestamp - START_TIME), sold, _compound(unsafeWadDiv(int256(amount), int256(balance))) ) * balance) / 1e18); } function getAmountForPrice(uint256 price) public view returns (uint256 amount) { int256 balance = int256(butter.balanceOf(address(this))); return uint256( wadMul(_getPercentForPrice(int256(price), balance), balance) ); } function canEmit() public view returns (bool) { return block.timestamp / EMISSION_INTERVAL > lastEmissionTimestamp / EMISSION_INTERVAL; } function _getPercentForPrice(int256 price, int256 balance) public view returns (int256 percent) { return _uncompound(_getCompoundedPercentForPrice(price, balance)); } function _getCompoundedPercentForPrice(int256 price, int256 balance) public view returns (int256 logInvPercent) { return int256( getVRGDAAmountForPrice( toDaysWadUnsafe(block.timestamp - START_TIME), sold, unsafeWadDiv(price, balance) ) ); } function _uncompound(int256 value) internal pure returns (int256) { return 1e18 - wadExp(-value); } function _compound(int256 value) internal pure returns (int256) { return -wadLn(1e18 - value); } function mint(address to) public payable { int256 balance = int256(butter.balanceOf(address(this))); int256 compPercent = _getCompoundedPercentForPrice( int256(msg.value), balance ); sold += int104(compPercent); butter.transfer(to, uint256(wadMul(_uncompound(compPercent), balance))); _updateEmissionMA(msg.value); if (canEmit()) _emit(); } function forceEmit() public { forceEmit(keyHash, subId); } function forceEmit(bytes32 keyHash_, uint64 subId_) public { require(canEmit(), "Cannot emit yet"); _updateEmissionMA(0); _emit(keyHash_, subId_); } function _updateEmissionMA(uint256 amount) internal { uint256 timeSinceLastUpdate = block.timestamp - lastEmissionMAUpdateTimestamp; lastEmissionMAUpdateTimestamp = uint40(block.timestamp); timeSinceLastUpdate = Math.max(timeSinceLastUpdate, 1); emissionMA = uint104( updateEMA( emissionMA, (amount * EMISSION_MULTIPLIER * EMISSION_INTERVAL) / timeSinceLastUpdate, (timeSinceLastUpdate * 1e18) / EMISSION_SMOOTHING_INTERVAL ) ); } function _emit() internal { _emit(keyHash, subId); } function _emit(bytes32 keyHash_, uint64 subId_) internal { lastEmissionTimestamp = uint40(block.timestamp); _requestSeed(keyHash_, subId_); } function _requestSeed(bytes32 keyHash_, uint64 subId_) internal { // Will revert if subscription is not set and funded. COORDINATOR.requestRandomWords( keyHash_, subId_, VRF_MIN_BLOCKS, VRF_GAS_LIMIT, 1 ); } function fulfillRandomWords(uint256, uint256[] memory randomWords) internal override { galaxy.addEmission(uint128(randomWords[0]), uint128(emissionMA)); } /* OWNER FUNCTIONS */ function setKeyHash(bytes32 keyHash_) external onlyOwner { keyHash = keyHash_; } function setSubId(uint64 subId_) external onlyOwner { subId = subId_; } function setGalaxy(address galaxy_) external onlyOwner { galaxy = GenesisGalaxy(galaxy_); } function setButter(address butter_) external onlyOwner { butter = IERC20Resource(butter_); } function withdraw(uint256 amount) public onlyOwner { (bool success, ) = msg.sender.call{value: amount}(""); require(success, "Transfer failed."); } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.4; /** **************************************************************************** * @notice Interface for contracts using VRF randomness * ***************************************************************************** * @dev PURPOSE * * @dev Reggie the Random Oracle (not his real job) wants to provide randomness * @dev to Vera the verifier in such a way that Vera can be sure he's not * @dev making his output up to suit himself. Reggie provides Vera a public key * @dev to which he knows the secret key. Each time Vera provides a seed to * @dev Reggie, he gives back a value which is computed completely * @dev deterministically from the seed and the secret key. * * @dev Reggie provides a proof by which Vera can verify that the output was * @dev correctly computed once Reggie tells it to her, but without that proof, * @dev the output is indistinguishable to her from a uniform random sample * @dev from the output space. * * @dev The purpose of this contract is to make it easy for unrelated contracts * @dev to talk to Vera the verifier about the work Reggie is doing, to provide * @dev simple access to a verifiable source of randomness. It ensures 2 things: * @dev 1. The fulfillment came from the VRFCoordinator * @dev 2. The consumer contract implements fulfillRandomWords. * ***************************************************************************** * @dev USAGE * * @dev Calling contracts must inherit from VRFConsumerBase, and can * @dev initialize VRFConsumerBase's attributes in their constructor as * @dev shown: * * @dev contract VRFConsumer { * @dev constructor(<other arguments>, address _vrfCoordinator, address _link) * @dev VRFConsumerBase(_vrfCoordinator) public { * @dev <initialization with other arguments goes here> * @dev } * @dev } * * @dev The oracle will have given you an ID for the VRF keypair they have * @dev committed to (let's call it keyHash). Create subscription, fund it * @dev and your consumer contract as a consumer of it (see VRFCoordinatorInterface * @dev subscription management functions). * @dev Call requestRandomWords(keyHash, subId, minimumRequestConfirmations, * @dev callbackGasLimit, numWords), * @dev see (VRFCoordinatorInterface for a description of the arguments). * * @dev Once the VRFCoordinator has received and validated the oracle's response * @dev to your request, it will call your contract's fulfillRandomWords method. * * @dev The randomness argument to fulfillRandomWords is a set of random words * @dev generated from your requestId and the blockHash of the request. * * @dev If your contract could have concurrent requests open, you can use the * @dev requestId returned from requestRandomWords to track which response is associated * @dev with which randomness request. * @dev See "SECURITY CONSIDERATIONS" for principles to keep in mind, * @dev if your contract could have multiple requests in flight simultaneously. * * @dev Colliding `requestId`s are cryptographically impossible as long as seeds * @dev differ. * * ***************************************************************************** * @dev SECURITY CONSIDERATIONS * * @dev A method with the ability to call your fulfillRandomness method directly * @dev could spoof a VRF response with any random value, so it's critical that * @dev it cannot be directly called by anything other than this base contract * @dev (specifically, by the VRFConsumerBase.rawFulfillRandomness method). * * @dev For your users to trust that your contract's random behavior is free * @dev from malicious interference, it's best if you can write it so that all * @dev behaviors implied by a VRF response are executed *during* your * @dev fulfillRandomness method. If your contract must store the response (or * @dev anything derived from it) and use it later, you must ensure that any * @dev user-significant behavior which depends on that stored value cannot be * @dev manipulated by a subsequent VRF request. * * @dev Similarly, both miners and the VRF oracle itself have some influence * @dev over the order in which VRF responses appear on the blockchain, so if * @dev your contract could have multiple VRF requests in flight simultaneously, * @dev you must ensure that the order in which the VRF responses arrive cannot * @dev be used to manipulate your contract's user-significant behavior. * * @dev Since the block hash of the block which contains the requestRandomness * @dev call is mixed into the input to the VRF *last*, a sufficiently powerful * @dev miner could, in principle, fork the blockchain to evict the block * @dev containing the request, forcing the request to be included in a * @dev different block with a different hash, and therefore a different input * @dev to the VRF. However, such an attack would incur a substantial economic * @dev cost. This cost scales with the number of blocks the VRF oracle waits * @dev until it calls responds to a request. It is for this reason that * @dev that you can signal to an oracle you'd like them to wait longer before * @dev responding to the request (however this is not enforced in the contract * @dev and so remains effective only in the case of unmodified oracle software). */ abstract contract VRFConsumerBaseV2 { error OnlyCoordinatorCanFulfill(address have, address want); address private immutable vrfCoordinator; /** * @param _vrfCoordinator address of VRFCoordinator contract */ constructor(address _vrfCoordinator) { vrfCoordinator = _vrfCoordinator; } /** * @notice fulfillRandomness handles the VRF response. Your contract must * @notice implement it. See "SECURITY CONSIDERATIONS" above for important * @notice principles to keep in mind when implementing your fulfillRandomness * @notice method. * * @dev VRFConsumerBaseV2 expects its subcontracts to have a method with this * @dev signature, and will call it once it has verified the proof * @dev associated with the randomness. (It is triggered via a call to * @dev rawFulfillRandomness, below.) * * @param requestId The Id initially returned by requestRandomness * @param randomWords the VRF output expanded to the requested number of words */ function fulfillRandomWords(uint256 requestId, uint256[] memory randomWords) internal virtual; // rawFulfillRandomness is called by VRFCoordinator when it receives a valid VRF // proof. rawFulfillRandomness then calls fulfillRandomness, after validating // the origin of the call function rawFulfillRandomWords(uint256 requestId, uint256[] memory randomWords) external { if (msg.sender != vrfCoordinator) { revert OnlyCoordinatorCanFulfill(msg.sender, vrfCoordinator); } fulfillRandomWords(requestId, randomWords); } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; interface VRFCoordinatorV2Interface { /** * @notice Get configuration relevant for making requests * @return minimumRequestConfirmations global min for request confirmations * @return maxGasLimit global max for request gas limit * @return s_provingKeyHashes list of registered key hashes */ function getRequestConfig() external view returns ( uint16, uint32, bytes32[] memory ); /** * @notice Request a set of random words. * @param keyHash - Corresponds to a particular oracle job which uses * that key for generating the VRF proof. Different keyHash's have different gas price * ceilings, so you can select a specific one to bound your maximum per request cost. * @param subId - The ID of the VRF subscription. Must be funded * with the minimum subscription balance required for the selected keyHash. * @param minimumRequestConfirmations - How many blocks you'd like the * oracle to wait before responding to the request. See SECURITY CONSIDERATIONS * for why you may want to request more. The acceptable range is * [minimumRequestBlockConfirmations, 200]. * @param callbackGasLimit - How much gas you'd like to receive in your * fulfillRandomWords callback. Note that gasleft() inside fulfillRandomWords * may be slightly less than this amount because of gas used calling the function * (argument decoding etc.), so you may need to request slightly more than you expect * to have inside fulfillRandomWords. The acceptable range is * [0, maxGasLimit] * @param numWords - The number of uint256 random values you'd like to receive * in your fulfillRandomWords callback. Note these numbers are expanded in a * secure way by the VRFCoordinator from a single random value supplied by the oracle. * @return requestId - A unique identifier of the request. Can be used to match * a request to a response in fulfillRandomWords. */ function requestRandomWords( bytes32 keyHash, uint64 subId, uint16 minimumRequestConfirmations, uint32 callbackGasLimit, uint32 numWords ) external returns (uint256 requestId); /** * @notice Create a VRF subscription. * @return subId - A unique subscription id. * @dev You can manage the consumer set dynamically with addConsumer/removeConsumer. * @dev Note to fund the subscription, use transferAndCall. For example * @dev LINKTOKEN.transferAndCall( * @dev address(COORDINATOR), * @dev amount, * @dev abi.encode(subId)); */ function createSubscription() external returns (uint64 subId); /** * @notice Get a VRF subscription. * @param subId - ID of the subscription * @return balance - LINK balance of the subscription in juels. * @return reqCount - number of requests for this subscription, determines fee tier. * @return owner - owner of the subscription. * @return consumers - list of consumer address which are able to use this subscription. */ function getSubscription(uint64 subId) external view returns ( uint96 balance, uint64 reqCount, address owner, address[] memory consumers ); /** * @notice Request subscription owner transfer. * @param subId - ID of the subscription * @param newOwner - proposed new owner of the subscription */ function requestSubscriptionOwnerTransfer(uint64 subId, address newOwner) external; /** * @notice Request subscription owner transfer. * @param subId - ID of the subscription * @dev will revert if original owner of subId has * not requested that msg.sender become the new owner. */ function acceptSubscriptionOwnerTransfer(uint64 subId) external; /** * @notice Add a consumer to a VRF subscription. * @param subId - ID of the subscription * @param consumer - New consumer which can use the subscription */ function addConsumer(uint64 subId, address consumer) external; /** * @notice Remove a consumer from a VRF subscription. * @param subId - ID of the subscription * @param consumer - Consumer to remove from the subscription */ function removeConsumer(uint64 subId, address consumer) external; /** * @notice Cancel a subscription * @param subId - ID of the subscription * @param to - Where to send the remaining LINK to */ function cancelSubscription(uint64 subId, address to) external; /* * @notice Check to see if there exists a request commitment consumers * for all consumers and keyhashes for a given sub. * @param subId - ID of the subscription * @return true if there exists at least one unfulfilled request for the subscription, false * otherwise. */ function pendingRequestExists(uint64 subId) external view returns (bool); }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts v4.4.1 (interfaces/IERC1363.sol) pragma solidity ^0.8.0; import "./IERC20.sol"; import "./IERC165.sol"; interface IERC1363 is IERC165, IERC20 { /* * Note: the ERC-165 identifier for this interface is 0x4bbee2df. * 0x4bbee2df === * bytes4(keccak256('transferAndCall(address,uint256)')) ^ * bytes4(keccak256('transferAndCall(address,uint256,bytes)')) ^ * bytes4(keccak256('transferFromAndCall(address,address,uint256)')) ^ * bytes4(keccak256('transferFromAndCall(address,address,uint256,bytes)')) */ /* * Note: the ERC-165 identifier for this interface is 0xfb9ec8ce. * 0xfb9ec8ce === * bytes4(keccak256('approveAndCall(address,uint256)')) ^ * bytes4(keccak256('approveAndCall(address,uint256,bytes)')) */ /** * @dev Transfer tokens from `msg.sender` to another address and then call `onTransferReceived` on receiver * @param to address The address which you want to transfer to * @param value uint256 The amount of tokens to be transferred * @return true unless throwing */ function transferAndCall(address to, uint256 value) external returns (bool); /** * @dev Transfer tokens from `msg.sender` to another address and then call `onTransferReceived` on receiver * @param to address The address which you want to transfer to * @param value uint256 The amount of tokens to be transferred * @param data bytes Additional data with no specified format, sent in call to `to` * @return true unless throwing */ function transferAndCall( address to, uint256 value, bytes memory data ) external returns (bool); /** * @dev Transfer tokens from one address to another and then call `onTransferReceived` on receiver * @param from address The address which you want to send tokens from * @param to address The address which you want to transfer to * @param value uint256 The amount of tokens to be transferred * @return true unless throwing */ function transferFromAndCall( address from, address to, uint256 value ) external returns (bool); /** * @dev Transfer tokens from one address to another and then call `onTransferReceived` on receiver * @param from address The address which you want to send tokens from * @param to address The address which you want to transfer to * @param value uint256 The amount of tokens to be transferred * @param data bytes Additional data with no specified format, sent in call to `to` * @return true unless throwing */ function transferFromAndCall( address from, address to, uint256 value, bytes memory data ) external returns (bool); /** * @dev Approve the passed address to spend the specified amount of tokens on behalf of msg.sender * and then call `onApprovalReceived` on spender. * @param spender address The address which will spend the funds * @param value uint256 The amount of tokens to be spent */ function approveAndCall(address spender, uint256 value) external returns (bool); /** * @dev Approve the passed address to spend the specified amount of tokens on behalf of msg.sender * and then call `onApprovalReceived` on spender. * @param spender address The address which will spend the funds * @param value uint256 The amount of tokens to be spent * @param data bytes Additional data with no specified format, sent in call to `spender` */ function approveAndCall( address spender, uint256 value, bytes memory data ) external returns (bool); }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts v4.4.1 (interfaces/IERC165.sol) pragma solidity ^0.8.0; import "../utils/introspection/IERC165.sol";
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts v4.4.1 (interfaces/IERC20.sol) pragma solidity ^0.8.0; import "../token/ERC20/IERC20.sol";
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.7.0) (access/Ownable.sol) pragma solidity ^0.8.0; import "../utils/Context.sol"; /** * @dev Contract module which provides a basic access control mechanism, where * there is an account (an owner) that can be granted exclusive access to * specific functions. * * By default, the owner account will be the one that deploys the contract. This * can later be changed with {transferOwnership}. * * This module is used through inheritance. It will make available the modifier * `onlyOwner`, which can be applied to your functions to restrict their use to * the owner. */ abstract contract Ownable is Context { address private _owner; event OwnershipTransferred(address indexed previousOwner, address indexed newOwner); /** * @dev Initializes the contract setting the deployer as the initial owner. */ constructor() { _transferOwnership(_msgSender()); } /** * @dev Throws if called by any account other than the owner. */ modifier onlyOwner() { _checkOwner(); _; } /** * @dev Returns the address of the current owner. */ function owner() public view virtual returns (address) { return _owner; } /** * @dev Throws if the sender is not the owner. */ function _checkOwner() internal view virtual { require(owner() == _msgSender(), "Ownable: caller is not the owner"); } /** * @dev Leaves the contract without owner. It will not be possible to call * `onlyOwner` functions anymore. Can only be called by the current owner. * * NOTE: Renouncing ownership will leave the contract without an owner, * thereby removing any functionality that is only available to the owner. */ function renounceOwnership() public virtual onlyOwner { _transferOwnership(address(0)); } /** * @dev Transfers ownership of the contract to a new account (`newOwner`). * Can only be called by the current owner. */ function transferOwnership(address newOwner) public virtual onlyOwner { require(newOwner != address(0), "Ownable: new owner is the zero address"); _transferOwnership(newOwner); } /** * @dev Transfers ownership of the contract to a new account (`newOwner`). * Internal function without access restriction. */ function _transferOwnership(address newOwner) internal virtual { address oldOwner = _owner; _owner = newOwner; emit OwnershipTransferred(oldOwner, newOwner); } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.8.0) (proxy/utils/Initializable.sol) pragma solidity ^0.8.2; import "../../utils/Address.sol"; /** * @dev This is a base contract to aid in writing upgradeable contracts, or any kind of contract that will be deployed * behind a proxy. Since proxied contracts do not make use of a constructor, it's common to move constructor logic to an * external initializer function, usually called `initialize`. It then becomes necessary to protect this initializer * function so it can only be called once. The {initializer} modifier provided by this contract will have this effect. * * The initialization functions use a version number. Once a version number is used, it is consumed and cannot be * reused. This mechanism prevents re-execution of each "step" but allows the creation of new initialization steps in * case an upgrade adds a module that needs to be initialized. * * For example: * * [.hljs-theme-light.nopadding] * ``` * contract MyToken is ERC20Upgradeable { * function initialize() initializer public { * __ERC20_init("MyToken", "MTK"); * } * } * contract MyTokenV2 is MyToken, ERC20PermitUpgradeable { * function initializeV2() reinitializer(2) public { * __ERC20Permit_init("MyToken"); * } * } * ``` * * TIP: To avoid leaving the proxy in an uninitialized state, the initializer function should be called as early as * possible by providing the encoded function call as the `_data` argument to {ERC1967Proxy-constructor}. * * CAUTION: When used with inheritance, manual care must be taken to not invoke a parent initializer twice, or to ensure * that all initializers are idempotent. This is not verified automatically as constructors are by Solidity. * * [CAUTION] * ==== * Avoid leaving a contract uninitialized. * * An uninitialized contract can be taken over by an attacker. This applies to both a proxy and its implementation * contract, which may impact the proxy. To prevent the implementation contract from being used, you should invoke * the {_disableInitializers} function in the constructor to automatically lock it when it is deployed: * * [.hljs-theme-light.nopadding] * ``` * /// @custom:oz-upgrades-unsafe-allow constructor * constructor() { * _disableInitializers(); * } * ``` * ==== */ abstract contract Initializable { /** * @dev Indicates that the contract has been initialized. * @custom:oz-retyped-from bool */ uint8 private _initialized; /** * @dev Indicates that the contract is in the process of being initialized. */ bool private _initializing; /** * @dev Triggered when the contract has been initialized or reinitialized. */ event Initialized(uint8 version); /** * @dev A modifier that defines a protected initializer function that can be invoked at most once. In its scope, * `onlyInitializing` functions can be used to initialize parent contracts. * * Similar to `reinitializer(1)`, except that functions marked with `initializer` can be nested in the context of a * constructor. * * Emits an {Initialized} event. */ modifier initializer() { bool isTopLevelCall = !_initializing; require( (isTopLevelCall && _initialized < 1) || (!Address.isContract(address(this)) && _initialized == 1), "Initializable: contract is already initialized" ); _initialized = 1; if (isTopLevelCall) { _initializing = true; } _; if (isTopLevelCall) { _initializing = false; emit Initialized(1); } } /** * @dev A modifier that defines a protected reinitializer function that can be invoked at most once, and only if the * contract hasn't been initialized to a greater version before. In its scope, `onlyInitializing` functions can be * used to initialize parent contracts. * * A reinitializer may be used after the original initialization step. This is essential to configure modules that * are added through upgrades and that require initialization. * * When `version` is 1, this modifier is similar to `initializer`, except that functions marked with `reinitializer` * cannot be nested. If one is invoked in the context of another, execution will revert. * * Note that versions can jump in increments greater than 1; this implies that if multiple reinitializers coexist in * a contract, executing them in the right order is up to the developer or operator. * * WARNING: setting the version to 255 will prevent any future reinitialization. * * Emits an {Initialized} event. */ modifier reinitializer(uint8 version) { require(!_initializing && _initialized < version, "Initializable: contract is already initialized"); _initialized = version; _initializing = true; _; _initializing = false; emit Initialized(version); } /** * @dev Modifier to protect an initialization function so that it can only be invoked by functions with the * {initializer} and {reinitializer} modifiers, directly or indirectly. */ modifier onlyInitializing() { require(_initializing, "Initializable: contract is not initializing"); _; } /** * @dev Locks the contract, preventing any future reinitialization. This cannot be part of an initializer call. * Calling this in the constructor of a contract will prevent that contract from being initialized or reinitialized * to any version. It is recommended to use this to lock implementation contracts that are designed to be called * through proxies. * * Emits an {Initialized} event the first time it is successfully executed. */ function _disableInitializers() internal virtual { require(!_initializing, "Initializable: contract is initializing"); if (_initialized < type(uint8).max) { _initialized = type(uint8).max; emit Initialized(type(uint8).max); } } /** * @dev Internal function that returns the initialized version. Returns `_initialized` */ function _getInitializedVersion() internal view returns (uint8) { return _initialized; } /** * @dev Internal function that returns the initialized version. Returns `_initializing` */ function _isInitializing() internal view returns (bool) { return _initializing; } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.6.0) (token/ERC20/IERC20.sol) pragma solidity ^0.8.0; /** * @dev Interface of the ERC20 standard as defined in the EIP. */ interface IERC20 { /** * @dev Emitted when `value` tokens are moved from one account (`from`) to * another (`to`). * * Note that `value` may be zero. */ event Transfer(address indexed from, address indexed to, uint256 value); /** * @dev Emitted when the allowance of a `spender` for an `owner` is set by * a call to {approve}. `value` is the new allowance. */ event Approval(address indexed owner, address indexed spender, uint256 value); /** * @dev Returns the amount of tokens in existence. */ function totalSupply() external view returns (uint256); /** * @dev Returns the amount of tokens owned by `account`. */ function balanceOf(address account) external view returns (uint256); /** * @dev Moves `amount` tokens from the caller's account to `to`. * * Returns a boolean value indicating whether the operation succeeded. * * Emits a {Transfer} event. */ function transfer(address to, uint256 amount) external returns (bool); /** * @dev Returns the remaining number of tokens that `spender` will be * allowed to spend on behalf of `owner` through {transferFrom}. This is * zero by default. * * This value changes when {approve} or {transferFrom} are called. */ function allowance(address owner, address spender) external view returns (uint256); /** * @dev Sets `amount` as the allowance of `spender` over the caller's tokens. * * Returns a boolean value indicating whether the operation succeeded. * * IMPORTANT: Beware that changing an allowance with this method brings the risk * that someone may use both the old and the new allowance by unfortunate * transaction ordering. One possible solution to mitigate this race * condition is to first reduce the spender's allowance to 0 and set the * desired value afterwards: * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729 * * Emits an {Approval} event. */ function approve(address spender, uint256 amount) external returns (bool); /** * @dev Moves `amount` tokens from `from` to `to` using the * allowance mechanism. `amount` is then deducted from the caller's * allowance. * * Returns a boolean value indicating whether the operation succeeded. * * Emits a {Transfer} event. */ function transferFrom( address from, address to, uint256 amount ) external returns (bool); }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.8.0) (token/ERC721/IERC721.sol) pragma solidity ^0.8.0; import "../../utils/introspection/IERC165.sol"; /** * @dev Required interface of an ERC721 compliant contract. */ interface IERC721 is IERC165 { /** * @dev Emitted when `tokenId` token is transferred 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`. * * 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; /** * @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 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: Note that the caller is responsible to confirm that the recipient is capable of receiving ERC721 * or else they may be permanently lost. Usage of {safeTransferFrom} prevents loss, though the caller must * understand this adds an external call which potentially creates a reentrancy vulnerability. * * 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 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 the account approved for `tokenId` token. * * Requirements: * * - `tokenId` must exist. */ function getApproved(uint256 tokenId) external view returns (address operator); /** * @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); }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.8.0) (utils/Address.sol) pragma solidity ^0.8.1; /** * @dev Collection of functions related to the address type */ library Address { /** * @dev Returns true if `account` is a contract. * * [IMPORTANT] * ==== * It is unsafe to assume that an address for which this function returns * false is an externally-owned account (EOA) and not a contract. * * Among others, `isContract` will return false for the following * types of addresses: * * - an externally-owned account * - a contract in construction * - an address where a contract will be created * - an address where a contract lived, but was destroyed * ==== * * [IMPORTANT] * ==== * You shouldn't rely on `isContract` to protect against flash loan attacks! * * Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets * like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract * constructor. * ==== */ function isContract(address account) internal view returns (bool) { // This method relies on extcodesize/address.code.length, which returns 0 // for contracts in construction, since the code is only stored at the end // of the constructor execution. return account.code.length > 0; } /** * @dev Replacement for Solidity's `transfer`: sends `amount` wei to * `recipient`, forwarding all available gas and reverting on errors. * * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost * of certain opcodes, possibly making contracts go over the 2300 gas limit * imposed by `transfer`, making them unable to receive funds via * `transfer`. {sendValue} removes this limitation. * * https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more]. * * IMPORTANT: because control is transferred to `recipient`, care must be * taken to not create reentrancy vulnerabilities. Consider using * {ReentrancyGuard} or the * https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern]. */ function sendValue(address payable recipient, uint256 amount) internal { require(address(this).balance >= amount, "Address: insufficient balance"); (bool success, ) = recipient.call{value: amount}(""); require(success, "Address: unable to send value, recipient may have reverted"); } /** * @dev Performs a Solidity function call using a low level `call`. A * plain `call` is an unsafe replacement for a function call: use this * function instead. * * If `target` reverts with a revert reason, it is bubbled up by this * function (like regular Solidity function calls). * * Returns the raw returned data. To convert to the expected return value, * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`]. * * Requirements: * * - `target` must be a contract. * - calling `target` with `data` must not revert. * * _Available since v3.1._ */ function functionCall(address target, bytes memory data) internal returns (bytes memory) { return functionCallWithValue(target, data, 0, "Address: low-level call failed"); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with * `errorMessage` as a fallback revert reason when `target` reverts. * * _Available since v3.1._ */ function functionCall( address target, bytes memory data, string memory errorMessage ) internal returns (bytes memory) { return functionCallWithValue(target, data, 0, errorMessage); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], * but also transferring `value` wei to `target`. * * Requirements: * * - the calling contract must have an ETH balance of at least `value`. * - the called Solidity function must be `payable`. * * _Available since v3.1._ */ function functionCallWithValue( address target, bytes memory data, uint256 value ) internal returns (bytes memory) { return functionCallWithValue(target, data, value, "Address: low-level call with value failed"); } /** * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but * with `errorMessage` as a fallback revert reason when `target` reverts. * * _Available since v3.1._ */ function functionCallWithValue( address target, bytes memory data, uint256 value, string memory errorMessage ) internal returns (bytes memory) { require(address(this).balance >= value, "Address: insufficient balance for call"); (bool success, bytes memory returndata) = target.call{value: value}(data); return verifyCallResultFromTarget(target, success, returndata, errorMessage); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], * but performing a static call. * * _Available since v3.3._ */ function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) { return functionStaticCall(target, data, "Address: low-level static call failed"); } /** * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`], * but performing a static call. * * _Available since v3.3._ */ function functionStaticCall( address target, bytes memory data, string memory errorMessage ) internal view returns (bytes memory) { (bool success, bytes memory returndata) = target.staticcall(data); return verifyCallResultFromTarget(target, success, returndata, errorMessage); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], * but performing a delegate call. * * _Available since v3.4._ */ function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) { return functionDelegateCall(target, data, "Address: low-level delegate call failed"); } /** * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`], * but performing a delegate call. * * _Available since v3.4._ */ function functionDelegateCall( address target, bytes memory data, string memory errorMessage ) internal returns (bytes memory) { (bool success, bytes memory returndata) = target.delegatecall(data); return verifyCallResultFromTarget(target, success, returndata, errorMessage); } /** * @dev Tool to verify that a low level call to smart-contract was successful, and revert (either by bubbling * the revert reason or using the provided one) in case of unsuccessful call or if target was not a contract. * * _Available since v4.8._ */ function verifyCallResultFromTarget( address target, bool success, bytes memory returndata, string memory errorMessage ) internal view returns (bytes memory) { if (success) { if (returndata.length == 0) { // only check isContract if the call was successful and the return data is empty // otherwise we already know that it was a contract require(isContract(target), "Address: call to non-contract"); } return returndata; } else { _revert(returndata, errorMessage); } } /** * @dev Tool to verify that a low level call was successful, and revert if it wasn't, either by bubbling the * revert reason or using the provided one. * * _Available since v4.3._ */ function verifyCallResult( bool success, bytes memory returndata, string memory errorMessage ) internal pure returns (bytes memory) { if (success) { return returndata; } else { _revert(returndata, errorMessage); } } function _revert(bytes memory returndata, string memory errorMessage) private pure { // Look for revert reason and bubble it up if present if (returndata.length > 0) { // The easiest way to bubble the revert reason is using memory via assembly /// @solidity memory-safe-assembly assembly { let returndata_size := mload(returndata) revert(add(32, returndata), returndata_size) } } else { revert(errorMessage); } } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts v4.4.1 (utils/Context.sol) pragma solidity ^0.8.0; /** * @dev Provides information about the current execution context, including the * sender of the transaction and its data. While these are generally available * via msg.sender and msg.data, they should not be accessed in such a direct * manner, since when dealing with meta-transactions the account sending and * paying for execution may not be the actual sender (as far as an application * is concerned). * * This contract is only required for intermediate, library-like contracts. */ abstract contract Context { function _msgSender() internal view virtual returns (address) { return msg.sender; } function _msgData() internal view virtual returns (bytes calldata) { return msg.data; } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.5.0) (utils/Multicall.sol) pragma solidity ^0.8.0; import "./Address.sol"; /** * @dev Provides a function to batch together multiple calls in a single external call. * * _Available since v4.1._ */ abstract contract Multicall { /** * @dev Receives and executes a batch of function calls on this contract. */ function multicall(bytes[] calldata data) external virtual returns (bytes[] memory results) { results = new bytes[](data.length); for (uint256 i = 0; i < data.length; i++) { results[i] = Address.functionDelegateCall(address(this), data[i]); } return results; } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts v4.4.1 (utils/introspection/IERC165.sol) pragma solidity ^0.8.0; /** * @dev Interface of the ERC165 standard, as defined in the * https://eips.ethereum.org/EIPS/eip-165[EIP]. * * Implementers can declare support of contract interfaces, which can then be * queried by others ({ERC165Checker}). * * For an implementation, see {ERC165}. */ interface IERC165 { /** * @dev Returns true if this contract implements the interface defined by * `interfaceId`. See the corresponding * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section] * to learn more about how these ids are created. * * This function call must use less than 30 000 gas. */ function supportsInterface(bytes4 interfaceId) external view returns (bool); }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.8.0) (utils/math/Math.sol) pragma solidity ^0.8.0; /** * @dev Standard math utilities missing in the Solidity language. */ library Math { enum Rounding { Down, // Toward negative infinity Up, // Toward infinity Zero // Toward zero } /** * @dev Returns the largest of two numbers. */ function max(uint256 a, uint256 b) internal pure returns (uint256) { return a > b ? a : b; } /** * @dev Returns the smallest of two numbers. */ function min(uint256 a, uint256 b) internal pure returns (uint256) { return a < b ? a : b; } /** * @dev Returns the average of two numbers. The result is rounded towards * zero. */ function average(uint256 a, uint256 b) internal pure returns (uint256) { // (a + b) / 2 can overflow. return (a & b) + (a ^ b) / 2; } /** * @dev Returns the ceiling of the division of two numbers. * * This differs from standard division with `/` in that it rounds up instead * of rounding down. */ function ceilDiv(uint256 a, uint256 b) internal pure returns (uint256) { // (a + b - 1) / b can overflow on addition, so we distribute. return a == 0 ? 0 : (a - 1) / b + 1; } /** * @notice Calculates floor(x * y / denominator) with full precision. Throws if result overflows a uint256 or denominator == 0 * @dev Original credit to Remco Bloemen under MIT license (https://xn--2-umb.com/21/muldiv) * with further edits by Uniswap Labs also under MIT license. */ function mulDiv( uint256 x, uint256 y, uint256 denominator ) internal pure returns (uint256 result) { unchecked { // 512-bit multiply [prod1 prod0] = x * y. Compute the product mod 2^256 and mod 2^256 - 1, then use // use the Chinese Remainder Theorem to reconstruct the 512 bit result. The result is stored in two 256 // variables such that product = prod1 * 2^256 + prod0. uint256 prod0; // Least significant 256 bits of the product uint256 prod1; // Most significant 256 bits of the product assembly { let mm := mulmod(x, y, not(0)) prod0 := mul(x, y) prod1 := sub(sub(mm, prod0), lt(mm, prod0)) } // Handle non-overflow cases, 256 by 256 division. if (prod1 == 0) { return prod0 / denominator; } // Make sure the result is less than 2^256. Also prevents denominator == 0. require(denominator > prod1); /////////////////////////////////////////////// // 512 by 256 division. /////////////////////////////////////////////// // Make division exact by subtracting the remainder from [prod1 prod0]. uint256 remainder; assembly { // Compute remainder using mulmod. remainder := mulmod(x, y, denominator) // Subtract 256 bit number from 512 bit number. prod1 := sub(prod1, gt(remainder, prod0)) prod0 := sub(prod0, remainder) } // Factor powers of two out of denominator and compute largest power of two divisor of denominator. Always >= 1. // See https://cs.stackexchange.com/q/138556/92363. // Does not overflow because the denominator cannot be zero at this stage in the function. uint256 twos = denominator & (~denominator + 1); assembly { // Divide denominator by twos. denominator := div(denominator, twos) // Divide [prod1 prod0] by twos. prod0 := div(prod0, twos) // Flip twos such that it is 2^256 / twos. If twos is zero, then it becomes one. twos := add(div(sub(0, twos), twos), 1) } // Shift in bits from prod1 into prod0. prod0 |= prod1 * twos; // Invert denominator mod 2^256. Now that denominator is an odd number, it has an inverse modulo 2^256 such // that denominator * inv = 1 mod 2^256. Compute the inverse by starting with a seed that is correct for // four bits. That is, denominator * inv = 1 mod 2^4. uint256 inverse = (3 * denominator) ^ 2; // Use the Newton-Raphson iteration to improve the precision. Thanks to Hensel's lifting lemma, this also works // in modular arithmetic, doubling the correct bits in each step. inverse *= 2 - denominator * inverse; // inverse mod 2^8 inverse *= 2 - denominator * inverse; // inverse mod 2^16 inverse *= 2 - denominator * inverse; // inverse mod 2^32 inverse *= 2 - denominator * inverse; // inverse mod 2^64 inverse *= 2 - denominator * inverse; // inverse mod 2^128 inverse *= 2 - denominator * inverse; // inverse mod 2^256 // Because the division is now exact we can divide by multiplying with the modular inverse of denominator. // This will give us the correct result modulo 2^256. Since the preconditions guarantee that the outcome is // less than 2^256, this is the final result. We don't need to compute the high bits of the result and prod1 // is no longer required. result = prod0 * inverse; return result; } } /** * @notice Calculates x * y / denominator with full precision, following the selected rounding direction. */ function mulDiv( uint256 x, uint256 y, uint256 denominator, Rounding rounding ) internal pure returns (uint256) { uint256 result = mulDiv(x, y, denominator); if (rounding == Rounding.Up && mulmod(x, y, denominator) > 0) { result += 1; } return result; } /** * @dev Returns the square root of a number. If the number is not a perfect square, the value is rounded down. * * Inspired by Henry S. Warren, Jr.'s "Hacker's Delight" (Chapter 11). */ function sqrt(uint256 a) internal pure returns (uint256) { if (a == 0) { return 0; } // For our first guess, we get the biggest power of 2 which is smaller than the square root of the target. // // We know that the "msb" (most significant bit) of our target number `a` is a power of 2 such that we have // `msb(a) <= a < 2*msb(a)`. This value can be written `msb(a)=2**k` with `k=log2(a)`. // // This can be rewritten `2**log2(a) <= a < 2**(log2(a) + 1)` // → `sqrt(2**k) <= sqrt(a) < sqrt(2**(k+1))` // → `2**(k/2) <= sqrt(a) < 2**((k+1)/2) <= 2**(k/2 + 1)` // // Consequently, `2**(log2(a) / 2)` is a good first approximation of `sqrt(a)` with at least 1 correct bit. uint256 result = 1 << (log2(a) >> 1); // At this point `result` is an estimation with one bit of precision. We know the true value is a uint128, // since it is the square root of a uint256. Newton's method converges quadratically (precision doubles at // every iteration). We thus need at most 7 iteration to turn our partial result with one bit of precision // into the expected uint128 result. unchecked { result = (result + a / result) >> 1; result = (result + a / result) >> 1; result = (result + a / result) >> 1; result = (result + a / result) >> 1; result = (result + a / result) >> 1; result = (result + a / result) >> 1; result = (result + a / result) >> 1; return min(result, a / result); } } /** * @notice Calculates sqrt(a), following the selected rounding direction. */ function sqrt(uint256 a, Rounding rounding) internal pure returns (uint256) { unchecked { uint256 result = sqrt(a); return result + (rounding == Rounding.Up && result * result < a ? 1 : 0); } } /** * @dev Return the log in base 2, rounded down, of a positive value. * Returns 0 if given 0. */ function log2(uint256 value) internal pure returns (uint256) { uint256 result = 0; unchecked { if (value >> 128 > 0) { value >>= 128; result += 128; } if (value >> 64 > 0) { value >>= 64; result += 64; } if (value >> 32 > 0) { value >>= 32; result += 32; } if (value >> 16 > 0) { value >>= 16; result += 16; } if (value >> 8 > 0) { value >>= 8; result += 8; } if (value >> 4 > 0) { value >>= 4; result += 4; } if (value >> 2 > 0) { value >>= 2; result += 2; } if (value >> 1 > 0) { result += 1; } } return result; } /** * @dev Return the log in base 2, following the selected rounding direction, of a positive value. * Returns 0 if given 0. */ function log2(uint256 value, Rounding rounding) internal pure returns (uint256) { unchecked { uint256 result = log2(value); return result + (rounding == Rounding.Up && 1 << result < value ? 1 : 0); } } /** * @dev Return the log in base 10, rounded down, of a positive value. * Returns 0 if given 0. */ function log10(uint256 value) internal pure returns (uint256) { uint256 result = 0; unchecked { if (value >= 10**64) { value /= 10**64; result += 64; } if (value >= 10**32) { value /= 10**32; result += 32; } if (value >= 10**16) { value /= 10**16; result += 16; } if (value >= 10**8) { value /= 10**8; result += 8; } if (value >= 10**4) { value /= 10**4; result += 4; } if (value >= 10**2) { value /= 10**2; result += 2; } if (value >= 10**1) { result += 1; } } return result; } /** * @dev Return the log in base 10, following the selected rounding direction, of a positive value. * Returns 0 if given 0. */ function log10(uint256 value, Rounding rounding) internal pure returns (uint256) { unchecked { uint256 result = log10(value); return result + (rounding == Rounding.Up && 10**result < value ? 1 : 0); } } /** * @dev Return the log in base 256, rounded down, of a positive value. * Returns 0 if given 0. * * Adding one to the result gives the number of pairs of hex symbols needed to represent `value` as a hex string. */ function log256(uint256 value) internal pure returns (uint256) { uint256 result = 0; unchecked { if (value >> 128 > 0) { value >>= 128; result += 16; } if (value >> 64 > 0) { value >>= 64; result += 8; } if (value >> 32 > 0) { value >>= 32; result += 4; } if (value >> 16 > 0) { value >>= 16; result += 2; } if (value >> 8 > 0) { result += 1; } } return result; } /** * @dev Return the log in base 10, following the selected rounding direction, of a positive value. * Returns 0 if given 0. */ function log256(uint256 value, Rounding rounding) internal pure returns (uint256) { unchecked { uint256 result = log256(value); return result + (rounding == Rounding.Up && 1 << (result * 8) < value ? 1 : 0); } } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.8.0) (utils/math/SignedMath.sol) pragma solidity ^0.8.0; /** * @dev Standard signed math utilities missing in the Solidity language. */ library SignedMath { /** * @dev Returns the largest of two signed numbers. */ function max(int256 a, int256 b) internal pure returns (int256) { return a > b ? a : b; } /** * @dev Returns the smallest of two signed numbers. */ function min(int256 a, int256 b) internal pure returns (int256) { return a < b ? a : b; } /** * @dev Returns the average of two signed numbers without overflow. * The result is rounded towards zero. */ function average(int256 a, int256 b) internal pure returns (int256) { // Formula from the book "Hacker's Delight" int256 x = (a & b) + ((a ^ b) >> 1); return x + (int256(uint256(x) >> 255) & (a ^ b)); } /** * @dev Returns the absolute unsigned value of a signed value. */ function abs(int256 n) internal pure returns (uint256) { unchecked { // must be unchecked in order to support `n = type(int256).min` return uint256(n >= 0 ? n : -n); } } }
// SPDX-License-Identifier: MIT pragma solidity >=0.8.0; /// @notice Signed 18 decimal fixed point (wad) arithmetic library. /// @author Solmate (https://github.com/transmissions11/solmate/blob/main/src/utils/SignedWadMath.sol) /// @author Modified from Remco Bloemen (https://xn--2-umb.com/22/exp-ln/index.html) /// @dev Will not revert on overflow, only use where overflow is not possible. function toWadUnsafe(uint256 x) pure returns (int256 r) { /// @solidity memory-safe-assembly assembly { // Multiply x by 1e18. r := mul(x, 1000000000000000000) } } /// @dev Takes an integer amount of seconds and converts it to a wad amount of days. /// @dev Will not revert on overflow, only use where overflow is not possible. /// @dev Not meant for negative second amounts, it assumes x is positive. function toDaysWadUnsafe(uint256 x) pure returns (int256 r) { /// @solidity memory-safe-assembly assembly { // Multiply x by 1e18 and then divide it by 86400. r := div(mul(x, 1000000000000000000), 86400) } } /// @dev Takes a wad amount of days and converts it to an integer amount of seconds. /// @dev Will not revert on overflow, only use where overflow is not possible. /// @dev Not meant for negative day amounts, it assumes x is positive. function fromDaysWadUnsafe(int256 x) pure returns (uint256 r) { /// @solidity memory-safe-assembly assembly { // Multiply x by 86400 and then divide it by 1e18. r := div(mul(x, 86400), 1000000000000000000) } } /// @dev Will not revert on overflow, only use where overflow is not possible. function unsafeWadMul(int256 x, int256 y) pure returns (int256 r) { /// @solidity memory-safe-assembly assembly { // Multiply x by y and divide by 1e18. r := sdiv(mul(x, y), 1000000000000000000) } } /// @dev Will return 0 instead of reverting if y is zero and will /// not revert on overflow, only use where overflow is not possible. function unsafeWadDiv(int256 x, int256 y) pure returns (int256 r) { /// @solidity memory-safe-assembly assembly { // Multiply x by 1e18 and divide it by y. r := sdiv(mul(x, 1000000000000000000), y) } } function wadMul(int256 x, int256 y) pure returns (int256 r) { /// @solidity memory-safe-assembly assembly { // Store x * y in r for now. r := mul(x, y) // Equivalent to require(x == 0 || (x * y) / x == y) if iszero(or(iszero(x), eq(sdiv(r, x), y))) { revert(0, 0) } // Scale the result down by 1e18. r := sdiv(r, 1000000000000000000) } } function wadDiv(int256 x, int256 y) pure returns (int256 r) { /// @solidity memory-safe-assembly assembly { // Store x * 1e18 in r for now. r := mul(x, 1000000000000000000) // Equivalent to require(y != 0 && ((x * 1e18) / 1e18 == x)) if iszero(and(iszero(iszero(y)), eq(sdiv(r, 1000000000000000000), x))) { revert(0, 0) } // Divide r by y. r := sdiv(r, y) } } /// @dev Will not work with negative bases, only use when x is positive. function wadPow(int256 x, int256 y) pure returns (int256) { // Equivalent to x to the power of y because x ** y = (e ** ln(x)) ** y = e ** (ln(x) * y) return wadExp((wadLn(x) * y) / 1e18); // Using ln(x) means x must be greater than 0. } function wadExp(int256 x) pure returns (int256 r) { unchecked { // When the result is < 0.5 we return zero. This happens when // x <= floor(log(0.5e18) * 1e18) ~ -42e18 if (x <= -42139678854452767551) return 0; // When the result is > (2**255 - 1) / 1e18 we can not represent it as an // int. This happens when x >= floor(log((2**255 - 1) / 1e18) * 1e18) ~ 135. if (x >= 135305999368893231589) revert("EXP_OVERFLOW"); // x is now in the range (-42, 136) * 1e18. Convert to (-42, 136) * 2**96 // for more intermediate precision and a binary basis. This base conversion // is a multiplication by 1e18 / 2**96 = 5**18 / 2**78. x = (x << 78) / 5**18; // Reduce range of x to (-½ ln 2, ½ ln 2) * 2**96 by factoring out powers // of two such that exp(x) = exp(x') * 2**k, where k is an integer. // Solving this gives k = round(x / log(2)) and x' = x - k * log(2). int256 k = ((x << 96) / 54916777467707473351141471128 + 2**95) >> 96; x = x - k * 54916777467707473351141471128; // k is in the range [-61, 195]. // Evaluate using a (6, 7)-term rational approximation. // p is made monic, we'll multiply by a scale factor later. int256 y = x + 1346386616545796478920950773328; y = ((y * x) >> 96) + 57155421227552351082224309758442; int256 p = y + x - 94201549194550492254356042504812; p = ((p * y) >> 96) + 28719021644029726153956944680412240; p = p * x + (4385272521454847904659076985693276 << 96); // We leave p in 2**192 basis so we don't need to scale it back up for the division. int256 q = x - 2855989394907223263936484059900; q = ((q * x) >> 96) + 50020603652535783019961831881945; q = ((q * x) >> 96) - 533845033583426703283633433725380; q = ((q * x) >> 96) + 3604857256930695427073651918091429; q = ((q * x) >> 96) - 14423608567350463180887372962807573; q = ((q * x) >> 96) + 26449188498355588339934803723976023; /// @solidity memory-safe-assembly assembly { // Div in assembly because solidity adds a zero check despite the unchecked. // The q polynomial won't have zeros in the domain as all its roots are complex. // No scaling is necessary because p is already 2**96 too large. r := sdiv(p, q) } // r should be in the range (0.09, 0.25) * 2**96. // We now need to multiply r by: // * the scale factor s = ~6.031367120. // * the 2**k factor from the range reduction. // * the 1e18 / 2**96 factor for base conversion. // We do this all at once, with an intermediate result in 2**213 // basis, so the final right shift is always by a positive amount. r = int256((uint256(r) * 3822833074963236453042738258902158003155416615667) >> uint256(195 - k)); } } function wadLn(int256 x) pure returns (int256 r) { unchecked { require(x > 0, "UNDEFINED"); // We want to convert x from 10**18 fixed point to 2**96 fixed point. // We do this by multiplying by 2**96 / 10**18. But since // ln(x * C) = ln(x) + ln(C), we can simply do nothing here // and add ln(2**96 / 10**18) at the end. /// @solidity memory-safe-assembly assembly { r := shl(7, lt(0xffffffffffffffffffffffffffffffff, x)) r := or(r, shl(6, lt(0xffffffffffffffff, shr(r, x)))) r := or(r, shl(5, lt(0xffffffff, shr(r, x)))) r := or(r, shl(4, lt(0xffff, shr(r, x)))) r := or(r, shl(3, lt(0xff, shr(r, x)))) r := or(r, shl(2, lt(0xf, shr(r, x)))) r := or(r, shl(1, lt(0x3, shr(r, x)))) r := or(r, lt(0x1, shr(r, x))) } // Reduce range of x to (1, 2) * 2**96 // ln(2^k * x) = k * ln(2) + ln(x) int256 k = r - 96; x <<= uint256(159 - k); x = int256(uint256(x) >> 159); // Evaluate using a (8, 8)-term rational approximation. // p is made monic, we will multiply by a scale factor later. int256 p = x + 3273285459638523848632254066296; p = ((p * x) >> 96) + 24828157081833163892658089445524; p = ((p * x) >> 96) + 43456485725739037958740375743393; p = ((p * x) >> 96) - 11111509109440967052023855526967; p = ((p * x) >> 96) - 45023709667254063763336534515857; p = ((p * x) >> 96) - 14706773417378608786704636184526; p = p * x - (795164235651350426258249787498 << 96); // We leave p in 2**192 basis so we don't need to scale it back up for the division. // q is monic by convention. int256 q = x + 5573035233440673466300451813936; q = ((q * x) >> 96) + 71694874799317883764090561454958; q = ((q * x) >> 96) + 283447036172924575727196451306956; q = ((q * x) >> 96) + 401686690394027663651624208769553; q = ((q * x) >> 96) + 204048457590392012362485061816622; q = ((q * x) >> 96) + 31853899698501571402653359427138; q = ((q * x) >> 96) + 909429971244387300277376558375; /// @solidity memory-safe-assembly assembly { // Div in assembly because solidity adds a zero check despite the unchecked. // The q polynomial is known not to have zeros in the domain. // No scaling required because p is already 2**96 too large. r := sdiv(p, q) } // r is in the range (0, 0.125) * 2**96 // Finalization, we need to: // * multiply by the scale factor s = 5.549… // * add ln(2**96 / 10**18) // * add k * ln(2) // * multiply by 10**18 / 2**96 = 5**18 >> 78 // mul s * 5e18 * 2**96, base is now 5**18 * 2**192 r *= 1677202110996718588342820967067443963516166; // add ln(2) * k * 5e18 * 2**192 r += 16597577552685614221487285958193947469193820559219878177908093499208371 * k; // add ln(2**96 / 10**18) * 5e18 * 2**192 r += 600920179829731861736702779321621459595472258049074101567377883020018308; // base conversion: mul 2**18 / 2**192 r >>= 174; } } /// @dev Will return 0 instead of reverting if y is zero. function unsafeDiv(int256 x, int256 y) pure returns (int256 r) { /// @solidity memory-safe-assembly assembly { // Divide x by y. r := sdiv(x, y) } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.17; import "@openzeppelin/contracts/access/Ownable.sol"; import "@openzeppelin/contracts/proxy/utils/Initializable.sol"; import "@openzeppelin/contracts/token/ERC721/IERC721.sol"; import "@openzeppelin/contracts/utils/Multicall.sol"; import "./utils/EntityUtils.sol"; import "./utils/Sample.sol"; import "./systems/SpatialSystem.sol"; import "./systems/MiningSystem.sol"; import "./IERC20Resource.sol"; import "./IMiaocraft.sol"; import "./constants.sol"; struct EmissionInfo { uint128 seed; uint128 amount; } struct AsteroidInfo { address resource; uint256 initialSupply; uint256 rewardPerSecond; int256 x; int256 y; } struct AsteroidInfoExtended { uint256 id; uint128 emissionId; uint32 index; bool identified; AsteroidInfo asteroidInfo; MineInfo mineInfo; } contract GenesisGalaxy is SpatialSystem, MiningSystem, Initializable, Ownable, Multicall { uint256 public immutable ASTEROIDS_PER_EMISSION; uint256 public immutable MAX_DEPLETION_INTERVAL; uint256 public immutable MAX_RADIUS; uint256 public immutable SPEED; // per second IERC20Resource public butter; IMiaocraft public miaocraft; address public sbh; EmissionInfo[] public _emissionInfos; mapping(uint256 => uint256) public identifiedBitmaps; constructor( uint256 asteroidsPerEmission, uint256 maxDepletionInterval, uint256 maxRadius, uint256 speed ) { ASTEROIDS_PER_EMISSION = asteroidsPerEmission; MAX_DEPLETION_INTERVAL = maxDepletionInterval; MAX_RADIUS = maxRadius; SPEED = speed; } function initialize( address butter_, address miaocraft_, address sbh_ ) public initializer { butter = IERC20Resource(butter_); miaocraft = IMiaocraft(miaocraft_); sbh = sbh_; // initialize the origin _add(getOrigin()); _transferOwnership(msg.sender); } function getEmission(uint256 emissionId) public view returns (EmissionInfo memory emissionInfo) { emissionInfo = _emissionInfos[emissionId]; } function getEmissionCount() public view returns (uint256) { return _emissionInfos.length; } function getAsteroids(uint256 emissionId) public view returns (AsteroidInfo[] memory asteroidInfos) { asteroidInfos = new AsteroidInfo[](ASTEROIDS_PER_EMISSION); for (uint256 i = 0; i < ASTEROIDS_PER_EMISSION; i++) { asteroidInfos[i] = getAsteroid(emissionId, i); } } function getAsteroid(uint256 emissionId, uint256 index) public view returns (AsteroidInfo memory asteroidInfo) { uint256 seed = uint256( keccak256(abi.encodePacked(_emissionInfos[emissionId].seed, index)) ); // Although sqrt(1/(1e-18 + x)) is bounded, a manipulated vrf can force // the multiplier to go to 1e9, which destroys the econmomy in an // instant. So use sqrt(1/(1e-15 + x)) to cap the multiplier at 31.6 uint256 initialSupply = (sampleInvSqrt(seed++, 1e15) * _emissionInfos[emissionId].amount) / 1e18 / ASTEROIDS_PER_EMISSION; // min reward rate is 1/2 the supply / depletion interval. Multiply b 2 // so that the min reward rate is supply / depletion interval. uint256 rewardPerSecond = (2 * (sampleInvSqrt(seed++, 1e15) * initialSupply)) / 1e18 / MAX_DEPLETION_INTERVAL; (int256 x, int256 y) = sampleCircle( seed, MAX_RADIUS / ASTEROID_COORD_PRECISION ); asteroidInfo = AsteroidInfo({ resource: address(butter), initialSupply: initialSupply, rewardPerSecond: rewardPerSecond, x: x * int256(ASTEROID_COORD_PRECISION), y: y * int256(ASTEROID_COORD_PRECISION) }); } function getAsteroidExtended(uint256 emissionId, uint256 index) public view returns (AsteroidInfoExtended memory) { return _getAsteroidExtended( emissionId, index, identifiedBitmaps[emissionId] ); } function getOrigin() public view returns (AsteroidInfo memory) { uint256 genesisCost = GENESIS_SUPPLY * miaocraft.buildCost(SPINS_PRECISION); return AsteroidInfo({ resource: address(butter), initialSupply: 100 * genesisCost, rewardPerSecond: genesisCost / MAX_DEPLETION_INTERVAL, x: 0, y: 0 }); } function getOriginExtended() public view returns (AsteroidInfoExtended memory) { return AsteroidInfoExtended({ id: 0, emissionId: 0, index: uint32(ASTEROIDS_PER_EMISSION), identified: true, asteroidInfo: getOrigin(), mineInfo: getMineInfo(tokenToEntity(address(this), 0)) }); } function coordinateToAsteroidId(int256 x, int256 y) public pure returns (uint256) { x /= int256(ASTEROID_COORD_PRECISION); y /= int256(ASTEROID_COORD_PRECISION); return (uint256(x < 0 ? -x + ASTEROID_COORD_NEG_FLAG : x) * uint256(ASTEROID_COORD_NEG_FLAG * 10)) + (uint256(y < 0 ? -y + ASTEROID_COORD_NEG_FLAG : y)); } function asteroidIdToCoordinate(uint256 asteroidId) public pure returns (int256 x, int256 y) { x = int256(asteroidId) / ASTEROID_COORD_NEG_FLAG / 10; y = int256(asteroidId) - x * ASTEROID_COORD_NEG_FLAG * 10; x = ( x / ASTEROID_COORD_NEG_FLAG == 0 ? x : -(x - ASTEROID_COORD_NEG_FLAG) ) * int256(ASTEROID_COORD_PRECISION); y = ( y / ASTEROID_COORD_NEG_FLAG == 0 ? y : -(y - ASTEROID_COORD_NEG_FLAG) ) * int256(ASTEROID_COORD_PRECISION); } function identified(uint256 emissionId, uint256 index) public view returns (bool) { return _mapped(identifiedBitmaps[emissionId], index); } function _getAsteroidExtended( uint256 emissionId, uint256 index, uint256 identifiedBitmap ) internal view returns (AsteroidInfoExtended memory info) { AsteroidInfo memory asteroidInfo = getAsteroid(emissionId, index); uint256 asteroidId = coordinateToAsteroidId( asteroidInfo.x, asteroidInfo.y ); return AsteroidInfoExtended({ id: asteroidId, emissionId: uint128(emissionId), index: uint32(index), identified: _mapped(identifiedBitmap, index), asteroidInfo: asteroidInfo, mineInfo: getMineInfo(tokenToEntity(address(this), asteroidId)) }); } function _getAsteroidId(uint256 emissionId, uint256 index) internal view returns (uint256) { AsteroidInfo memory info = getAsteroid(emissionId, index); return coordinateToAsteroidId(info.x, info.y); } function _mapped(uint256 bitmap, uint256 index) private pure returns (bool) { return bitmap & (1 << index) != 0; } function _requireDocked(uint256 shipEntityId, uint256 asteroidEntityId) internal view { require(locked(shipEntityId), "Not docked"); require(collocated(asteroidEntityId, shipEntityId), "Not docked here"); } function addEmission(uint256 seed, uint256 amount) public { require(msg.sender == sbh, "Only sbh"); _emissionInfos.push( EmissionInfo({seed: uint128(seed), amount: uint128(amount)}) ); } function identifyMultiple(uint256 emissionId, uint256[] memory indices) public { for (uint256 i = 0; i < indices.length; i++) { identify(emissionId, indices[i]); } } function identifyAll(uint256 emissionId) public { uint256 bitmap = identifiedBitmaps[emissionId]; for (uint256 i = 0; i < ASTEROIDS_PER_EMISSION; i++) { if (!_mapped(bitmap, i)) identify(emissionId, i); } } function identify(uint256 emissionId, uint256 index) public returns (uint256 asteroidId) { require(emissionId < _emissionInfos.length, "Invalid emissionId"); require(index < ASTEROIDS_PER_EMISSION, "Invalid index"); require(!identified(emissionId, index), "Already identified"); identifiedBitmaps[emissionId] |= 1 << index; asteroidId = _add(getAsteroid(emissionId, index)); } function dock(uint256 shipId, uint256 asteroidId) public onlyApprovedOrShipOwner(shipId) { uint256 shipEntityId = tokenToEntity(address(miaocraft), shipId); uint256 asteroidEntityId = tokenToEntity(address(this), asteroidId); require(!locked(shipEntityId), "Already docked"); _updateLocation(shipEntityId); require(collocated(asteroidEntityId, shipEntityId), "Out of orbit"); _lock(shipEntityId); _dock(shipEntityId, asteroidEntityId, miaocraft.spinsOf(shipId)); } function redock(uint256 shipId, uint256 asteroidId) public { uint256 shipEntityId = tokenToEntity(address(miaocraft), shipId); uint256 asteroidEntityId = tokenToEntity(address(this), asteroidId); _requireDocked(shipEntityId, asteroidEntityId); uint256 sharesBefore = getExtractorInfo(asteroidEntityId, shipEntityId) .shares; uint256 sharesAfter = miaocraft.spinsOf(shipId); if (sharesBefore > sharesAfter) { _undock(shipEntityId, asteroidEntityId, sharesBefore - sharesAfter); } else { _dock(shipEntityId, asteroidEntityId, sharesAfter - sharesBefore); } } function extract(uint256 shipId, uint256 asteroidId) public { _extract( tokenToEntity(address(miaocraft), shipId), tokenToEntity(address(this), asteroidId) ); } function identifyAndDock( uint256 emissionId, uint256 index, uint256 shipId ) public { uint256 asteroidId; if (!identified(emissionId, index)) { asteroidId = identify(emissionId, index); } else { asteroidId = _getAsteroidId(emissionId, index); } dock(shipId, asteroidId); } function undockAndExtract(uint256 shipId, uint256 asteroidId) public onlyApprovedOrShipOwner(shipId) { uint256 shipEntityId = tokenToEntity(address(miaocraft), shipId); uint256 asteroidEntityId = tokenToEntity(address(this), asteroidId); _requireDocked(shipEntityId, asteroidEntityId); _undockAndExtract( shipEntityId, asteroidEntityId, getExtractorInfo(asteroidEntityId, shipEntityId).shares ); _unlock(shipEntityId); } function emergencyUndock(uint256 shipId, uint256 asteroidId) public onlyApprovedOrShipOwner(shipId) { uint256 shipEntityId = tokenToEntity(address(miaocraft), shipId); _emergencyUndock( shipEntityId, tokenToEntity(address(this), asteroidId) ); _unlock(shipEntityId); } function undockExtractAndMove( uint256 shipId, uint256 fromAsteroidId, uint256 toAsteroidId ) public { (int256 x, int256 y) = coordinate( tokenToEntity(address(this), toAsteroidId) ); undockExtractAndMove(shipId, fromAsteroidId, x, y); } function undockExtractAndMove( uint256 shipId, uint256 asteroidId, int256 xDest, int256 yDest ) public onlyApprovedOrShipOwner(shipId) { uint256 shipEntityId = tokenToEntity(address(miaocraft), shipId); uint256 asteroidEntityId = tokenToEntity(address(this), asteroidId); _requireDocked(shipEntityId, asteroidEntityId); _undockAndExtract( shipEntityId, asteroidEntityId, getExtractorInfo(asteroidEntityId, shipEntityId).shares ); _unlock(shipEntityId); _move(shipEntityId, xDest, yDest, SPEED); } function move(uint256 shipId, uint256 asteroidId) public { (int256 x, int256 y) = coordinate( tokenToEntity(address(this), asteroidId) ); move(shipId, x, y); } function move( uint256 shipId, int256 xDest, int256 yDest ) public onlyApprovedOrShipOwner(shipId) { _move(tokenToEntity(address(miaocraft), shipId), xDest, yDest, SPEED); } function remove(uint256 shipId, uint256 asteroidId) public { try miaocraft.ownerOf(shipId) { revert("Ship exists"); } catch Error(string memory reason) { require( keccak256(abi.encodePacked(reason)) == keccak256("ERC721: invalid token ID"), "Invalid reason" ); _destroyExtractor( tokenToEntity(address(this), asteroidId), tokenToEntity(address(miaocraft), shipId) ); } } function _add(AsteroidInfo memory asteroidInfo) internal returns (uint256 asteroidId) { asteroidId = coordinateToAsteroidId(asteroidInfo.x, asteroidInfo.y); uint256 asteroidEntityId = tokenToEntity(address(this), asteroidId); IERC20Resource(asteroidInfo.resource).mint( asteroidEntityId, asteroidInfo.initialSupply ); _setCoordinate(asteroidEntityId, asteroidInfo.x, asteroidInfo.y); _add( asteroidEntityId, asteroidInfo.resource, asteroidInfo.rewardPerSecond ); } modifier onlyApprovedOrShipOwner(uint256 shipId) { require( miaocraft.isApprovedOrOwner(msg.sender, shipId), "Only approved or owner" ); _; } /* DATA QUERY FUNCTIONS */ function paginateEmissions(uint256 offset, uint256 limit) public view returns (EmissionInfo[] memory emissionInfos_) { limit = Math.min(limit, _emissionInfos.length - offset); emissionInfos_ = new EmissionInfo[](limit); uint256 start = _emissionInfos.length - offset - 1; for (uint256 i = 0; i < limit; i++) { emissionInfos_[i] = _emissionInfos[start - i]; } } function paginateAsteroids(uint256 offset, uint256 limit) public view returns (AsteroidInfoExtended[] memory asteroidInfos) { limit = Math.min(limit, _emissionInfos.length - offset); asteroidInfos = new AsteroidInfoExtended[]( limit * ASTEROIDS_PER_EMISSION ); uint256 start = _emissionInfos.length - offset - 1; for (uint256 i = 0; i < limit; i++) { uint256 emissionId = start - i; uint256 bitmap = identifiedBitmaps[i]; asteroidInfos[ emissionId * ASTEROIDS_PER_EMISSION + 0 ] = _getAsteroidExtended(emissionId, 0, bitmap); asteroidInfos[ emissionId * ASTEROIDS_PER_EMISSION + 1 ] = _getAsteroidExtended(emissionId, 1, bitmap); asteroidInfos[ emissionId * ASTEROIDS_PER_EMISSION + 2 ] = _getAsteroidExtended(emissionId, 2, bitmap); asteroidInfos[ emissionId * ASTEROIDS_PER_EMISSION + 3 ] = _getAsteroidExtended(emissionId, 3, bitmap); asteroidInfos[ emissionId * ASTEROIDS_PER_EMISSION + 4 ] = _getAsteroidExtended(emissionId, 4, bitmap); asteroidInfos[ emissionId * ASTEROIDS_PER_EMISSION + 5 ] = _getAsteroidExtended(emissionId, 5, bitmap); asteroidInfos[ emissionId * ASTEROIDS_PER_EMISSION + 6 ] = _getAsteroidExtended(emissionId, 6, bitmap); asteroidInfos[ emissionId * ASTEROIDS_PER_EMISSION + 7 ] = _getAsteroidExtended(emissionId, 7, bitmap); asteroidInfos[ emissionId * ASTEROIDS_PER_EMISSION + 8 ] = _getAsteroidExtended(emissionId, 8, bitmap); asteroidInfos[ emissionId * ASTEROIDS_PER_EMISSION + 9 ] = _getAsteroidExtended(emissionId, 9, bitmap); asteroidInfos[ emissionId * ASTEROIDS_PER_EMISSION + 10 ] = _getAsteroidExtended(emissionId, 10, bitmap); } } /* OWNER FUNCTIONS */ function setButter(IERC20Resource butter_) public onlyOwner { butter = butter_; } function setMiaocraft(IMiaocraft miaocraft_) public onlyOwner { miaocraft = miaocraft_; } function setSbh(address sbh_) public onlyOwner { sbh = sbh_; } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.17; import "./extensions/IERC20EntityBurnable.sol"; interface IERC20Resource is IERC20EntityBurnable { function mint(address to, uint256 amount) external; function mint(uint256 to, uint256 amount) external; function mintAndCall(address to, uint256 amount) external; }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.17; import "@openzeppelin/contracts/token/ERC721/IERC721.sol"; struct ShipInfo { uint96 spins; uint96 spinsBurned; uint40 lastServiceTime; string name; } interface IMiaocraft is IERC721 { event Build( address indexed owner, uint256 indexed id, uint256 spins, string name ); event Upgrade(address indexed owner, uint256 indexed id, uint256 spins); event Merge( address indexed owner, uint256 indexed id1, uint256 indexed id2, uint256 spins ); event Scrap( address indexed scavengerOwner, uint256 indexed scavengerId, uint256 indexed targetId ); event Service( address indexed owner, uint256 indexed id, uint256 spins, uint256 cost ); event Rename(address indexed owner, uint256 indexed id, string name); function spinsOf(uint256 id) external view returns (uint256); function spinsDecayOf(uint256 id) external view returns (uint256); function buildCost(uint256 spins_) external view returns (uint256); function serviceCostOf(uint256 id) external view returns (uint256); function getShipInfo(uint256 id) external view returns (ShipInfo memory); function build(uint256 spins_, string calldata name_) external; function upgrade(uint256 id, uint256 spins_) external; function merge(uint256 id1, uint256 id2) external; function scrap(uint256 scavengerId, uint256 targetId) external; function service(uint256 id) external; function rename(uint256 id, string calldata name_) external; function isApprovedOrOwner(address spender, uint256 id) external view returns (bool); }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.17; uint16 constant VRF_MIN_BLOCKS = 3; uint32 constant VRF_GAS_LIMIT = 300000; uint256 constant SPINS_PRECISION = 1e18; uint256 constant GENESIS_SUPPLY = 2000; uint256 constant ASTEROID_COORD_PRECISION = 1e3; int256 constant ASTEROID_COORD_NEG_FLAG = 1e3;
// SPDX-License-Identifier: MIT pragma solidity ^0.8.17; import "@openzeppelin/contracts/Interfaces/IERC1363.sol"; /// @title ERC20 with entity-based ownership and allowances. /// @author boffee /// @author Modified from openzeppelin (https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/token/ERC20/IERC20.sol) interface IERC20Entity is IERC1363 { /** * @dev Emitted when `value` tokens are moved from one entity (`from`) to * another (`to`). * * Note that `value` may be zero. */ event EntityTransfer( uint256 indexed from, uint256 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 EntityApproval( uint256 indexed owner, uint256 indexed spender, uint256 value ); /** * @dev Returns the amount of tokens owned by `entity`. */ function balanceOf(uint256 entity) external view returns (uint256); /** * @dev Moves `amount` tokens from the caller's entity to `to`. * * Returns a boolean value indicating whether the operation succeeded. * * Emits a {EntityTransfer} event. */ function transfer(uint256 to, uint256 amount) external returns (bool); /** * @dev Returns the remaining number of tokens that `spender` will be * allowed to spend on behalf of `owner` through {transferFrom}. This is * zero by default. * * This value changes when {approve} or {transferFrom} are called. */ function allowance(uint256 owner, uint256 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(uint256 spender, uint256 amount) external returns (bool); /** * @dev Moves `amount` tokens from `from` to `to` using the * allowance mechanism. `amount` is then deducted from the caller's * allowance. * * Returns a boolean value indicating whether the operation succeeded. * * Emits a {EntityTransfer} event. */ function transferFrom( uint256 from, uint256 to, uint256 amount ) external returns (bool); }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.17; import "./IERC20Entity.sol"; interface IERC20EntityBurnable is IERC20Entity { function burn(uint256 amount) external; function burnFrom(uint256 entity, uint256 amount) external; function burnFrom(address account, uint256 amount) external; }
// SPDX-License-Identifier: MIT pragma solidity >=0.8.0; import {wadExp, wadLn, wadMul, unsafeWadDiv, unsafeWadMul, toWadUnsafe} from "solmate/utils/SignedWadMath.sol"; /// @title Log Linear Variable Rate Gradual Dutch Auction /// @author boffee /// @author Modified from (https://github.com/transmissions11/VRGDAs/blob/master/src/VRGDA.sol) /// @notice Sell tokens roughly according to an issuance schedule. contract LogLinearVRGDA { /*////////////////////////////////////////////////////////////// VRGDA PARAMETERS //////////////////////////////////////////////////////////////*/ /// @notice Target price for a token, to be scaled according to sales pace. /// @dev Represented as an 18 decimal fixed point number. int256 public immutable targetPrice; /// @dev Precomputed constant that allows us to rewrite a pow() as an exp(). /// @dev Represented as an 18 decimal fixed point number. int256 internal immutable decayConstant; /// @dev The total number of tokens to target selling every full unit of time. /// @dev Represented as an 18 decimal fixed point number. int256 internal immutable perTimeUnit; /// @notice Sets target price and per time unit price decay for the VRGDA. /// @param _targetPrice The target price for a token if sold on pace, scaled by 1e18. /// @param _priceDecayPercent The percent price decays per unit of time with no sales, scaled by 1e18. /// @param _perTimeUnit The number of tokens to target selling in 1 full unit of time, scaled by 1e18. constructor( int256 _targetPrice, int256 _priceDecayPercent, int256 _perTimeUnit ) { targetPrice = _targetPrice; decayConstant = wadLn(1e18 - _priceDecayPercent); // The decay constant must be negative for VRGDAs to work. require(decayConstant < 0, "NON_NEGATIVE_DECAY_CONSTANT"); perTimeUnit = _perTimeUnit; } /*////////////////////////////////////////////////////////////// PRICING LOGIC //////////////////////////////////////////////////////////////*/ function getVRGDAAmountForPrice( int256 timeSinceStart, int256 sold, int256 price ) public view virtual returns (uint256 amount) { amount = uint256( -unsafeWadDiv( wadLn( 1e18 - unsafeWadDiv( unsafeWadMul(price, decayConstant + 1e18), int256(getVRGDAPrice(timeSinceStart, sold)) ) ), decayConstant + 1e18 ) ); } function getVRGDAPrice( int256 timeSinceStart, int256 sold, int256 amount ) public view virtual returns (uint256 price) { price = uint256( wadMul( unsafeWadDiv( int256(getVRGDAPrice(timeSinceStart, sold)), decayConstant + 1e18 ), 1e18 - wadExp(unsafeWadMul(-amount, decayConstant + 1e18)) ) ); } /// @notice Calculate the price of a token according to the VRGDA formula. /// @param timeSinceStart Time passed since the VRGDA began, scaled by 1e18. /// @param sold The total number of tokens that have been sold so far, scaled by 1e18. /// @return The price of a token according to VRGDA, scaled by 1e18. function getVRGDAPrice(int256 timeSinceStart, int256 sold) public view virtual returns (uint256) { unchecked { // prettier-ignore return uint256(wadMul(targetPrice, wadExp(unsafeWadMul(decayConstant, // Theoretically calling toWadUnsafe with sold can silently overflow but under // any reasonable circumstance it will never be large enough. We use sold + 1 as // the VRGDA formula's n param represents the nth token and sold is the n-1th token. timeSinceStart - getTargetSaleTime(sold) )))); } } /// @dev Given a number of tokens sold, return the target time that number of tokens should be sold by. /// @param sold A number of tokens sold, scaled by 1e18, to get the corresponding target sale time for. /// @return The target time the tokens should be sold by, scaled by 1e18, where the time is /// relative, such that 0 means the tokens should be sold immediately when the VRGDA begins. function getTargetSaleTime(int256 sold) public view virtual returns (int256) { return unsafeWadDiv(sold, perTimeUnit); } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.17; struct LocationInfo { int40 xOrigin; int40 yOrigin; int40 xDest; int40 yDest; uint40 speed; uint40 departureTime; bool locked; } interface ISpatialSystem { event UpdateLocation( uint256 indexed entityId, int256 xOrigin, int256 yOrigin, int256 xDest, int256 yDest, uint256 speed, uint256 departureTime ); event Move( uint256 indexed entityId, int256 xOrigin, int256 yOrigin, int256 xDest, int256 yDest, uint256 speed, uint256 departureTime ); event SetLocation( uint256 indexed entityId, int256 xOrigin, int256 yOrigin, int256 xDest, int256 yDest, uint256 speed, uint256 departureTime ); event SetCoordinate(uint256 indexed entityId, int256 x, int256 y); event Locked(uint256 indexed entityId); event Unlocked(uint256 indexed entityId); function coordinate(uint256 entityId) external view returns (int256 x, int256 y); function collocated(uint256 entityId1, uint256 entityId2) external view returns (bool); function collocated( uint256 entityId1, uint256 entityId2, uint256 radius ) external view returns (bool); function getLocationInfo(uint256 entityId) external view returns (LocationInfo memory); function locked(uint256 entityId) external view returns (bool); function updateLocation(uint256 entityId) external; }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.17; import "@openzeppelin/contracts/utils/math/Math.sol"; import "../extensions/IERC20Entity.sol"; struct ExtractorInfo { uint128 shares; int128 rewardDebt; } struct MineInfo { uint128 rewardPerShare; uint64 lastRewardTimestamp; uint64 rewardPerSecond; uint128 totalShares; uint128 totalReward; } /// @title Mining System /// @author boffee /// @author Modified fro MasterChef V2 (https://github.com/sushiswap/sushiswap/blob/master/protocols/masterchef/contracts/MasterChefV2.sol) /// @notice This contract is used to manage mining. contract MiningSystem { event Dock( uint256 indexed extractorId, uint256 indexed mineId, uint256 shares ); event Undock( uint256 indexed extractorId, uint256 indexed mineId, uint256 shares ); event EmergencyUndock( uint256 indexed extractorId, uint256 indexed mineId, uint256 shares ); event Extract( uint256 indexed extractorId, uint256 indexed mineId, uint256 reward ); event AddMine( uint256 indexed mineId, address indexed rewardToken, uint256 rewardPerSecond, uint256 rewardPool ); event SetMine( uint256 indexed mineId, address indexed rewardToken, uint256 rewardPerSecond, uint256 rewardPool ); event UpdateMine( uint256 indexed mineId, uint64 lastRewardTimestamp, uint256 totalShares, uint256 rewardPerShare ); event DestroyMine(uint256 indexed mineId); uint256 public constant REWARD_PER_SHARE_PRECISION = 1e12; /// @notice Info of each mine. mapping(uint256 => MineInfo) private _mineInfos; /// @notice Info of each extractor at each mine. mapping(uint256 => mapping(uint256 => ExtractorInfo)) private _extractorInfos; /// @notice Mine reward token address. mapping(uint256 => IERC20Entity) public rewardTokens; function exists(uint256 mineId) public view returns (bool) { return address(rewardTokens[mineId]) != address(0); } /// @notice View function to see pending reward on frontend. /// @param extractorId Address of extractor. /// @param mineId id of the mine. See `_mineInfos`. /// @return pending reward for a given extractor. function pendingReward(uint256 extractorId, uint256 mineId) external view returns (uint256 pending) { MineInfo memory mineInfo = _mineInfos[mineId]; ExtractorInfo storage extractorInfo = _extractorInfos[mineId][ extractorId ]; uint256 rewardPerShare = mineInfo.rewardPerShare; if ( block.timestamp > mineInfo.lastRewardTimestamp && mineInfo.totalShares != 0 ) { uint256 duration = block.timestamp - mineInfo.lastRewardTimestamp; uint256 reward = Math.min( duration * mineInfo.rewardPerSecond, rewardTokens[mineId].balanceOf(mineId) - mineInfo.totalReward ); // total reward cannot excceed mine balance rewardPerShare += (reward * REWARD_PER_SHARE_PRECISION) / mineInfo.totalShares; } pending = uint256( int256( (extractorInfo.shares * rewardPerShare) / REWARD_PER_SHARE_PRECISION ) - extractorInfo.rewardDebt ); } /// @notice get mine info /// @param mineId id of the mine. See `_mineInfos`. /// @return mineInfo function getMineInfo(uint256 mineId) public view returns (MineInfo memory) { return _mineInfos[mineId]; } /// @notice get extractor info /// @param mineId id of the mine. See `_mineInfos`. /// @param extractorId id of the extractor. See `_extractorInfos`. /// @return extractorInfo function getExtractorInfo(uint256 mineId, uint256 extractorId) public view returns (ExtractorInfo memory) { return _extractorInfos[mineId][extractorId]; } /// @notice Update reward variables for all mines. /// @param mineIds Mine IDs of all to be updated. function massUpdateMines(uint256[] calldata mineIds) external { uint256 len = mineIds.length; for (uint256 i = 0; i < len; ++i) { updateMine(mineIds[i]); } } /// @notice Update reward variables of the given mine. /// @param mineId id of the mine. See `_mineInfos`. /// @return mineInfo Returns the mine that was updated. function updateMine(uint256 mineId) public returns (MineInfo memory mineInfo) { mineInfo = _mineInfos[mineId]; if (block.timestamp > mineInfo.lastRewardTimestamp) { if (mineInfo.totalShares > 0) { uint256 duration = block.timestamp - mineInfo.lastRewardTimestamp; uint256 reward = Math.min( duration * mineInfo.rewardPerSecond, rewardTokens[mineId].balanceOf(mineId) - mineInfo.totalReward ); mineInfo.totalReward += uint128(reward); // total reward cannot excceed mine balance mineInfo.rewardPerShare += uint128( (reward * REWARD_PER_SHARE_PRECISION) / mineInfo.totalShares ); } mineInfo.lastRewardTimestamp = uint64(block.timestamp); _mineInfos[mineId] = mineInfo; emit UpdateMine( mineId, mineInfo.lastRewardTimestamp, mineInfo.totalShares, mineInfo.rewardPerShare ); } } /// @notice Dock extractor to mine for BUTTER allocation. /// @param extractorId The receiver of `shares` dock benefit. /// @param mineId id of the mine. See `_mineInfos`. /// @param shares The amount of shares to be docked. function _dock( uint256 extractorId, uint256 mineId, uint256 shares ) internal { MineInfo memory mineInfo = updateMine(mineId); require( (mineInfo.totalShares * uint256(mineInfo.rewardPerShare)) / REWARD_PER_SHARE_PRECISION < rewardTokens[mineId].balanceOf(mineId), "Mine depleted" ); ExtractorInfo storage extractorInfo = _extractorInfos[mineId][ extractorId ]; // Effects extractorInfo.shares += uint128(shares); extractorInfo.rewardDebt += int128( uint128( (shares * mineInfo.rewardPerShare) / REWARD_PER_SHARE_PRECISION ) ); _mineInfos[mineId].totalShares += uint128(shares); emit Dock(extractorId, mineId, shares); } /// @notice Undock extractor from mine. /// @param extractorId Receiver of the reward. /// @param mineId id of the mine. See `_mineInfos`. /// @param shares Extractor shares to undock. function _undock( uint256 extractorId, uint256 mineId, uint256 shares ) internal { MineInfo memory mineInfo = updateMine(mineId); ExtractorInfo storage extractorInfo = _extractorInfos[mineId][ extractorId ]; // Effects extractorInfo.rewardDebt -= int128( uint128( (shares * mineInfo.rewardPerShare) / REWARD_PER_SHARE_PRECISION ) ); extractorInfo.shares -= uint128(shares); _mineInfos[mineId].totalShares -= uint128(shares); _tryDestroy(mineId); emit Undock(extractorId, mineId, shares); } /// @notice Extract proceeds for extractor. /// @param extractorId Receiver of rewards. /// @param mineId id of the mine. See `_mineInfos`. function _extract(uint256 extractorId, uint256 mineId) internal { MineInfo memory mineInfo = updateMine(mineId); ExtractorInfo storage extractorInfo = _extractorInfos[mineId][ extractorId ]; int256 accumulatedReward = int256( (extractorInfo.shares * uint256(mineInfo.rewardPerShare)) / REWARD_PER_SHARE_PRECISION ); uint256 _pendingReward = uint256( accumulatedReward - extractorInfo.rewardDebt ); // Effects extractorInfo.rewardDebt = int128(accumulatedReward); _mineInfos[mineId].totalReward -= uint128(_pendingReward); rewardTokens[mineId].transferFrom(mineId, extractorId, _pendingReward); _tryDestroy(mineId); emit Extract(extractorId, mineId, _pendingReward); } /// @notice Undock extractor from mine and extract proceeds. /// @param extractorId Receiver of the rewards. /// @param mineId id of the mine. See `_mineInfos`. /// @param shares Extractor shares to undock. function _undockAndExtract( uint256 extractorId, uint256 mineId, uint256 shares ) internal { MineInfo memory mineInfo = updateMine(mineId); ExtractorInfo storage extractorInfo = _extractorInfos[mineId][ extractorId ]; int256 accumulatedReward = int256( (extractorInfo.shares * uint256(mineInfo.rewardPerShare)) / REWARD_PER_SHARE_PRECISION ); uint256 _pendingReward = uint256( accumulatedReward - extractorInfo.rewardDebt ); // Effects extractorInfo.rewardDebt = int128( accumulatedReward - int256( (shares * mineInfo.rewardPerShare) / REWARD_PER_SHARE_PRECISION ) ); extractorInfo.shares -= uint128(shares); _mineInfos[mineId].totalShares -= uint128(shares); _mineInfos[mineId].totalReward -= uint128(_pendingReward); rewardTokens[mineId].transferFrom(mineId, extractorId, _pendingReward); _tryDestroy(mineId); emit Undock(extractorId, mineId, shares); emit Extract(extractorId, mineId, _pendingReward); } /// @notice Undock without caring about rewards. EMERGENCY ONLY. /// @param extractorId Receiver of the reward. /// @param mineId id of the mine. See `_mineInfos`. function _emergencyUndock(uint256 extractorId, uint256 mineId) internal { ExtractorInfo storage extractorInfo = _extractorInfos[mineId][ extractorId ]; uint256 shares = extractorInfo.shares; if (_mineInfos[mineId].totalShares >= shares) { _mineInfos[mineId].totalShares -= uint128(shares); } delete _extractorInfos[mineId][extractorId]; emit EmergencyUndock(extractorId, mineId, shares); } /// @notice Add a new mine. /// @param mineId The id of the mine. /// @param rewardToken The address of the reward token. /// @param rewardPerSecond reward rate of the new mine. function _add( uint256 mineId, address rewardToken, uint256 rewardPerSecond ) internal { require( _mineInfos[mineId].lastRewardTimestamp == 0, "Mine already exists" ); _mineInfos[mineId] = MineInfo({ rewardPerSecond: uint64(rewardPerSecond), lastRewardTimestamp: uint64(block.timestamp), rewardPerShare: 0, totalShares: 0, totalReward: 0 }); rewardTokens[mineId] = IERC20Entity(rewardToken); emit AddMine( mineId, rewardToken, rewardPerSecond, IERC20Entity(rewardToken).balanceOf(mineId) ); } /// @notice Update the given mine's reward rate. /// @param mineId The entity id of the mine. /// @param rewardPerSecond New reward rate of the mine. function _set(uint256 mineId, uint256 rewardPerSecond) internal { _mineInfos[mineId].rewardPerSecond = uint64(rewardPerSecond); IERC20Entity rewardToken = rewardTokens[mineId]; emit SetMine( mineId, address(rewardToken), rewardPerSecond, rewardToken.balanceOf(mineId) ); } /// @notice Destroy the given mine if its depleted and has no shares. /// @param mineId The entity id of the mine. function _tryDestroy(uint256 mineId) internal { if ( rewardTokens[mineId].balanceOf(mineId) < 1e15 && _mineInfos[mineId].totalShares < 1e15 ) { _destroy(mineId); } } /// @notice Destroy the given mine. /// @param mineId The entity id of the mine. function _destroy(uint256 mineId) internal { delete _mineInfos[mineId]; delete rewardTokens[mineId]; emit DestroyMine(mineId); } function _destroyExtractor(uint256 mineId, uint256 extractorId) internal { ExtractorInfo memory extractorInfo = _extractorInfos[mineId][ extractorId ]; _mineInfos[mineId].totalShares -= uint128(extractorInfo.shares); _mineInfos[mineId].totalReward -= uint128( uint256( int256( (extractorInfo.shares * uint256(_mineInfos[mineId].rewardPerShare)) / REWARD_PER_SHARE_PRECISION ) - extractorInfo.rewardDebt ) ); delete _extractorInfos[mineId][extractorId]; } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.17; import "@openzeppelin/contracts/token/ERC721/IERC721.sol"; import "../utils/VectorWadMath.sol"; import "../utils/EntityUtils.sol"; import "./ISpatialSystem.sol"; contract SpatialSystem is ISpatialSystem { mapping(uint256 => LocationInfo) private _locationInfos; function coordinate(uint256 entityId) public view virtual override returns (int256 x, int256 y) { return _coordinate(entityId); } function coordinate(address token, uint256 id) public view virtual returns (int256 x, int256 y) { return _coordinate(tokenToEntity(token, id)); } function locked(uint256 entityId) public view virtual override returns (bool) { return _locationInfos[entityId].locked; } function collocated(uint256 entityId1, uint256 entityId2) public view virtual override returns (bool) { (int256 x1, int256 y1) = _coordinate(entityId1); (int256 x2, int256 y2) = _coordinate(entityId2); return x1 == x2 && y1 == y2; } function collocated( uint256 entityId1, uint256 entityId2, uint256 radius ) public view virtual override returns (bool) { (int256 x1, int256 y1) = _coordinate(entityId1); (int256 x2, int256 y2) = _coordinate(entityId2); return VectorWadMath.distance(x1 * 1e18, y1 * 1e18, x2 * 1e18, y2 * 1e18) <= radius * 1e18; } function getLocationInfo(uint256 entityId) public view virtual override returns (LocationInfo memory) { return _locationInfos[entityId]; } function _coordinate(uint256 entityId) internal view virtual returns (int256 x, int256 y) { LocationInfo memory info = _locationInfos[entityId]; // ship is only not moving if it's at its destination if (info.speed == 0) { return (info.xOrigin, info.yOrigin); } uint256 distance = VectorWadMath.distance( info.xOrigin, info.yOrigin, info.xDest, info.yDest ); uint256 distanceTraveled = (block.timestamp - info.departureTime) * info.speed; // reached destination already if (distanceTraveled >= distance) { return (info.xDest, info.yDest); } (x, y) = VectorWadMath.scaleVector( info.xOrigin, info.yOrigin, info.xDest, info.yDest, int256((distanceTraveled * 1e18) / distance) ); } function updateLocation(uint256 entityId) public virtual override { _updateLocation(entityId); } function updateLocation(address token, uint256 id) public virtual { _updateLocation(tokenToEntity(token, id)); } function _move( uint256 entityId, int256 xDest, int256 yDest, uint256 speed ) internal virtual { require(!_locationInfos[entityId].locked, "Locked"); (int256 x, int256 y) = _coordinate(entityId); _locationInfos[entityId] = LocationInfo({ // update origin to current coordinate xOrigin: int40(x), yOrigin: int40(y), // set destination xDest: int40(xDest), yDest: int40(yDest), speed: uint40(speed), departureTime: uint40(block.timestamp), locked: false }); emit Move( entityId, x, y, xDest, yDest, speed, block.timestamp ); } function _updateLocation(uint256 entityId) internal virtual { (int256 x, int256 y) = _coordinate(entityId); LocationInfo memory info = _locationInfos[entityId]; // arrived, so set speed to 0 if ( x == info.xDest && y == info.yDest ) { info.speed = 0; } // update origin to current coordinate info.xOrigin = int40(x); info.yOrigin = int40(y); info.departureTime = uint40(block.timestamp); _locationInfos[entityId] = info; emit UpdateLocation( entityId, x, y, info.xDest, info.yDest, info.speed, block.timestamp ); } function _setLocation( uint256 entityId, LocationInfo memory info ) internal virtual { _locationInfos[entityId] = info; emit SetLocation( entityId, info.xOrigin, info.yOrigin, info.xDest, info.yDest, info.speed, info.departureTime ); } function _setCoordinate( uint256 entityId, int256 x, int256 y ) internal virtual { _locationInfos[entityId] = LocationInfo({ xOrigin: int40(x), yOrigin: int40(y), xDest: int40(x), yDest: int40(y), speed: 0, departureTime: uint40(block.timestamp), locked: false }); emit SetCoordinate(entityId, x, y); } function _lock( uint256 entityId ) internal virtual { require(_locationInfos[entityId].speed == 0, "Moving"); _locationInfos[entityId].locked = true; emit Locked(entityId); } function _unlock( uint256 entityId ) internal virtual { _locationInfos[entityId].locked = false; emit Unlocked(entityId); } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.17; function tokenToEntity(address token, uint256 id) pure returns (uint256) { return (uint256(uint160(token)) << 96) | id; } function entityToToken(uint256 entity) pure returns (address token, uint256 id) { token = address(uint160(entity >> 96)); id = entity & 0xffffffffffffffffffffffff; } function accountToEntity(address account) pure returns (uint256) { return (uint256(uint160(account))); } function entityToAccount(uint256 entity) pure returns (address account) { account = address(uint160(entity)); } function entityIsAccount(uint256 entity) pure returns (bool) { return entity >> 160 == 0; }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.17; import "solmate/utils/SignedWadMath.sol"; function updateEMA( uint256 curr, uint256 update, uint256 weight ) pure returns (uint256) { weight = 1e18 - uint256(wadExp(-int256(weight))); return unsafeUpdateMA(curr, update, weight); } function unsafeUpdateMA( uint256 curr, uint256 update, uint256 weight ) pure returns (uint256) { return (curr * (1e18 - weight) + update * weight) / 1e18; }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.17; import "@openzeppelin/contracts/utils/math/Math.sol"; import "solmate/utils/SignedWadMath.sol"; function wadSigmoid(int256 x) pure returns (uint256) { return uint256(unsafeWadDiv(1e18, 1e18 + wadExp(-x))); } function random(uint256 seed, uint256 max) pure returns (uint256) { return uint256(keccak256(abi.encodePacked(seed))) % max; } function sampleCircle(uint256 seed, uint256 radius) pure returns (int256 x, int256 y) { unchecked { seed = uint256(keccak256(abi.encodePacked(seed))); int256 r = int256(random(seed++, radius)) + 1; int256 xUnit = int256(random(seed++, 2e18)) - 1e18; int256 yUnit = int256(Math.sqrt(1e36 - uint256(xUnit * xUnit))); x = int256((xUnit * r) / 1e18); y = int256((yUnit * r) / 1e18); if (random(seed, 2) == 0) { y = -y; } } } function sampleInvSqrt(uint256 seed, uint256 e) pure returns (uint256) { return wadInvSqrt(random(seed, 1e18), e) / 2; } function wadInvSqrt(uint256 x, uint256 e) pure returns (uint256) { return Math.sqrt(1e54 / (e + x)); }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.17; import "@openzeppelin/contracts/utils/math/SignedMath.sol"; import "@openzeppelin/contracts/utils/math/Math.sol"; library VectorWadMath { using Math for uint256; using SignedMath for int256; int256 constant PRECISION = 1e18; int256 constant PRECISION_UINT = 1e18; function distance( int256 x1, int256 y1, int256 x2, int256 y2 ) internal pure returns (uint256) { return ((x2 - x1).abs()**2 + (y2 - y1).abs()**2).sqrt(); } function unitVector( int256 x1, int256 y1, int256 x2, int256 y2 ) internal pure returns (int256, int256) { int256 dist = int256(distance(x1, y1, x2, y2)); return (((x2 - x1) * PRECISION) / dist, ((y2 - y1) * PRECISION) / dist); } function scaleVector( int256 x1, int256 y1, int256 x2, int256 y2, int256 scale ) internal pure returns (int256, int256) { return ( x1 + ((x2 - x1) * scale) / PRECISION, y1 + ((y2 - y1) * scale) / PRECISION ); } }
{ "remappings": [ "@chainlink/=lib/chainlink/contracts/src/", "@openzeppelin/=lib/openzeppelin-contracts/", "chainlink/=lib/chainlink/integration-tests/contracts/ethereum/src/", "ds-test/=lib/forge-std/lib/ds-test/src/", "forge-std/=lib/forge-std/src/", "miaocraft/=src/", "solmate/=lib/solmate/src/" ], "optimizer": { "enabled": true, "runs": 200 }, "metadata": { "bytecodeHash": "ipfs" }, "outputSelection": { "*": { "*": [ "evm.bytecode", "evm.deployedBytecode", "devdoc", "userdoc", "metadata", "abi" ] } }, "evmVersion": "london", "libraries": {} }
Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
[{"inputs":[{"internalType":"address","name":"vrfCoordinator","type":"address"},{"internalType":"uint256","name":"emissionInterval","type":"uint256"},{"internalType":"uint256","name":"emissionSmoothingInterval","type":"uint256"},{"internalType":"uint256","name":"emissionMultiplier","type":"uint256"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[{"internalType":"address","name":"have","type":"address"},{"internalType":"address","name":"want","type":"address"}],"name":"OnlyCoordinatorCanFulfill","type":"error"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint8","name":"version","type":"uint8"}],"name":"Initialized","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"previousOwner","type":"address"},{"indexed":true,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnershipTransferred","type":"event"},{"inputs":[],"name":"EMISSION_INTERVAL","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"EMISSION_MULTIPLIER","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"EMISSION_SMOOTHING_INTERVAL","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"int256","name":"price","type":"int256"},{"internalType":"int256","name":"balance","type":"int256"}],"name":"_getCompoundedPercentForPrice","outputs":[{"internalType":"int256","name":"logInvPercent","type":"int256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"int256","name":"price","type":"int256"},{"internalType":"int256","name":"balance","type":"int256"}],"name":"_getPercentForPrice","outputs":[{"internalType":"int256","name":"percent","type":"int256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"butter","outputs":[{"internalType":"contract IERC20Resource","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"canEmit","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"emissionMA","outputs":[{"internalType":"uint104","name":"","type":"uint104"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"keyHash_","type":"bytes32"},{"internalType":"uint64","name":"subId_","type":"uint64"}],"name":"forceEmit","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"forceEmit","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"galaxy","outputs":[{"internalType":"contract GenesisGalaxy","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"price","type":"uint256"}],"name":"getAmountForPrice","outputs":[{"internalType":"uint256","name":"amount","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"getPrice","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"int256","name":"sold","type":"int256"}],"name":"getTargetSaleTime","outputs":[{"internalType":"int256","name":"","type":"int256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"int256","name":"timeSinceStart","type":"int256"},{"internalType":"int256","name":"sold","type":"int256"},{"internalType":"int256","name":"price","type":"int256"}],"name":"getVRGDAAmountForPrice","outputs":[{"internalType":"uint256","name":"amount","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"int256","name":"timeSinceStart","type":"int256"},{"internalType":"int256","name":"sold","type":"int256"}],"name":"getVRGDAPrice","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"int256","name":"timeSinceStart","type":"int256"},{"internalType":"int256","name":"sold","type":"int256"},{"internalType":"int256","name":"amount","type":"int256"}],"name":"getVRGDAPrice","outputs":[{"internalType":"uint256","name":"price","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"butter_","type":"address"},{"internalType":"address","name":"galaxy_","type":"address"},{"internalType":"bytes32","name":"keyHash_","type":"bytes32"},{"internalType":"uint64","name":"subId_","type":"uint64"}],"name":"initialize","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"keyHash","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"lastEmissionMAUpdateTimestamp","outputs":[{"internalType":"uint40","name":"","type":"uint40"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"lastEmissionTimestamp","outputs":[{"internalType":"uint40","name":"","type":"uint40"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"to","type":"address"}],"name":"mint","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"requestId","type":"uint256"},{"internalType":"uint256[]","name":"randomWords","type":"uint256[]"}],"name":"rawFulfillRandomWords","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"renounceOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"butter_","type":"address"}],"name":"setButter","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"galaxy_","type":"address"}],"name":"setGalaxy","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"keyHash_","type":"bytes32"}],"name":"setKeyHash","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint64","name":"subId_","type":"uint64"}],"name":"setSubId","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"sold","outputs":[{"internalType":"int104","name":"","type":"int104"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"subId","outputs":[{"internalType":"uint64","name":"","type":"uint64"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"targetPrice","outputs":[{"internalType":"int256","name":"","type":"int256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"withdraw","outputs":[],"stateMutability":"nonpayable","type":"function"}]
Contract Creation Code
6101a06040523480156200001257600080fd5b50604051620022773803806200227783398101604081905262000035916200038f565b6001600160a01b03841660805266038d7ea4c6800060a08190526706f05b59d3b20000670de0b6b3a764000062000077620000718383620003dc565b6200010b565b60c0819052600013620000d15760405162461bcd60e51b815260206004820152601b60248201527f4e4f4e5f4e454741544956455f44454341595f434f4e5354414e54000000000060448201526064015b60405180910390fd5b60e05250620000e290503362000334565b6001600160a01b0390931661018052610100919091526101205261014052426101605262000412565b60008082136200014a5760405162461bcd60e51b815260206004820152600960248201526815539111519253915160ba1b6044820152606401620000c8565b5060606001600160801b03821160071b82811c6001600160401b031060061b1782811c63ffffffff1060051b1782811c61ffff1060041b1782811c60ff10600390811b90911783811c600f1060021b1783811c909110600190811b90911783811c90911017609f81810383019390931b90921c6c465772b2bbbb5f824b15207a3081018102821d6d0388eaa27412d5aca026815d636e018102821d6d0df99ac502031bf953eff472fdcc018102821d6d13cdffb29d51d99322bdff5f2211018102821d6d0a0f742023def783a307a986912e018102821d6d01920d8043ca89b5239253284e42018102821d6c0b7a86d7375468fac667a0a527016c29508e458543d8aa4df2abee7882018202831d6d0139601a2efabe717e604cbb4894018202831d6d02247f7a7b6594320649aa03aba1018202831d6c8c3f38e95a6b1ff2ab1c3b343619018202831d6d02384773bdf1ac5676facced60901901820290921d6cb9a025d814b29c212b8b1a07cd19010260016c0504a838426634cdd8738f543560611b03190105711340daa0d5f769dba1915cef59f0815a550602605f19919091017d0267a36c0c95b3975ab3ee5b203a7614a3f75373f047d803ae7b6687f2b302017d57115e47018c7177eebf7cd370a3356a1b7863008a5ae8028c72b88642840160ae1d90565b600080546001600160a01b038381166201000081810262010000600160b01b0319851617855560405193049190911692909183917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e091a35050565b60008060008060808587031215620003a657600080fd5b84516001600160a01b0381168114620003be57600080fd5b60208601516040870151606090970151919890975090945092505050565b81810360008312801583831316838312821617156200040b57634e487b7160e01b600052601160045260246000fd5b5092915050565b60805160a05160c05160e0516101005161012051610140516101605161018051611da0620004d760003960006118f9015260008181610dee0152610ede01526000818161055b0152818161107601526114c70152600081816103e0015261150201526000818161021001528181610b9e01528181610bd601526114a301526000610b4e01526000818161085201528181610c3901528181610c8b0152610cf501526000818161058f015261082b01526000818161070f01526107510152611da06000f3fe6080604052600436106101f95760003560e01c80638da5cb5b1161010d578063e0e63cc5116100a0578063f2fde38b1161006f578063f2fde38b14610645578063f61f0b3014610665578063f890e58414610685578063fa1f390d146106a5578063fd28c397146106c557600080fd5b8063e0e63cc5146105b1578063e6c643c2146105d6578063e7572230146105eb578063eb1d28bb1461060b57600080fd5b8063d1e120b4116100dc578063d1e120b414610509578063d419c9ee14610529578063d867982b14610549578063dc38679c1461057d57600080fd5b80638da5cb5b1461048557806398544710146104a95780639a5abe9c146104c9578063b7be5dd4146104e957600080fd5b80633e2831fe1161019057806361728f391161015f57806361728f39146104025780636a627842146104185780636d9d33b71461042b578063715018a61461044b578063883184f11461046057600080fd5b80633e2831fe1461034f57806342fca82e1461036f578063437748641461038f57806349c8f6c7146103ce57600080fd5b80632e1a7d4d116101cc5780632e1a7d4d146102cf5780633731a58a146102ef578063388931b91461030f5780633b47b9451461032f57600080fd5b8063013f7d58146101fe57806302c7e7af146102455780630e223619146102725780631fe543e3146102ad575b600080fd5b34801561020a57600080fd5b506102327f000000000000000000000000000000000000000000000000000000000000000081565b6040519081526020015b60405180910390f35b34801561025157600080fd5b5060045461025f90600c0b81565b604051600c9190910b815260200161023c565b34801561027e57600080fd5b5060045461029790600160d01b900464ffffffffff1681565b60405164ffffffffff909116815260200161023c565b3480156102b957600080fd5b506102cd6102c83660046119c9565b610704565b005b3480156102db57600080fd5b506102cd6102ea366004611a93565b610791565b3480156102fb57600080fd5b5061023261030a366004611aac565b610824565b34801561031b57600080fd5b506102cd61032a366004611aeb565b61089e565b34801561033b57600080fd5b5061023261034a366004611a93565b6108f8565b34801561035b57600080fd5b506102cd61036a366004611b17565b610985565b34801561037b57600080fd5b506102cd61038a366004611b49565b6109b1565b34801561039b57600080fd5b506002546103b690600160401b90046001600160a01b031681565b6040516001600160a01b03909116815260200161023c565b3480156103da57600080fd5b506102327f000000000000000000000000000000000000000000000000000000000000000081565b34801561040e57600080fd5b5061023260015481565b6102cd610426366004611b49565b6109db565b34801561043757600080fd5b50610232610446366004611a93565b610b4a565b34801561045757600080fd5b506102cd610b7e565b34801561046c57600080fd5b50610475610b92565b604051901515815260200161023c565b34801561049157600080fd5b506000546201000090046001600160a01b03166103b6565b3480156104b557600080fd5b506102cd6104c4366004611a93565b610c01565b3480156104d557600080fd5b506102326104e4366004611aac565b610c0e565b3480156104f557600080fd5b50610232610504366004611b64565b610c22565b34801561051557600080fd5b50610232610524366004611b64565b610ce1565b34801561053557600080fd5b506003546103b6906001600160a01b031681565b34801561055557600080fd5b506102327f000000000000000000000000000000000000000000000000000000000000000081565b34801561058957600080fd5b506102327f000000000000000000000000000000000000000000000000000000000000000081565b3480156105bd57600080fd5b5060035461029790600160a01b900464ffffffffff1681565b3480156105e257600080fd5b506102cd610d4c565b3480156105f757600080fd5b50610232610606366004611a93565b610d66565b34801561061757600080fd5b5060025461062c9067ffffffffffffffff1681565b60405167ffffffffffffffff909116815260200161023c565b34801561065157600080fd5b506102cd610660366004611b49565b610e58565b34801561067157600080fd5b50610232610680366004611aac565b610ed1565b34801561069157600080fd5b506102cd6106a0366004611b49565b610f1c565b3480156106b157600080fd5b506102cd6106c0366004611b90565b610f55565b3480156106d157600080fd5b506004546106ec90600160681b90046001600160681b031681565b6040516001600160681b03909116815260200161023c565b336001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016146107835760405163073e64fd60e21b81523360048201526001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001660248201526044015b60405180910390fd5b61078d8282611152565b5050565b61079961120c565b604051600090339083908381818185875af1925050503d80600081146107db576040519150601f19603f3d011682016040523d82523d6000602084013e6107e0565b606091505b505090508061078d5760405162461bcd60e51b815260206004820152601060248201526f2a3930b739b332b9103330b4b632b21760811b604482015260640161077a565b60006108957f000000000000000000000000000000000000000000000000000000000000000061089061088b7f000000000000000000000000000000000000000000000000000000000000000061087a87610b4a565b8803670de0b6b3a764000091020590565b61126d565b611416565b90505b92915050565b6108a6610b92565b6108e45760405162461bcd60e51b815260206004820152600f60248201526e10d85b9b9bdd08195b5a5d081e595d608a1b604482015260640161077a565b6108ee600061143b565b61078d828261156c565b6003546040516370a0823160e01b815230600482015260009182916001600160a01b03909116906370a0823190602401602060405180830381865afa158015610945573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906109699190611bdd565b905061097e6109788483610c0e565b82611416565b9392505050565b61098d61120c565b6002805467ffffffffffffffff191667ffffffffffffffff92909216919091179055565b6109b961120c565b600380546001600160a01b0319166001600160a01b0392909216919091179055565b6003546040516370a0823160e01b81523060048201526000916001600160a01b0316906370a0823190602401602060405180830381865afa158015610a24573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610a489190611bdd565b90506000610a563483610ed1565b600480549192508291600090610a70908490600c0b611c0c565b82546001600160681b039182166101009390930a9283029190920219909116179055506003546001600160a01b031663a9059cbb84610ab7610ab185611596565b86611416565b6040516001600160e01b031960e085901b1681526001600160a01b03909216600483015260248201526044016020604051808303816000875af1158015610b02573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610b269190611c45565b50610b303461143b565b610b38610b92565b15610b4557610b456115b6565b505050565b60007f0000000000000000000000000000000000000000000000000000000000000000670de0b6b3a7640000830205610898565b610b8661120c565b610b9060006115d0565b565b600354600090610bd1907f000000000000000000000000000000000000000000000000000000000000000090600160a01b900464ffffffffff16611c67565b610bfb7f000000000000000000000000000000000000000000000000000000000000000042611c67565b11905090565b610c0961120c565b600155565b6000610895610c1d8484610ed1565b611596565b6000610cd9610c77610c348686610824565b610c667f0000000000000000000000000000000000000000000000000000000000000000670de0b6b3a7640000611c89565b670de0b6b3a7640000919091020590565b610cc761088b610c8686611cb1565b610cb87f0000000000000000000000000000000000000000000000000000000000000000670de0b6b3a7640000611c89565b670de0b6b3a764000091020590565b61089090670de0b6b3a7640000611ccd565b949350505050565b6000610d43610c34610d2c610d2285610cb87f0000000000000000000000000000000000000000000000000000000000000000670de0b6b3a7640000611c89565b610c668888610824565b610d3e90670de0b6b3a7640000611ccd565b61162b565b610cd990611cb1565b600154600254610b90919067ffffffffffffffff1661089e565b6003546040516370a0823160e01b815230600482015260009182916001600160a01b03909116906370a0823190602401602060405180830381865afa158015610db3573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610dd79190611bdd565b9050670de0b6b3a764000081610e44610e28610e137f000000000000000000000000000000000000000000000000000000000000000042611cf4565b62015180670de0b6b3a7640000919091020490565b600454600c0b610504670de0b6b3a76400008902879005611859565b610e4e9190611d07565b61097e9190611c67565b610e6061120c565b6001600160a01b038116610ec55760405162461bcd60e51b815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201526564647265737360d01b606482015260840161077a565b610ece816115d0565b50565b6000610895610f03610e137f000000000000000000000000000000000000000000000000000000000000000042611cf4565b600454600c0b670de0b6b3a76400008602859005610ce1565b610f2461120c565b600280546001600160a01b03909216600160401b0268010000000000000000600160e01b0319909216919091179055565b600054610100900460ff1615808015610f755750600054600160ff909116105b80610f8f5750303b158015610f8f575060005460ff166001145b610ff25760405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201526d191e481a5b9a5d1a585b1a5e995960921b606482015260840161077a565b6000805460ff191660011790558015611015576000805461ff0019166101001790555b600380546001600160a01b0319166001600160a01b03878116919091179091556002805460018690556001600160e01b031916600160401b9287169290920267ffffffffffffffff19169190911767ffffffffffffffff84161790556110a37f0000000000000000000000000000000000000000000000000000000000000000670de0b6b3a7640000611d1e565b6004805471ffffffffffffffffffffffffffffffffffff60681b1916600160681b6001600160681b03939093169290920264ffffffffff60d01b191691909117600160d01b4264ffffffffff16021790556110fc6115b6565b611105336115d0565b801561114b576000805461ff0019169055604051600181527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a15b5050505050565b600260089054906101000a90046001600160a01b03166001600160a01b031663d88423c08260008151811061118957611189611d41565b60209081029190910101516004805460405160e085901b6001600160e01b03191681526001600160801b0390931691830191909152600160681b90046001600160681b03166024820152604401600060405180830381600087803b1580156111f057600080fd5b505af1158015611204573d6000803e3d6000fd5b505050505050565b6000546001600160a01b0362010000909104163314610b905760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e6572604482015260640161077a565b6000680248ce36a70cb26b3e19821361128857506000919050565b680755bf798b4a1bf1e582126112cf5760405162461bcd60e51b815260206004820152600c60248201526b4558505f4f564552464c4f5760a01b604482015260640161077a565b6503782dace9d9604e83901b059150600060606bb17217f7d1cf79abc9e3b39884821b056001605f1b01901d6bb17217f7d1cf79abc9e3b39881029093036c240c330e9fb2d9cbaf0fd5aafb1981018102606090811d6d0277594991cfc85f6e2461837cd9018202811d6d1a521255e34f6a5061b25ef1c9c319018202811d6db1bbb201f443cf962f1a1d3db4a5018202811d6e02c72388d9f74f51a9331fed693f1419018202811d6e05180bb14799ab47a8a8cb2a527d57016d02d16720577bd19bf614176fe9ea6c10fe68e7fd37d0007b713f765084018402831d9081019084016d01d3967ed30fc4f89c02bab5708119010290911d6e0587f503bb6ea29d25fcb740196450019091026d360d7aeea093263ecc6e0ecb291760621b010574029d9dc38563c32e5c2f6dc192ee70ef65f9978af30260c3939093039290921c92915050565b818102821583820583141761142a57600080fd5b670de0b6b3a7640000900592915050565b60045460009061145990600160d01b900464ffffffffff1642611cf4565b6004805464ffffffffff60d01b1916600160d01b4264ffffffffff16021790559050611486816001611879565b60045490915061154290600160681b90046001600160681b0316827f00000000000000000000000000000000000000000000000000000000000000006114ec7f000000000000000000000000000000000000000000000000000000000000000087611d07565b6114f69190611d07565b6115009190611c67565b7f000000000000000000000000000000000000000000000000000000000000000061153385670de0b6b3a7640000611d07565b61153d9190611c67565b61188f565b6004600d6101000a8154816001600160681b0302191690836001600160681b031602179055505050565b6003805464ffffffffff60a01b1916600160a01b4264ffffffffff160217905561078d82826118bc565b60006115a461088b83611cb1565b61089890670de0b6b3a7640000611ccd565b600154600254610b90919067ffffffffffffffff1661156c565b600080546001600160a01b038381166201000081810262010000600160b01b0319851617855560405193049190911692909183917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e091a35050565b60008082136116685760405162461bcd60e51b815260206004820152600960248201526815539111519253915160ba1b604482015260640161077a565b5060606001600160801b03821160071b82811c67ffffffffffffffff1060061b1782811c63ffffffff1060051b1782811c61ffff1060041b1782811c60ff10600390811b90911783811c600f1060021b1783811c909110600190811b90911783811c90911017609f81810383019390931b90921c6c465772b2bbbb5f824b15207a3081018102821d6d0388eaa27412d5aca026815d636e018102821d6d0df99ac502031bf953eff472fdcc018102821d6d13cdffb29d51d99322bdff5f2211018102821d6d0a0f742023def783a307a986912e018102821d6d01920d8043ca89b5239253284e42018102821d6c0b7a86d7375468fac667a0a527016c29508e458543d8aa4df2abee7882018202831d6d0139601a2efabe717e604cbb4894018202831d6d02247f7a7b6594320649aa03aba1018202831d6c8c3f38e95a6b1ff2ab1c3b343619018202831d6d02384773bdf1ac5676facced60901901820290921d6cb9a025d814b29c212b8b1a07cd190102780a09507084cc699bb0e71ea869ffffffffffffffffffffffff190105711340daa0d5f769dba1915cef59f0815a550602605f19919091017d0267a36c0c95b3975ab3ee5b203a7614a3f75373f047d803ae7b6687f2b302017d57115e47018c7177eebf7cd370a3356a1b7863008a5ae8028c72b88642840160ae1d90565b6000611870610d3e83670de0b6b3a7640000611ccd565b61089890611cb1565b60008183116118885781610895565b5090919050565b600061189d61088b83611cb1565b6118af90670de0b6b3a7640000611cf4565b9150610cd984848461196e565b6040516305d3b1d360e41b81526004810183905267ffffffffffffffff8216602482015260036044820152620493e06064820152600160848201527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031690635d3b1d309060a4016020604051808303816000875af115801561194a573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610b459190611bdd565b6000670de0b6b3a76400006119838385611d07565b61199584670de0b6b3a7640000611cf4565b61199f9087611d07565b6119a99190611d57565b610cd99190611c67565b634e487b7160e01b600052604160045260246000fd5b600080604083850312156119dc57600080fd5b8235915060208084013567ffffffffffffffff808211156119fc57600080fd5b818601915086601f830112611a1057600080fd5b813581811115611a2257611a226119b3565b8060051b604051601f19603f83011681018181108582111715611a4757611a476119b3565b604052918252848201925083810185019189831115611a6557600080fd5b938501935b82851015611a8357843584529385019392850192611a6a565b8096505050505050509250929050565b600060208284031215611aa557600080fd5b5035919050565b60008060408385031215611abf57600080fd5b50508035926020909101359150565b803567ffffffffffffffff81168114611ae657600080fd5b919050565b60008060408385031215611afe57600080fd5b82359150611b0e60208401611ace565b90509250929050565b600060208284031215611b2957600080fd5b61089582611ace565b80356001600160a01b0381168114611ae657600080fd5b600060208284031215611b5b57600080fd5b61089582611b32565b600080600060608486031215611b7957600080fd5b505081359360208301359350604090920135919050565b60008060008060808587031215611ba657600080fd5b611baf85611b32565b9350611bbd60208601611b32565b925060408501359150611bd260608601611ace565b905092959194509250565b600060208284031215611bef57600080fd5b5051919050565b634e487b7160e01b600052601160045260246000fd5b600c81810b9083900b016c7fffffffffffffffffffffffff81136c7fffffffffffffffffffffffff198212171561089857610898611bf6565b600060208284031215611c5757600080fd5b8151801515811461097e57600080fd5b600082611c8457634e487b7160e01b600052601260045260246000fd5b500490565b8082018281126000831280158216821582161715611ca957611ca9611bf6565b505092915050565b6000600160ff1b8201611cc657611cc6611bf6565b5060000390565b8181036000831280158383131683831282161715611ced57611ced611bf6565b5092915050565b8181038181111561089857610898611bf6565b808202811582820484141761089857610898611bf6565b6001600160681b03818116838216028082169190828114611ca957611ca9611bf6565b634e487b7160e01b600052603260045260246000fd5b8082018082111561089857610898611bf656fea26469706673582212201f08db9c31f664397cb493ddc67cfc3002263060a150399693fc0515269fe19964736f6c63430008110033000000000000000000000000271682deb8c4e0901d1a1550ad2e64d568e6990900000000000000000000000000000000000000000000000000000000000151800000000000000000000000000000000000000000000000000000000000278d00000000000000000000000000000000000000000000000000000000000000c350
Deployed Bytecode
0x6080604052600436106101f95760003560e01c80638da5cb5b1161010d578063e0e63cc5116100a0578063f2fde38b1161006f578063f2fde38b14610645578063f61f0b3014610665578063f890e58414610685578063fa1f390d146106a5578063fd28c397146106c557600080fd5b8063e0e63cc5146105b1578063e6c643c2146105d6578063e7572230146105eb578063eb1d28bb1461060b57600080fd5b8063d1e120b4116100dc578063d1e120b414610509578063d419c9ee14610529578063d867982b14610549578063dc38679c1461057d57600080fd5b80638da5cb5b1461048557806398544710146104a95780639a5abe9c146104c9578063b7be5dd4146104e957600080fd5b80633e2831fe1161019057806361728f391161015f57806361728f39146104025780636a627842146104185780636d9d33b71461042b578063715018a61461044b578063883184f11461046057600080fd5b80633e2831fe1461034f57806342fca82e1461036f578063437748641461038f57806349c8f6c7146103ce57600080fd5b80632e1a7d4d116101cc5780632e1a7d4d146102cf5780633731a58a146102ef578063388931b91461030f5780633b47b9451461032f57600080fd5b8063013f7d58146101fe57806302c7e7af146102455780630e223619146102725780631fe543e3146102ad575b600080fd5b34801561020a57600080fd5b506102327f000000000000000000000000000000000000000000000000000000000001518081565b6040519081526020015b60405180910390f35b34801561025157600080fd5b5060045461025f90600c0b81565b604051600c9190910b815260200161023c565b34801561027e57600080fd5b5060045461029790600160d01b900464ffffffffff1681565b60405164ffffffffff909116815260200161023c565b3480156102b957600080fd5b506102cd6102c83660046119c9565b610704565b005b3480156102db57600080fd5b506102cd6102ea366004611a93565b610791565b3480156102fb57600080fd5b5061023261030a366004611aac565b610824565b34801561031b57600080fd5b506102cd61032a366004611aeb565b61089e565b34801561033b57600080fd5b5061023261034a366004611a93565b6108f8565b34801561035b57600080fd5b506102cd61036a366004611b17565b610985565b34801561037b57600080fd5b506102cd61038a366004611b49565b6109b1565b34801561039b57600080fd5b506002546103b690600160401b90046001600160a01b031681565b6040516001600160a01b03909116815260200161023c565b3480156103da57600080fd5b506102327f0000000000000000000000000000000000000000000000000000000000278d0081565b34801561040e57600080fd5b5061023260015481565b6102cd610426366004611b49565b6109db565b34801561043757600080fd5b50610232610446366004611a93565b610b4a565b34801561045757600080fd5b506102cd610b7e565b34801561046c57600080fd5b50610475610b92565b604051901515815260200161023c565b34801561049157600080fd5b506000546201000090046001600160a01b03166103b6565b3480156104b557600080fd5b506102cd6104c4366004611a93565b610c01565b3480156104d557600080fd5b506102326104e4366004611aac565b610c0e565b3480156104f557600080fd5b50610232610504366004611b64565b610c22565b34801561051557600080fd5b50610232610524366004611b64565b610ce1565b34801561053557600080fd5b506003546103b6906001600160a01b031681565b34801561055557600080fd5b506102327f000000000000000000000000000000000000000000000000000000000000c35081565b34801561058957600080fd5b506102327f00000000000000000000000000000000000000000000000000038d7ea4c6800081565b3480156105bd57600080fd5b5060035461029790600160a01b900464ffffffffff1681565b3480156105e257600080fd5b506102cd610d4c565b3480156105f757600080fd5b50610232610606366004611a93565b610d66565b34801561061757600080fd5b5060025461062c9067ffffffffffffffff1681565b60405167ffffffffffffffff909116815260200161023c565b34801561065157600080fd5b506102cd610660366004611b49565b610e58565b34801561067157600080fd5b50610232610680366004611aac565b610ed1565b34801561069157600080fd5b506102cd6106a0366004611b49565b610f1c565b3480156106b157600080fd5b506102cd6106c0366004611b90565b610f55565b3480156106d157600080fd5b506004546106ec90600160681b90046001600160681b031681565b6040516001600160681b03909116815260200161023c565b336001600160a01b037f000000000000000000000000271682deb8c4e0901d1a1550ad2e64d568e6990916146107835760405163073e64fd60e21b81523360048201526001600160a01b037f000000000000000000000000271682deb8c4e0901d1a1550ad2e64d568e699091660248201526044015b60405180910390fd5b61078d8282611152565b5050565b61079961120c565b604051600090339083908381818185875af1925050503d80600081146107db576040519150601f19603f3d011682016040523d82523d6000602084013e6107e0565b606091505b505090508061078d5760405162461bcd60e51b815260206004820152601060248201526f2a3930b739b332b9103330b4b632b21760811b604482015260640161077a565b60006108957f00000000000000000000000000000000000000000000000000038d7ea4c6800061089061088b7ffffffffffffffffffffffffffffffffffffffffffffffffff661724fcda931a261087a87610b4a565b8803670de0b6b3a764000091020590565b61126d565b611416565b90505b92915050565b6108a6610b92565b6108e45760405162461bcd60e51b815260206004820152600f60248201526e10d85b9b9bdd08195b5a5d081e595d608a1b604482015260640161077a565b6108ee600061143b565b61078d828261156c565b6003546040516370a0823160e01b815230600482015260009182916001600160a01b03909116906370a0823190602401602060405180830381865afa158015610945573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906109699190611bdd565b905061097e6109788483610c0e565b82611416565b9392505050565b61098d61120c565b6002805467ffffffffffffffff191667ffffffffffffffff92909216919091179055565b6109b961120c565b600380546001600160a01b0319166001600160a01b0392909216919091179055565b6003546040516370a0823160e01b81523060048201526000916001600160a01b0316906370a0823190602401602060405180830381865afa158015610a24573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610a489190611bdd565b90506000610a563483610ed1565b600480549192508291600090610a70908490600c0b611c0c565b82546001600160681b039182166101009390930a9283029190920219909116179055506003546001600160a01b031663a9059cbb84610ab7610ab185611596565b86611416565b6040516001600160e01b031960e085901b1681526001600160a01b03909216600483015260248201526044016020604051808303816000875af1158015610b02573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610b269190611c45565b50610b303461143b565b610b38610b92565b15610b4557610b456115b6565b505050565b60007f0000000000000000000000000000000000000000000000000de0b6b3a7640000670de0b6b3a7640000830205610898565b610b8661120c565b610b9060006115d0565b565b600354600090610bd1907f000000000000000000000000000000000000000000000000000000000001518090600160a01b900464ffffffffff16611c67565b610bfb7f000000000000000000000000000000000000000000000000000000000001518042611c67565b11905090565b610c0961120c565b600155565b6000610895610c1d8484610ed1565b611596565b6000610cd9610c77610c348686610824565b610c667ffffffffffffffffffffffffffffffffffffffffffffffffff661724fcda931a2670de0b6b3a7640000611c89565b670de0b6b3a7640000919091020590565b610cc761088b610c8686611cb1565b610cb87ffffffffffffffffffffffffffffffffffffffffffffffffff661724fcda931a2670de0b6b3a7640000611c89565b670de0b6b3a764000091020590565b61089090670de0b6b3a7640000611ccd565b949350505050565b6000610d43610c34610d2c610d2285610cb87ffffffffffffffffffffffffffffffffffffffffffffffffff661724fcda931a2670de0b6b3a7640000611c89565b610c668888610824565b610d3e90670de0b6b3a7640000611ccd565b61162b565b610cd990611cb1565b600154600254610b90919067ffffffffffffffff1661089e565b6003546040516370a0823160e01b815230600482015260009182916001600160a01b03909116906370a0823190602401602060405180830381865afa158015610db3573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610dd79190611bdd565b9050670de0b6b3a764000081610e44610e28610e137f0000000000000000000000000000000000000000000000000000000063cefb6742611cf4565b62015180670de0b6b3a7640000919091020490565b600454600c0b610504670de0b6b3a76400008902879005611859565b610e4e9190611d07565b61097e9190611c67565b610e6061120c565b6001600160a01b038116610ec55760405162461bcd60e51b815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201526564647265737360d01b606482015260840161077a565b610ece816115d0565b50565b6000610895610f03610e137f0000000000000000000000000000000000000000000000000000000063cefb6742611cf4565b600454600c0b670de0b6b3a76400008602859005610ce1565b610f2461120c565b600280546001600160a01b03909216600160401b0268010000000000000000600160e01b0319909216919091179055565b600054610100900460ff1615808015610f755750600054600160ff909116105b80610f8f5750303b158015610f8f575060005460ff166001145b610ff25760405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201526d191e481a5b9a5d1a585b1a5e995960921b606482015260840161077a565b6000805460ff191660011790558015611015576000805461ff0019166101001790555b600380546001600160a01b0319166001600160a01b03878116919091179091556002805460018690556001600160e01b031916600160401b9287169290920267ffffffffffffffff19169190911767ffffffffffffffff84161790556110a37f000000000000000000000000000000000000000000000000000000000000c350670de0b6b3a7640000611d1e565b6004805471ffffffffffffffffffffffffffffffffffff60681b1916600160681b6001600160681b03939093169290920264ffffffffff60d01b191691909117600160d01b4264ffffffffff16021790556110fc6115b6565b611105336115d0565b801561114b576000805461ff0019169055604051600181527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a15b5050505050565b600260089054906101000a90046001600160a01b03166001600160a01b031663d88423c08260008151811061118957611189611d41565b60209081029190910101516004805460405160e085901b6001600160e01b03191681526001600160801b0390931691830191909152600160681b90046001600160681b03166024820152604401600060405180830381600087803b1580156111f057600080fd5b505af1158015611204573d6000803e3d6000fd5b505050505050565b6000546001600160a01b0362010000909104163314610b905760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e6572604482015260640161077a565b6000680248ce36a70cb26b3e19821361128857506000919050565b680755bf798b4a1bf1e582126112cf5760405162461bcd60e51b815260206004820152600c60248201526b4558505f4f564552464c4f5760a01b604482015260640161077a565b6503782dace9d9604e83901b059150600060606bb17217f7d1cf79abc9e3b39884821b056001605f1b01901d6bb17217f7d1cf79abc9e3b39881029093036c240c330e9fb2d9cbaf0fd5aafb1981018102606090811d6d0277594991cfc85f6e2461837cd9018202811d6d1a521255e34f6a5061b25ef1c9c319018202811d6db1bbb201f443cf962f1a1d3db4a5018202811d6e02c72388d9f74f51a9331fed693f1419018202811d6e05180bb14799ab47a8a8cb2a527d57016d02d16720577bd19bf614176fe9ea6c10fe68e7fd37d0007b713f765084018402831d9081019084016d01d3967ed30fc4f89c02bab5708119010290911d6e0587f503bb6ea29d25fcb740196450019091026d360d7aeea093263ecc6e0ecb291760621b010574029d9dc38563c32e5c2f6dc192ee70ef65f9978af30260c3939093039290921c92915050565b818102821583820583141761142a57600080fd5b670de0b6b3a7640000900592915050565b60045460009061145990600160d01b900464ffffffffff1642611cf4565b6004805464ffffffffff60d01b1916600160d01b4264ffffffffff16021790559050611486816001611879565b60045490915061154290600160681b90046001600160681b0316827f00000000000000000000000000000000000000000000000000000000000151806114ec7f000000000000000000000000000000000000000000000000000000000000c35087611d07565b6114f69190611d07565b6115009190611c67565b7f0000000000000000000000000000000000000000000000000000000000278d0061153385670de0b6b3a7640000611d07565b61153d9190611c67565b61188f565b6004600d6101000a8154816001600160681b0302191690836001600160681b031602179055505050565b6003805464ffffffffff60a01b1916600160a01b4264ffffffffff160217905561078d82826118bc565b60006115a461088b83611cb1565b61089890670de0b6b3a7640000611ccd565b600154600254610b90919067ffffffffffffffff1661156c565b600080546001600160a01b038381166201000081810262010000600160b01b0319851617855560405193049190911692909183917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e091a35050565b60008082136116685760405162461bcd60e51b815260206004820152600960248201526815539111519253915160ba1b604482015260640161077a565b5060606001600160801b03821160071b82811c67ffffffffffffffff1060061b1782811c63ffffffff1060051b1782811c61ffff1060041b1782811c60ff10600390811b90911783811c600f1060021b1783811c909110600190811b90911783811c90911017609f81810383019390931b90921c6c465772b2bbbb5f824b15207a3081018102821d6d0388eaa27412d5aca026815d636e018102821d6d0df99ac502031bf953eff472fdcc018102821d6d13cdffb29d51d99322bdff5f2211018102821d6d0a0f742023def783a307a986912e018102821d6d01920d8043ca89b5239253284e42018102821d6c0b7a86d7375468fac667a0a527016c29508e458543d8aa4df2abee7882018202831d6d0139601a2efabe717e604cbb4894018202831d6d02247f7a7b6594320649aa03aba1018202831d6c8c3f38e95a6b1ff2ab1c3b343619018202831d6d02384773bdf1ac5676facced60901901820290921d6cb9a025d814b29c212b8b1a07cd190102780a09507084cc699bb0e71ea869ffffffffffffffffffffffff190105711340daa0d5f769dba1915cef59f0815a550602605f19919091017d0267a36c0c95b3975ab3ee5b203a7614a3f75373f047d803ae7b6687f2b302017d57115e47018c7177eebf7cd370a3356a1b7863008a5ae8028c72b88642840160ae1d90565b6000611870610d3e83670de0b6b3a7640000611ccd565b61089890611cb1565b60008183116118885781610895565b5090919050565b600061189d61088b83611cb1565b6118af90670de0b6b3a7640000611cf4565b9150610cd984848461196e565b6040516305d3b1d360e41b81526004810183905267ffffffffffffffff8216602482015260036044820152620493e06064820152600160848201527f000000000000000000000000271682deb8c4e0901d1a1550ad2e64d568e699096001600160a01b031690635d3b1d309060a4016020604051808303816000875af115801561194a573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610b459190611bdd565b6000670de0b6b3a76400006119838385611d07565b61199584670de0b6b3a7640000611cf4565b61199f9087611d07565b6119a99190611d57565b610cd99190611c67565b634e487b7160e01b600052604160045260246000fd5b600080604083850312156119dc57600080fd5b8235915060208084013567ffffffffffffffff808211156119fc57600080fd5b818601915086601f830112611a1057600080fd5b813581811115611a2257611a226119b3565b8060051b604051601f19603f83011681018181108582111715611a4757611a476119b3565b604052918252848201925083810185019189831115611a6557600080fd5b938501935b82851015611a8357843584529385019392850192611a6a565b8096505050505050509250929050565b600060208284031215611aa557600080fd5b5035919050565b60008060408385031215611abf57600080fd5b50508035926020909101359150565b803567ffffffffffffffff81168114611ae657600080fd5b919050565b60008060408385031215611afe57600080fd5b82359150611b0e60208401611ace565b90509250929050565b600060208284031215611b2957600080fd5b61089582611ace565b80356001600160a01b0381168114611ae657600080fd5b600060208284031215611b5b57600080fd5b61089582611b32565b600080600060608486031215611b7957600080fd5b505081359360208301359350604090920135919050565b60008060008060808587031215611ba657600080fd5b611baf85611b32565b9350611bbd60208601611b32565b925060408501359150611bd260608601611ace565b905092959194509250565b600060208284031215611bef57600080fd5b5051919050565b634e487b7160e01b600052601160045260246000fd5b600c81810b9083900b016c7fffffffffffffffffffffffff81136c7fffffffffffffffffffffffff198212171561089857610898611bf6565b600060208284031215611c5757600080fd5b8151801515811461097e57600080fd5b600082611c8457634e487b7160e01b600052601260045260246000fd5b500490565b8082018281126000831280158216821582161715611ca957611ca9611bf6565b505092915050565b6000600160ff1b8201611cc657611cc6611bf6565b5060000390565b8181036000831280158383131683831282161715611ced57611ced611bf6565b5092915050565b8181038181111561089857610898611bf6565b808202811582820484141761089857610898611bf6565b6001600160681b03818116838216028082169190828114611ca957611ca9611bf6565b634e487b7160e01b600052603260045260246000fd5b8082018082111561089857610898611bf656fea26469706673582212201f08db9c31f664397cb493ddc67cfc3002263060a150399693fc0515269fe19964736f6c63430008110033
Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)
000000000000000000000000271682deb8c4e0901d1a1550ad2e64d568e6990900000000000000000000000000000000000000000000000000000000000151800000000000000000000000000000000000000000000000000000000000278d00000000000000000000000000000000000000000000000000000000000000c350
-----Decoded View---------------
Arg [0] : vrfCoordinator (address): 0x271682DEB8C4E0901D1a1550aD2e64D568E69909
Arg [1] : emissionInterval (uint256): 86400
Arg [2] : emissionSmoothingInterval (uint256): 2592000
Arg [3] : emissionMultiplier (uint256): 50000
-----Encoded View---------------
4 Constructor Arguments found :
Arg [0] : 000000000000000000000000271682deb8c4e0901d1a1550ad2e64d568e69909
Arg [1] : 0000000000000000000000000000000000000000000000000000000000015180
Arg [2] : 0000000000000000000000000000000000000000000000000000000000278d00
Arg [3] : 000000000000000000000000000000000000000000000000000000000000c350
Loading...
Loading
Loading...
Loading
Multichain Portfolio | 30 Chains
Chain | Token | Portfolio % | Price | Amount | Value |
---|---|---|---|---|---|
ETH | Ether (ETH) | 100.00% | $3,694.94 | 0.00713047 | $26.35 |
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.