Source Code
More Info
Private Name Tags
ContractCreator
TokenTracker
Latest 25 from a total of 1,469 transactions
| Transaction Hash |
|
Block
|
From
|
To
|
|||||
|---|---|---|---|---|---|---|---|---|---|
| Claim Secondary ... | 4640262 | 596 days ago | IN | 0 ETH | 0.00000906 | ||||
| Claim Grand Priz... | 4640258 | 596 days ago | IN | 0 ETH | 0.00000855 | ||||
| Claim Secondary ... | 4637286 | 596 days ago | IN | 0 ETH | 0.00000826 | ||||
| Claim Secondary ... | 4637282 | 596 days ago | IN | 0 ETH | 0.00000558 | ||||
| Claim Secondary ... | 4637278 | 596 days ago | IN | 0 ETH | 0.00000642 | ||||
| Claim Secondary ... | 4637274 | 596 days ago | IN | 0 ETH | 0.00001006 | ||||
| Claim Secondary ... | 4637270 | 596 days ago | IN | 0 ETH | 0.00000345 | ||||
| Claim Secondary ... | 4637266 | 596 days ago | IN | 0 ETH | 0.00000576 | ||||
| Claim Secondary ... | 4637262 | 596 days ago | IN | 0 ETH | 0.00000445 | ||||
| Close Round | 4637189 | 596 days ago | IN | 0 ETH | 0.00013511 | ||||
| Start New Round | 4637185 | 596 days ago | IN | 0 ETH | 0.0002456 | ||||
| Close Round | 4637173 | 596 days ago | IN | 0 ETH | 0.00013186 | ||||
| Start New Round | 4637170 | 596 days ago | IN | 0 ETH | 0.0002456 | ||||
| Close Round | 4637158 | 596 days ago | IN | 0 ETH | 0.00013186 | ||||
| Start New Round | 4637155 | 596 days ago | IN | 0 ETH | 0.00024559 | ||||
| Close Round | 4637143 | 596 days ago | IN | 0 ETH | 0.00013186 | ||||
| Start New Round | 4637138 | 596 days ago | IN | 0 ETH | 0.0002456 | ||||
| Close Round | 4637126 | 596 days ago | IN | 0 ETH | 0.00010674 | ||||
| Start New Round | 4637122 | 596 days ago | IN | 0 ETH | 0.0002456 | ||||
| Close Round | 4637111 | 596 days ago | IN | 0 ETH | 0.00013186 | ||||
| Start New Round | 4637107 | 596 days ago | IN | 0 ETH | 0.0002456 | ||||
| Close Round | 4637095 | 596 days ago | IN | 0 ETH | 0.00013186 | ||||
| Start New Round | 4637092 | 596 days ago | IN | 0 ETH | 0.0002456 | ||||
| Close Round | 4637080 | 596 days ago | IN | 0 ETH | 0.00013187 | ||||
| Start New Round | 4637077 | 596 days ago | IN | 0 ETH | 0.00024562 |
Latest 25 internal transactions (View All)
Advanced mode:
| Parent Transaction Hash | Block | From | To | |||
|---|---|---|---|---|---|---|
| 4640262 | 596 days ago | 0.00031869 ETH | ||||
| 4640258 | 596 days ago | 0.00102146 ETH | ||||
| 4637286 | 596 days ago | 0.00002122 ETH | ||||
| 4637282 | 596 days ago | 0.00002259 ETH | ||||
| 4637278 | 596 days ago | 0.00002652 ETH | ||||
| 4637274 | 596 days ago | 0.00002888 ETH | ||||
| 4637270 | 596 days ago | 0.00003183 ETH | ||||
| 4637266 | 596 days ago | 0.00006366 ETH | ||||
| 4637262 | 596 days ago | 0.00015934 ETH | ||||
| 4637069 | 596 days ago | 0.0003064 ETH | ||||
| 4637060 | 596 days ago | 0.00131988 ETH | ||||
| 4637026 | 596 days ago | 0.0027194 ETH | ||||
| 4636980 | 596 days ago | 0.00308622 ETH | ||||
| 4636956 | 596 days ago | 0.00024746 ETH | ||||
| 4636939 | 596 days ago | 0.0004084 ETH | ||||
| 4636924 | 596 days ago | 0.00080903 ETH | ||||
| 4636909 | 596 days ago | 0.00040098 ETH | ||||
| 4636891 | 596 days ago | 0.00079524 ETH | ||||
| 4636876 | 596 days ago | 0.00071003 ETH | ||||
| 4636797 | 596 days ago | 0.00144806 ETH | ||||
| 4636781 | 596 days ago | 0.0011349 ETH | ||||
| 4635762 | 596 days ago | 0.00013201 ETH | ||||
| 4635756 | 596 days ago | 0.00006599 ETH | ||||
| 4635712 | 596 days ago | 0.00006508 ETH | ||||
| 4632414 | 596 days ago | 0.00004879 ETH |
Cross-Chain Transactions
Loading...
Loading
Contract Name:
BlastInfiltration
Compiler Version
v0.8.24+commit.e11b9ed9
Optimization Enabled:
Yes with 888888 runs
Other Settings:
paris EvmVersion
Contract Source Code (Solidity Standard Json-Input format)
// SPDX-License-Identifier: MIT
pragma solidity 0.8.24;
import {Infiltration} from "./Infiltration.sol";
import {IBlast, YieldMode, GasMode} from "./interfaces/IBlast.sol";
import {IBlastPoints} from "./interfaces/IBlastPoints.sol";
/**
* @title BlastInfiltration
* @author LooksRare protocol team (👀,💎)
* @notice Survival game on Blast
*/
contract BlastInfiltration is Infiltration {
/**
* @param constructorCalldata Constructor calldata. See IInfiltration.ConstructorCalldata for its key values.
* @param blast Blast precompile
* @param blastPoints Blast points
* @param blastPointsOperator Blast points operator
*/
constructor(
ConstructorCalldata memory constructorCalldata,
address blast,
address blastPoints,
address blastPointsOperator
) Infiltration(constructorCalldata) {
IBlast(blast).configure(YieldMode.CLAIMABLE, GasMode.CLAIMABLE, constructorCalldata.owner);
IBlastPoints(blastPoints).configurePointsOperator(blastPointsOperator);
}
}// 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
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.17; /** * @notice It is emitted if the call recipient is not a contract. */ error NotAContract();
// SPDX-License-Identifier: MIT pragma solidity ^0.8.17; /** * @notice It is emitted if the ETH transfer fails. */ error ETHTransferFail(); /** * @notice It is emitted if the ERC20 approval fails. */ error ERC20ApprovalFail(); /** * @notice It is emitted if the ERC20 transfer fails. */ error ERC20TransferFail(); /** * @notice It is emitted if the ERC20 transferFrom fails. */ error ERC20TransferFromFail(); /** * @notice It is emitted if the ERC721 transferFrom fails. */ error ERC721TransferFromFail(); /** * @notice It is emitted if the ERC1155 safeTransferFrom fails. */ error ERC1155SafeTransferFromFail(); /** * @notice It is emitted if the ERC1155 safeBatchTransferFrom fails. */ error ERC1155SafeBatchTransferFromFail();
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.17;
interface IERC20 {
event Transfer(address indexed from, address indexed to, uint256 value);
event Approval(address indexed owner, address indexed spender, uint256 value);
function totalSupply() external view returns (uint256);
function balanceOf(address account) external view returns (uint256);
function transfer(address to, uint256 amount) external returns (bool);
function allowance(address owner, address spender) external view returns (uint256);
function approve(address spender, uint256 amount) external returns (bool);
function transferFrom(address from, address to, uint256 amount) external returns (bool);
function decimals() external view returns (uint8);
}// SPDX-License-Identifier: MIT
pragma solidity >=0.5.0;
interface IWETH {
function deposit() external payable;
function transfer(address dst, uint256 wad) external returns (bool);
function withdraw(uint256 wad) external;
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.17;
/**
* @title IOwnableTwoSteps
* @author LooksRare protocol team (👀,💎)
*/
interface IOwnableTwoSteps {
/**
* @notice This enum keeps track of the ownership status.
* @param NoOngoingTransfer The default status when the owner is set
* @param TransferInProgress The status when a transfer to a new owner is initialized
* @param RenouncementInProgress The status when a transfer to address(0) is initialized
*/
enum Status {
NoOngoingTransfer,
TransferInProgress,
RenouncementInProgress
}
/**
* @notice This is returned when there is no transfer of ownership in progress.
*/
error NoOngoingTransferInProgress();
/**
* @notice This is returned when the caller is not the owner.
*/
error NotOwner();
/**
* @notice This is returned when there is no renouncement in progress but
* the owner tries to validate the ownership renouncement.
*/
error RenouncementNotInProgress();
/**
* @notice This is returned when the transfer is already in progress but the owner tries
* initiate a new ownership transfer.
*/
error TransferAlreadyInProgress();
/**
* @notice This is returned when there is no ownership transfer in progress but the
* ownership change tries to be approved.
*/
error TransferNotInProgress();
/**
* @notice This is returned when the ownership transfer is attempted to be validated by the
* a caller that is not the potential owner.
*/
error WrongPotentialOwner();
/**
* @notice This is emitted if the ownership transfer is cancelled.
*/
event CancelOwnershipTransfer();
/**
* @notice This is emitted if the ownership renouncement is initiated.
*/
event InitiateOwnershipRenouncement();
/**
* @notice This is emitted if the ownership transfer is initiated.
* @param previousOwner Previous/current owner
* @param potentialOwner Potential/future owner
*/
event InitiateOwnershipTransfer(address previousOwner, address potentialOwner);
/**
* @notice This is emitted when there is a new owner.
*/
event NewOwner(address newOwner);
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.17;
/**
* @title IReentrancyGuard
* @author LooksRare protocol team (👀,💎)
*/
interface IReentrancyGuard {
/**
* @notice This is returned when there is a reentrant call.
*/
error ReentrancyFail();
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.17;
// Interfaces
import {IERC20} from "../interfaces/generic/IERC20.sol";
// Errors
import {ERC20TransferFail, ERC20TransferFromFail} from "../errors/LowLevelErrors.sol";
import {NotAContract} from "../errors/GenericErrors.sol";
/**
* @title LowLevelERC20Transfer
* @notice This contract contains low-level calls to transfer ERC20 tokens.
* @author LooksRare protocol team (👀,💎)
*/
contract LowLevelERC20Transfer {
/**
* @notice Execute ERC20 transferFrom
* @param currency Currency address
* @param from Sender address
* @param to Recipient address
* @param amount Amount to transfer
*/
function _executeERC20TransferFrom(address currency, address from, address to, uint256 amount) internal {
if (currency.code.length == 0) {
revert NotAContract();
}
(bool status, bytes memory data) = currency.call(abi.encodeCall(IERC20.transferFrom, (from, to, amount)));
if (!status) {
revert ERC20TransferFromFail();
}
if (data.length > 0) {
if (!abi.decode(data, (bool))) {
revert ERC20TransferFromFail();
}
}
}
/**
* @notice Execute ERC20 (direct) transfer
* @param currency Currency address
* @param to Recipient address
* @param amount Amount to transfer
*/
function _executeERC20DirectTransfer(address currency, address to, uint256 amount) internal {
if (currency.code.length == 0) {
revert NotAContract();
}
(bool status, bytes memory data) = currency.call(abi.encodeCall(IERC20.transfer, (to, amount)));
if (!status) {
revert ERC20TransferFail();
}
if (data.length > 0) {
if (!abi.decode(data, (bool))) {
revert ERC20TransferFail();
}
}
}
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.17;
// Interfaces
import {IWETH} from "../interfaces/generic/IWETH.sol";
/**
* @title LowLevelWETH
* @notice This contract contains a function to transfer ETH with an option to wrap to WETH.
* If the ETH transfer fails within a gas limit, the amount in ETH is wrapped to WETH and then transferred.
* @author LooksRare protocol team (👀,💎)
*/
contract LowLevelWETH {
/**
* @notice It transfers ETH to a recipient with a specified gas limit.
* If the original transfers fails, it wraps to WETH and transfers the WETH to recipient.
* @param _WETH WETH address
* @param _to Recipient address
* @param _amount Amount to transfer
* @param _gasLimit Gas limit to perform the ETH transfer
*/
function _transferETHAndWrapIfFailWithGasLimit(
address _WETH,
address _to,
uint256 _amount,
uint256 _gasLimit
) internal {
bool status;
assembly {
status := call(_gasLimit, _to, _amount, 0, 0, 0, 0)
}
if (!status) {
IWETH(_WETH).deposit{value: _amount}();
IWETH(_WETH).transfer(_to, _amount);
}
}
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.17;
// Interfaces
import {IOwnableTwoSteps} from "./interfaces/IOwnableTwoSteps.sol";
/**
* @title OwnableTwoSteps
* @notice This contract offers transfer of ownership in two steps with potential owner
* having to confirm the transaction to become the owner.
* Renouncement of the ownership is also a two-step process since the next potential owner is the address(0).
* @author LooksRare protocol team (👀,💎)
*/
abstract contract OwnableTwoSteps is IOwnableTwoSteps {
/**
* @notice Address of the current owner.
*/
address public owner;
/**
* @notice Address of the potential owner.
*/
address public potentialOwner;
/**
* @notice Ownership status.
*/
Status public ownershipStatus;
/**
* @notice Modifier to wrap functions for contracts that inherit this contract.
*/
modifier onlyOwner() {
_onlyOwner();
_;
}
/**
* @notice Constructor
* @param _owner The contract's owner
*/
constructor(address _owner) {
owner = _owner;
emit NewOwner(_owner);
}
/**
* @notice This function is used to cancel the ownership transfer.
* @dev This function can be used for both cancelling a transfer to a new owner and
* cancelling the renouncement of the ownership.
*/
function cancelOwnershipTransfer() external onlyOwner {
Status _ownershipStatus = ownershipStatus;
if (_ownershipStatus == Status.NoOngoingTransfer) {
revert NoOngoingTransferInProgress();
}
if (_ownershipStatus == Status.TransferInProgress) {
delete potentialOwner;
}
delete ownershipStatus;
emit CancelOwnershipTransfer();
}
/**
* @notice This function is used to confirm the ownership renouncement.
*/
function confirmOwnershipRenouncement() external onlyOwner {
if (ownershipStatus != Status.RenouncementInProgress) {
revert RenouncementNotInProgress();
}
delete owner;
delete ownershipStatus;
emit NewOwner(address(0));
}
/**
* @notice This function is used to confirm the ownership transfer.
* @dev This function can only be called by the current potential owner.
*/
function confirmOwnershipTransfer() external {
if (ownershipStatus != Status.TransferInProgress) {
revert TransferNotInProgress();
}
if (msg.sender != potentialOwner) {
revert WrongPotentialOwner();
}
owner = msg.sender;
delete ownershipStatus;
delete potentialOwner;
emit NewOwner(msg.sender);
}
/**
* @notice This function is used to initiate the transfer of ownership to a new owner.
* @param newPotentialOwner New potential owner address
*/
function initiateOwnershipTransfer(address newPotentialOwner) external onlyOwner {
if (ownershipStatus != Status.NoOngoingTransfer) {
revert TransferAlreadyInProgress();
}
ownershipStatus = Status.TransferInProgress;
potentialOwner = newPotentialOwner;
/**
* @dev This function can only be called by the owner, so msg.sender is the owner.
* We don't have to SLOAD the owner again.
*/
emit InitiateOwnershipTransfer(msg.sender, newPotentialOwner);
}
/**
* @notice This function is used to initiate the ownership renouncement.
*/
function initiateOwnershipRenouncement() external onlyOwner {
if (ownershipStatus != Status.NoOngoingTransfer) {
revert TransferAlreadyInProgress();
}
ownershipStatus = Status.RenouncementInProgress;
emit InitiateOwnershipRenouncement();
}
function _onlyOwner() private view {
if (msg.sender != owner) revert NotOwner();
}
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.17;
// Interfaces
import {IReentrancyGuard} from "./interfaces/IReentrancyGuard.sol";
/**
* @title PackableReentrancyGuard
* @notice This contract protects against reentrancy attacks.
* It is adjusted from OpenZeppelin.
* The only difference between this contract and ReentrancyGuard
* is that _status is uint8 instead of uint256 so that it can be
* packed with other contracts' storage variables.
* @author LooksRare protocol team (👀,💎)
*/
abstract contract PackableReentrancyGuard is IReentrancyGuard {
uint8 private _status;
/**
* @notice Modifier to wrap functions to prevent reentrancy calls.
*/
modifier nonReentrant() {
if (_status == 2) {
revert ReentrancyFail();
}
_status = 2;
_;
_status = 1;
}
constructor() {
_status = 1;
}
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.17;
/**
* @title ProtocolFee
* @notice This contract makes it possible for a contract to charge a protocol fee.
* @author LooksRare protocol team (👀,💎)
*/
abstract contract ProtocolFee {
/**
* @dev Emitted when the protocol fee basis points is updated.
*/
event ProtocolFeeBpUpdated(uint16 protocolFeeBp);
/**
* @dev Emitted when the protocol fee recipient is updated.
*/
event ProtocolFeeRecipientUpdated(address protocolFeeRecipient);
/**
* @dev This error is used when the protocol fee basis points is too high
* or when the protocol fee recipient is a zero address.
*/
error ProtocolFee__InvalidValue();
/**
* @notice The maximum protocol fee in basis points, which is 25%.
*/
uint16 public constant MAXIMUM_PROTOCOL_FEE_BP = 2_500;
/**
* @notice The address of the protocol fee recipient.
*/
address public protocolFeeRecipient;
/**
* @notice The protocol fee basis points.
*/
uint16 public protocolFeeBp;
/**
* @dev This function is used to update the protocol fee recipient. It should be overridden
* by the contract that inherits from this contract. The function should be guarded
* by an access control mechanism to prevent unauthorized users from calling it.
* @param _protocolFeeRecipient The address of the protocol fee recipient
*/
function updateProtocolFeeRecipient(address _protocolFeeRecipient) external virtual;
/**
* @dev This function is used to update the protocol fee basis points. It should be overridden
* by the contract that inherits from this contract. The function should be guarded
* by an access control mechanism to prevent unauthorized users from calling it.
* @param _protocolFeeBp The protocol fee basis points
*/
function updateProtocolFeeBp(uint16 _protocolFeeBp) external virtual;
/**
* @param _protocolFeeRecipient The new protocol fee recipient address
*/
function _updateProtocolFeeRecipient(address _protocolFeeRecipient) internal {
if (_protocolFeeRecipient == address(0)) {
revert ProtocolFee__InvalidValue();
}
protocolFeeRecipient = _protocolFeeRecipient;
emit ProtocolFeeRecipientUpdated(_protocolFeeRecipient);
}
/**
* @param _protocolFeeBp The new protocol fee in basis points
*/
function _updateProtocolFeeBp(uint16 _protocolFeeBp) internal {
if (_protocolFeeBp > MAXIMUM_PROTOCOL_FEE_BP) {
revert ProtocolFee__InvalidValue();
}
protocolFeeBp = _protocolFeeBp;
emit ProtocolFeeBpUpdated(_protocolFeeBp);
}
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;
enum TokenType {
ERC20,
ERC721,
ERC1155
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;
// Enums
import {TokenType} from "../enums/TokenType.sol";
/**
* @title ITransferManager
* @author LooksRare protocol team (👀,💎)
*/
interface ITransferManager {
/**
* @notice This struct is only used for transferBatchItemsAcrossCollections.
* @param tokenAddress Token address
* @param tokenType 0 for ERC721, 1 for ERC1155
* @param itemIds Array of item ids to transfer
* @param amounts Array of amounts to transfer
*/
struct BatchTransferItem {
address tokenAddress;
TokenType tokenType;
uint256[] itemIds;
uint256[] amounts;
}
/**
* @notice It is emitted if operators' approvals to transfer NFTs are granted by a user.
* @param user Address of the user
* @param operators Array of operator addresses
*/
event ApprovalsGranted(address user, address[] operators);
/**
* @notice It is emitted if operators' approvals to transfer NFTs are revoked by a user.
* @param user Address of the user
* @param operators Array of operator addresses
*/
event ApprovalsRemoved(address user, address[] operators);
/**
* @notice It is emitted if a new operator is added to the global allowlist.
* @param operator Operator address
*/
event OperatorAllowed(address operator);
/**
* @notice It is emitted if an operator is removed from the global allowlist.
* @param operator Operator address
*/
event OperatorRemoved(address operator);
/**
* @notice It is returned if the operator to approve has already been approved by the user.
*/
error OperatorAlreadyApprovedByUser();
/**
* @notice It is returned if the operator to revoke has not been previously approved by the user.
*/
error OperatorNotApprovedByUser();
/**
* @notice It is returned if the transfer caller is already allowed by the owner.
* @dev This error can only be returned for owner operations.
*/
error OperatorAlreadyAllowed();
/**
* @notice It is returned if the operator to approve is not in the global allowlist defined by the owner.
* @dev This error can be returned if the user tries to grant approval to an operator address not in the
* allowlist or if the owner tries to remove the operator from the global allowlist.
*/
error OperatorNotAllowed();
/**
* @notice It is returned if the transfer caller is invalid.
* For a transfer called to be valid, the operator must be in the global allowlist and
* approved by the 'from' user.
*/
error TransferCallerInvalid();
/**
* @notice This function transfers ERC20 tokens.
* @param tokenAddress Token address
* @param from Sender address
* @param to Recipient address
* @param amount amount
*/
function transferERC20(
address tokenAddress,
address from,
address to,
uint256 amount
) external;
/**
* @notice This function transfers a single item for a single ERC721 collection.
* @param tokenAddress Token address
* @param from Sender address
* @param to Recipient address
* @param itemId Item ID
*/
function transferItemERC721(
address tokenAddress,
address from,
address to,
uint256 itemId
) external;
/**
* @notice This function transfers items for a single ERC721 collection.
* @param tokenAddress Token address
* @param from Sender address
* @param to Recipient address
* @param itemIds Array of itemIds
* @param amounts Array of amounts
*/
function transferItemsERC721(
address tokenAddress,
address from,
address to,
uint256[] calldata itemIds,
uint256[] calldata amounts
) external;
/**
* @notice This function transfers a single item for a single ERC1155 collection.
* @param tokenAddress Token address
* @param from Sender address
* @param to Recipient address
* @param itemId Item ID
* @param amount Amount
*/
function transferItemERC1155(
address tokenAddress,
address from,
address to,
uint256 itemId,
uint256 amount
) external;
/**
* @notice This function transfers items for a single ERC1155 collection.
* @param tokenAddress Token address
* @param from Sender address
* @param to Recipient address
* @param itemIds Array of itemIds
* @param amounts Array of amounts
* @dev It does not allow batch transferring if from = msg.sender since native function should be used.
*/
function transferItemsERC1155(
address tokenAddress,
address from,
address to,
uint256[] calldata itemIds,
uint256[] calldata amounts
) external;
/**
* @notice This function transfers items across an array of tokens that can be ERC20, ERC721 and ERC1155.
* @param items Array of BatchTransferItem
* @param from Sender address
* @param to Recipient address
*/
function transferBatchItemsAcrossCollections(
BatchTransferItem[] calldata items,
address from,
address to
) external;
/**
* @notice This function allows a user to grant approvals for an array of operators.
* Users cannot grant approvals if the operator is not allowed by this contract's owner.
* @param operators Array of operator addresses
* @dev Each operator address must be globally allowed to be approved.
*/
function grantApprovals(address[] calldata operators) external;
/**
* @notice This function allows a user to revoke existing approvals for an array of operators.
* @param operators Array of operator addresses
* @dev Each operator address must be approved at the user level to be revoked.
*/
function revokeApprovals(address[] calldata operators) external;
/**
* @notice This function allows an operator to be added for the shared transfer system.
* Once the operator is allowed, users can grant NFT approvals to this operator.
* @param operator Operator address to allow
* @dev Only callable by owner.
*/
function allowOperator(address operator) external;
/**
* @notice This function allows the user to remove an operator for the shared transfer system.
* @param operator Operator address to remove
* @dev Only callable by owner.
*/
function removeOperator(address operator) external;
/**
* @notice This returns whether the user has approved the operator address.
* The first address is the user and the second address is the operator.
*/
function hasUserApprovedOperator(address user, address operator) external view returns (bool);
}// SPDX-License-Identifier: MIT
pragma solidity 0.8.24;
import {IInfiltration} from "./interfaces/IInfiltration.sol";
import {OwnableTwoSteps} from "@looksrare/contracts-libs/contracts/OwnableTwoSteps.sol";
import {IERC20} from "@looksrare/contracts-libs/contracts/interfaces/generic/IERC20.sol";
import {ProtocolFee} from "@looksrare/contracts-libs/contracts/ProtocolFee.sol";
import {PackableReentrancyGuard} from "@looksrare/contracts-libs/contracts/PackableReentrancyGuard.sol";
import {LowLevelERC20Transfer} from "@looksrare/contracts-libs/contracts/lowLevelCallers/LowLevelERC20Transfer.sol";
import {LowLevelWETH} from "@looksrare/contracts-libs/contracts/lowLevelCallers/LowLevelWETH.sol";
import {ITransferManager} from "@looksrare/contracts-transfer-manager/contracts/interfaces/ITransferManager.sol";
import {VRFCoordinatorV2Interface} from "@chainlink/contracts/src/v0.8/interfaces/VRFCoordinatorV2Interface.sol";
import {VRFConsumerBaseV2} from "@chainlink/contracts/src/v0.8/VRFConsumerBaseV2.sol";
import "erc721a/contracts/ERC721A.sol";
import {UnsafeMathUint256} from "./libraries/UnsafeMathUint256.sol";
// .:^^^^^^:::::::::::::::::::::::::::::::::::::::::::::.
// :~7777!!!77?JJ??????!?YYYYYYYYJ?7~~!!!!!!!!!7???7~~~!~~^:.
// :~!!!~~77JYYYJJYJJJJJ7J5PPPPP55?!!!!!!!7!!~~~~~~!77??7?!7!!~^.
// .^~!!!7JYYYYYYJJJJJJJJJ7Y5PPPY?!!!!!!~~~~~~!7!!~~~~~~!????J??7!!^.
// .:^!!?JYYYYYYYYJJJJJJJYJJ!J55YJ?!!!!!~~~~~~~~~~~!!7!!!!!7!!!!!77?JJ?!~:.
// .:^~?YYYYYYYYYJJJJJJJJJJJJ??YYJ?!!!77!!!!!!!!!!!!!!~~!!!77!!!!!!!!!!!7?J7~:.
// .^~~!~JYYYYYYYYYJJJJJJJJ???~^??7^.........:::::::^^^^!!!!!77!!!!!!!!!!~~!!7?7!^.
// :^!!!!!~~JYYYYYYJJJJJJJ7!~^:::!????~.... ...:::::::::::^^~77!!!!!!!!!~~~!!!77!!^.
// :~77~!7!!~!JYJJJJJJJJJ!^^^^^^^:^JJ???7!^^::::::::..::::::::::::.:~!!!!!~7?!~~~~!!!!~~!^.
// :!?7!!!77!~~JJJJJJJJ?!^^^^^^^^^::J???5PPG##GPPP5555?77!::::::::.....::^!!!J5Y?!~~~~!77~~~!~:
// .:7J?!~!77!~~~!JJJJJ?~^^^^^^^^^^^::~?5##&@@@@@&BGBGPPPP555YJ!^::......:::...^?55YJ?!~~!!!!~~!!!~:
// .^7J?7!!!!!!~~~~JJJJ7~^^^^^^^^^^^^:^J##@@@@@@@@@@@&#GGPPP555PPP55?:...::::::.. :!?JJJJ7!~~!77!~!!~!~:.
// .:!?77!!!!!!~~~~~7JJ7~^^^^^^^^^^^^::~J#@@@@@@@@@@@@@@@#BGP55PPPPPGGGJ^......:::. ^~:^7???7!!!!!!~~!!!~!~:.
// .:!7!~~!!!!!!!~~~~!J7~^^^^^^^^^^^^^::7PB&@@@@@@@@&&B55555YGGPPPPPPGGBBBG7......:::..:^::^!7777!!!!!~~!!!!~!~^.
// .:^~!?J!~!7!!!!!~~~!~~^^~^^^^^:::::::.7PGB&&&&@@@&G?~~~!!!!~~~75GBBBBBBBB#B? ...... .... :~!7!!!!~~!!!!!7!~7?~.
// .:^~!?5PPJ!~!!!!!~!!^::!~!!!^:....... .^JPB&&&&&&&G?~~!!7?JJ7!~^:^!5###&#####P~ :^^: .^!!~~!7777!!!!~7Y5J!.
// .:^~!JY5PPPPY!~~~~!!^. .:^!!^. ::YBB####&&&P~^~!~~~^^^^:::::.^P&&&&&#&&&5 .:!????7!^::. .^!!77777777!~!J5PPY!:
// .:~~~?Y5555PP5Y?~~!!^. .^:..^^^!77?!5BB######B~:^^^::::::::......^#&&&&&&&&5 .:!???????????7!!^::~7?7?77777777?Y555J~.
// .:^~!!7?J??????7!!!7~. .......:^77?JJ!5BBBBBBB#B^:::::....::::::::.~&@@@@&&&&5...^^^^^^^^^^^~^^^^^^:.~7!!~~~~~!!!!!77?7~:.
// .:^~!~!77!!!!!~~~!!!^:..... .::~~:....:^^:?GBBBGPPP5~.....:::::::::::.:7&&&&&&&&&P:::^:^^^^^:. .:. .^~~~~~~~~~~~~~!77!~:.
// .:^~!!!77!!!~~~~~~!!^. .::!77~^:......!Y555555555!:..::::::::::..:?#&&&&&&@@&5!7???????!. :~:.. .^!!~~~~~~~~~~~!!7!~:.
// ..:^~!!7?!!~~~~~~~~!!~:.:^!7!^.:^: .....755PPPPPPGG57:..::::::..:7P#&&&&&&@@@P!7????JJJ!. :^::.:~!!~~~~~~~~!!!!!7!~:..
// .....:^~!!77!~~~~~~~!!!!!^!7!:....^^ .. :?PPGGGGGBBBBPYJ^^^^^^JYG####&&&#&@@G?7????JJJ~. :^:.:!777!!!!!!!!!!!!7!~:.....
// .........:^~!!77!~~~~~~!??JY?!:... .^^ .. :?PGBBBB####&@&######&&&#######&&#P?7????JJ7~. :^:^!?77777777777!!!7!^:.........
// ..........:::^~!!77!!~~~~!JJ5J7!:. .^^. ....~PBB#####&&@@@@@@@@&&########&#J77????J?7: :^^!?77777777??7!!!7!^:::...........
// ..........:::::::^~~!7?7~~~~~7JY7!~~^. .^^. . ^7?G###&&&@@@@@@@@&&######GJY?77????J?7: :!!!J?777777??7!!!!~^:::::::..........
// ..........::::::::^^^^~~?J7!~~~~~??7^757^^. .^^. :7?PBB#&&&&&&&&&&#BBP?7^!777????J?7..~~?5?!????????7!!!!~^^^^::::::::..........
// ..........:::::::^^^^^^^^^!???!~~~~!?77J?:~~^^:^: . .::!JJJJJJJJJJ!^^^:..777??????!~^7J!JY77JJJJ??7!!!!~^^^^^^^^:::::::..........
// .........:::::::^^^^^^~~~~^^^!7J?!!~~~77!^:~~!~~~~:... . .. .::::::::::::::.^777?77??7~~7J5!!7?JJJJ?7!!!!~^^~~~~^^^^^^:::::::.........
// .........:::::::^^^^^~~~~~~!~~^^!JJ?7!~!!!~^^^~~~~!??!^~^.... .. .:::::::::::::::77???Y5Y7~~?Y5YJJJJJJ??7~!!~~~!!~~~~~~^^^^^:::::::.........
// ........::::::^^^^^^~~~~~!!!!!!!~~!??77!!!~~~~:^~~~!?J???7777~^~^~~~~!!~~~~~~~!7JYYP5PG57^!?Y55YYYJJJJ7!!!~~!!!!!!!~~~~~^^^^^^::::::........
// ......:::::::^^^^^~~~~~~!!!!!7777!~~!??7777!~!~^^~!^!??J??????????555PP5555555J?55P5PP57^!?Y55P5YYYJ?!!!~~!7777!!!!!~~~~~~^^^^^:::::::......
// .....:::::::^^^^^~~~~~!!!!!!77777??7~~!???7?777!^~!!7???77???????JY55GG555555Y??5555PY?77JY55PPP5Y?!!!~!7??777777!!!!!~~~~~^^^^^^::::::.....
// ....::::::^^^^^^~~~~~!!!!!77777??????!^^!?YY??!!!^~!777!^!??7!!!!!7Y5PP5YYYYJ7~Y5P55?7?JJY5555PPY7!!^^!??????77777!!!!!~~~~~^^^^^^::::::....
// ...::::::^^^^^~~~~~!!!!!!77777??77!~~~~^:~7JP5J7^~~!!!7!7??!7777?JJ5YYYYPPP5J77555PJ77?JY555PP5J?7~^^~~~~!77??77777!!!!!!~~~~~^^^^^::::::...
// ..::::::^^^^^~~~~~!!!!!777777!!~~~~~!!!!!~^~?5PY7~~!77!!?7!!7????JJ55555555Y?7JP5YJ?7JJY55555Y?7~^~!!!!!~~~~~!!777777!!!!!~~~~~^^^^^::::::..
// ..::::::^^^^~~~~~!!!!!77!!~~~~~~~~7?JJJ?77!^:~?Y5Y!~!7!^7J7~~!7777?YYYYYYYYJ7?55J7JJ7J55555Y?!^:^!77?JJJ?7~~~~~~~~!!77!!!!!~~~~~^^^^^:::::..
// .::::::^^^^^~~~~!!!!!!!^^^^^^~!!7777JJY?77!!~^.^7YY?~^!!^?J7~^^!77?YYYYYYYY7~75Y7JJ?JY555Y?!^:^~!!77?YJJ7777!!~^^^^^^!!!!!!!~~~~^^^^^::::::.
// ::::::^^^^^~~~~~!!!!7!:!!^:^~~!!!7!777?JJ?77!~.::^7JJ7^^~~~????77?Y5PP5P55Y7?5Y?J???Y55Y?!^:::~!77?JJ?777!7!!!~~^:^!!^!7!!!!~~~~~^^^^^::::::
// :::::^^^^^~~~~~!!!!77!:J?!^^^~~~!!!!!777??777~.^^::^7YJ!^^!!77!!7JJY555555J7!!77J??JYY?!^::^^:!777??777!!!!!~~~^^^!?J^!77!!!!~~~~~^^^^^:::::
// :::::^^^^^~~~~!!!!!777~^!???7~^~~~!!!!!777777!.^~~~^^~?J!~^~~~!7??JJ55555Y?77!!???J?~^^:^~~~^:!777777!!!!!~~~^~7???!^~777!!!!!~~~~^^^^^:::::
// ::::^^^^^~~~~~!!!!77777~^^~!??7~^~~~~~!!!!!777!.^!!~!!^^!?7!77!~!?JJ5555YJ7~^7JJJ!~:.:!!~!!^:!777!!!!!~~~~~^~7??!~^^~77777!!!!~~~~~^^^^^::::
// ::::^^^^^~~~~!!!!!7777??7!^^^!??7~^~~~~~~!!!!!!.^~!!7??^.^!????????YPPPPJ~^~7JJ?!^:.^??7!!~^:!!!!!!~~~~~~^~7??!^^^!7??7777!!!!!~~~~^^^^^::::
// ::::^^^^~~~~~!!!!77777777??~^^^~7?7~^~^~~~~!~!~.:!!7!75J::::!7????7?PPP5!^~7777~::::J57!7!!^:!!~!~~~~^~^~7?7~^^^~??77777777!!!!~~~~~^^^^::::
// :::^^^^^~~~~!!!!!~~~^:::^^~7^:^^^~7?7!^^^^~~~~~..!!!77?5J:^^::~7?J?7JPPJ:~77!^::^^:J5?77!!!..~~~~~^^^^!7?7~^^^^~7~^^:::^~~~!!!!!~~~~^^^^^:::
// ::::^^^^~~~~!!!~^^^^~^^^^:.::::^~^:~7??!^::^^^: :~!!!77?5J:^~~::~?JJ?P5~!??~::~~^:J5?77!!!~: :^^^::^!??7~:^~^::::.:^^^^~^^^^~!!!~~~~^^^^::::
// ::::::^^~~~~!!~^^^~~~~^^^^:.::::^~^::~7??!^::::.::!7!!!7?5J^^~!!~^~?YPP?7~^~!!~^^J5?7!!!7!::.::::^!??7~::^~^::::.:^^^^~~~~^^^~!!~~~~^^::::::
// ^^^^~~^^^^~~!~:^^~~!~~~^^^^:.::^~~^^:::^!??!:~!~::^!!!!!7?5J^^~!77~^~??~^~77!~^^J5?7!!!!!^::~!~:!??!^:::^^~~^::.:^^^^~~~!~~^^:~!~~^^^^~~^^^^
// ^^^~~^:^^^^^~:^^~~!!!!!!!~~~^::~^^^^^^:::!J?!^!7!^::~!!!!7?5Y!^~!!7!~^^~!7!!~^!Y5?7!!!!~::^!7!^!?J!:::^^^^^^~::^~~~!!!!!!!~~^^:~^^^^::^~~^^^
// !!~!7^.::^^::.^~~!!!!!77?JJJJ?!~^::^^^^^^~7?~:!!77!^^~~!!!7?J5Y7~^^~!~~!~^^~7Y5J?7!!!~~^^!77!!:~?7~^^^^^^::^~!?JJJJ?77!!!!!~~^.::^^::.^7!~!!
// 777J?:.:^^^...:^~!!!7Y??7?777???!.:^~^^^~!~~!!!!!!7?7~^^^~~!77?JJ??~~~~~~??JJ?77!~~^^^~7?7!!!!!!~~!~^^^~^:.!??7777?7??Y7!!!~^:...^^^:.:?J777
// !!7Y?::!77~:^^:.:^~7J??!!!7^~!!77~.:~7~~~~^^?J?!^^~~!7??!~^^^~~!!7????????7!!~~^^^~!??7!~~^^!?J?^^~~~~7~:.~777~^~~7!!??J7~^:.:^^:~77!::?Y7!!
// !!7Y?::!!~:~?7~^:::^~~7!!7!^~~~7!!~.:~!!~~~^^^~: .:^^^^~~!7!~~~^:^^^^^^^^^^:^~~~!7!~~^^^^:. :~^^^~~~!!~:.~!!7!^~!~~7!7~~^:::^~7?~:~!!::?Y7!!
// ?77?Y7^:^:~!??J?7!^::^~!!!~~~~!!!!~^.:^7?!~~^^^^::.:^^~!!~~~~~~^^^^^^^^^^^^^^~~~~~~!!~^^:.::^^^^~~!?7^:.^~!!!!~~~~!!!~^::^!7?J??!~:^:^7Y?77?
// ??!7YJ^.:^!7???YYJ?7~~^^~~7!!!~~~~~~^::^~7??777!~!^^^^:::^~~~!!!!!!!!!!!!!!!!!!~~~^:::^^^^!~!777??7~^::^~~~~~~!!!7~~^^~~7?JYY???7!^:.^JY7!??
// ??77YJ~.^~!77?JJJYYYYJ7!^^^~!777!!~~~~^::^^~!77????77?7!!~~~~^::::::::::::::::^~~~~!!7?77????77!~^^::^~~~~!!777!~^^^!7JYYYYJJJ?77!~^.~JY77??
// J??77YJ~.^!!!JJ??777??YYJJ7!~^^~!77!~~~~~~~^^^^^~~!7777??????777777777777777777??????7777!~~^^^^^~~~~~~~!77!~^^~!7JJYY??777??JJ!!!^.~JY77??J
// YY?77JY!:^!!!YJ?7!!!~~!!??JYJJ7!~^~~!!!~!!!!7777~~~~^^^~~~~~!777777777777777777!~~~~~^^^~~~~7777!!!!~!!!~~^~!7JJYJ??!!~~!!!7?JY!!!^:!YJ77?YY
// YYJ?77JY!:~!!?Y?7!!!~~~~~~!!7?JYJ?7~^^~~!!!!7????????777777~~~~~~~~~~~~~~~~~~~~~~777777????????7!!!!~~^^~7?JYJ?7!!~~~~~~!!!7?Y?!!~:!YJ77?JYY
// YJYJJ?7?J?^:!!?J?!!!~~~~~~~~~~~!7JJYY?~^^~!!77!7777?????????JJJJJJJJJJJJJJJJJJJJ?????????7777!77!!~^^~?YYJJ7!~~~~~~~~~~~!!!?J?!!:^?J?7?JJYJY
/**
* @title Infiltration
* @author LooksRare protocol team (👀,💎)
* @notice Survival game
*/
contract Infiltration is
IInfiltration,
OwnableTwoSteps,
ERC721A,
VRFConsumerBaseV2,
LowLevelERC20Transfer,
LowLevelWETH,
ProtocolFee,
PackableReentrancyGuard
{
using UnsafeMathUint256 for uint256;
/**
* @notice When the frontrun lock is unlocked, agents can escape or heal.
*/
uint8 private constant FRONTRUN_LOCK__UNLOCKED = 1;
/**
* @notice When the frontrun lock is locked, agents cannot escape or heal.
*/
uint8 private constant FRONTRUN_LOCK__LOCKED = 2;
/**
* @notice When VRF is being requested, agents cannot escape or heal. It unlocks when the randomness is fulfilled.
* @dev frontrunLock is initially set as locked so that agents cannot escape or heal before the game starts.
* It is unlocked when the first round's randomness is fulfilled.
*/
uint8 private frontrunLock = FRONTRUN_LOCK__LOCKED;
/**
* @notice 100% in basis points.
*/
uint256 private constant ONE_HUNDRED_PERCENT_IN_BASIS_POINTS = 10_000;
/**
* @notice 100% in basis points squared.
*/
uint256 private constant ONE_HUNDRED_PERCENT_IN_BASIS_POINTS_SQUARED = 10_000 ** 2;
/**
* @notice The number of secondary prize pool winners. Their entitled shares are based on their placements.
* When the number of active agents is less than or equal to this number, 1 agent is instantly killed
* in each round.
*/
uint256 private constant NUMBER_OF_SECONDARY_PRIZE_POOL_WINNERS = 300;
uint256 private constant PROBABILITY_PRECISION = 100_000_000;
/**
* @notice Max agent supply.
*/
uint256 public immutable MAX_SUPPLY;
/**
* @notice Max mint per address.
*/
uint256 public immutable MAX_MINT_PER_ADDRESS;
/**
* @notice The price of minting 1 agent.
*/
uint256 public immutable PRICE;
/**
* @notice The number of seconds per round.
*/
uint256 public immutable SECONDS_PER_ROUND;
/**
* @notice The percentage of agents to wound per round in basis points.
*/
uint256 public immutable AGENTS_TO_WOUND_PER_ROUND_IN_BASIS_POINTS;
/**
* @notice The number of rounds for agents to be wounded before getting killed.
*/
uint256 public immutable ROUNDS_TO_BE_WOUNDED_BEFORE_DEAD;
/**
* @notice This value is used as the denominator in healProbability.
*/
uint256 private immutable ROUNDS_TO_BE_WOUNDED_BEFORE_DEAD_MINUS_ONE;
/**
* @notice This value is used as the minuend in healProbability.
*/
uint256 private immutable HEAL_PROBABILITY_MINUEND;
/**
* @notice The base cost of healing an agent. The cost increases for each successful heal.
*/
uint256 public immutable HEAL_BASE_COST;
/**
* @notice WETH address.
*/
address private immutable WETH;
/**
* @notice LOOKS address.
*/
address private immutable LOOKS;
/**
* @notice Chainlink VRF key hash.
*/
bytes32 private immutable KEY_HASH;
/**
* @notice Chainlink VRF coordinator.
*/
VRFCoordinatorV2Interface private immutable VRF_COORDINATOR;
/**
* @notice Chainlink VRF subscription ID.
*/
uint64 private immutable SUBSCRIPTION_ID;
/**
* @notice The transfer manager contract that manages LOOKS approvals.
*/
ITransferManager private immutable TRANSFER_MANAGER;
/**
* @notice The timestamp at which the mint period starts.
*/
uint40 public mintStart;
/**
* @notice The timestamp at which the mint period ends.
*/
uint40 public mintEnd;
/**
* @notice The bitmap of the placements of the secondary prize pool winners.
* @dev Only bit 1 to 50 are used. Bit 0 is not used.
*/
uint56 private prizesClaimedBitmap;
/**
* @notice The base URI of the collection.
*/
string private baseURI;
/**
* @notice Amount of agents minted per address.
*/
mapping(address minter => uint256 amount) public amountMintedPerAddress;
/**
* @notice Chainlink randomness requests.
*/
mapping(uint256 requestId => RandomnessRequest) public randomnessRequests;
/**
* @notice The mapping agents acts as an "array". In the beginning of the game, the "length" of the "array"
* is the total supply. As the game progresses, the "length" of the "array" decreases
* as agents are killed. The function agentsAlive() returns the "length" of the "array".
*
* When an Agent struct has 0 value for every field with its index within the total supply,
* it means that the agent is active.
*
* Index 0 is not used as agent ID starts from 1.
*/
mapping(uint256 index => Agent) private agents;
/**
* @notice It is used to find the index of an agent in the agents mapping given its agent ID.
* If the index is 0, it means the agent's index is the same as its agent ID as no swaps
* have been made.
*/
mapping(uint256 agentId => uint256 index) private agentIdToIndex;
address private constant BURN_ADDRESS = 0x000000000000000000000000000000000000dEaD;
/**
* @notice The maximum healing or wounded agents allowed per round.
*/
uint256 private constant MAXIMUM_HEALING_OR_WOUNDED_AGENTS_PER_ROUND = 150;
/**
* @notice The maximum healing or wounded agents allowed per round + 1 for storing the array length.
*/
uint256 private constant MAXIMUM_HEALING_OR_WOUNDED_AGENTS_PER_ROUND_AND_LENGTH = 151;
/**
* @notice The first element of the array is the length of the array.
*/
mapping(uint256 roundId => uint16[MAXIMUM_HEALING_OR_WOUNDED_AGENTS_PER_ROUND_AND_LENGTH] agentIds)
private woundedAgentIdsPerRound;
/**
* @notice The first element of the array is the length of the array.
*/
mapping(uint256 roundId => uint16[MAXIMUM_HEALING_OR_WOUNDED_AGENTS_PER_ROUND_AND_LENGTH] agentIds)
private healingAgentIdsPerRound;
/**
* @notice Game information.
*/
GameInfo public gameInfo;
/**
* @dev Agent struct status offset for bitwise operations.
*/
uint256 private constant AGENT__STATUS_OFFSET = 16;
/**
* @dev Agent struct wounded at offset for bitwise operations.
*/
uint256 private constant AGENT__WOUNDED_AT_OFFSET = 24;
/**
* @dev Agent struct heal count offset for bitwise operations.
*/
uint256 private constant AGENT__HEAL_COUNT_OFFSET = 64;
/**
* @dev GameInfo struct wounded agents offset for bitwise operations.
*/
uint256 private constant GAME_INFO__WOUNDED_AGENTS_OFFSET = 16;
/**
* @dev GameInfo struct healing agents offset for bitwise operations.
*/
uint256 private constant GAME_INFO__HEALING_AGENTS_OFFSET = 32;
/**
* @dev GameInfo struct dead agents offset for bitwise operations.
*/
uint256 private constant GAME_INFO__DEAD_AGENTS_OFFSET = 48;
/**
* @dev GameInfo struct escaped agents offset for bitwise operations.
*/
uint256 private constant GAME_INFO__ESCAPED_AGENTS_OFFSET = 64;
/**
* @dev GameInfo struct current round ID offset for bitwise operations.
*/
uint256 private constant GAME_INFO__CURRENT_ROUND_ID_OFFSET = 80;
/**
* @dev GameInfo struct current round block timestamp offset for bitwise operations.
*/
uint256 private constant GAME_INFO__CURRENT_ROUND_BLOCK_TIMESTAMP_OFFSET = 120;
/**
* @dev RandomnessRequest struct exists offset for bitwise operations.
*/
uint256 private constant RANDOMNESS_REQUESTS__EXISTS_OFFSET = 8;
/**
* @dev 2 bytes bitmask.
*/
uint256 private constant TWO_BYTES_BITMASK = 0xffff;
/**
* @dev 5 bytes bitmask.
*/
uint256 private constant FIVE_BYTES_BITMASK = 0xffffffffff;
/**
* @param constructorCalldata Constructor calldata. See IInfiltration.ConstructorCalldata for its key values.
*/
constructor(
ConstructorCalldata memory constructorCalldata
)
OwnableTwoSteps(constructorCalldata.owner)
ERC721A(constructorCalldata.name, constructorCalldata.symbol)
VRFConsumerBaseV2(constructorCalldata.vrfCoordinator)
{
if (
constructorCalldata.maxSupply <= NUMBER_OF_SECONDARY_PRIZE_POOL_WINNERS ||
constructorCalldata.maxSupply > type(uint16).max
) {
revert InvalidMaxSupply();
}
if (
(constructorCalldata.maxSupply * constructorCalldata.agentsToWoundPerRoundInBasisPoints) >
MAXIMUM_HEALING_OR_WOUNDED_AGENTS_PER_ROUND * ONE_HUNDRED_PERCENT_IN_BASIS_POINTS
) {
revert WoundedAgentIdsPerRoundExceeded();
}
if (constructorCalldata.roundsToBeWoundedBeforeDead < 3) {
revert RoundsToBeWoundedBeforeDeadTooLow();
}
PRICE = constructorCalldata.price;
MAX_SUPPLY = constructorCalldata.maxSupply;
MAX_MINT_PER_ADDRESS = constructorCalldata.maxMintPerAddress;
SECONDS_PER_ROUND = constructorCalldata.secondsPerRound;
AGENTS_TO_WOUND_PER_ROUND_IN_BASIS_POINTS = constructorCalldata.agentsToWoundPerRoundInBasisPoints;
ROUNDS_TO_BE_WOUNDED_BEFORE_DEAD = constructorCalldata.roundsToBeWoundedBeforeDead;
// The next 2 values are used in healProbability
ROUNDS_TO_BE_WOUNDED_BEFORE_DEAD_MINUS_ONE = ROUNDS_TO_BE_WOUNDED_BEFORE_DEAD.unsafeSubtract(1);
HEAL_PROBABILITY_MINUEND =
((ROUNDS_TO_BE_WOUNDED_BEFORE_DEAD * 100 - 70) * PROBABILITY_PRECISION) /
ROUNDS_TO_BE_WOUNDED_BEFORE_DEAD_MINUS_ONE;
LOOKS = constructorCalldata.looks;
HEAL_BASE_COST = constructorCalldata.healBaseCost;
KEY_HASH = constructorCalldata.keyHash;
VRF_COORDINATOR = VRFCoordinatorV2Interface(constructorCalldata.vrfCoordinator);
SUBSCRIPTION_ID = constructorCalldata.subscriptionId;
TRANSFER_MANAGER = ITransferManager(constructorCalldata.transferManager);
WETH = constructorCalldata.weth;
baseURI = constructorCalldata.baseURI;
_updateProtocolFeeRecipient(constructorCalldata.protocolFeeRecipient);
_updateProtocolFeeBp(constructorCalldata.protocolFeeBp);
}
/**
* @dev updateProtocolFeeBp is not implemented in this contract.
*/
function updateProtocolFeeBp(uint16) external pure override {
revert Immutable();
}
/**
* @dev updateProtocolFeeRecipient is not implemented in this contract.
*/
function updateProtocolFeeRecipient(address) external pure override {
revert Immutable();
}
/**
* @inheritdoc IInfiltration
*/
function setMintPeriod(uint40 newMintStart, uint40 newMintEnd) external onlyOwner {
if (newMintStart >= newMintEnd) {
revert InvalidMintPeriod();
}
if (newMintStart != 0) {
if (block.timestamp > newMintStart) {
revert MintStartIsInThePast();
}
uint256 currentMintStart = mintStart;
if (currentMintStart != 0) {
if (block.timestamp >= currentMintStart) {
revert MintAlreadyStarted();
}
}
mintStart = newMintStart;
}
if (block.timestamp > newMintEnd || newMintEnd < mintEnd) {
revert MintCanOnlyBeExtended();
}
mintEnd = newMintEnd;
emit MintPeriodUpdated(newMintStart == 0 ? mintStart : newMintStart, newMintEnd);
}
/**
* @inheritdoc IInfiltration
* @notice As long as the game has not started (after mint end), the owner can still mint.
*/
function premint(address to, uint256 quantity) external payable onlyOwner {
_assertExactNativeTokensSupplied(quantity);
_assertTotalSupplyNotBreached(quantity);
_assertGameNotYetBegun();
_mintERC2309(to, quantity);
}
/**
* @inheritdoc IInfiltration
*/
function mint(uint256 quantity) external payable nonReentrant {
if (block.timestamp < mintStart || block.timestamp > mintEnd) {
revert NotInMintPeriod();
}
_assertGameNotYetBegun();
uint256 amountMinted = amountMintedPerAddress[msg.sender] + quantity;
if (amountMinted > MAX_MINT_PER_ADDRESS) {
revert TooManyMinted();
}
_assertExactNativeTokensSupplied(quantity);
_assertTotalSupplyNotBreached(quantity);
amountMintedPerAddress[msg.sender] = amountMinted;
_mintERC2309(msg.sender, quantity);
}
/**
* @inheritdoc IInfiltration
* @dev If Chainlink randomness callback does not come back after 1 day, we can call
* startNewRound to trigger a new randomness request.
*/
function startGame() external onlyOwner {
uint256 numberOfAgents = totalSupply();
if (numberOfAgents < MAX_SUPPLY) {
if (block.timestamp < mintEnd) {
revert StillMinting();
}
}
if (numberOfAgents < NUMBER_OF_SECONDARY_PRIZE_POOL_WINNERS) {
revert NotEnoughMinted();
}
_assertGameNotYetBegun();
gameInfo.currentRoundId = 1;
gameInfo.activeAgents = uint16(numberOfAgents);
uint256 balance = address(this).balance;
uint256 protocolFee = balance.unsafeMultiply(protocolFeeBp).unsafeDivide(ONE_HUNDRED_PERCENT_IN_BASIS_POINTS);
unchecked {
gameInfo.prizePool = balance - protocolFee;
}
emit RoundStarted(1);
_transferETHAndWrapIfFailWithGasLimit(WETH, protocolFeeRecipient, protocolFee, gasleft());
_requestForRandomness();
}
/**
* @inheritdoc IInfiltration
*/
function emergencyWithdraw() external onlyOwner {
uint256 activeAgents;
uint256 woundedAgents;
uint256 healingAgents;
uint256 escapedAgents;
uint256 deadAgents;
uint256 currentRoundId;
uint256 currentRoundBlockTimestamp;
assembly {
let gameInfoSlot0Value := sload(gameInfo.slot)
activeAgents := and(gameInfoSlot0Value, TWO_BYTES_BITMASK)
woundedAgents := and(shr(GAME_INFO__WOUNDED_AGENTS_OFFSET, gameInfoSlot0Value), TWO_BYTES_BITMASK)
healingAgents := and(shr(GAME_INFO__HEALING_AGENTS_OFFSET, gameInfoSlot0Value), TWO_BYTES_BITMASK)
escapedAgents := and(shr(GAME_INFO__ESCAPED_AGENTS_OFFSET, gameInfoSlot0Value), TWO_BYTES_BITMASK)
deadAgents := and(shr(GAME_INFO__DEAD_AGENTS_OFFSET, gameInfoSlot0Value), TWO_BYTES_BITMASK)
currentRoundId := and(shr(GAME_INFO__CURRENT_ROUND_ID_OFFSET, gameInfoSlot0Value), FIVE_BYTES_BITMASK)
currentRoundBlockTimestamp := and(
shr(GAME_INFO__CURRENT_ROUND_BLOCK_TIMESTAMP_OFFSET, gameInfoSlot0Value),
FIVE_BYTES_BITMASK
)
}
bool conditionOne = currentRoundId != 0 &&
activeAgents + woundedAgents + healingAgents + escapedAgents + deadAgents != totalSupply();
bool conditionTwo = currentRoundId != 0 &&
activeAgents > 1 &&
block.timestamp > currentRoundBlockTimestamp + 36 hours;
// Just in case startGame reverts, we can withdraw the ETH balance and redistribute to addresses that participated in the mint.
bool conditionThree = currentRoundId == 0 && block.timestamp > uint256(mintEnd).unsafeAdd(36 hours);
if (conditionOne || conditionTwo || conditionThree) {
uint256 ethBalance = address(this).balance;
_transferETHAndWrapIfFailWithGasLimit(WETH, msg.sender, ethBalance, gasleft());
uint256 looksBalance = IERC20(LOOKS).balanceOf(address(this));
_executeERC20DirectTransfer(LOOKS, msg.sender, looksBalance);
emit EmergencyWithdrawal(ethBalance, looksBalance);
}
}
/**
* @inheritdoc IInfiltration
* @dev If Chainlink randomness callback does not come back after 1 day, we can try by calling
* startNewRound again.
*/
function startNewRound() external nonReentrant {
uint256 currentRoundId = gameInfo.currentRoundId;
if (currentRoundId == 0) {
revert GameNotYetBegun();
}
if (block.timestamp < uint256(gameInfo.randomnessLastRequestedAt).unsafeAdd(1 days)) {
revert TooEarlyToRetryRandomnessRequest();
}
uint256 agentsRemaining = agentsAlive();
uint256 activeAgents = gameInfo.activeAgents;
if (agentsRemaining == 1) {
if (activeAgents == 1) {
revert GameOver();
}
}
if (activeAgents <= NUMBER_OF_SECONDARY_PRIZE_POOL_WINNERS) {
_assertNotTooEarlyToStartNewRound(SECONDS_PER_ROUND / 3);
uint256 woundedAgents = gameInfo.woundedAgents;
if (woundedAgents != 0) {
uint256 killRoundId = currentRoundId > ROUNDS_TO_BE_WOUNDED_BEFORE_DEAD
? currentRoundId.unsafeSubtract(ROUNDS_TO_BE_WOUNDED_BEFORE_DEAD)
: 1;
uint256 totalDeadAgentsFromKilling;
while (woundedAgentIdsPerRound[killRoundId][0] != 0) {
uint256 deadAgentsFromKilling = _killWoundedAgents({
currentRoundId: currentRoundId,
roundId: killRoundId,
currentRoundAgentsAlive: agentsRemaining
});
unchecked {
totalDeadAgentsFromKilling += deadAgentsFromKilling;
agentsRemaining -= deadAgentsFromKilling;
++killRoundId;
}
}
// This is equivalent to
// unchecked {
// gameInfo.deadAgents += uint16(totalDeadAgentsFromKilling);
// }
// gameInfo.woundedAgents = 0;
assembly {
let gameInfoSlot0Value := sload(gameInfo.slot)
let deadAgents := and(shr(GAME_INFO__DEAD_AGENTS_OFFSET, gameInfoSlot0Value), TWO_BYTES_BITMASK)
gameInfoSlot0Value := and(
gameInfoSlot0Value,
// This is equivalent to
// not(
// or(
// shl(GAME_INFO__WOUNDED_AGENTS_OFFSET, TWO_BYTES_BITMASK),
// shl(GAME_INFO__DEAD_AGENTS_OFFSET, TWO_BYTES_BITMASK)
// )
// )
0xffffffffffffffffffffffffffffffffffffffffffffffff0000ffff0000ffff
)
gameInfoSlot0Value := or(
gameInfoSlot0Value,
shl(GAME_INFO__DEAD_AGENTS_OFFSET, add(deadAgents, totalDeadAgentsFromKilling))
)
sstore(gameInfo.slot, gameInfoSlot0Value)
}
}
if (agentsRemaining > 1) {
_requestForRandomness();
} else {
_emitWonEventIfOnlyOneAgentRemaining(agentsRemaining, activeAgents);
}
} else {
_assertNotTooEarlyToStartNewRound(SECONDS_PER_ROUND);
_requestForRandomness();
}
}
/**
* @inheritdoc IInfiltration
*/
function claimGrandPrize() external nonReentrant {
_assertGameOver();
uint256 agentId = _agentIndexToId(agents[1], 1);
_assertAgentOwnership(agentId);
uint256 prizePool = gameInfo.prizePool;
if (prizePool == 0) {
revert NothingToClaim();
}
gameInfo.prizePool = 0;
_transferETHAndWrapIfFailWithGasLimit(WETH, msg.sender, prizePool, gasleft());
emit PrizeClaimed(agentId, address(0), prizePool);
}
/**
* @inheritdoc IInfiltration
*/
function claimSecondaryPrizes(uint256 agentId) external nonReentrant {
_assertGameOver();
_assertAgentOwnership(agentId);
uint256 placement = agentIndex(agentId);
_assertValidPlacement(placement);
uint56 _prizesClaimedBitmap = prizesClaimedBitmap;
if ((_prizesClaimedBitmap >> placement) & 1 != 0) {
revert NothingToClaim();
}
prizesClaimedBitmap = _prizesClaimedBitmap | uint56(1 << placement);
uint256 ethAmount = secondaryPrizePoolShareAmount(gameInfo.secondaryPrizePool, placement);
if (ethAmount != 0) {
_transferETHAndWrapIfFailWithGasLimit(WETH, msg.sender, ethAmount, gasleft());
emit PrizeClaimed(agentId, address(0), ethAmount);
}
uint256 secondaryLooksPrizePool = gameInfo.secondaryLooksPrizePool;
if (secondaryLooksPrizePool == 0) {
secondaryLooksPrizePool = IERC20(LOOKS).balanceOf(address(this));
if (secondaryLooksPrizePool == 0) {
return;
}
gameInfo.secondaryLooksPrizePool = secondaryLooksPrizePool;
}
uint256 looksAmount = secondaryPrizePoolShareAmount(secondaryLooksPrizePool, placement);
if (looksAmount != 0) {
_executeERC20DirectTransfer(LOOKS, msg.sender, looksAmount);
emit PrizeClaimed(agentId, LOOKS, looksAmount);
}
}
/**
* @inheritdoc IInfiltration
*/
function escape(uint256[] calldata agentIds) external nonReentrant {
_assertFrontrunLockIsOff();
uint256 agentIdsCount = agentIds.length;
_assertNotEmptyAgentIdsArrayProvided(agentIdsCount);
uint256 activeAgents = gameInfo.activeAgents;
uint256 activeAgentsAfterEscape = activeAgents - agentIdsCount;
_assertGameIsNotOverAfterEscape(activeAgentsAfterEscape);
uint256 currentRoundAgentsAlive = agentsAlive();
uint256 prizePool = gameInfo.prizePool;
uint256 secondaryPrizePool = gameInfo.secondaryPrizePool;
uint256 reward;
uint256[] memory rewards = new uint256[](agentIdsCount);
for (uint256 i; i < agentIdsCount; ) {
uint256 agentId = agentIds[i];
_assertAgentOwnership(agentId);
uint256 index = agentIndex(agentId);
_assertAgentStatus(agents[index], agentId, AgentStatus.Active);
uint256 totalEscapeValue = prizePool / currentRoundAgentsAlive;
uint256 rewardForPlayer = (totalEscapeValue * _escapeMultiplier(currentRoundAgentsAlive)) /
ONE_HUNDRED_PERCENT_IN_BASIS_POINTS;
rewards[i] = rewardForPlayer;
reward += rewardForPlayer;
uint256 rewardToSecondaryPrizePool = (totalEscapeValue.unsafeSubtract(rewardForPlayer) *
_escapeRewardSplitForSecondaryPrizePool(currentRoundAgentsAlive)) / ONE_HUNDRED_PERCENT_IN_BASIS_POINTS;
unchecked {
prizePool = prizePool - rewardForPlayer - rewardToSecondaryPrizePool;
}
secondaryPrizePool += rewardToSecondaryPrizePool;
_swap({
currentAgentIndex: index,
lastAgentIndex: currentRoundAgentsAlive,
agentId: agentId,
newStatus: AgentStatus.Escaped
});
unchecked {
--currentRoundAgentsAlive;
++i;
}
}
// This is equivalent to
// unchecked {
// gameInfo.activeAgents = uint16(activeAgentsAfterEscape);
// gameInfo.escapedAgents += uint16(agentIdsCount);
// }
assembly {
let gameInfoSlot0Value := sload(gameInfo.slot)
let escapedAgents := add(
and(shr(GAME_INFO__ESCAPED_AGENTS_OFFSET, gameInfoSlot0Value), TWO_BYTES_BITMASK),
agentIdsCount
)
gameInfoSlot0Value := and(
gameInfoSlot0Value,
// This is the equivalent of not(or(TWO_BYTES_BITMASK, shl(GAME_INFO__ESCAPED_AGENTS_OFFSET, TWO_BYTES_BITMASK)))
0xffffffffffffffffffffffffffffffffffffffffffff0000ffffffffffff0000
)
gameInfoSlot0Value := or(gameInfoSlot0Value, activeAgentsAfterEscape)
gameInfoSlot0Value := or(gameInfoSlot0Value, shl(GAME_INFO__ESCAPED_AGENTS_OFFSET, escapedAgents))
sstore(gameInfo.slot, gameInfoSlot0Value)
}
gameInfo.prizePool = prizePool;
gameInfo.secondaryPrizePool = secondaryPrizePool;
_transferETHAndWrapIfFailWithGasLimit(WETH, msg.sender, reward, gasleft());
emit Escaped(gameInfo.currentRoundId, agentIds, rewards);
_emitWonEventIfOnlyOneAgentRemaining(currentRoundAgentsAlive, activeAgentsAfterEscape);
}
/**
* @inheritdoc IInfiltration
*/
function heal(uint256[] calldata agentIds) external nonReentrant {
_assertFrontrunLockIsOff();
if (gameInfo.activeAgents <= NUMBER_OF_SECONDARY_PRIZE_POOL_WINNERS) {
revert HealingDisabled();
}
uint256 agentIdsCount = agentIds.length;
_assertNotEmptyAgentIdsArrayProvided(agentIdsCount);
uint256 currentRoundId = gameInfo.currentRoundId;
uint16[MAXIMUM_HEALING_OR_WOUNDED_AGENTS_PER_ROUND_AND_LENGTH]
storage healingAgentIds = healingAgentIdsPerRound[currentRoundId];
uint256 currentHealingAgentIdsCount = healingAgentIds[0];
uint256 newHealingAgentIdsCount = currentHealingAgentIdsCount.unsafeAdd(agentIdsCount);
if (newHealingAgentIdsCount > MAXIMUM_HEALING_OR_WOUNDED_AGENTS_PER_ROUND) {
revert MaximumHealingRequestPerRoundExceeded();
}
uint256 cost;
uint256[] memory costs = new uint256[](agentIdsCount);
for (uint256 i; i < agentIdsCount; ) {
uint256 agentId = agentIds[i];
uint256 index = agentIndex(agentId);
_assertAgentStatus(agents[index], agentId, AgentStatus.Wounded);
bytes32 agentSlot = _getAgentStorageSlot(index);
uint256 agentSlotValue;
uint256 woundedAt;
// This is equivalent to
// uint256 woundedAt = agent.woundedAt;
assembly {
agentSlotValue := sload(agentSlot)
woundedAt := and(shr(AGENT__WOUNDED_AT_OFFSET, agentSlotValue), FIVE_BYTES_BITMASK)
}
// This is equivalent to
// healCount = agent.healCount;
// agent.status = AgentStatus.Healing;
uint256 healCount;
assembly {
healCount := and(shr(AGENT__HEAL_COUNT_OFFSET, agentSlotValue), TWO_BYTES_BITMASK)
agentSlotValue := and(
agentSlotValue,
// This is the equivalent of not(shl(AGENT__STATUS_OFFSET, 0xff))
0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ffff
)
agentSlotValue := or(
agentSlotValue,
// AgentStatus.Healing is 2
// This is equivalent to shl(AGENT__STATUS_OFFSET, 2)
0x20000
)
sstore(agentSlot, agentSlotValue)
}
costs[i] = _costToHeal(healCount);
cost += costs[i];
unchecked {
++i;
healingAgentIds[currentHealingAgentIdsCount + i] = uint16(agentId);
}
}
healingAgentIds[0] = uint16(newHealingAgentIdsCount);
// This is equivalent to
// unchecked {
// gameInfo.healingAgents += uint16(agentIdsCount);
// gameInfo.woundedAgents -= uint16(agentIdsCount);
// }
assembly {
let gameInfoSlot0Value := sload(gameInfo.slot)
let healingAgents := add(
and(shr(GAME_INFO__HEALING_AGENTS_OFFSET, gameInfoSlot0Value), TWO_BYTES_BITMASK),
agentIdsCount
)
let woundedAgents := sub(
and(shr(GAME_INFO__WOUNDED_AGENTS_OFFSET, gameInfoSlot0Value), TWO_BYTES_BITMASK),
agentIdsCount
)
gameInfoSlot0Value := and(
gameInfoSlot0Value,
// This is equivalent to
// not(
// or(
// shl(GAME_INFO__HEALING_AGENTS_OFFSET, TWO_BYTES_BITMASK),
// shl(GAME_INFO__WOUNDED_AGENTS_OFFSET, TWO_BYTES_BITMASK)
// )
// )
0xffffffffffffffffffffffffffffffffffffffffffffffffffff00000000ffff
)
gameInfoSlot0Value := or(gameInfoSlot0Value, shl(GAME_INFO__HEALING_AGENTS_OFFSET, healingAgents))
gameInfoSlot0Value := or(gameInfoSlot0Value, shl(GAME_INFO__WOUNDED_AGENTS_OFFSET, woundedAgents))
sstore(gameInfo.slot, gameInfoSlot0Value)
}
TRANSFER_MANAGER.transferERC20(LOOKS, msg.sender, address(this), cost);
_executeERC20DirectTransfer(LOOKS, BURN_ADDRESS, cost / 2);
emit HealRequestSubmitted(currentRoundId, agentIds, costs);
}
/**
* @notice Only active and wounded agents are allowed to be transferred or traded.
* @param from The current owner of the token.
* @param to The new owner of the token.
* @param tokenId The token ID.
*/
function transferFrom(address from, address to, uint256 tokenId) public payable override {
AgentStatus status = agents[agentIndex(tokenId)].status;
if (status > AgentStatus.Wounded && to != BURN_ADDRESS) {
revert InvalidAgentStatus(tokenId, status);
}
super.transferFrom(from, to, tokenId);
}
/**
* @inheritdoc IInfiltration
*/
function getAgent(uint256 index) external view returns (Agent memory agent) {
agent = agents[index];
agent.agentId = uint16(_agentIndexToId(agents[index], index));
}
/**
* @inheritdoc IInfiltration
* @dev Unlike the actual heal function, this function does not revert if duplicated agent IDs are provided.
*/
function costToHeal(uint256[] calldata agentIds) external view returns (uint256 cost) {
uint256 agentIdsCount = agentIds.length;
for (uint256 i; i < agentIdsCount; ) {
uint256 agentId = agentIds[i];
Agent storage agent = agents[agentIndex(agentId)];
_assertAgentStatus(agent, agentId, AgentStatus.Wounded);
cost += _costToHeal(agent.healCount);
unchecked {
++i;
}
}
}
/**
* @inheritdoc IInfiltration
* @dev Unlike the actual escape function, this function does not revert if duplicated agent IDs are provided.
*/
function escapeReward(uint256[] calldata agentIds) external view returns (uint256 reward) {
uint256 agentIdsCount = agentIds.length;
_assertGameIsNotOverAfterEscape(gameInfo.activeAgents - agentIdsCount);
uint256 currentRoundAgentsAlive = agentsAlive();
uint256 prizePool = gameInfo.prizePool;
uint256 secondaryPrizePool = gameInfo.secondaryPrizePool;
for (uint256 i; i < agentIdsCount; ) {
uint256 agentId = agentIds[i];
uint256 index = agentIndex(agentId);
_assertAgentStatus(agents[index], agentId, AgentStatus.Active);
uint256 totalEscapeValue = prizePool / currentRoundAgentsAlive;
uint256 rewardForPlayer = (totalEscapeValue * _escapeMultiplier(currentRoundAgentsAlive)) /
ONE_HUNDRED_PERCENT_IN_BASIS_POINTS;
reward += rewardForPlayer;
uint256 rewardToSecondaryPrizePool = (totalEscapeValue.unsafeSubtract(rewardForPlayer) *
_escapeRewardSplitForSecondaryPrizePool(currentRoundAgentsAlive)) / ONE_HUNDRED_PERCENT_IN_BASIS_POINTS;
secondaryPrizePool += rewardToSecondaryPrizePool;
unchecked {
prizePool = prizePool - rewardForPlayer - rewardToSecondaryPrizePool;
--currentRoundAgentsAlive;
++i;
}
}
}
/**
* @notice
*
* Variables:
* Attempted_Heal_Round - the round at which a user attempts to heal - this is x
* Heal_Rounds_Maximum - the maximum number of rounds after a user is wounded in which they can heal (ROUNDS_TO_BE_WOUNDED_BEFORE_DEAD) - this is x2
* Heal_Rounds_Minimum - the minimum number of rounds after a user is wounded until they can heal (a user cannot heal the same round as wound, so we select one round after wound hence 1) - this is x1
* Maximum_Heal_Percentage - the maximum % chance a user can heal for, this will be if they heal in Heal_Rounds_Minimum (we have set this to 100% of a successful healing) - this is y1
* Minimum_Heal_Percentage - the minimum % chance a user can heal for, this will be if they heal in Heal_Rounds_Maximum (we have set this to 70% of a successful healing) - this is y2
*
* Equation:
* If you substitute all of these into the following equation:
* y = (( x * (y2-y1)) / (x2-x1)) + ((x2 * y1 - x1 * y2) / (x2 - x1))
* You will get an equation for y which is the PercentageChanceToHealSuccessfully given an Attempted_Heal_Round number.
* Explanation:
* i.e if a user is wounded in round 2, and they try to heal in round 4, their Attempted_Heal_Round relative to themselves is 2, hence by subsituting 2 into the place of x in the above equation, their PercentageChanceToHealSuccessfully will be 98.59574468%.
*
* @param healingRoundsDelay The number of rounds elapsed since the agent was wounded.
*/
function healProbability(uint256 healingRoundsDelay) public view returns (uint256 y) {
if (healingRoundsDelay == 0 || healingRoundsDelay > ROUNDS_TO_BE_WOUNDED_BEFORE_DEAD) {
revert InvalidHealingRoundsDelay();
}
y =
HEAL_PROBABILITY_MINUEND -
((healingRoundsDelay * 30) * PROBABILITY_PRECISION) /
ROUNDS_TO_BE_WOUNDED_BEFORE_DEAD_MINUS_ONE;
}
/**
* @notice The formula is 80 - 50 * PercentageOfAgentsRemaining ** 2.
*/
function escapeMultiplier() public view returns (uint256 multiplier) {
multiplier = _escapeMultiplier(agentsAlive());
}
/**
* @notice The formula is the lesser of (9,980 / 99) - (UsersRemaining / TotalUsers) * (8,000 / 99) and 100.
*/
function escapeRewardSplitForSecondaryPrizePool() public view returns (uint256 split) {
split = _escapeRewardSplitForSecondaryPrizePool(agentsAlive());
}
/**
* @notice An agent's secondary prize pool share amount. The formula is 1.31817 * 995 / (placement * 49) - 15 / 49.
* @param secondaryPrizePoolAmount The secondary prize pool amount.
* @param placement The agent's rank in the leaderboard. This is not meant to be called with placement that is not between 1 and NUMBER_OF_SECONDARY_PRIZE_POOL_WINNERS.
*/
function secondaryPrizePoolShareAmount(
uint256 secondaryPrizePoolAmount,
uint256 placement
) public pure returns (uint256 shareAmount) {
shareAmount =
(secondaryPrizePoolAmount * secondaryPrizePoolShareBp(placement)) /
ONE_HUNDRED_PERCENT_IN_BASIS_POINTS;
}
/**
* @notice An agent's secondary prize pool share in basis points. The formula is 162,280 / (placement * 100) - 15 / 100.
* @param placement The agent's rank in the leaderboard. This is not meant to be called with placement that is not between 1 and NUMBER_OF_SECONDARY_PRIZE_POOL_WINNERS.
*/
function secondaryPrizePoolShareBp(uint256 placement) public pure returns (uint256 share) {
share = (162_280_000_000 / (placement * 100) - uint256(15_000_000) / 100) / 1_000_000;
}
/**
* @inheritdoc IInfiltration
*/
function agentsAlive() public view returns (uint256) {
return totalSupply() - gameInfo.deadAgents - gameInfo.escapedAgents;
}
/**
* @inheritdoc IInfiltration
*/
function agentIndex(uint256 agentId) public view returns (uint256 index) {
index = agentIdToIndex[agentId];
if (index == 0) {
index = agentId;
}
}
/**
* @inheritdoc IInfiltration
*/
function getRoundInfo(
uint256 roundId
) external view returns (uint256[] memory woundedAgentIds, uint256[] memory healingAgentIds) {
woundedAgentIds = _buildAgentIdsPerRoundArray(woundedAgentIdsPerRound[roundId]);
healingAgentIds = _buildAgentIdsPerRoundArray(healingAgentIdsPerRound[roundId]);
}
/**
* @param requestId The VRF request ID.
* @param randomWords The random words returned from Chainlink. We only request 1 random word.
*/
function fulfillRandomWords(uint256 requestId, uint256[] memory randomWords) internal override {
RandomnessRequest storage randomnessRequest = randomnessRequests[requestId];
uint256 currentRoundId = gameInfo.currentRoundId;
uint256 randomnessRequestRoundId = randomnessRequest.roundId;
if (
randomnessRequestRoundId != currentRoundId || randomnessRequest.status != RandomnessRequestStatus.Requested
) {
emit InvalidRandomnessFulfillment(requestId, randomnessRequestRoundId, currentRoundId);
return;
}
randomnessRequest.randomWord = randomWords[0];
randomnessRequest.status = RandomnessRequestStatus.Fulfilled;
emit RandomnessFulfilled(randomnessRequest.roundId, requestId);
}
/**
* @inheritdoc IInfiltration
*/
function closeRound(uint256 requestId) external {
uint256 currentRoundId = gameInfo.currentRoundId;
RandomnessRequest storage randomnessRequest = randomnessRequests[requestId];
if (
randomnessRequest.roundId != currentRoundId || randomnessRequest.status != RandomnessRequestStatus.Fulfilled
) {
revert InvalidRandomnessRequestId();
}
uint256 currentRandomWord = randomnessRequest.randomWord;
uint256 currentRoundAgentsAlive = agentsAlive();
uint256 activeAgents = gameInfo.activeAgents;
uint256 healingAgents = gameInfo.healingAgents;
uint256 deadAgentsFromHealing;
if (healingAgents != 0) {
uint256 healedAgents;
(healedAgents, deadAgentsFromHealing, currentRandomWord) = _healRequestFulfilled(
currentRoundId,
currentRoundAgentsAlive,
currentRandomWord
);
unchecked {
currentRoundAgentsAlive -= deadAgentsFromHealing;
activeAgents += healedAgents;
gameInfo.healingAgents = uint16(healingAgents - healedAgents - deadAgentsFromHealing);
}
}
if (activeAgents > NUMBER_OF_SECONDARY_PRIZE_POOL_WINNERS) {
uint256 woundedAgents = _woundRequestFulfilled(
currentRoundId,
currentRoundAgentsAlive,
activeAgents,
currentRandomWord
);
uint256 deadAgentsFromKilling;
if (currentRoundId > ROUNDS_TO_BE_WOUNDED_BEFORE_DEAD) {
deadAgentsFromKilling = _killWoundedAgents({
currentRoundId: currentRoundId,
roundId: currentRoundId.unsafeSubtract(ROUNDS_TO_BE_WOUNDED_BEFORE_DEAD),
currentRoundAgentsAlive: currentRoundAgentsAlive
});
}
// We only need to deduct wounded agents from active agents, dead agents from killing are already inactive.
// This is equivalent to
// unchecked {
// gameInfo.activeAgents = activeAgents - woundedAgents;
// gameInfo.woundedAgents = gameInfo.woundedAgents + woundedAgents - deadAgentsFromKilling;
// gameInfo.deadAgents += (deadAgentsFromHealing + deadAgentsFromKilling);
// }
// SSTORE is called in _incrementRound
uint256 gameInfoSlot0Value;
assembly {
gameInfoSlot0Value := sload(gameInfo.slot)
let currentWoundedAgents := and(
shr(GAME_INFO__WOUNDED_AGENTS_OFFSET, gameInfoSlot0Value),
TWO_BYTES_BITMASK
)
let currentDeadAgents := and(shr(GAME_INFO__DEAD_AGENTS_OFFSET, gameInfoSlot0Value), TWO_BYTES_BITMASK)
gameInfoSlot0Value := and(
gameInfoSlot0Value,
// This is equivalent to
// not(
// or(
// TWO_BYTES_BITMASK,
// or(
// shl(GAME_INFO__WOUNDED_AGENTS_OFFSET, TWO_BYTES_BITMASK),
// shl(GAME_INFO__DEAD_AGENTS_OFFSET, TWO_BYTES_BITMASK)
// )
// )
// )
0xffffffffffffffffffffffffffffffffffffffffffffffff0000ffff00000000
)
gameInfoSlot0Value := or(gameInfoSlot0Value, sub(activeAgents, woundedAgents))
gameInfoSlot0Value := or(
gameInfoSlot0Value,
shl(
GAME_INFO__WOUNDED_AGENTS_OFFSET,
sub(add(currentWoundedAgents, woundedAgents), deadAgentsFromKilling)
)
)
gameInfoSlot0Value := or(
gameInfoSlot0Value,
shl(
GAME_INFO__DEAD_AGENTS_OFFSET,
add(currentDeadAgents, add(deadAgentsFromHealing, deadAgentsFromKilling))
)
)
}
_incrementRound(currentRoundId, gameInfoSlot0Value);
} else {
bool shouldKillOneAgent = activeAgents > 1;
if (shouldKillOneAgent) {
uint256 killedAgentIndex = (currentRandomWord % activeAgents).unsafeAdd(1);
Agent storage agentToKill = agents[killedAgentIndex];
uint256 agentId = _agentIndexToId(agentToKill, killedAgentIndex);
_swap({
currentAgentIndex: killedAgentIndex,
lastAgentIndex: currentRoundAgentsAlive,
agentId: agentId,
newStatus: AgentStatus.Dead
});
uint256[] memory killedAgentId = new uint256[](1);
killedAgentId[0] = agentId;
emit Killed(currentRoundId, killedAgentId);
unchecked {
--activeAgents;
--currentRoundAgentsAlive;
}
}
// This is equivalent to
// unchecked {
// gameInfo.activeAgents = activeAgents;
// gameInfo.deadAgents = gameInfo.deadAgents + deadAgentsFromHealing + 1;
// }
// SSTORE is called in _incrementRound
uint256 gameInfoSlot0Value;
assembly {
gameInfoSlot0Value := sload(gameInfo.slot)
let deadAgents := and(shr(GAME_INFO__DEAD_AGENTS_OFFSET, gameInfoSlot0Value), TWO_BYTES_BITMASK)
gameInfoSlot0Value := and(
gameInfoSlot0Value,
// This is equivalent to not(or(TWO_BYTES_BITMASK, shl(GAME_INFO__DEAD_AGENTS_OFFSET, TWO_BYTES_BITMASK)))
0xffffffffffffffffffffffffffffffffffffffffffffffff0000ffffffff0000
)
gameInfoSlot0Value := or(gameInfoSlot0Value, activeAgents)
// If shouldKillOneAgent is true, then add 1. If false, then add 0.
gameInfoSlot0Value := or(
gameInfoSlot0Value,
shl(GAME_INFO__DEAD_AGENTS_OFFSET, add(add(deadAgents, deadAgentsFromHealing), shouldKillOneAgent))
)
}
_emitWonEventIfOnlyOneAgentRemaining(currentRoundAgentsAlive, activeAgents);
_incrementRound(currentRoundId, gameInfoSlot0Value);
}
frontrunLock = FRONTRUN_LOCK__UNLOCKED;
unchecked {
emit RoundStarted(currentRoundId + 1);
}
}
/**
* @dev This function doesn't check currentRoundId to be <= type(uint40).max but it's fine as
* it's practically impossible to reach this number of rounds.
* @param currentRoundId The current round ID.
* @param gameInfoSlot0Value The value of gameInfo.slot.
*/
function _incrementRound(uint256 currentRoundId, uint256 gameInfoSlot0Value) private {
// This is equivalent to
// unchecked {
// uint256 newRoundId = currentRoundId + 1;
// gameInfo.currentRoundId = newRoundId;
// gameInfo.currentRoundBlockTimestamp = uint40(block.timestamp);
// gameInfo.randomnessLastRequestedAt = 0;
// }
assembly {
gameInfoSlot0Value := and(
gameInfoSlot0Value,
// This is equivalent to
// let gameInfoRandomnessLastRequestedAtOffset := 160
// not(
// or(
// or(
// shl(GAME_INFO__CURRENT_ROUND_ID_OFFSET, FIVE_BYTES_BITMASK),
// shl(GAME_INFO__CURRENT_ROUND_BLOCK_TIMESTAMP_OFFSET, FIVE_BYTES_BITMASK)
// ),
// shl(gameInfoRandomnessLastRequestedAtOffset, FIVE_BYTES_BITMASK)
// )
// )
0xffffffffffffff000000000000000000000000000000ffffffffffffffffffff
)
gameInfoSlot0Value := or(
gameInfoSlot0Value,
shl(GAME_INFO__CURRENT_ROUND_ID_OFFSET, add(currentRoundId, 1))
)
gameInfoSlot0Value := or(
gameInfoSlot0Value,
shl(GAME_INFO__CURRENT_ROUND_BLOCK_TIMESTAMP_OFFSET, timestamp())
)
sstore(gameInfo.slot, gameInfoSlot0Value)
}
}
/**
* @dev This function requests for a random word from Chainlink VRF for wounding and healing.
*/
function _requestForRandomness() private {
uint256 requestId = VRF_COORDINATOR.requestRandomWords({
keyHash: KEY_HASH,
subId: SUBSCRIPTION_ID,
minimumRequestConfirmations: uint16(3),
callbackGasLimit: uint32(2_500_000),
numWords: uint32(1)
});
if (randomnessRequests[requestId].status != RandomnessRequestStatus.None) {
revert RandomnessRequestAlreadyExists();
}
uint40 currentRoundId = gameInfo.currentRoundId;
gameInfo.randomnessLastRequestedAt = uint40(block.timestamp);
// This is equivalent to
// randomnessRequests[requestId].status = RandomnessRequestStatus.Requested;
// randomnessRequests[requestId].roundId = currentRoundId;
assembly {
// 1 is RandomnessRequestStatus.Requested
let randomnessRequest := or(1, shl(RANDOMNESS_REQUESTS__EXISTS_OFFSET, currentRoundId))
mstore(0x00, requestId)
mstore(0x20, randomnessRequests.slot)
let randomnessRequestStoragSlot := keccak256(0x00, 0x40)
sstore(randomnessRequestStoragSlot, randomnessRequest)
}
frontrunLock = FRONTRUN_LOCK__LOCKED;
emit RandomnessRequested(currentRoundId, requestId);
}
/**
* @param roundId The current round ID.
* @param currentRoundAgentsAlive The number of agents alive currently.
* @param randomWord The random word returned from Chainlink.
* @return healedAgentsCount The number of agents that were healed.
* @return deadAgentsCount The number of agents that were killed.
* @return currentRandomWord The current random word after running the function.
*/
function _healRequestFulfilled(
uint256 roundId,
uint256 currentRoundAgentsAlive,
uint256 randomWord
) private returns (uint256 healedAgentsCount, uint256 deadAgentsCount, uint256 currentRandomWord) {
uint16[MAXIMUM_HEALING_OR_WOUNDED_AGENTS_PER_ROUND_AND_LENGTH]
storage healingAgentIds = healingAgentIdsPerRound[roundId];
uint256 healingAgentIdsCount = healingAgentIds[0];
if (healingAgentIdsCount != 0) {
HealResult[] memory healResults = new HealResult[](healingAgentIdsCount);
for (uint256 i; i < healingAgentIdsCount; ) {
uint256 healingAgentId = healingAgentIds[i.unsafeAdd(1)];
uint256 index = agentIndex(healingAgentId);
Agent storage agent = agents[index];
healResults[i].agentId = healingAgentId;
// 1. An agent's "healing at" round ID is always equal to the current round ID
// as it immediately settles upon randomness fulfillment.
//
// 2. 10_000_000_000 == 100 * PROBABILITY_PRECISION
if (randomWord % 10_000_000_000 <= healProbability(roundId.unsafeSubtract(agent.woundedAt))) {
// This line is not needed as HealOutcome.Healed is 0. It is here for clarity.
// healResults[i].outcome = HealOutcome.Healed;
_healAgent(agent);
} else {
healResults[i].outcome = HealOutcome.Killed;
_swap({
currentAgentIndex: index,
lastAgentIndex: currentRoundAgentsAlive - deadAgentsCount,
agentId: healingAgentId,
newStatus: AgentStatus.Dead
});
unchecked {
++deadAgentsCount;
}
}
randomWord = _nextRandomWord(randomWord);
unchecked {
++i;
}
}
unchecked {
healedAgentsCount = healingAgentIdsCount - deadAgentsCount;
}
emit HealRequestFulfilled(roundId, healResults);
}
currentRandomWord = randomWord;
}
/**
* @param roundId The current round ID.
* @param currentRoundAgentsAlive The number of agents alive currently.
* @param activeAgents The number of currently active agents.
* @param randomWord The random word returned from Chainlink.
* @return woundedAgentsCount The number of agents that were wounded.
*/
function _woundRequestFulfilled(
uint256 roundId,
uint256 currentRoundAgentsAlive,
uint256 activeAgents,
uint256 randomWord
) private returns (uint256 woundedAgentsCount) {
woundedAgentsCount =
(activeAgents * AGENTS_TO_WOUND_PER_ROUND_IN_BASIS_POINTS) /
ONE_HUNDRED_PERCENT_IN_BASIS_POINTS;
if (woundedAgentsCount < 3) {
woundedAgentsCount = 3;
}
uint256[] memory woundedAgentIds = new uint256[](woundedAgentsCount);
uint16[MAXIMUM_HEALING_OR_WOUNDED_AGENTS_PER_ROUND_AND_LENGTH]
storage currentRoundWoundedAgentIds = woundedAgentIdsPerRound[roundId];
for (uint256 i; i < woundedAgentsCount; ) {
uint256 woundedAgentIndex = (randomWord % currentRoundAgentsAlive).unsafeAdd(1);
Agent storage agentToWound = agents[woundedAgentIndex];
if (agentToWound.status == AgentStatus.Active) {
// This is equivalent to
// agentToWound.status = AgentStatus.Wounded;
// agentToWound.woundedAt = roundId;
assembly {
let agentSlotValue := sload(agentToWound.slot)
agentSlotValue := and(
agentSlotValue,
// This is equivalent to
// or(
// TWO_BYTES_BITMASK,
// shl(64, TWO_BYTES_BITMASK)
// )
0x00000000000000000000000000000000000000000000ffff000000000000ffff
)
// AgentStatus.Wounded is 1
agentSlotValue := or(agentSlotValue, shl(AGENT__STATUS_OFFSET, 1))
agentSlotValue := or(agentSlotValue, shl(AGENT__WOUNDED_AT_OFFSET, roundId))
sstore(agentToWound.slot, agentSlotValue)
}
uint256 woundedAgentId = _agentIndexToId(agentToWound, woundedAgentIndex);
woundedAgentIds[i] = woundedAgentId;
unchecked {
++i;
currentRoundWoundedAgentIds[i] = uint16(woundedAgentId);
}
}
randomWord = _nextRandomWord(randomWord);
}
currentRoundWoundedAgentIds[0] = uint16(woundedAgentsCount);
emit Wounded(roundId, woundedAgentIds);
}
/**
* @dev This function emits the Killed event but some agent IDs in the array can be 0 because
* they might have been healed or are dead already.
* @param currentRoundId The current round ID.
* @param roundId The round ID in which the wounded agents should be killed.
* @param currentRoundAgentsAlive The number of agents alive currently.
* @return deadAgentsCount The number of agents that were killed.
*/
function _killWoundedAgents(
uint256 currentRoundId,
uint256 roundId,
uint256 currentRoundAgentsAlive
) private returns (uint256 deadAgentsCount) {
uint16[MAXIMUM_HEALING_OR_WOUNDED_AGENTS_PER_ROUND_AND_LENGTH]
storage woundedAgentIdsInRound = woundedAgentIdsPerRound[roundId];
uint256 woundedAgentIdsCount = woundedAgentIdsInRound[0];
uint256[] memory woundedAgentIds = new uint256[](woundedAgentIdsCount);
for (uint256 i; i < woundedAgentIdsCount; ) {
uint256 woundedAgentId = woundedAgentIdsInRound[i.unsafeAdd(1)];
uint256 index = agentIndex(woundedAgentId);
Agent storage agent = agents[index];
if (agent.status == AgentStatus.Wounded) {
if (agent.woundedAt == roundId) {
woundedAgentIds[i] = woundedAgentId;
_swap({
currentAgentIndex: index,
lastAgentIndex: currentRoundAgentsAlive - deadAgentsCount,
agentId: woundedAgentId,
newStatus: AgentStatus.Dead
});
unchecked {
++deadAgentsCount;
}
}
}
unchecked {
++i;
}
}
emit Killed(currentRoundId, woundedAgentIds);
}
/**
* @param agent The agent to check.
* @param index The agent's index in the agents mapping.
* @return agentId The agent's ID.
*/
function _agentIndexToId(Agent storage agent, uint256 index) private view returns (uint256 agentId) {
agentId = agent.agentId;
agentId = agentId == 0 ? index : agentId;
}
/**
* @param healCount The number of times the agent has been successfully healed.
* @return cost The cost to heal the agent based on the agent's successful heal count.
*/
function _costToHeal(uint256 healCount) private view returns (uint256 cost) {
cost = HEAL_BASE_COST * (2 ** healCount);
}
/**
* @param agent The agent to heal.
*/
function _healAgent(Agent storage agent) private {
// This is equivalent to
// agent.status = AgentStatus.Active;
// agent.woundedAt = 0;
// lastHealCount = agent.healCount;
// ++agent.healCount;
assembly {
let agentSlotValue := sload(agent.slot)
let lastHealCount := and(shr(AGENT__HEAL_COUNT_OFFSET, agentSlotValue), TWO_BYTES_BITMASK)
agentSlotValue := and(agentSlotValue, TWO_BYTES_BITMASK)
agentSlotValue := or(agentSlotValue, shl(AGENT__HEAL_COUNT_OFFSET, add(lastHealCount, 1)))
sstore(agent.slot, agentSlotValue)
}
}
/**
* @notice An agent is killed by swapping it with the last agent in the agents mapping and decrementing `agentsAlive`
* by adding 1 to `gameInfo.deadAgents`.
* @notice An agent escapes by swapping it with the last agent in the agents mapping and decrementing `agentsAlive`
* by adding 1 to `gameInfo.escapedAgents`.
* @param currentAgentIndex The agent (whose status is being updated)'s index in the agents mapping.
* @param lastAgentIndex Last agent's index in the agents mapping.
* @param agentId The agent (whose status is being updated) 's ID.
* @param newStatus The new status of the agent.
*/
function _swap(uint256 currentAgentIndex, uint256 lastAgentIndex, uint256 agentId, AgentStatus newStatus) private {
Agent storage lastAgent = agents[lastAgentIndex];
uint256 lastAgentId = _agentIndexToId(lastAgent, lastAgentIndex);
agentIdToIndex[agentId] = lastAgentIndex;
agentIdToIndex[lastAgentId] = currentAgentIndex;
/**
* If last agent's agent ID is 0 that means it was never touched and is active.
*
* This is equivalent to
*
* agent.agentId = uint16(lastAgentId);
* agent.status = lastAgent.status;
* agent.woundedAt = lastAgent.woundedAt;
* agent.healCount = lastAgent.healCount;
* lastAgent.agentId = uint16(agentId);
* lastAgent.status = newStatus;
* lastAgent.woundedAt = 0;
* lastAgent.healCount = 0;
*/
bytes32 currentAgentSlot = _getAgentStorageSlot(currentAgentIndex);
bytes32 lastAgentSlot = _getAgentStorageSlot(lastAgentIndex);
assembly {
let lastAgentCurrentValue := sload(lastAgentSlot)
// The last agent's ID is either 0 or lastAgentId, so we do not need to clear the last 16 bits
// as it can only be or(0, lastAgentId) or or(lastAgentId, lastAgentId) which both ends up being lastAgentId.
lastAgentCurrentValue := or(lastAgentCurrentValue, lastAgentId)
sstore(currentAgentSlot, lastAgentCurrentValue)
let lastAgentNewValue := agentId
lastAgentNewValue := or(lastAgentNewValue, shl(AGENT__STATUS_OFFSET, newStatus))
sstore(lastAgentSlot, lastAgentNewValue)
}
}
/**
* @notice Returns the next random word by hashing.
* @param randomWord The current random word.
* @return nextRandomWord The next random word.
*/
function _nextRandomWord(uint256 randomWord) private pure returns (uint256 nextRandomWord) {
// This is equivalent to
// randomWord = uint256(keccak256(abi.encode(randomWord)));
assembly {
mstore(0x00, randomWord)
nextRandomWord := keccak256(0x00, 0x20)
}
}
/**
* @param index The agent's index in the agents mapping.
* @return agentStorageSlot The agent's storage slot.
*/
function _getAgentStorageSlot(uint256 index) private pure returns (bytes32 agentStorageSlot) {
assembly {
mstore(0x00, index)
mstore(0x20, agents.slot)
agentStorageSlot := keccak256(0x00, 0x40)
}
}
/**
* @dev ONE_HUNDRED_PERCENT_IN_BASIS_POINTS is used as an amplifier to prevent a loss of precision.
* @param agentsRemaining The number of agents remaining including wounded and healing agents.
* @return multiplier The escape multiplier in basis points. This portion of the reward goes to the owner of the escaping agent.
*/
function _escapeMultiplier(uint256 agentsRemaining) private view returns (uint256 multiplier) {
multiplier =
((90 *
ONE_HUNDRED_PERCENT_IN_BASIS_POINTS_SQUARED -
50 *
(((agentsRemaining * ONE_HUNDRED_PERCENT_IN_BASIS_POINTS) / totalSupply()) ** 2)) * 100) /
ONE_HUNDRED_PERCENT_IN_BASIS_POINTS_SQUARED;
}
/**
* @dev ONE_HUNDRED_PERCENT_IN_BASIS_POINTS is used as an amplifier to prevent a loss of precision.
* @param agentsRemaining The number of agents remaining including wounded and healing agents.
* @return split The split of the remaining escape reward between the the secondary prize pool and the main prize pool in basis points.
*/
function _escapeRewardSplitForSecondaryPrizePool(uint256 agentsRemaining) private view returns (uint256 split) {
split =
((9_980 * ONE_HUNDRED_PERCENT_IN_BASIS_POINTS) /
99 -
(((agentsRemaining * ONE_HUNDRED_PERCENT_IN_BASIS_POINTS) / totalSupply()) * uint256(8_000)) /
99) /
100;
if (split > ONE_HUNDRED_PERCENT_IN_BASIS_POINTS) {
split = ONE_HUNDRED_PERCENT_IN_BASIS_POINTS;
}
}
/**
* @dev Emit the Won event if there is only 1 active agent remaining in the game.
* @param agentsRemaining The number of alive agents.
* @param activeAgentsRemaining The number of active agents remaining.
*/
function _emitWonEventIfOnlyOneAgentRemaining(uint256 agentsRemaining, uint256 activeAgentsRemaining) private {
if (agentsRemaining == 1) {
if (activeAgentsRemaining == 1) {
emit Won(gameInfo.currentRoundId, _agentIndexToId(agents[1], 1));
}
}
}
/**
* @notice Validate max supply is not breached after minting "quantity" amount of agents
* @param quantity The quantity of agents to mint.
*/
function _assertTotalSupplyNotBreached(uint256 quantity) private view {
if (totalSupply() + quantity > MAX_SUPPLY) {
revert ExceededTotalSupply();
}
}
/**
* @notice Validate the game has not begun.
*/
function _assertGameNotYetBegun() private view {
if (gameInfo.currentRoundId != 0) {
revert GameAlreadyBegun();
}
}
/**
* @notice Validate exact ETH amount has been paid for the mint.
* @param quantity The quantity of agents to mint.
*/
function _assertExactNativeTokensSupplied(uint256 quantity) private view {
if (quantity * PRICE != msg.value) {
revert InexactNativeTokensSupplied();
}
}
/**
* @notice Validate the msg.sender is the owner of the agent ID.
* @param agentId The agent ID to validate.
*/
function _assertAgentOwnership(uint256 agentId) private view {
if (ownerOf(agentId) != msg.sender) {
revert NotAgentOwner();
}
}
/**
* @notice Validate the agent's status is the expected status.
* @param agent The agent to validate.
* @param agentId The agent's ID.
* @param status The expected status.
*/
function _assertAgentStatus(Agent storage agent, uint256 agentId, AgentStatus status) private view {
if (agent.status != status) {
revert InvalidAgentStatus(agentId, status);
}
}
/**
* @notice Validate the placement is between 1 and 50.
* @param placement The placement to validate.
*/
function _assertValidPlacement(uint256 placement) private pure {
if (placement == 0 || placement > NUMBER_OF_SECONDARY_PRIZE_POOL_WINNERS) {
revert InvalidPlacement();
}
}
/**
* @notice Validate the game is over by checking there is only 1 active agent and 0 wounded/healing agents.
*/
function _assertGameOver() private view {
if (gameInfo.activeAgents != 1 || gameInfo.woundedAgents != 0 || gameInfo.healingAgents != 0) {
revert GameIsStillRunning();
}
}
/**
* @notice Validate the frontrun lock is off.
*/
function _assertFrontrunLockIsOff() private view {
if (frontrunLock == FRONTRUN_LOCK__LOCKED) {
revert FrontrunLockIsOn();
}
}
/**
* @notice Validate the agent IDs array is not empty.
*/
function _assertNotEmptyAgentIdsArrayProvided(uint256 agentIdsCount) private pure {
if (agentIdsCount == 0) {
revert NoAgentsProvided();
}
}
/**
* @notice Validate the game's active agents to be greater than 0 after escape.
*/
function _assertGameIsNotOverAfterEscape(uint256 activeAgentsAfterEscape) private pure {
if (activeAgentsAfterEscape < 1) {
revert NoAgentsLeft();
}
}
/**
* @param secondsPerRound The current number of seconds per round
*/
function _assertNotTooEarlyToStartNewRound(uint256 secondsPerRound) private view {
if (block.timestamp < uint256(gameInfo.currentRoundBlockTimestamp).unsafeAdd(secondsPerRound)) {
revert TooEarlyToStartNewRound();
}
}
/**
* @notice The starting token ID is 1.
*/
function _startTokenId() internal pure override returns (uint256) {
return 1;
}
/**
* @notice The base URI of the collection.
*/
function _baseURI() internal view override returns (string memory) {
return baseURI;
}
/**
* @param agentIdsPerRound The storage pointer to either a round's woundedAgentIdsPerRound or healingAgentIdsPerRound.
* @return agentIds The agent IDs (now dynamically sized) in the round with the length removed.
*/
function _buildAgentIdsPerRoundArray(
uint16[MAXIMUM_HEALING_OR_WOUNDED_AGENTS_PER_ROUND_AND_LENGTH] storage agentIdsPerRound
) private view returns (uint256[] memory agentIds) {
uint256 count = agentIdsPerRound[0];
agentIds = new uint256[](count);
for (uint256 i; i < count; ) {
unchecked {
agentIds[i] = agentIdsPerRound[i + 1];
++i;
}
}
}
}// SPDX-License-Identifier: MIT
pragma solidity 0.8.24;
enum YieldMode {
AUTOMATIC,
VOID,
CLAIMABLE
}
enum GasMode {
VOID,
CLAIMABLE
}
interface IBlast {
// configure
function configureContract(address contractAddress, YieldMode _yield, GasMode gasMode, address governor) external;
function configure(YieldMode _yield, GasMode gasMode, address governor) external;
// base configuration options
function configureClaimableYield() external;
function configureClaimableYieldOnBehalf(address contractAddress) external;
function configureAutomaticYield() external;
function configureAutomaticYieldOnBehalf(address contractAddress) external;
function configureVoidYield() external;
function configureVoidYieldOnBehalf(address contractAddress) external;
function configureClaimableGas() external;
function configureClaimableGasOnBehalf(address contractAddress) external;
function configureVoidGas() external;
function configureVoidGasOnBehalf(address contractAddress) external;
function configureGovernor(address _governor) external;
function configureGovernorOnBehalf(address _newGovernor, address contractAddress) external;
// claim yield
function claimYield(address contractAddress, address recipientOfYield, uint256 amount) external returns (uint256);
function claimAllYield(address contractAddress, address recipientOfYield) external returns (uint256);
// claim gas
function claimAllGas(address contractAddress, address recipientOfGas) external returns (uint256);
function claimGasAtMinClaimRate(
address contractAddress,
address recipientOfGas,
uint256 minClaimRateBips
) external returns (uint256);
function claimMaxGas(address contractAddress, address recipientOfGas) external returns (uint256);
function claimGas(
address contractAddress,
address recipientOfGas,
uint256 gasToClaim,
uint256 gasSecondsToConsume
) external returns (uint256);
// read functions
function readClaimableYield(address contractAddress) external view returns (uint256);
function readYieldConfiguration(address contractAddress) external view returns (uint8);
function readGasParams(
address contractAddress
) external view returns (uint256 etherSeconds, uint256 etherBalance, uint256 lastUpdated, GasMode);
}// SPDX-License-Identifier: MIT
pragma solidity 0.8.24;
interface IBlastPoints {
function configurePointsOperator(address operator) external;
}// SPDX-License-Identifier: MIT
pragma solidity 0.8.24;
interface IInfiltration {
/**
* @notice Agent statuses.
* 1. Active: The agent is active.
* 2. Wounded: The agent is wounded. The agent can be healed for a number of blocks.
* 3. Healing: The agent is healing. The outcome of the healing is not yet known.
* 4. Escaped: The agent escaped from the game and took some rewards with him.
* 5. Dead: The agent is dead. It can be due to the agent being wounded for too long or a failed healing.
*/
enum AgentStatus {
Active,
Wounded,
Healing,
Escaped,
Dead
}
/**
* @notice Heal outcomes. The agent can either be healed or killed.
*/
enum HealOutcome {
Healed,
Killed
}
/**
* @notice Randomness request statuses.
*/
enum RandomnessRequestStatus {
None,
Requested,
Fulfilled
}
/**
* @notice An agent.
* @dev The storage layout of an agent is as follows:
* |---------------------------------------------------------------------------------------------------|
* | empty (176 bits) | healCount (16 bits) | woundedAt (40 bits) | status (8 bits) | agentId (16 bits)|
* |---------------------------------------------------------------------------------------------------|
* @param agentId The ID of the agent.
* @param status The status of the agent.
* @param woundedAt The round number when the agent was wounded.
* @param healCount The number of times the agent has been successfully healed.
*/
struct Agent {
uint16 agentId;
AgentStatus status;
uint40 woundedAt;
uint16 healCount;
}
/**
* @notice The constructor calldata.
* @param owner The owner of the contract.
* @param name The name of the collection.
* @param symbol The symbol of the collection.
* @param price The mint price.
* @param maxSupply The maximum supply of the collection.
* @param maxMintPerAddress The maximum number of agents that can be minted per address.
* @param secondsPerRound The number of seconds per round.
* @param agentsToWoundPerRoundInBasisPoints The number of agents to wound per round in basis points.
* @param roundsToBeWoundedBeforeDead The number of rounds for an agent to be wounded before getting killed.
* @param looks The LOOKS token address.
* @param vrfCoordinator The VRF coordinator address.
* @param keyHash The VRF key hash.
* @param subscriptionId The VRF subscription ID.
* @param transferManager The transfer manager address.
* @param healBaseCost The base cost to heal an agent.
* @param protocolFeeRecipient The protocol fee recipient.
* @param protocolFeeBp The protocol fee basis points.
* @param weth The WETH address.
* @param baseURI The base URI of the collection.
*/
struct ConstructorCalldata {
address owner;
string name;
string symbol;
uint256 price;
uint256 maxSupply;
uint256 maxMintPerAddress;
uint256 secondsPerRound;
uint256 agentsToWoundPerRoundInBasisPoints;
uint256 roundsToBeWoundedBeforeDead;
address looks;
address vrfCoordinator;
bytes32 keyHash;
uint64 subscriptionId;
address transferManager;
uint256 healBaseCost;
address protocolFeeRecipient;
uint16 protocolFeeBp;
address weth;
string baseURI;
}
/**
* @notice Game info.
* @dev The storage layout of game info is as follows:
* |-------------------------------------------------------------------------------------------------------------------------------|
* | empty (56 bits) | randomnessLastRequestedAt (40 bits) | currentRoundBlockTimestamp (40 bits) | currentRoundId (40 bits) |
* | escapedAgents (16 bits) | deadAgents (16 bits) | healingAgents (16 bits) | woundedAgents (16 bits) | activeAgents (16 bits) |
* |-------------------------------------------------------------------------------------------------------------------------------|
* | prizePool (256 bits) |
* |-------------------------------------------------------------------------------------------------------------------------------|
* | secondaryPrizePool (256 bits) |
* |-------------------------------------------------------------------------------------------------------------------------------|
* | secondaryLooksPrizePool (256 bits) |
* |-------------------------------------------------------------------------------------------------------------------------------|
* @param activeAgents The number of active agents.
* @param woundedAgents The number of wounded agents.
* @param healingAgents The number of healing agents.
* @param deadAgents The number of dead agents.
* @param escapedAgents The number of escaped agents.
* @param currentRoundId The current round ID.
* @param currentRoundBlockTimestamp The current round block timestamp.
* @param randomnessLastRequestedAt The timestamp when the randomness was last requested.
* @param prizePool The ETH prize pool for the final winner.
* @param secondaryPrizePool The secondary ETH prize pool for the top X winners.
* @param secondaryLooksPrizePool The secondary LOOKS prize pool for the top X winners.
*/
struct GameInfo {
uint16 activeAgents;
uint16 woundedAgents;
uint16 healingAgents;
uint16 deadAgents;
uint16 escapedAgents;
uint40 currentRoundId;
uint40 currentRoundBlockTimestamp;
uint40 randomnessLastRequestedAt;
uint256 prizePool;
uint256 secondaryPrizePool;
uint256 secondaryLooksPrizePool;
}
/**
* @notice A Chainlink randomness request.
* @param status The status of the randomness request.
* @param roundId The round ID when the randomness request occurred.
* @param randomWord The returned random word.
*/
struct RandomnessRequest {
RandomnessRequestStatus status;
uint40 roundId;
uint256 randomWord;
}
/**
* @notice A heal result that is used to emit events.
* @param agentId The agent ID.
* @param outcome The outcome of the healing.
*/
struct HealResult {
uint256 agentId;
HealOutcome outcome;
}
event EmergencyWithdrawal(uint256 ethAmount, uint256 looksAmount);
event MintPeriodUpdated(uint256 mintStart, uint256 mintEnd);
event HealRequestSubmitted(uint256 roundId, uint256[] agentIds, uint256[] costs);
event HealRequestFulfilled(uint256 roundId, HealResult[] healResults);
event RandomnessRequested(uint256 roundId, uint256 requestId);
event RandomnessFulfilled(uint256 roundId, uint256 requestId);
event InvalidRandomnessFulfillment(uint256 requestId, uint256 randomnessRequestRoundId, uint256 currentRoundId);
event RoundStarted(uint256 roundId);
event Escaped(uint256 roundId, uint256[] agentIds, uint256[] rewards);
event PrizeClaimed(uint256 agentId, address currency, uint256 amount);
event Wounded(uint256 roundId, uint256[] agentIds);
event Killed(uint256 roundId, uint256[] agentIds);
event Won(uint256 roundId, uint256 agentId);
error ExceededTotalSupply();
error FrontrunLockIsOn();
error GameAlreadyBegun();
error GameNotYetBegun();
error GameIsStillRunning();
error GameOver();
error HealingDisabled();
error InexactNativeTokensSupplied();
error InvalidAgentStatus(uint256 agentId, AgentStatus expectedStatus);
error InvalidHealingRoundsDelay();
error InvalidMaxSupply();
error InvalidMintPeriod();
error InvalidPlacement();
error MaximumHealingRequestPerRoundExceeded();
error MintAlreadyStarted();
error MintCanOnlyBeExtended();
error MintStartIsInThePast();
error NoAgentsLeft();
error NoAgentsProvided();
error NotEnoughMinted();
error NothingToClaim();
error NotInMintPeriod();
error NotAgentOwner();
error Immutable();
error RandomnessRequestAlreadyExists();
error InvalidRandomnessRequestId();
error RoundsToBeWoundedBeforeDeadTooLow();
error StillMinting();
error TooEarlyToStartNewRound();
error TooEarlyToRetryRandomnessRequest();
error TooManyMinted();
error WoundedAgentIdsPerRoundExceeded();
/**
* @notice Sets the mint period.
* @dev If _mintStart is 0, the function call is just a mint end extension.
* @param _mintStart The starting timestamp of the mint period.
* @param _mintEnd The ending timestamp of the mint period.
*/
function setMintPeriod(uint40 _mintStart, uint40 _mintEnd) external;
/**
* @notice Mints a number of agents.
* @param to The recipient
* @param quantity The number of agents to mint.
*/
function premint(address to, uint256 quantity) external payable;
/**
* @notice Mints a number of agents.
* @param quantity The number of agents to mint.
*/
function mint(uint256 quantity) external payable;
/**
* @notice This function is here in case the game's invariant condition does not hold or the game is stuck.
* Only callable by the contract owner.
*/
function emergencyWithdraw() external;
/**
* @notice Starts the game.
* @dev Starting the game sets the current round ID to 1.
*/
function startGame() external;
/**
* @notice Starts a new round.
*/
function startNewRound() external;
/**
* @notice Close a round after randomness is fullfilled by Chainlink.
* @param requestId The Chainlink request ID.
*/
function closeRound(uint256 requestId) external;
/**
* @notice Claims the grand prize. Only callable by the winner.
*/
function claimGrandPrize() external;
/**
* @notice Claims the secondary prizes. Only callable by top 50 agents.
* @param agentId The agent ID.
*/
function claimSecondaryPrizes(uint256 agentId) external;
/**
* @notice Escape from the game and take some rewards. 80% of the prize pool is distributed to
* the escaped agents and the rest to the secondary prize pool.
* @param agentIds The agent IDs to escape.
*/
function escape(uint256[] calldata agentIds) external;
/**
* @notice Submits a heal request for the specified agent IDs.
* @param agentIds The agent IDs to heal.
*/
function heal(uint256[] calldata agentIds) external;
/**
* @notice Get the agent at the specified index.
* @return agent The agent at the specified index.
*/
function getAgent(uint256 index) external view returns (Agent memory agent);
/**
* @notice Returns the cost to heal the specified agents
* @dev The cost doubles for each time the agent is healed.
* @param agentIds The agent IDs to heal.
* @return cost The cost to heal the specified agents.
*/
function costToHeal(uint256[] calldata agentIds) external view returns (uint256 cost);
/**
* @notice Returns the reward for escaping the game.
* @param agentIds The agent IDs to escape.
* @return reward The reward for escaping the game.
*/
function escapeReward(uint256[] calldata agentIds) external view returns (uint256 reward);
/**
* @notice Returns the total number of agents alive.
*/
function agentsAlive() external view returns (uint256);
/**
* @notice Returns the index of a specific agent ID inside the agents mapping.
* @param agentId The agent ID.
* @return index The index of the agent ID.
*/
function agentIndex(uint256 agentId) external view returns (uint256 index);
/**
* @notice Returns a specific round's information.
* @param roundId The round ID.
* @return woundedAgentIds The agent IDs of the wounded agents in the specified round.
* @return healingAgentIds The agent IDs of the healing agents in the specified round.
*/
function getRoundInfo(
uint256 roundId
) external view returns (uint256[] memory woundedAgentIds, uint256[] memory healingAgentIds);
}// SPDX-License-Identifier: MIT
pragma solidity 0.8.24;
library UnsafeMathUint256 {
function unsafeAdd(uint256 a, uint256 b) internal pure returns (uint256) {
unchecked {
return a + b;
}
}
function unsafeSubtract(uint256 a, uint256 b) internal pure returns (uint256) {
unchecked {
return a - b;
}
}
function unsafeMultiply(uint256 a, uint256 b) internal pure returns (uint256) {
unchecked {
return a * b;
}
}
function unsafeDivide(uint256 a, uint256 b) internal pure returns (uint256) {
unchecked {
return a / b;
}
}
}// SPDX-License-Identifier: MIT
// ERC721A Contracts v4.2.3
// Creator: Chiru Labs
pragma solidity ^0.8.4;
import './IERC721A.sol';
/**
* @dev Interface of ERC721 token receiver.
*/
interface ERC721A__IERC721Receiver {
function onERC721Received(
address operator,
address from,
uint256 tokenId,
bytes calldata data
) external returns (bytes4);
}
/**
* @title ERC721A
*
* @dev Implementation of the [ERC721](https://eips.ethereum.org/EIPS/eip-721)
* Non-Fungible Token Standard, including the Metadata extension.
* Optimized for lower gas during batch mints.
*
* Token IDs are minted in sequential order (e.g. 0, 1, 2, 3, ...)
* starting from `_startTokenId()`.
*
* Assumptions:
*
* - An owner cannot have more than 2**64 - 1 (max value of uint64) of supply.
* - The maximum token ID cannot exceed 2**256 - 1 (max value of uint256).
*/
contract ERC721A is IERC721A {
// Bypass for a `--via-ir` bug (https://github.com/chiru-labs/ERC721A/pull/364).
struct TokenApprovalRef {
address value;
}
// =============================================================
// CONSTANTS
// =============================================================
// Mask of an entry in packed address data.
uint256 private constant _BITMASK_ADDRESS_DATA_ENTRY = (1 << 64) - 1;
// The bit position of `numberMinted` in packed address data.
uint256 private constant _BITPOS_NUMBER_MINTED = 64;
// The bit position of `numberBurned` in packed address data.
uint256 private constant _BITPOS_NUMBER_BURNED = 128;
// The bit position of `aux` in packed address data.
uint256 private constant _BITPOS_AUX = 192;
// Mask of all 256 bits in packed address data except the 64 bits for `aux`.
uint256 private constant _BITMASK_AUX_COMPLEMENT = (1 << 192) - 1;
// The bit position of `startTimestamp` in packed ownership.
uint256 private constant _BITPOS_START_TIMESTAMP = 160;
// The bit mask of the `burned` bit in packed ownership.
uint256 private constant _BITMASK_BURNED = 1 << 224;
// The bit position of the `nextInitialized` bit in packed ownership.
uint256 private constant _BITPOS_NEXT_INITIALIZED = 225;
// The bit mask of the `nextInitialized` bit in packed ownership.
uint256 private constant _BITMASK_NEXT_INITIALIZED = 1 << 225;
// The bit position of `extraData` in packed ownership.
uint256 private constant _BITPOS_EXTRA_DATA = 232;
// Mask of all 256 bits in a packed ownership except the 24 bits for `extraData`.
uint256 private constant _BITMASK_EXTRA_DATA_COMPLEMENT = (1 << 232) - 1;
// The mask of the lower 160 bits for addresses.
uint256 private constant _BITMASK_ADDRESS = (1 << 160) - 1;
// The maximum `quantity` that can be minted with {_mintERC2309}.
// This limit is to prevent overflows on the address data entries.
// For a limit of 5000, a total of 3.689e15 calls to {_mintERC2309}
// is required to cause an overflow, which is unrealistic.
uint256 private constant _MAX_MINT_ERC2309_QUANTITY_LIMIT = 5000;
// The `Transfer` event signature is given by:
// `keccak256(bytes("Transfer(address,address,uint256)"))`.
bytes32 private constant _TRANSFER_EVENT_SIGNATURE =
0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef;
// =============================================================
// STORAGE
// =============================================================
// The next token ID to be minted.
uint256 private _currentIndex;
// The number of tokens burned.
uint256 private _burnCounter;
// Token name
string private _name;
// Token symbol
string private _symbol;
// Mapping from token ID to ownership details
// An empty struct value does not necessarily mean the token is unowned.
// See {_packedOwnershipOf} implementation for details.
//
// Bits Layout:
// - [0..159] `addr`
// - [160..223] `startTimestamp`
// - [224] `burned`
// - [225] `nextInitialized`
// - [232..255] `extraData`
mapping(uint256 => uint256) private _packedOwnerships;
// Mapping owner address to address data.
//
// Bits Layout:
// - [0..63] `balance`
// - [64..127] `numberMinted`
// - [128..191] `numberBurned`
// - [192..255] `aux`
mapping(address => uint256) private _packedAddressData;
// Mapping from token ID to approved address.
mapping(uint256 => TokenApprovalRef) private _tokenApprovals;
// Mapping from owner to operator approvals
mapping(address => mapping(address => bool)) private _operatorApprovals;
// =============================================================
// CONSTRUCTOR
// =============================================================
constructor(string memory name_, string memory symbol_) {
_name = name_;
_symbol = symbol_;
_currentIndex = _startTokenId();
}
// =============================================================
// TOKEN COUNTING OPERATIONS
// =============================================================
/**
* @dev Returns the starting token ID.
* To change the starting token ID, please override this function.
*/
function _startTokenId() internal view virtual returns (uint256) {
return 0;
}
/**
* @dev Returns the next token ID to be minted.
*/
function _nextTokenId() internal view virtual returns (uint256) {
return _currentIndex;
}
/**
* @dev Returns the total number of tokens in existence.
* Burned tokens will reduce the count.
* To get the total number of tokens minted, please see {_totalMinted}.
*/
function totalSupply() public view virtual override returns (uint256) {
// Counter underflow is impossible as _burnCounter cannot be incremented
// more than `_currentIndex - _startTokenId()` times.
unchecked {
return _currentIndex - _burnCounter - _startTokenId();
}
}
/**
* @dev Returns the total amount of tokens minted in the contract.
*/
function _totalMinted() internal view virtual returns (uint256) {
// Counter underflow is impossible as `_currentIndex` does not decrement,
// and it is initialized to `_startTokenId()`.
unchecked {
return _currentIndex - _startTokenId();
}
}
/**
* @dev Returns the total number of tokens burned.
*/
function _totalBurned() internal view virtual returns (uint256) {
return _burnCounter;
}
// =============================================================
// ADDRESS DATA OPERATIONS
// =============================================================
/**
* @dev Returns the number of tokens in `owner`'s account.
*/
function balanceOf(address owner) public view virtual override returns (uint256) {
if (owner == address(0)) revert BalanceQueryForZeroAddress();
return _packedAddressData[owner] & _BITMASK_ADDRESS_DATA_ENTRY;
}
/**
* Returns the number of tokens minted by `owner`.
*/
function _numberMinted(address owner) internal view returns (uint256) {
return (_packedAddressData[owner] >> _BITPOS_NUMBER_MINTED) & _BITMASK_ADDRESS_DATA_ENTRY;
}
/**
* Returns the number of tokens burned by or on behalf of `owner`.
*/
function _numberBurned(address owner) internal view returns (uint256) {
return (_packedAddressData[owner] >> _BITPOS_NUMBER_BURNED) & _BITMASK_ADDRESS_DATA_ENTRY;
}
/**
* Returns the auxiliary data for `owner`. (e.g. number of whitelist mint slots used).
*/
function _getAux(address owner) internal view returns (uint64) {
return uint64(_packedAddressData[owner] >> _BITPOS_AUX);
}
/**
* Sets the auxiliary data for `owner`. (e.g. number of whitelist mint slots used).
* If there are multiple variables, please pack them into a uint64.
*/
function _setAux(address owner, uint64 aux) internal virtual {
uint256 packed = _packedAddressData[owner];
uint256 auxCasted;
// Cast `aux` with assembly to avoid redundant masking.
assembly {
auxCasted := aux
}
packed = (packed & _BITMASK_AUX_COMPLEMENT) | (auxCasted << _BITPOS_AUX);
_packedAddressData[owner] = packed;
}
// =============================================================
// IERC165
// =============================================================
/**
* @dev Returns true if this contract implements the interface defined by
* `interfaceId`. See the corresponding
* [EIP section](https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified)
* to learn more about how these ids are created.
*
* This function call must use less than 30000 gas.
*/
function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {
// The interface IDs are constants representing the first 4 bytes
// of the XOR of all function selectors in the interface.
// See: [ERC165](https://eips.ethereum.org/EIPS/eip-165)
// (e.g. `bytes4(i.functionA.selector ^ i.functionB.selector ^ ...)`)
return
interfaceId == 0x01ffc9a7 || // ERC165 interface ID for ERC165.
interfaceId == 0x80ac58cd || // ERC165 interface ID for ERC721.
interfaceId == 0x5b5e139f; // ERC165 interface ID for ERC721Metadata.
}
// =============================================================
// IERC721Metadata
// =============================================================
/**
* @dev Returns the token collection name.
*/
function name() public view virtual override returns (string memory) {
return _name;
}
/**
* @dev Returns the token collection symbol.
*/
function symbol() public view virtual override returns (string memory) {
return _symbol;
}
/**
* @dev Returns the Uniform Resource Identifier (URI) for `tokenId` token.
*/
function tokenURI(uint256 tokenId) public view virtual override returns (string memory) {
if (!_exists(tokenId)) revert URIQueryForNonexistentToken();
string memory baseURI = _baseURI();
return bytes(baseURI).length != 0 ? string(abi.encodePacked(baseURI, _toString(tokenId))) : '';
}
/**
* @dev Base URI for computing {tokenURI}. If set, the resulting URI for each
* token will be the concatenation of the `baseURI` and the `tokenId`. Empty
* by default, it can be overridden in child contracts.
*/
function _baseURI() internal view virtual returns (string memory) {
return '';
}
// =============================================================
// OWNERSHIPS OPERATIONS
// =============================================================
/**
* @dev Returns the owner of the `tokenId` token.
*
* Requirements:
*
* - `tokenId` must exist.
*/
function ownerOf(uint256 tokenId) public view virtual override returns (address) {
return address(uint160(_packedOwnershipOf(tokenId)));
}
/**
* @dev Gas spent here starts off proportional to the maximum mint batch size.
* It gradually moves to O(1) as tokens get transferred around over time.
*/
function _ownershipOf(uint256 tokenId) internal view virtual returns (TokenOwnership memory) {
return _unpackedOwnership(_packedOwnershipOf(tokenId));
}
/**
* @dev Returns the unpacked `TokenOwnership` struct at `index`.
*/
function _ownershipAt(uint256 index) internal view virtual returns (TokenOwnership memory) {
return _unpackedOwnership(_packedOwnerships[index]);
}
/**
* @dev Initializes the ownership slot minted at `index` for efficiency purposes.
*/
function _initializeOwnershipAt(uint256 index) internal virtual {
if (_packedOwnerships[index] == 0) {
_packedOwnerships[index] = _packedOwnershipOf(index);
}
}
/**
* Returns the packed ownership data of `tokenId`.
*/
function _packedOwnershipOf(uint256 tokenId) private view returns (uint256) {
uint256 curr = tokenId;
unchecked {
if (_startTokenId() <= curr)
if (curr < _currentIndex) {
uint256 packed = _packedOwnerships[curr];
// If not burned.
if (packed & _BITMASK_BURNED == 0) {
// Invariant:
// There will always be an initialized ownership slot
// (i.e. `ownership.addr != address(0) && ownership.burned == false`)
// before an unintialized ownership slot
// (i.e. `ownership.addr == address(0) && ownership.burned == false`)
// Hence, `curr` will not underflow.
//
// We can directly compare the packed value.
// If the address is zero, packed will be zero.
while (packed == 0) {
packed = _packedOwnerships[--curr];
}
return packed;
}
}
}
revert OwnerQueryForNonexistentToken();
}
/**
* @dev Returns the unpacked `TokenOwnership` struct from `packed`.
*/
function _unpackedOwnership(uint256 packed) private pure returns (TokenOwnership memory ownership) {
ownership.addr = address(uint160(packed));
ownership.startTimestamp = uint64(packed >> _BITPOS_START_TIMESTAMP);
ownership.burned = packed & _BITMASK_BURNED != 0;
ownership.extraData = uint24(packed >> _BITPOS_EXTRA_DATA);
}
/**
* @dev Packs ownership data into a single uint256.
*/
function _packOwnershipData(address owner, uint256 flags) private view returns (uint256 result) {
assembly {
// Mask `owner` to the lower 160 bits, in case the upper bits somehow aren't clean.
owner := and(owner, _BITMASK_ADDRESS)
// `owner | (block.timestamp << _BITPOS_START_TIMESTAMP) | flags`.
result := or(owner, or(shl(_BITPOS_START_TIMESTAMP, timestamp()), flags))
}
}
/**
* @dev Returns the `nextInitialized` flag set if `quantity` equals 1.
*/
function _nextInitializedFlag(uint256 quantity) private pure returns (uint256 result) {
// For branchless setting of the `nextInitialized` flag.
assembly {
// `(quantity == 1) << _BITPOS_NEXT_INITIALIZED`.
result := shl(_BITPOS_NEXT_INITIALIZED, eq(quantity, 1))
}
}
// =============================================================
// APPROVAL OPERATIONS
// =============================================================
/**
* @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) public payable virtual override {
address owner = ownerOf(tokenId);
if (_msgSenderERC721A() != owner)
if (!isApprovedForAll(owner, _msgSenderERC721A())) {
revert ApprovalCallerNotOwnerNorApproved();
}
_tokenApprovals[tokenId].value = to;
emit Approval(owner, to, tokenId);
}
/**
* @dev Returns the account approved for `tokenId` token.
*
* Requirements:
*
* - `tokenId` must exist.
*/
function getApproved(uint256 tokenId) public view virtual override returns (address) {
if (!_exists(tokenId)) revert ApprovalQueryForNonexistentToken();
return _tokenApprovals[tokenId].value;
}
/**
* @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) public virtual override {
_operatorApprovals[_msgSenderERC721A()][operator] = approved;
emit ApprovalForAll(_msgSenderERC721A(), operator, approved);
}
/**
* @dev Returns if the `operator` is allowed to manage all of the assets of `owner`.
*
* See {setApprovalForAll}.
*/
function isApprovedForAll(address owner, address operator) public view virtual override returns (bool) {
return _operatorApprovals[owner][operator];
}
/**
* @dev Returns whether `tokenId` exists.
*
* Tokens can be managed by their owner or approved accounts via {approve} or {setApprovalForAll}.
*
* Tokens start existing when they are minted. See {_mint}.
*/
function _exists(uint256 tokenId) internal view virtual returns (bool) {
return
_startTokenId() <= tokenId &&
tokenId < _currentIndex && // If within bounds,
_packedOwnerships[tokenId] & _BITMASK_BURNED == 0; // and not burned.
}
/**
* @dev Returns whether `msgSender` is equal to `approvedAddress` or `owner`.
*/
function _isSenderApprovedOrOwner(
address approvedAddress,
address owner,
address msgSender
) private pure returns (bool result) {
assembly {
// Mask `owner` to the lower 160 bits, in case the upper bits somehow aren't clean.
owner := and(owner, _BITMASK_ADDRESS)
// Mask `msgSender` to the lower 160 bits, in case the upper bits somehow aren't clean.
msgSender := and(msgSender, _BITMASK_ADDRESS)
// `msgSender == owner || msgSender == approvedAddress`.
result := or(eq(msgSender, owner), eq(msgSender, approvedAddress))
}
}
/**
* @dev Returns the storage slot and value for the approved address of `tokenId`.
*/
function _getApprovedSlotAndAddress(uint256 tokenId)
private
view
returns (uint256 approvedAddressSlot, address approvedAddress)
{
TokenApprovalRef storage tokenApproval = _tokenApprovals[tokenId];
// The following is equivalent to `approvedAddress = _tokenApprovals[tokenId].value`.
assembly {
approvedAddressSlot := tokenApproval.slot
approvedAddress := sload(approvedAddressSlot)
}
}
// =============================================================
// TRANSFER OPERATIONS
// =============================================================
/**
* @dev Transfers `tokenId` from `from` to `to`.
*
* 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
) public payable virtual override {
uint256 prevOwnershipPacked = _packedOwnershipOf(tokenId);
if (address(uint160(prevOwnershipPacked)) != from) revert TransferFromIncorrectOwner();
(uint256 approvedAddressSlot, address approvedAddress) = _getApprovedSlotAndAddress(tokenId);
// The nested ifs save around 20+ gas over a compound boolean condition.
if (!_isSenderApprovedOrOwner(approvedAddress, from, _msgSenderERC721A()))
if (!isApprovedForAll(from, _msgSenderERC721A())) revert TransferCallerNotOwnerNorApproved();
if (to == address(0)) revert TransferToZeroAddress();
_beforeTokenTransfers(from, to, tokenId, 1);
// Clear approvals from the previous owner.
assembly {
if approvedAddress {
// This is equivalent to `delete _tokenApprovals[tokenId]`.
sstore(approvedAddressSlot, 0)
}
}
// Underflow of the sender's balance is impossible because we check for
// ownership above and the recipient's balance can't realistically overflow.
// Counter overflow is incredibly unrealistic as `tokenId` would have to be 2**256.
unchecked {
// We can directly increment and decrement the balances.
--_packedAddressData[from]; // Updates: `balance -= 1`.
++_packedAddressData[to]; // Updates: `balance += 1`.
// Updates:
// - `address` to the next owner.
// - `startTimestamp` to the timestamp of transfering.
// - `burned` to `false`.
// - `nextInitialized` to `true`.
_packedOwnerships[tokenId] = _packOwnershipData(
to,
_BITMASK_NEXT_INITIALIZED | _nextExtraData(from, to, prevOwnershipPacked)
);
// If the next slot may not have been initialized (i.e. `nextInitialized == false`) .
if (prevOwnershipPacked & _BITMASK_NEXT_INITIALIZED == 0) {
uint256 nextTokenId = tokenId + 1;
// If the next slot's address is zero and not burned (i.e. packed value is zero).
if (_packedOwnerships[nextTokenId] == 0) {
// If the next slot is within bounds.
if (nextTokenId != _currentIndex) {
// Initialize the next slot to maintain correctness for `ownerOf(tokenId + 1)`.
_packedOwnerships[nextTokenId] = prevOwnershipPacked;
}
}
}
}
emit Transfer(from, to, tokenId);
_afterTokenTransfers(from, to, tokenId, 1);
}
/**
* @dev Equivalent to `safeTransferFrom(from, to, tokenId, '')`.
*/
function safeTransferFrom(
address from,
address to,
uint256 tokenId
) public payable virtual override {
safeTransferFrom(from, to, tokenId, '');
}
/**
* @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 memory _data
) public payable virtual override {
transferFrom(from, to, tokenId);
if (to.code.length != 0)
if (!_checkContractOnERC721Received(from, to, tokenId, _data)) {
revert TransferToNonERC721ReceiverImplementer();
}
}
/**
* @dev Hook that is called before a set of serially-ordered token IDs
* are about to be transferred. This includes minting.
* And also called before burning one token.
*
* `startTokenId` - the first token ID to be transferred.
* `quantity` - the amount to be transferred.
*
* Calling conditions:
*
* - When `from` and `to` are both non-zero, `from`'s `tokenId` will be
* transferred to `to`.
* - When `from` is zero, `tokenId` will be minted for `to`.
* - When `to` is zero, `tokenId` will be burned by `from`.
* - `from` and `to` are never both zero.
*/
function _beforeTokenTransfers(
address from,
address to,
uint256 startTokenId,
uint256 quantity
) internal virtual {}
/**
* @dev Hook that is called after a set of serially-ordered token IDs
* have been transferred. This includes minting.
* And also called after one token has been burned.
*
* `startTokenId` - the first token ID to be transferred.
* `quantity` - the amount to be transferred.
*
* Calling conditions:
*
* - When `from` and `to` are both non-zero, `from`'s `tokenId` has been
* transferred to `to`.
* - When `from` is zero, `tokenId` has been minted for `to`.
* - When `to` is zero, `tokenId` has been burned by `from`.
* - `from` and `to` are never both zero.
*/
function _afterTokenTransfers(
address from,
address to,
uint256 startTokenId,
uint256 quantity
) internal virtual {}
/**
* @dev Private function to invoke {IERC721Receiver-onERC721Received} on a target contract.
*
* `from` - Previous owner of the given token ID.
* `to` - Target address that will receive the token.
* `tokenId` - Token ID to be transferred.
* `_data` - Optional data to send along with the call.
*
* Returns whether the call correctly returned the expected magic value.
*/
function _checkContractOnERC721Received(
address from,
address to,
uint256 tokenId,
bytes memory _data
) private returns (bool) {
try ERC721A__IERC721Receiver(to).onERC721Received(_msgSenderERC721A(), from, tokenId, _data) returns (
bytes4 retval
) {
return retval == ERC721A__IERC721Receiver(to).onERC721Received.selector;
} catch (bytes memory reason) {
if (reason.length == 0) {
revert TransferToNonERC721ReceiverImplementer();
} else {
assembly {
revert(add(32, reason), mload(reason))
}
}
}
}
// =============================================================
// MINT OPERATIONS
// =============================================================
/**
* @dev Mints `quantity` tokens and transfers them to `to`.
*
* Requirements:
*
* - `to` cannot be the zero address.
* - `quantity` must be greater than 0.
*
* Emits a {Transfer} event for each mint.
*/
function _mint(address to, uint256 quantity) internal virtual {
uint256 startTokenId = _currentIndex;
if (quantity == 0) revert MintZeroQuantity();
_beforeTokenTransfers(address(0), to, startTokenId, quantity);
// Overflows are incredibly unrealistic.
// `balance` and `numberMinted` have a maximum limit of 2**64.
// `tokenId` has a maximum limit of 2**256.
unchecked {
// Updates:
// - `balance += quantity`.
// - `numberMinted += quantity`.
//
// We can directly add to the `balance` and `numberMinted`.
_packedAddressData[to] += quantity * ((1 << _BITPOS_NUMBER_MINTED) | 1);
// Updates:
// - `address` to the owner.
// - `startTimestamp` to the timestamp of minting.
// - `burned` to `false`.
// - `nextInitialized` to `quantity == 1`.
_packedOwnerships[startTokenId] = _packOwnershipData(
to,
_nextInitializedFlag(quantity) | _nextExtraData(address(0), to, 0)
);
uint256 toMasked;
uint256 end = startTokenId + quantity;
// Use assembly to loop and emit the `Transfer` event for gas savings.
// The duplicated `log4` removes an extra check and reduces stack juggling.
// The assembly, together with the surrounding Solidity code, have been
// delicately arranged to nudge the compiler into producing optimized opcodes.
assembly {
// Mask `to` to the lower 160 bits, in case the upper bits somehow aren't clean.
toMasked := and(to, _BITMASK_ADDRESS)
// Emit the `Transfer` event.
log4(
0, // Start of data (0, since no data).
0, // End of data (0, since no data).
_TRANSFER_EVENT_SIGNATURE, // Signature.
0, // `address(0)`.
toMasked, // `to`.
startTokenId // `tokenId`.
)
// The `iszero(eq(,))` check ensures that large values of `quantity`
// that overflows uint256 will make the loop run out of gas.
// The compiler will optimize the `iszero` away for performance.
for {
let tokenId := add(startTokenId, 1)
} iszero(eq(tokenId, end)) {
tokenId := add(tokenId, 1)
} {
// Emit the `Transfer` event. Similar to above.
log4(0, 0, _TRANSFER_EVENT_SIGNATURE, 0, toMasked, tokenId)
}
}
if (toMasked == 0) revert MintToZeroAddress();
_currentIndex = end;
}
_afterTokenTransfers(address(0), to, startTokenId, quantity);
}
/**
* @dev Mints `quantity` tokens and transfers them to `to`.
*
* This function is intended for efficient minting only during contract creation.
*
* It emits only one {ConsecutiveTransfer} as defined in
* [ERC2309](https://eips.ethereum.org/EIPS/eip-2309),
* instead of a sequence of {Transfer} event(s).
*
* Calling this function outside of contract creation WILL make your contract
* non-compliant with the ERC721 standard.
* For full ERC721 compliance, substituting ERC721 {Transfer} event(s) with the ERC2309
* {ConsecutiveTransfer} event is only permissible during contract creation.
*
* Requirements:
*
* - `to` cannot be the zero address.
* - `quantity` must be greater than 0.
*
* Emits a {ConsecutiveTransfer} event.
*/
function _mintERC2309(address to, uint256 quantity) internal virtual {
uint256 startTokenId = _currentIndex;
if (to == address(0)) revert MintToZeroAddress();
if (quantity == 0) revert MintZeroQuantity();
if (quantity > _MAX_MINT_ERC2309_QUANTITY_LIMIT) revert MintERC2309QuantityExceedsLimit();
_beforeTokenTransfers(address(0), to, startTokenId, quantity);
// Overflows are unrealistic due to the above check for `quantity` to be below the limit.
unchecked {
// Updates:
// - `balance += quantity`.
// - `numberMinted += quantity`.
//
// We can directly add to the `balance` and `numberMinted`.
_packedAddressData[to] += quantity * ((1 << _BITPOS_NUMBER_MINTED) | 1);
// Updates:
// - `address` to the owner.
// - `startTimestamp` to the timestamp of minting.
// - `burned` to `false`.
// - `nextInitialized` to `quantity == 1`.
_packedOwnerships[startTokenId] = _packOwnershipData(
to,
_nextInitializedFlag(quantity) | _nextExtraData(address(0), to, 0)
);
emit ConsecutiveTransfer(startTokenId, startTokenId + quantity - 1, address(0), to);
_currentIndex = startTokenId + quantity;
}
_afterTokenTransfers(address(0), to, startTokenId, quantity);
}
/**
* @dev Safely mints `quantity` tokens and transfers them to `to`.
*
* Requirements:
*
* - If `to` refers to a smart contract, it must implement
* {IERC721Receiver-onERC721Received}, which is called for each safe transfer.
* - `quantity` must be greater than 0.
*
* See {_mint}.
*
* Emits a {Transfer} event for each mint.
*/
function _safeMint(
address to,
uint256 quantity,
bytes memory _data
) internal virtual {
_mint(to, quantity);
unchecked {
if (to.code.length != 0) {
uint256 end = _currentIndex;
uint256 index = end - quantity;
do {
if (!_checkContractOnERC721Received(address(0), to, index++, _data)) {
revert TransferToNonERC721ReceiverImplementer();
}
} while (index < end);
// Reentrancy protection.
if (_currentIndex != end) revert();
}
}
}
/**
* @dev Equivalent to `_safeMint(to, quantity, '')`.
*/
function _safeMint(address to, uint256 quantity) internal virtual {
_safeMint(to, quantity, '');
}
// =============================================================
// BURN OPERATIONS
// =============================================================
/**
* @dev Equivalent to `_burn(tokenId, false)`.
*/
function _burn(uint256 tokenId) internal virtual {
_burn(tokenId, false);
}
/**
* @dev Destroys `tokenId`.
* The approval is cleared when the token is burned.
*
* Requirements:
*
* - `tokenId` must exist.
*
* Emits a {Transfer} event.
*/
function _burn(uint256 tokenId, bool approvalCheck) internal virtual {
uint256 prevOwnershipPacked = _packedOwnershipOf(tokenId);
address from = address(uint160(prevOwnershipPacked));
(uint256 approvedAddressSlot, address approvedAddress) = _getApprovedSlotAndAddress(tokenId);
if (approvalCheck) {
// The nested ifs save around 20+ gas over a compound boolean condition.
if (!_isSenderApprovedOrOwner(approvedAddress, from, _msgSenderERC721A()))
if (!isApprovedForAll(from, _msgSenderERC721A())) revert TransferCallerNotOwnerNorApproved();
}
_beforeTokenTransfers(from, address(0), tokenId, 1);
// Clear approvals from the previous owner.
assembly {
if approvedAddress {
// This is equivalent to `delete _tokenApprovals[tokenId]`.
sstore(approvedAddressSlot, 0)
}
}
// Underflow of the sender's balance is impossible because we check for
// ownership above and the recipient's balance can't realistically overflow.
// Counter overflow is incredibly unrealistic as `tokenId` would have to be 2**256.
unchecked {
// Updates:
// - `balance -= 1`.
// - `numberBurned += 1`.
//
// We can directly decrement the balance, and increment the number burned.
// This is equivalent to `packed -= 1; packed += 1 << _BITPOS_NUMBER_BURNED;`.
_packedAddressData[from] += (1 << _BITPOS_NUMBER_BURNED) - 1;
// Updates:
// - `address` to the last owner.
// - `startTimestamp` to the timestamp of burning.
// - `burned` to `true`.
// - `nextInitialized` to `true`.
_packedOwnerships[tokenId] = _packOwnershipData(
from,
(_BITMASK_BURNED | _BITMASK_NEXT_INITIALIZED) | _nextExtraData(from, address(0), prevOwnershipPacked)
);
// If the next slot may not have been initialized (i.e. `nextInitialized == false`) .
if (prevOwnershipPacked & _BITMASK_NEXT_INITIALIZED == 0) {
uint256 nextTokenId = tokenId + 1;
// If the next slot's address is zero and not burned (i.e. packed value is zero).
if (_packedOwnerships[nextTokenId] == 0) {
// If the next slot is within bounds.
if (nextTokenId != _currentIndex) {
// Initialize the next slot to maintain correctness for `ownerOf(tokenId + 1)`.
_packedOwnerships[nextTokenId] = prevOwnershipPacked;
}
}
}
}
emit Transfer(from, address(0), tokenId);
_afterTokenTransfers(from, address(0), tokenId, 1);
// Overflow not possible, as _burnCounter cannot be exceed _currentIndex times.
unchecked {
_burnCounter++;
}
}
// =============================================================
// EXTRA DATA OPERATIONS
// =============================================================
/**
* @dev Directly sets the extra data for the ownership data `index`.
*/
function _setExtraDataAt(uint256 index, uint24 extraData) internal virtual {
uint256 packed = _packedOwnerships[index];
if (packed == 0) revert OwnershipNotInitializedForExtraData();
uint256 extraDataCasted;
// Cast `extraData` with assembly to avoid redundant masking.
assembly {
extraDataCasted := extraData
}
packed = (packed & _BITMASK_EXTRA_DATA_COMPLEMENT) | (extraDataCasted << _BITPOS_EXTRA_DATA);
_packedOwnerships[index] = packed;
}
/**
* @dev Called during each token transfer to set the 24bit `extraData` field.
* Intended to be overridden by the cosumer contract.
*
* `previousExtraData` - the value of `extraData` before transfer.
*
* Calling conditions:
*
* - When `from` and `to` are both non-zero, `from`'s `tokenId` will be
* transferred to `to`.
* - When `from` is zero, `tokenId` will be minted for `to`.
* - When `to` is zero, `tokenId` will be burned by `from`.
* - `from` and `to` are never both zero.
*/
function _extraData(
address from,
address to,
uint24 previousExtraData
) internal view virtual returns (uint24) {}
/**
* @dev Returns the next extra data for the packed ownership data.
* The returned result is shifted into position.
*/
function _nextExtraData(
address from,
address to,
uint256 prevOwnershipPacked
) private view returns (uint256) {
uint24 extraData = uint24(prevOwnershipPacked >> _BITPOS_EXTRA_DATA);
return uint256(_extraData(from, to, extraData)) << _BITPOS_EXTRA_DATA;
}
// =============================================================
// OTHER OPERATIONS
// =============================================================
/**
* @dev Returns the message sender (defaults to `msg.sender`).
*
* If you are writing GSN compatible contracts, you need to override this function.
*/
function _msgSenderERC721A() internal view virtual returns (address) {
return msg.sender;
}
/**
* @dev Converts a uint256 to its ASCII string decimal representation.
*/
function _toString(uint256 value) internal pure virtual returns (string memory str) {
assembly {
// The maximum value of a uint256 contains 78 digits (1 byte per digit), but
// we allocate 0xa0 bytes to keep the free memory pointer 32-byte word aligned.
// We will need 1 word for the trailing zeros padding, 1 word for the length,
// and 3 words for a maximum of 78 digits. Total: 5 * 0x20 = 0xa0.
let m := add(mload(0x40), 0xa0)
// Update the free memory pointer to allocate.
mstore(0x40, m)
// Assign the `str` to the end.
str := sub(m, 0x20)
// Zeroize the slot after the string.
mstore(str, 0)
// Cache the end of the memory to calculate the length later.
let end := str
// We write the string from rightmost digit to leftmost digit.
// The following is essentially a do-while loop that also handles the zero case.
// prettier-ignore
for { let temp := value } 1 {} {
str := sub(str, 1)
// Write the character to the pointer.
// The ASCII index of the '0' character is 48.
mstore8(str, add(48, mod(temp, 10)))
// Keep dividing `temp` until zero.
temp := div(temp, 10)
// prettier-ignore
if iszero(temp) { break }
}
let length := sub(end, str)
// Move the pointer 32 bytes leftwards to make room for the length.
str := sub(str, 0x20)
// Store the length.
mstore(str, length)
}
}
}// SPDX-License-Identifier: MIT
// ERC721A Contracts v4.2.3
// Creator: Chiru Labs
pragma solidity ^0.8.4;
/**
* @dev Interface of ERC721A.
*/
interface IERC721A {
/**
* The caller must own the token or be an approved operator.
*/
error ApprovalCallerNotOwnerNorApproved();
/**
* The token does not exist.
*/
error ApprovalQueryForNonexistentToken();
/**
* Cannot query the balance for the zero address.
*/
error BalanceQueryForZeroAddress();
/**
* Cannot mint to the zero address.
*/
error MintToZeroAddress();
/**
* The quantity of tokens minted must be more than zero.
*/
error MintZeroQuantity();
/**
* The token does not exist.
*/
error OwnerQueryForNonexistentToken();
/**
* The caller must own the token or be an approved operator.
*/
error TransferCallerNotOwnerNorApproved();
/**
* The token must be owned by `from`.
*/
error TransferFromIncorrectOwner();
/**
* Cannot safely transfer to a contract that does not implement the
* ERC721Receiver interface.
*/
error TransferToNonERC721ReceiverImplementer();
/**
* Cannot transfer to the zero address.
*/
error TransferToZeroAddress();
/**
* The token does not exist.
*/
error URIQueryForNonexistentToken();
/**
* The `quantity` minted with ERC2309 exceeds the safety limit.
*/
error MintERC2309QuantityExceedsLimit();
/**
* The `extraData` cannot be set on an unintialized ownership slot.
*/
error OwnershipNotInitializedForExtraData();
// =============================================================
// STRUCTS
// =============================================================
struct TokenOwnership {
// The address of the owner.
address addr;
// Stores the start time of ownership with minimal overhead for tokenomics.
uint64 startTimestamp;
// Whether the token has been burned.
bool burned;
// Arbitrary data similar to `startTimestamp` that can be set via {_extraData}.
uint24 extraData;
}
// =============================================================
// TOKEN COUNTERS
// =============================================================
/**
* @dev Returns the total number of tokens in existence.
* Burned tokens will reduce the count.
* To get the total number of tokens minted, please see {_totalMinted}.
*/
function totalSupply() external view returns (uint256);
// =============================================================
// IERC165
// =============================================================
/**
* @dev Returns true if this contract implements the interface defined by
* `interfaceId`. See the corresponding
* [EIP section](https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified)
* to learn more about how these ids are created.
*
* This function call must use less than 30000 gas.
*/
function supportsInterface(bytes4 interfaceId) external view returns (bool);
// =============================================================
// IERC721
// =============================================================
/**
* @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`,
* checking first that contract recipients are aware of the ERC721 protocol
* to prevent tokens from being forever locked.
*
* Requirements:
*
* - `from` cannot be the zero address.
* - `to` cannot be the zero address.
* - `tokenId` token must exist and be owned by `from`.
* - If the caller is not `from`, it must be have been allowed to move
* this token by either {approve} or {setApprovalForAll}.
* - If `to` refers to a smart contract, it must implement
* {IERC721Receiver-onERC721Received}, which is called upon a safe transfer.
*
* Emits a {Transfer} event.
*/
function safeTransferFrom(
address from,
address to,
uint256 tokenId,
bytes calldata data
) external payable;
/**
* @dev Equivalent to `safeTransferFrom(from, to, tokenId, '')`.
*/
function safeTransferFrom(
address from,
address to,
uint256 tokenId
) external payable;
/**
* @dev Transfers `tokenId` from `from` to `to`.
*
* WARNING: Usage of this method is discouraged, use {safeTransferFrom}
* whenever possible.
*
* Requirements:
*
* - `from` cannot be the zero address.
* - `to` cannot be the zero address.
* - `tokenId` token must be owned by `from`.
* - If the caller is not `from`, it must be approved to move this token
* by either {approve} or {setApprovalForAll}.
*
* Emits a {Transfer} event.
*/
function transferFrom(
address from,
address to,
uint256 tokenId
) external payable;
/**
* @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 payable;
/**
* @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);
// =============================================================
// IERC721Metadata
// =============================================================
/**
* @dev Returns the token collection name.
*/
function name() external view returns (string memory);
/**
* @dev Returns the token collection symbol.
*/
function symbol() external view returns (string memory);
/**
* @dev Returns the Uniform Resource Identifier (URI) for `tokenId` token.
*/
function tokenURI(uint256 tokenId) external view returns (string memory);
// =============================================================
// IERC2309
// =============================================================
/**
* @dev Emitted when tokens in `fromTokenId` to `toTokenId`
* (inclusive) is transferred from `from` to `to`, as defined in the
* [ERC2309](https://eips.ethereum.org/EIPS/eip-2309) standard.
*
* See {_mintERC2309} for more details.
*/
event ConsecutiveTransfer(uint256 indexed fromTokenId, uint256 toTokenId, address indexed from, address indexed to);
}{
"viaIR": true,
"optimizer": {
"enabled": true,
"runs": 888888
},
"evmVersion": "paris",
"outputSelection": {
"*": {
"*": [
"evm.bytecode",
"evm.deployedBytecode",
"devdoc",
"userdoc",
"metadata",
"abi"
]
}
},
"libraries": {}
}Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
Contract ABI
API[{"inputs":[{"components":[{"internalType":"address","name":"owner","type":"address"},{"internalType":"string","name":"name","type":"string"},{"internalType":"string","name":"symbol","type":"string"},{"internalType":"uint256","name":"price","type":"uint256"},{"internalType":"uint256","name":"maxSupply","type":"uint256"},{"internalType":"uint256","name":"maxMintPerAddress","type":"uint256"},{"internalType":"uint256","name":"secondsPerRound","type":"uint256"},{"internalType":"uint256","name":"agentsToWoundPerRoundInBasisPoints","type":"uint256"},{"internalType":"uint256","name":"roundsToBeWoundedBeforeDead","type":"uint256"},{"internalType":"address","name":"looks","type":"address"},{"internalType":"address","name":"vrfCoordinator","type":"address"},{"internalType":"bytes32","name":"keyHash","type":"bytes32"},{"internalType":"uint64","name":"subscriptionId","type":"uint64"},{"internalType":"address","name":"transferManager","type":"address"},{"internalType":"uint256","name":"healBaseCost","type":"uint256"},{"internalType":"address","name":"protocolFeeRecipient","type":"address"},{"internalType":"uint16","name":"protocolFeeBp","type":"uint16"},{"internalType":"address","name":"weth","type":"address"},{"internalType":"string","name":"baseURI","type":"string"}],"internalType":"struct IInfiltration.ConstructorCalldata","name":"constructorCalldata","type":"tuple"},{"internalType":"address","name":"blast","type":"address"},{"internalType":"address","name":"blastPoints","type":"address"},{"internalType":"address","name":"blastPointsOperator","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"ApprovalCallerNotOwnerNorApproved","type":"error"},{"inputs":[],"name":"ApprovalQueryForNonexistentToken","type":"error"},{"inputs":[],"name":"BalanceQueryForZeroAddress","type":"error"},{"inputs":[],"name":"ERC20TransferFail","type":"error"},{"inputs":[],"name":"ExceededTotalSupply","type":"error"},{"inputs":[],"name":"FrontrunLockIsOn","type":"error"},{"inputs":[],"name":"GameAlreadyBegun","type":"error"},{"inputs":[],"name":"GameIsStillRunning","type":"error"},{"inputs":[],"name":"GameNotYetBegun","type":"error"},{"inputs":[],"name":"GameOver","type":"error"},{"inputs":[],"name":"HealingDisabled","type":"error"},{"inputs":[],"name":"Immutable","type":"error"},{"inputs":[],"name":"InexactNativeTokensSupplied","type":"error"},{"inputs":[{"internalType":"uint256","name":"agentId","type":"uint256"},{"internalType":"enum IInfiltration.AgentStatus","name":"expectedStatus","type":"uint8"}],"name":"InvalidAgentStatus","type":"error"},{"inputs":[],"name":"InvalidHealingRoundsDelay","type":"error"},{"inputs":[],"name":"InvalidMaxSupply","type":"error"},{"inputs":[],"name":"InvalidMintPeriod","type":"error"},{"inputs":[],"name":"InvalidPlacement","type":"error"},{"inputs":[],"name":"InvalidRandomnessRequestId","type":"error"},{"inputs":[],"name":"MaximumHealingRequestPerRoundExceeded","type":"error"},{"inputs":[],"name":"MintAlreadyStarted","type":"error"},{"inputs":[],"name":"MintCanOnlyBeExtended","type":"error"},{"inputs":[],"name":"MintERC2309QuantityExceedsLimit","type":"error"},{"inputs":[],"name":"MintStartIsInThePast","type":"error"},{"inputs":[],"name":"MintToZeroAddress","type":"error"},{"inputs":[],"name":"MintZeroQuantity","type":"error"},{"inputs":[],"name":"NoAgentsLeft","type":"error"},{"inputs":[],"name":"NoAgentsProvided","type":"error"},{"inputs":[],"name":"NoOngoingTransferInProgress","type":"error"},{"inputs":[],"name":"NotAContract","type":"error"},{"inputs":[],"name":"NotAgentOwner","type":"error"},{"inputs":[],"name":"NotEnoughMinted","type":"error"},{"inputs":[],"name":"NotInMintPeriod","type":"error"},{"inputs":[],"name":"NotOwner","type":"error"},{"inputs":[],"name":"NothingToClaim","type":"error"},{"inputs":[{"internalType":"address","name":"have","type":"address"},{"internalType":"address","name":"want","type":"address"}],"name":"OnlyCoordinatorCanFulfill","type":"error"},{"inputs":[],"name":"OwnerQueryForNonexistentToken","type":"error"},{"inputs":[],"name":"OwnershipNotInitializedForExtraData","type":"error"},{"inputs":[],"name":"ProtocolFee__InvalidValue","type":"error"},{"inputs":[],"name":"RandomnessRequestAlreadyExists","type":"error"},{"inputs":[],"name":"ReentrancyFail","type":"error"},{"inputs":[],"name":"RenouncementNotInProgress","type":"error"},{"inputs":[],"name":"RoundsToBeWoundedBeforeDeadTooLow","type":"error"},{"inputs":[],"name":"StillMinting","type":"error"},{"inputs":[],"name":"TooEarlyToRetryRandomnessRequest","type":"error"},{"inputs":[],"name":"TooEarlyToStartNewRound","type":"error"},{"inputs":[],"name":"TooManyMinted","type":"error"},{"inputs":[],"name":"TransferAlreadyInProgress","type":"error"},{"inputs":[],"name":"TransferCallerNotOwnerNorApproved","type":"error"},{"inputs":[],"name":"TransferFromIncorrectOwner","type":"error"},{"inputs":[],"name":"TransferNotInProgress","type":"error"},{"inputs":[],"name":"TransferToNonERC721ReceiverImplementer","type":"error"},{"inputs":[],"name":"TransferToZeroAddress","type":"error"},{"inputs":[],"name":"URIQueryForNonexistentToken","type":"error"},{"inputs":[],"name":"WoundedAgentIdsPerRoundExceeded","type":"error"},{"inputs":[],"name":"WrongPotentialOwner","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"address","name":"approved","type":"address"},{"indexed":true,"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"Approval","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"address","name":"operator","type":"address"},{"indexed":false,"internalType":"bool","name":"approved","type":"bool"}],"name":"ApprovalForAll","type":"event"},{"anonymous":false,"inputs":[],"name":"CancelOwnershipTransfer","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"fromTokenId","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"toTokenId","type":"uint256"},{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"}],"name":"ConsecutiveTransfer","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"ethAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"looksAmount","type":"uint256"}],"name":"EmergencyWithdrawal","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"roundId","type":"uint256"},{"indexed":false,"internalType":"uint256[]","name":"agentIds","type":"uint256[]"},{"indexed":false,"internalType":"uint256[]","name":"rewards","type":"uint256[]"}],"name":"Escaped","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"roundId","type":"uint256"},{"components":[{"internalType":"uint256","name":"agentId","type":"uint256"},{"internalType":"enum IInfiltration.HealOutcome","name":"outcome","type":"uint8"}],"indexed":false,"internalType":"struct IInfiltration.HealResult[]","name":"healResults","type":"tuple[]"}],"name":"HealRequestFulfilled","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"roundId","type":"uint256"},{"indexed":false,"internalType":"uint256[]","name":"agentIds","type":"uint256[]"},{"indexed":false,"internalType":"uint256[]","name":"costs","type":"uint256[]"}],"name":"HealRequestSubmitted","type":"event"},{"anonymous":false,"inputs":[],"name":"InitiateOwnershipRenouncement","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"previousOwner","type":"address"},{"indexed":false,"internalType":"address","name":"potentialOwner","type":"address"}],"name":"InitiateOwnershipTransfer","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"requestId","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"randomnessRequestRoundId","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"currentRoundId","type":"uint256"}],"name":"InvalidRandomnessFulfillment","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"roundId","type":"uint256"},{"indexed":false,"internalType":"uint256[]","name":"agentIds","type":"uint256[]"}],"name":"Killed","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"mintStart","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"mintEnd","type":"uint256"}],"name":"MintPeriodUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"newOwner","type":"address"}],"name":"NewOwner","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"agentId","type":"uint256"},{"indexed":false,"internalType":"address","name":"currency","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"PrizeClaimed","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint16","name":"protocolFeeBp","type":"uint16"}],"name":"ProtocolFeeBpUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"protocolFeeRecipient","type":"address"}],"name":"ProtocolFeeRecipientUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"roundId","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"requestId","type":"uint256"}],"name":"RandomnessFulfilled","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"roundId","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"requestId","type":"uint256"}],"name":"RandomnessRequested","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"roundId","type":"uint256"}],"name":"RoundStarted","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":true,"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"Transfer","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"roundId","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"agentId","type":"uint256"}],"name":"Won","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"roundId","type":"uint256"},{"indexed":false,"internalType":"uint256[]","name":"agentIds","type":"uint256[]"}],"name":"Wounded","type":"event"},{"inputs":[],"name":"AGENTS_TO_WOUND_PER_ROUND_IN_BASIS_POINTS","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"HEAL_BASE_COST","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"MAXIMUM_PROTOCOL_FEE_BP","outputs":[{"internalType":"uint16","name":"","type":"uint16"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"MAX_MINT_PER_ADDRESS","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"MAX_SUPPLY","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"PRICE","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"ROUNDS_TO_BE_WOUNDED_BEFORE_DEAD","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"SECONDS_PER_ROUND","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"agentId","type":"uint256"}],"name":"agentIndex","outputs":[{"internalType":"uint256","name":"index","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"agentsAlive","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"minter","type":"address"}],"name":"amountMintedPerAddress","outputs":[{"internalType":"uint256","name":"amount","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"approve","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"}],"name":"balanceOf","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"cancelOwnershipTransfer","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"claimGrandPrize","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"agentId","type":"uint256"}],"name":"claimSecondaryPrizes","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"requestId","type":"uint256"}],"name":"closeRound","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"confirmOwnershipRenouncement","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"confirmOwnershipTransfer","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256[]","name":"agentIds","type":"uint256[]"}],"name":"costToHeal","outputs":[{"internalType":"uint256","name":"cost","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"emergencyWithdraw","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256[]","name":"agentIds","type":"uint256[]"}],"name":"escape","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"escapeMultiplier","outputs":[{"internalType":"uint256","name":"multiplier","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256[]","name":"agentIds","type":"uint256[]"}],"name":"escapeReward","outputs":[{"internalType":"uint256","name":"reward","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"escapeRewardSplitForSecondaryPrizePool","outputs":[{"internalType":"uint256","name":"split","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"gameInfo","outputs":[{"internalType":"uint16","name":"activeAgents","type":"uint16"},{"internalType":"uint16","name":"woundedAgents","type":"uint16"},{"internalType":"uint16","name":"healingAgents","type":"uint16"},{"internalType":"uint16","name":"deadAgents","type":"uint16"},{"internalType":"uint16","name":"escapedAgents","type":"uint16"},{"internalType":"uint40","name":"currentRoundId","type":"uint40"},{"internalType":"uint40","name":"currentRoundBlockTimestamp","type":"uint40"},{"internalType":"uint40","name":"randomnessLastRequestedAt","type":"uint40"},{"internalType":"uint256","name":"prizePool","type":"uint256"},{"internalType":"uint256","name":"secondaryPrizePool","type":"uint256"},{"internalType":"uint256","name":"secondaryLooksPrizePool","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"index","type":"uint256"}],"name":"getAgent","outputs":[{"components":[{"internalType":"uint16","name":"agentId","type":"uint16"},{"internalType":"enum IInfiltration.AgentStatus","name":"status","type":"uint8"},{"internalType":"uint40","name":"woundedAt","type":"uint40"},{"internalType":"uint16","name":"healCount","type":"uint16"}],"internalType":"struct IInfiltration.Agent","name":"agent","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"getApproved","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"roundId","type":"uint256"}],"name":"getRoundInfo","outputs":[{"internalType":"uint256[]","name":"woundedAgentIds","type":"uint256[]"},{"internalType":"uint256[]","name":"healingAgentIds","type":"uint256[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256[]","name":"agentIds","type":"uint256[]"}],"name":"heal","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"healingRoundsDelay","type":"uint256"}],"name":"healProbability","outputs":[{"internalType":"uint256","name":"y","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"initiateOwnershipRenouncement","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newPotentialOwner","type":"address"}],"name":"initiateOwnershipTransfer","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"},{"internalType":"address","name":"operator","type":"address"}],"name":"isApprovedForAll","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"quantity","type":"uint256"}],"name":"mint","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"mintEnd","outputs":[{"internalType":"uint40","name":"","type":"uint40"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"mintStart","outputs":[{"internalType":"uint40","name":"","type":"uint40"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"name","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"ownerOf","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"ownershipStatus","outputs":[{"internalType":"enum IOwnableTwoSteps.Status","name":"","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"potentialOwner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"quantity","type":"uint256"}],"name":"premint","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"protocolFeeBp","outputs":[{"internalType":"uint16","name":"","type":"uint16"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"protocolFeeRecipient","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"requestId","type":"uint256"}],"name":"randomnessRequests","outputs":[{"internalType":"enum IInfiltration.RandomnessRequestStatus","name":"status","type":"uint8"},{"internalType":"uint40","name":"roundId","type":"uint40"},{"internalType":"uint256","name":"randomWord","type":"uint256"}],"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":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"safeTransferFrom","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"},{"internalType":"bytes","name":"_data","type":"bytes"}],"name":"safeTransferFrom","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"uint256","name":"secondaryPrizePoolAmount","type":"uint256"},{"internalType":"uint256","name":"placement","type":"uint256"}],"name":"secondaryPrizePoolShareAmount","outputs":[{"internalType":"uint256","name":"shareAmount","type":"uint256"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"uint256","name":"placement","type":"uint256"}],"name":"secondaryPrizePoolShareBp","outputs":[{"internalType":"uint256","name":"share","type":"uint256"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"address","name":"operator","type":"address"},{"internalType":"bool","name":"approved","type":"bool"}],"name":"setApprovalForAll","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint40","name":"newMintStart","type":"uint40"},{"internalType":"uint40","name":"newMintEnd","type":"uint40"}],"name":"setMintPeriod","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"startGame","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"startNewRound","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes4","name":"interfaceId","type":"bytes4"}],"name":"supportsInterface","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"symbol","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"tokenURI","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalSupply","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"transferFrom","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"uint16","name":"","type":"uint16"}],"name":"updateProtocolFeeBp","outputs":[],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"updateProtocolFeeRecipient","outputs":[],"stateMutability":"pure","type":"function"}]Contract Creation Code
6102806040523462000c3c57600062006cf88038038091620000248261028062000c6b565b610280396080811262000c385761028051906001600160401b03821162000c34576102608282031262000c34576040519161026083016001600160401b0381118482101762000c20576040526200007f816102800162000c8f565b83526102a08101516001600160401b038111620007e057620000ad9083610280019083610280010162000ca4565b60208401526102c08101516001600160401b038111620007e057620000de9083610280019083610280010162000ca4565b60408401526102e08101516060840152610300810151608084015261032081015160a084015261034081015160c084015261036081015160e0840152610380810151610100840152620001356103a0820162000c8f565b6101208401526200014a6103c0820162000c8f565b6101408401526103e08101516101608401526104008101516001600160401b0381168103620007e05761018084015262000188610420820162000c8f565b6101a08401526104408101516101c0840152620001a9610460820162000c8f565b6101e084015261048081015161ffff81168103620007e057610200840152620001d66104a0820162000c8f565b6102208401526104c08101516001600160401b038111620007e05762000206926102800191610280010162000ca4565b610240820152620002196102a062000c8f565b90620002276102c062000c8f565b620002346102e062000c8f565b61014083015160208085015160408087015187518a546001600160a01b0319166001600160a01b039182169081178c5592519283529597959490941693927f3edd90e7770f06fafde38004653b33870066c33bfc923ff6102acd601f85dfbc91a18051906001600160401b03821162000c0c57600454600181811c9116801562000c01575b602082101462000bed579081601f84931162000b7d575b50602090601f831160011462000af0578a9262000ae4575b50508160011b916000199060031b1c1916176004555b8051906001600160401b03821162000ad057600554600181811c9116801562000ac5575b602082101462000ab1579081601f84931162000a5e575b50602090601f8311600114620009d1578992620009c5575b50508160011b916000199060031b1c1916176005555b60016002556080908152600a805461ffff60b01b191661020160b01b17905581015161012c811180159190620009b8575b50620009a657608081015160e08201519081810291818304149015171562000992576216e3601062000980576003610100820151106200096e57606081015160e052608081015160a05260a081015160c05260c08101516101005260e08101516101205261010081015180610140526000198101610160526064810290808204606414811517156200095a5760451982019182116200095a576305f5e10090828281020482148315171562000946576000198101156200093257600019019102046101809081526101208201516001600160a01b039081166101e0526101c0808401516101a0908152610160850151610200526101408501518316610220908152938501516001600160401b039081166102409081529186015184166102605293850151909216905282015180519182116200091e57600c54600181811c9116801562000913575b6020821014620008ff579081601f8493116200088f575b50602090601f831160011462000802578892620007f6575b50508160011b916000199060031b1c191617600c555b6101e08101516001600160a01b0316938415620007e457600a54947fc1b5345cce283376356748dc57f2dfa7120431d016fc7ca9ba641bc65f91411d6020604051838152a161020083015161ffff81166109c48111620007e4576001600160b01b031990971690911760a09190911b61ffff60a01b1617600a5560405194855285947fede4aee4284b8033b84c1aadcc51b229a4e46e6b42ab40092e237f07508b462690602090a190516001600160a01b039081169116803b15620007e05760648592604051978893849263c8992e6160e01b8452600260048501526001602485015260448401525af18015620007d557620007be575b91925082916001600160a01b0316803b15620007ba576040516336b91f2b60e01b81526001600160a01b0390921660048301529091908290602490829084905af18015620007af5762000794575b604051615fdd908162000d1b823960805181613e10015260a0518181816113f8015281816133790152614f8b015260c05181818161148a0152612991015260e0518181816123d70152614efe015261010051818181610d6101528181612d9b0152612f12015261012051818181612bc10152615885015261014051818181610ca4015281816120c101528181612e42015261447001526101605181614410015261018051816143c501526101a0518181816138d2015261522601526101c051818181610b90015281816126ad0152818161349c015281816135c8015261479401526101e0518181816118590152818161361b0152818161463c01526146d501526102005181615d0601526102205181615d7b01526102405181615d2c015261026051816118360152f35b620007a0829162000c41565b620007ac57806200066a565b80fd5b6040513d84823e3d90fd5b5050fd5b919092620007cc9062000c41565b9082906200061c565b6040513d85823e3d90fd5b8480fd5b604051635937835d60e01b8152600490fd5b0151905038806200050f565b600c89528893507fdf6966c971051c3d54ec59162606531493a51404a002842f56009d7e5cf4a8c791905b601f198416851062000873576001945083601f1981161062000859575b505050811b01600c5562000525565b015160001960f88460031b161c191690553880806200084a565b818101518355602094850194600190930192909101906200082d565b600c89529091507fdf6966c971051c3d54ec59162606531493a51404a002842f56009d7e5cf4a8c7601f840160051c810160208510620008f7575b90849392915b601f830160051c82018110620008e8575050620004f7565b8a8155859450600101620008d0565b5080620008ca565b634e487b7160e01b88526022600452602488fd5b90607f1690620004e0565b634e487b7160e01b87526041600452602487fd5b634e487b7160e01b88526012600452602488fd5b634e487b7160e01b88526011600452602488fd5b634e487b7160e01b87526011600452602487fd5b6040516334b8ab9f60e21b8152600490fd5b60405163691b800960e11b8152600490fd5b634e487b7160e01b86526011600452602486fd5b60405163066f305360e21b8152600490fd5b61ffff9150113862000398565b01519050388062000351565b60058a528993507f036b6384b5eca791c62761152d0c79bb0604c104a5fb6f4eb0703f3154bb3db091905b601f198416851062000a42576001945083601f1981161062000a28575b505050811b0160055562000367565b015160001960f88460031b161c1916905538808062000a19565b81810151835560209485019460019093019290910190620009fc565b9091506005895260208920601f840160051c81016020851062000aa9575b90849392915b601f830160051c8201811062000a9a57505062000339565b8b815585945060010162000a82565b508062000a7c565b634e487b7160e01b89526022600452602489fd5b90607f169062000322565b634e487b7160e01b88526041600452602488fd5b015190503880620002e8565b60048b528a93507f8a35acfbc15ff81a39ae7d344fd709f28e8600b4aa8c65c6b64bfe7fe36bd19b91905b601f198416851062000b61576001945083601f1981161062000b47575b505050811b01600455620002fe565b015160001960f88460031b161c1916905538808062000b38565b8181015183556020948501946001909301929091019062000b1b565b60048b529091507f8a35acfbc15ff81a39ae7d344fd709f28e8600b4aa8c65c6b64bfe7fe36bd19b601f840160051c81016020851062000be5575b90849392915b601f830160051c8201811062000bd6575050620002d0565b8c815585945060010162000bbe565b508062000bb8565b634e487b7160e01b8a52602260045260248afd5b90607f1690620002b9565b634e487b7160e01b89526041600452602489fd5b634e487b7160e01b85526041600452602485fd5b8280fd5b5080fd5b600080fd5b6001600160401b03811162000c5557604052565b634e487b7160e01b600052604160045260246000fd5b601f909101601f19168101906001600160401b0382119082101762000c5557604052565b51906001600160a01b038216820362000c3c57565b919080601f8401121562000c3c5782516001600160401b03811162000c55576020906040519262000cdf83601f19601f850116018562000c6b565b81845282828701011162000c3c5760005b81811062000d0657508260009394955001015290565b858101830151848201840152820162000cf056fe6080604052600436101561001257600080fd5b60003560e01c806301ffc9a7146103f757806306fdde03146103f25780630744f3d5146103ed578063081812fc146103e8578063095ea7b3146103e35780631613f92c146103de57806317d65508146103d957806318160ddd146103d45780631cecfca1146103cf5780631df47f80146103ca5780631fe543e3146103c557806323452b9c146103c057806323b872dd146103bb578063255e4685146103b65780632b5e3e26146103b15780632bb5a9e6146103ac5780632de5aaf7146103a7578063311b8d5c146103a257806332cb6b0c1461039d57806335a8bfca146103985780633acd6cb2146103935780633e5675391461038e57806342842e0e1461038957806349890e151461038457806352a43eed1461037f57806355b159091461037a5780635b6ac011146103755780635cb6dfff146103705780636352211e1461036b57806364df049e14610366578063703fd3f81461036157806370a082311461035c5780637200b829146103575780637762df25146103525780637c18f2b61461034d57806388c3ffb01461034857806388e01a98146103435780638d859f3e1461033e5780638da5cb5b1461033957806395d89b411461033457806398753c461461032f5780639c87e0a81461032a5780639feddaed14610325578063a0712d6814610320578063a1fb20151461031b578063a22cb46514610316578063b106857914610311578063b88d4fde1461030c578063bd85948c14610307578063c0b6f56114610302578063c87b56dd146102fd578063d580c87f146102f8578063d65ab5f2146102f3578063db2e21bc146102ee578063db73bfce146102e9578063e1c31530146102e4578063e67e1666146102df578063e9254d26146102da578063e985e9c5146102d5578063ea2b4ab2146102d0578063ee94cec9146102cb5763eedaaa8d146102c657600080fd5b613cd7565b613a7b565b613a10565b613976565b6138f5565b61389c565b61385b565b61379a565b613536565b613316565b6132b1565b6130ab565b612fc3565b612cc0565b612c1e565b612b8b565b612a9c565b612a51565b6128a6565b612816565b612573565b612530565b61244c565b6123fa565b6123a1565b611fca565b611f44565b611ebd565b611e6b565b611cfb565b611c5c565b611c20565b611bce565b611b74565b611b02565b611a26565b6119ea565b611600565b6115c5565b6115a2565b6114ad565b611454565b61141b565b6113c2565b61135c565b61126c565b6111ca565b61112c565b6110e6565b6110d4565b610f6c565b610ebf565b610d84565b610d2b565b610cc7565b610c6e565b610aa1565b610964565b610886565b61076f565b6105a0565b61042b565b7fffffffff0000000000000000000000000000000000000000000000000000000081160361042657565b600080fd5b346104265760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126104265760207fffffffff00000000000000000000000000000000000000000000000000000000600435610489816103fc565b167f01ffc9a70000000000000000000000000000000000000000000000000000000081149081156104f1575b81156104c7575b506040519015158152f35b7f5b5e139f00000000000000000000000000000000000000000000000000000000915014386104bc565b7f80ac58cd00000000000000000000000000000000000000000000000000000000811491506104b5565b600091031261042657565b60005b8381106105395750506000910152565b8181015183820152602001610529565b907fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f60209361058581518092818752878088019101610526565b0116010190565b90602061059d928181520190610549565b90565b34610426576000807ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc360112610701576040519080600454906001918060011c92600182169283156106f7575b6020926020861085146106ca57858852602088019490811561068b5750600114610632575b61062e8761062281890382610e66565b6040519182918261058c565b0390f35b600460005294509192917f8a35acfbc15ff81a39ae7d344fd709f28e8600b4aa8c65c6b64bfe7fe36bd19b5b83861061067a57505050910190506106228261062e3880610612565b80548587015294820194810161065e565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001685525050505090151560051b0190506106228261062e3880610612565b6024827f4e487b710000000000000000000000000000000000000000000000000000000081526022600452fd5b93607f16936105ed565b80fd5b9060207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc8301126104265760043567ffffffffffffffff9283821161042657806023830112156104265781600401359384116104265760248460051b83010111610426576024019190565b346104265761077d36610704565b6000916107a261079d8361079861ffff6013541661ffff1690565b613d4d565b614870565b6107aa614226565b91601454601554916000925b8184106107c857604051878152602090f35b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff60019161086261087661086f6108518b809d6108686108596108518f8f8f8f9061084061081e610845948b9461084b97613d89565b3561083b61082b82614852565b600052600f602052604060002090565b6148a3565b613dcd565b95614a0c565b85613ddc565b612710900490565b96878093613dff565b9e614a95565b9103613ddc565b8093613dff565b95030397019301929495916107b6565b346104265760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc360112610426576004356108c181614b11565b156108f4576000526008602052602073ffffffffffffffffffffffffffffffffffffffff60406000205416604051908152f35b60046040517fcf4700e4000000000000000000000000000000000000000000000000000000008152fd5b6004359073ffffffffffffffffffffffffffffffffffffffff8216820361042657565b6024359073ffffffffffffffffffffffffffffffffffffffff8216820361042657565b60407ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126104265761099661091e565b60243573ffffffffffffffffffffffffffffffffffffffff806109b8836153ca565b1690813303610a38575b600083815260086020526040812080547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff87161790559316907f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b9258480a480f35b81600052600960205260ff610a713360406000209073ffffffffffffffffffffffffffffffffffffffff16600052602052604060002090565b54166109c25760046040517fcfb3b942000000000000000000000000000000000000000000000000000000008152fd5b34610426576000807ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261070157600260ff600a5460b01c1614610c4457610b277602000000000000000000000000000000000000000000007fffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffffffff600a541617600a55565b610b2f614b65565b60018152600f602052604081205461ffff1680610c3f575060015b610b5381614be5565b6014548015610c15577f4aa95f981a8337cb337de335b965507da0879c3b49f799d20058e913f5ad2c2691610b886000601455565b610bb45a83337f0000000000000000000000000000000000000000000000000000000000000000614c4b565b6040805191825260006020830152810191909152606090a1610c127601000000000000000000000000000000000000000000007fffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffffffff600a541617600a55565b80f35b60046040517f969bf728000000000000000000000000000000000000000000000000000000008152fd5b610b4a565b60046040517f1bbee726000000000000000000000000000000000000000000000000000000008152fd5b346104265760007ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126104265760206040517f00000000000000000000000000000000000000000000000000000000000000008152f35b346104265760007ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261042657600254600354602091037fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff015b604051908152f35b346104265760007ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126104265760206040517f00000000000000000000000000000000000000000000000000000000000000008152f35b346104265760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261042657610dbb61091e565b5060046040517fbb7790e6000000000000000000000000000000000000000000000000000000008152fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b6080810190811067ffffffffffffffff821117610e3157604052565b610de6565b67ffffffffffffffff8111610e3157604052565b6020810190811067ffffffffffffffff821117610e3157604052565b90601f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0910116810190811067ffffffffffffffff821117610e3157604052565b67ffffffffffffffff8111610e315760051b60200190565b346104265760407ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126104265760243567ffffffffffffffff8111610426573660238201121561042657806004013590610f1a82610ea7565b90610f286040519283610e66565b8282526020926024602084019160051b8301019136831161042657602401905b828210610f5d57610f5b84600435613e0c565b005b81358152908401908401610f48565b34610426576000807ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261070157610fa4614ead565b60015460ff8160a01c16610fb7816111bb565b801561104a5780610fc96001926111bb565b1461101f575b507fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff600154166001557f8eca980489e87f7dba4f26917aa4bfc906eb3f2b4f7b4b9fd0ff2b8bb3e21ae38180a180f35b7fffffffffffffffffffffffff00000000000000000000000000000000000000001660015538610fcf565b60046040517fccf69db7000000000000000000000000000000000000000000000000000000008152fd5b7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc60609101126104265773ffffffffffffffffffffffffffffffffffffffff90600435828116810361042657916024359081168103610426579060443590565b610f5b6110e036611074565b91613ec1565b346104265760007ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261042657602064ffffffffff600a5460c01c16604051908152f35b60407ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261042657610f5b61116161091e565b6024359061116d614ead565b61117682614ef8565b61117f82614f55565b611187614fdb565b615018565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fd5b600311156111c557565b61118c565b346104265760007ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261042657602060ff60015460a01c1660405190611211816111bb565b8152f35b600511156111c557565b9060058210156111c55752565b919091606060808201938161ffff918281511685526112536020820151602087019061121f565b64ffffffffff6040820151166040860152015116910152565b346104265760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261042657600435604080606081516112ae81610e15565b600091818380935282602082015282858201520152838152600f60205220908051916112d983610e15565b5461ffff808216845260ff8260101c169160058310156111c55761062e9561132a61134a93611343936113529660208a015264ffffffffff8160181c16888a0152871c16606088019061ffff169052565b61133e81600052600f602052604060002090565b614bd2565b61ffff1690565b61ffff168352565b519182918261122c565b346104265760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126104265760043561ffff8116036104265760046040517fbb7790e6000000000000000000000000000000000000000000000000000000008152fd5b346104265760007ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126104265760206040517f00000000000000000000000000000000000000000000000000000000000000008152f35b346104265760007ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc360112610426576020610d23614226565b346104265760007ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126104265760206040517f00000000000000000000000000000000000000000000000000000000000000008152f35b34610426576000807ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc360112610701576114e5614ead565b600154600260ff8260a01c166114fa816111bb565b03611578577fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff907fffffffffffffffffffffffff00000000000000000000000000000000000000008354168355166001557f3edd90e7770f06fafde38004653b33870066c33bfc923ff6102acd601f85dfbc6020604051838152a180f35b60046040517f045c5122000000000000000000000000000000000000000000000000000000008152fd5b610f5b6115ae36611074565b90604051926115bc84610e4a565b600084526147e0565b346104265760007ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126104265760206040516109c48152f35b346104265761160e36610704565b600260ff600a5460b01c1614610c44576116647602000000000000000000000000000000000000000000007fffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffffffff600a541617600a55565b61166c6151a8565b6013549161ffff9261012c84821611156119c05764ffffffffff90611690846151e4565b60501c16906116a9826000526012602052604060002090565b926116b9611343855461ffff1690565b90808201926096841161199657600094916116d3816142d0565b916000935b8497838610156117ad576117a5908b6117896117796116f88a8989613d89565b359361175d8461172761170a88614852565b61082b8961172283600052600f602052604060002090565b6148f2565b805490620200007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ffff831617905560401c16615215565b6117678c8c61432c565b526117728b8b61432c565b5190613dff565b9860018091019c8b01018d614289565b919092169061ffff8084549260031b9316831b921b1916179055565b9693966116d8565b89547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00001661ffff898d1616178a5592848b6013547fffffffffffffffffffffffffffffffffffffffffffffffffffff00000000ffff8480848460101c160360101b938360201c160160201b9116171760135573ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000000000000000000000000000000000000000000016917f0000000000000000000000000000000000000000000000000000000000000000833b15610426576040517fda3e8ce400000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff8216600482015233602482015230604482015260648101889052936000908590608490829084905af1908115611991577fc336583a12cbbd0e56a944ad6e644ea9b89b312ea7174f79e72f27e83d23c1889761192f9561192393611978575b5060011c9061527a565b60405194859485614389565b0390a1610f5b7601000000000000000000000000000000000000000000007fffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffffffff600a541617600a55565b8061198561198b92610e36565b8061051b565b89611919565b614340565b60046040517f943c39b6000000000000000000000000000000000000000000000000000000008152fd5b60046040517fc90c904e000000000000000000000000000000000000000000000000000000008152fd5b346104265760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc360112610426576020610d236004356143b5565b34610426576000807ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261070157611a5e614ead565b60015460ff8160a01c16611a71816111bb565b611ad8577fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1674020000000000000000000000000000000000000000176001557f3ff05a45e46337fa1cbf20996d2eeb927280bce099f37252bcca1040609604ec8180a180f35b60046040517f74ed79ae000000000000000000000000000000000000000000000000000000008152fd5b346104265760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261042657600435600052600e60205260606040600020805464ffffffffff600160ff83169301549160405193611b62816111bb565b845260081c1660208301526040820152f35b346104265760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261042657602073ffffffffffffffffffffffffffffffffffffffff611bc56004356153ca565b16604051908152f35b346104265760007ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261042657602073ffffffffffffffffffffffffffffffffffffffff600a5416604051908152f35b346104265760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc360112610426576020610d23600435614496565b346104265760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126104265773ffffffffffffffffffffffffffffffffffffffff611ca861091e565b168015611cd1576000526007602052602067ffffffffffffffff60406000205416604051908152f35b60046040517f8f4eb604000000000000000000000000000000000000000000000000000000008152fd5b346104265760007ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261042657600154600160ff8260a01c16611d3f816111bb565b03611e415773ffffffffffffffffffffffffffffffffffffffff163303611e1757600080547fffffffffffffffffffffffff00000000000000000000000000000000000000001633179055611db77fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff60015416600155565b611de47fffffffffffffffffffffffff000000000000000000000000000000000000000060015416600155565b6040513381527f3edd90e7770f06fafde38004653b33870066c33bfc923ff6102acd601f85dfbc9080602081015b0390a1005b60046040517fafdcfb92000000000000000000000000000000000000000000000000000000008152fd5b60046040517f5e4f2826000000000000000000000000000000000000000000000000000000008152fd5b346104265760007ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261042657602073ffffffffffffffffffffffffffffffffffffffff60015416604051908152f35b346104265760407ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc360112610426576020612710611f07611eff602435614496565b600435613ddc565b04604051908152f35b90815180825260208080930193019160005b828110611f30575050505090565b835185529381019392810192600101611f22565b346104265760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261042657611fbc600435806000526011602052611f8f6040600020615486565b90600052601260205261062e611fa86040600020615486565b604051938493604085526040850190611f10565b908382036020850152611f10565b346104265760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126104265760135464ffffffffff808260501c1661201e600435600052600e602052604060002090565b91818354918260081c161490811591612389575b5061235f577f33a701182892fd888ed152ca2ac23771a32e814469b7cd255965471e1af3a65992600180930154612067614226565b9161ffff91828083169260201c169060009180612301575b5061012c8311156121b057846120bb7fffffffffffffffffffffffffffffffffffffffffffffffff0000ffff000000009285612144988a615878565b906000907f0000000000000000000000000000000000000000000000000000000000000000808a1161219c575b505081816013549501878660301c160160301b968560101c16010360101b9303911617171782907fffffffffffffff000000000000000000000000000000ffffffffffffffffffff60014260781b930160501b91161717601355565b61218b770100000000000000000000000000000000000000000000007fffffffffffffffff00ffffffffffffffffffffffffffffffffffffffffffffff600a541617600a55565b604051910181528060208101611e12565b6121a992508903896159f5565b38806120e8565b829187612237969411918261223c575b508293946121f27fffffffffffffffffffffffffffffffffffffffffffffffff0000ffffffff000094601354976157da565b8560301c16010160301b9216171782907fffffffffffffff000000000000000000000000000000ffffffffffffffffffff60014260781b930160501b91161717601355565b612144565b927f671c98e1063255ef19ccc962aca12d122b0043de83631fac15be1cb076e9f7b26122d2866122b28c612291867fffffffffffffffffffffffffffffffffffffffffffffffff0000ffffffff00009a614503565b016122aa8161133e81600052600f602052604060002090565b92839161574f565b6122ba6142a5565b906122c48261431f565b526040519182918c8361450d565b0390a17fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff9485019401926121c0565b92949150612359612314859284896155c2565b939180828097039901960303167fffffffffffffffffffffffffffffffffffffffffffffffffffff0000ffffffff65ffff000000006013549260201b16911617601355565b3861207f565b60046040517fe4c98f71000000000000000000000000000000000000000000000000000000008152fd5b6002915060ff16612399816111bb565b141538612032565b346104265760007ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126104265760206040517f00000000000000000000000000000000000000000000000000000000000000008152f35b346104265760007ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261042657602073ffffffffffffffffffffffffffffffffffffffff60005416604051908152f35b34610426576000807ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc360112610701576040519080600554906001918060011c9260018216928315612526575b6020926020861085146106ca57858852602088019490811561068b57506001146124cd5761062e8761062281890382610e66565b600560005294509192917f036b6384b5eca791c62761152d0c79bb0604c104a5fb6f4eb0703f3154bb3db05b83861061251557505050910190506106228261062e3880610612565b8054858701529482019481016124f9565b93607f1693612499565b346104265760007ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261042657602061ffff600a5460a01c16604051908152f35b346104265761258136610704565b90600260ff600a5460b01c1614610c44576125d87602000000000000000000000000000000000000000000007fffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffffffff600a541617600a55565b6125e06151a8565b6125e9826151e4565b6125fd8261079861134360135461ffff1690565b9061260782614870565b61260f614226565b9060145493601554946000612623836142d0565b9160005b8481106127395750916126d16126eb926126a86126f39a6126a37f537267dffdb0954f0c19f86e8ea73087f7db51b35dc6bea8a9df9b42b86c53d39998976013548d7fffffffffffffffffffffffffffffffffffffffffffff0000ffffffffffff00008b61ffff8460401c160160401b92161717601355601455565b601555565b5a90337f0000000000000000000000000000000000000000000000000000000000000000614c4b565b60135460501c64ffffffffff169260405194859485614524565b0390a16157da565b610f5b7601000000000000000000000000000000000000000000007fffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffffffff600a541617600a55565b958691819961274984888a613d89565b359061275482614be5565b61275d82614852565b928261277385600052600f602052604060002090565b9061277d916148a3565b6127878582613dcd565b9661279186614a0c565b61279b9089613ddc565b6127109004806127ac81998c61432c565b526127b691613dff565b96866127c187614a95565b9103906127cd91613ddc565b61271090049586910303946127e191613dff565b9a6127eb926157b4565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0195600101612627565b346104265760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261042657600260ff600a5460b01c1614610c445761289b7602000000000000000000000000000000000000000000007fffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffffffff600a541617600a55565b6126f3600435614558565b60207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261042657600435600260ff600a5460b01c1614610c44576129297602000000000000000000000000000000000000000000007fffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffffffff600a541617600a55565b600a546129459060c01c64ffffffffff165b64ffffffffff1690565b42108015612a36575b612a0c5761295a614fdb565b61298e816129883373ffffffffffffffffffffffffffffffffffffffff16600052600d602052604060002090565b54613dff565b907f000000000000000000000000000000000000000000000000000000000000000082116129e2576126f3916129c382614ef8565b6129cc82614f55565b336000908152600d602052604090205533615018565b60046040517fdb815ecd000000000000000000000000000000000000000000000000000000008152fd5b60046040517ffa073358000000000000000000000000000000000000000000000000000000008152fd5b50612a4a61293b600b5464ffffffffff1690565b421161294e565b346104265760007ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc360112610426576020610d23612a8d614226565b614a95565b8015150361042657565b346104265760407ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261042657612ad361091e565b73ffffffffffffffffffffffffffffffffffffffff60243591612af583612a92565b336000526009602052612b2c8160406000209073ffffffffffffffffffffffffffffffffffffffff16600052602052604060002090565b921515927fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0081541660ff851617905560405192835216907f17307eab39ab6107e8899845ad3d59bd9653f200f220920489ca2b5937696c3160203392a3005b346104265760007ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126104265760206040517f00000000000000000000000000000000000000000000000000000000000000008152f35b67ffffffffffffffff8111610e3157601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe01660200190565b60807ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261042657612c5061091e565b612c58610941565b6064359167ffffffffffffffff8311610426573660238401121561042657826004013591612c8583612be4565b92612c936040519485610e66565b8084523660248287010111610426576020816000926024610f5b98018388013785010152604435916147e0565b34610426576000807ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261070157600260ff600a5460b01c1614610c4457612d467602000000000000000000000000000000000000000000007fffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffffffff600a541617600a55565b60135464ffffffffff90818160501c16918215612f995762015180908260a01c16014210612f6f57612d76614226565b9161ffff80921691600191828514612f3e575b61012c8411612f08578290612dc060037f000000000000000000000000000000000000000000000000000000000000000004615c9e565b601354612dd39060101c61ffff16611343565b612e40575b505050821115612e32575050612dec615cde565b610c127601000000000000000000000000000000000000000000007fffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffffffff600a541617600a55565b612e3b916157da565b612dec565b7f000000000000000000000000000000000000000000000000000000000000000080821115612f015781035b9087925b612eb4575b50507fffffffffffffffffffffffffffffffffffffffffffffffff0000ffff0000ffff90601354928360301c160160301b911617601355388181612dd8565b909591612ed9611343612ed1896000526011602052604060002090565b5461ffff1690565b15612efa5790848092612eed858a856159f5565b8091019403970191612e70565b9195612e75565b5081612e6c565b5050505050612f367f0000000000000000000000000000000000000000000000000000000000000000615c9e565b612e3b615cde565b828403612d895760046040517fdf469ccb000000000000000000000000000000000000000000000000000000008152fd5b60046040517f9f0306e8000000000000000000000000000000000000000000000000000000008152fd5b60046040517fc1409a71000000000000000000000000000000000000000000000000000000008152fd5b346104265760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261042657612ffa61091e565b613002614ead565b60015460ff8160a01c16613015816111bb565b611ad8577fffffffffffffffffffffff0000000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff90911690811774010000000000000000000000000000000000000000176001556040805133815260208101929092527fb86c75c9bffca616b2d314cc914f7c3f1d174255b16b941c3f3ededee276d5ef919081908101611e12565b34610426576020807ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261042657600435906130e882614b11565b1561328757604051906000600c546001928160011c936001831692831561327d575b6020861084146132505785875286949360208601939291811561321257506001146131b0575b50505061313f92500382610e66565b80511561319e5761062261316c9161317261315c61062e95615f04565b604051948593602085019061483b565b9061483b565b037fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08101835282610e66565b505061062e6131ab614276565b610622565b9250936131df600c6000527fdf6966c971051c3d54ec59162606531493a51404a002842f56009d7e5cf4a8c790565b946000935b8285106131fc5750505061313f935001388080613130565b86548585015295860195879550938101936131e4565b91505061313f959293507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff009150168252151560051b01388080613130565b6024857f4e487b710000000000000000000000000000000000000000000000000000000081526022600452fd5b94607f169461310a565b60046040517fa14c4b50000000000000000000000000000000000000000000000000000000008152fd5b346104265760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126104265773ffffffffffffffffffffffffffffffffffffffff6132fd61091e565b16600052600d6020526020604060002054604051908152f35b346104265760007ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126104265761334d614ead565b60025460035490037fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff017f000000000000000000000000000000000000000000000000000000000000000081106134f2575b61012c81106134c85761ffff613421916133b7614fdb565b6133f16a01000000000000000000007fffffffffffffffffffffffffffffffffff0000000000ffffffffffffffffffff6013541617601355565b1661ffff167fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00006013541617601355565b6134c04761345161344961343f611343600a5461ffff9060a01c1690565b8302612710900490565b809203601455565b604051600181527f33a701182892fd888ed152ca2ac23771a32e814469b7cd255965471e1af3a65990602090a1600a5473ffffffffffffffffffffffffffffffffffffffff16905a917f0000000000000000000000000000000000000000000000000000000000000000614c4b565b610f5b615cde565b60046040517f93c93e01000000000000000000000000000000000000000000000000000000008152fd5b61350561293b600b5464ffffffffff1690565b42101561339f5760046040517f532b23d7000000000000000000000000000000000000000000000000000000008152fd5b34610426576000807ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126107015761356e614ead565b60135461ffff908181169164ffffffffff808360501c161592831594859384613733575b5083613728575b5082613711575b5050816136ef575b82156136e7575b5081156136df575b506135bf5780f35b476135ec5a82337f0000000000000000000000000000000000000000000000000000000000000000614c4b565b6040517f70a08231000000000000000000000000000000000000000000000000000000008152306004820152907f00000000000000000000000000000000000000000000000000000000000000009060208360248173ffffffffffffffffffffffffffffffffffffffff86165afa918215611991577f99010623e00d801536d5e2da7de373bda9592873b6d101d65738aa2582e645229385936136aa575b508261369791339061535c565b604080519182526020820192909252a180f35b6136979193506136d19060203d6020116136d8575b6136c98183610e66565b810190614549565b929061368a565b503d6136bf565b9050386135b7565b9150386135af565b90506201fa4061370861293b600b5464ffffffffff1690565b014211906135a8565b61371f925060781c16613def565b421138806135a0565b600110925038613599565b613767919650613762818460301c1691613762818660401c1691613762818860201c16918860101c168c613dff565b613dff565b60025460035490037fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0114159438613592565b346104265760007ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc360112610426576013546014546015546016546040805161ffff8087168252601087901c811660208084019190915287901c811682840152603087901c811660608301529186901c909116608082015264ffffffffff605086901c811660a080840191909152607887901c821660c08401529590951c90941660e085015261010084019290925261012083015261014082015261016090f35b346104265760007ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc360112610426576020610d23613897614226565b614a0c565b346104265760007ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126104265760206040517f00000000000000000000000000000000000000000000000000000000000000008152f35b346104265761390336610704565b60009182915b80841061391b57602083604051908152f35b909161395a61ffff61392e868587613d89565b3561393881614852565b600052600f6020526040906139518260002091826148f2565b54901c16615215565b810180911161397157600193909301929190613909565b613d1e565b346104265760407ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261042657602060ff613a046139b461091e565b73ffffffffffffffffffffffffffffffffffffffff6139d1610941565b91166000526009845260406000209073ffffffffffffffffffffffffffffffffffffffff16600052602052604060002090565b54166040519015158152f35b346104265760007ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261042657602064ffffffffff600b5416604051908152f35b6004359064ffffffffff8216820361042657565b6024359064ffffffffff8216820361042657565b34610426576040807ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261042657613ab3613a53565b90613abc613a67565b90613ac5614ead565b64ffffffffff8381169390831680851015613cae578415948515613bd3575b50804211908115613bb7575b50613b8e577fde0225a54e6c9fb403aa996cb755cf686017f93bc6bc8e4f9f37e398e3e146bd93613b4d8464ffffffffff167fffffffffffffffffffffffffffffffffffffffffffffffffffffff0000000000600b541617600b55565b15613b845750600a54611e129060c01c64ffffffffff16915b5164ffffffffff928316815292909116602083015281906040820190565b611e129091613b66565b600482517fbe62021d000000000000000000000000000000000000000000000000000000008152fd5b9050613bcc61293b600b5464ffffffffff1690565b1138613af0565b4211613c8557600a54613bef9060c01c64ffffffffff1661293b565b80613c4f575b50613c49827fffffff0000000000ffffffffffffffffffffffffffffffffffffffffffffffff7cffffffffff000000000000000000000000000000000000000000000000600a549260c01b16911617600a55565b38613ae4565b421015613c5c5738613bf5565b600483517fd8aefac8000000000000000000000000000000000000000000000000000000008152fd5b600483517f0fcb8b7b000000000000000000000000000000000000000000000000000000008152fd5b600483517f3ad9580b000000000000000000000000000000000000000000000000000000008152fd5b346104265760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc360112610426576020610d23600435614852565b600052602060002090565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b9190820391821161397157565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b9190811015613d995760051b0190565b613d5a565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b8115613dd7570490565b613d9e565b8181029291811591840414171561397157565b906201fa40820180921161397157565b9190820180921161397157565b91907f00000000000000000000000000000000000000000000000000000000000000009273ffffffffffffffffffffffffffffffffffffffff84163303613e5a57613e58929350614d80565b565b6040517f1cf993f400000000000000000000000000000000000000000000000000000000815233600482015273ffffffffffffffffffffffffffffffffffffffff85166024820152604490fd5b0390fd5b908152604081019291613e58916020019061121f565b90613ecb83614852565b600052600f60205260ff60406000205460101c1660058110156111c5576001811180614204575b6141ce5750613f00836153ca565b73ffffffffffffffffffffffffffffffffffffffff8084169283828416036141a457600086815260086020526040902080549092613f5e73ffffffffffffffffffffffffffffffffffffffff881633908114908414171590565b1590565b614115575b82169586156140eb5761403493613fa0926140e1575b5073ffffffffffffffffffffffffffffffffffffffff166000526007602052604060002090565b80547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff019055613ff08173ffffffffffffffffffffffffffffffffffffffff166000526007602052604060002090565b8054600101905573ffffffffffffffffffffffffffffffffffffffff164260a01b177c02000000000000000000000000000000000000000000000000000000001790565b614048856000526006602052604060002090565b557c0200000000000000000000000000000000000000000000000000000000811615614097575b507fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef600080a4565b600184016140af816000526006602052604060002090565b54156140bc575b5061406f565b60025481146140b6576140d9906000526006602052604060002090565b5538806140b6565b6000905538613f79565b60046040517fea553b34000000000000000000000000000000000000000000000000000000008152fd5b614175613f5a61416e336141498b73ffffffffffffffffffffffffffffffffffffffff166000526009602052604060002090565b9073ffffffffffffffffffffffffffffffffffffffff16600052602052604060002090565b5460ff1690565b15613f635760046040517f59c896be000000000000000000000000000000000000000000000000000000008152fd5b60046040517fa1148100000000000000000000000000000000000000000000000000000000008152fd5b83613ea76040519283927f0d5323a900000000000000000000000000000000000000000000000000000000845260048401613eab565b5061dead73ffffffffffffffffffffffffffffffffffffffff83161415613ef2565b60025460035490037fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0160135461ffff90818160301c1683039283116139715760401c1681039081116139715790565b6040519061428382610e4a565b60008252565b9190916097831015613d9957601e908360041c019260011b1690565b604051906040820182811067ffffffffffffffff821117610e31576040526001825260203681840137565b906142da82610ea7565b6142e76040519182610e66565b8281527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe06143158294610ea7565b0190602036910137565b805115613d995760200190565b8051821015613d995760209160051b010190565b6040513d6000823e3d90fd5b90918281527f07ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff83116104265760209260051b809284830137010190565b929161059d94926143a792855260606020860152606085019161434c565b916040818403910152611f10565b801580801561446d575b614443577f000000000000000000000000000000000000000000000000000000000000000091601e810291818304601e1417156139715763b2d05e0002908082046305f5e1001490151715613971577f0000000000000000000000000000000000000000000000000000000000000000908115613dd7570481039081116139715790565b60046040517f04ea02d5000000000000000000000000000000000000000000000000000000008152fd5b507f000000000000000000000000000000000000000000000000000000000000000082116143bf565b606481029080820460641490151715613971578015613dd7576425c8a44a00047ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffdb610810190811161397157620f4240900490565b6144ff906144f961271093614496565b90613ddc565b0490565b8115613dd7570690565b60409061059d939281528160208201520190611f10565b929161059d949264ffffffffff6143a79316855260606020860152606085019161434c565b90816020910312610426575190565b614560614b65565b61456981614be5565b61457281614852565b61457b81615b06565b600b5466ffffffffffffff9060281c811680831c600116610c15576145de916001841b16177fffffffffffffffffffffffffffffffffffffffff00000000000000ffffffffff6bffffffffffffff0000000000600b549260281b16911617600b55565b6145ea816015546144e9565b80614767575b50601654801561469f575b61460b906144f961271093614496565b0480614615575050565b7f4aa95f981a8337cb337de335b965507da0879c3b49f799d20058e913f5ad2c269161469a7f00000000000000000000000000000000000000000000000000000000000000009261466781338661535c565b6040519384938473ffffffffffffffffffffffffffffffffffffffff604092959493606083019683521660208201520152565b0390a1565b506040517f70a08231000000000000000000000000000000000000000000000000000000008152306004820152906020826024817f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff165afa91821561199157600092614746575b50818215614740576144f961460b9261473661271095601655565b93505090506145fb565b50505050565b61476091925060203d6020116136d8576136c98183610e66565b903861471b565b6147d77f4aa95f981a8337cb337de335b965507da0879c3b49f799d20058e913f5ad2c26916147b85a82337f0000000000000000000000000000000000000000000000000000000000000000614c4b565b6040805186815260006020820152908101919091529081906060820190565b0390a1386145f0565b9291906147ee828286613ec1565b803b6147fa5750505050565b61480393615b9e565b156148115738808080614740565b60046040517fd1a57ed6000000000000000000000000000000000000000000000000000000008152fd5b9061484e60209282815194859201610526565b0190565b9081600052601060205260406000205491821561486c5750565b9150565b60011161487957565b60046040517f61df2a20000000000000000000000000000000000000000000000000000000008152fd5b5460101c60ff1660058110156111c5576148ba5750565b604490604051907f0d5323a9000000000000000000000000000000000000000000000000000000008252600482015260006024820152fd5b5460101c60ff1660058110156111c55760010361490c5750565b604490604051907f0d5323a9000000000000000000000000000000000000000000000000000000008252600482015260016024820152fd5b8015614a065780806001146149ff576002146149f9576001908161013382101682600b831016176149f157906002815b8082116149aa575050817fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff048111613971570290565b9092807fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff048111613971578184166149e8575b800292811c90614974565b809202916149dd565b600291500a90565b50600490565b5050600190565b50600090565b612710908181029181830414901517156139715760025460035490037fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff018015613dd757614a5a9104614944565b8060320290603282040361397157640218711a0081810391818311613971576064830292830460641491141715613971576305f5e100900490565b9061271091828102908082048414901517156139715760025460035490037fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff01908115613dd75704611f4090818102918183041490151715613971576063620f61d09104810390811161397157606490049180831161486c5750565b80600111159081614b59575b81614b26575090565b905060005260066020527c0100000000000000000000000000000000000000000000000000000000604060002054161590565b60025481109150614b1d565b60135461ffff60018183161491821592614bc2575b8215614bb3575b5050614b8957565b60046040517fc7284d0e000000000000000000000000000000000000000000000000000000008152fd5b60201c16151590503880614b81565b9150808260101c16151591614b7a565b5461ffff1680614be0575090565b905090565b614c0373ffffffffffffffffffffffffffffffffffffffff916153ca565b163303614c0c57565b60046040517f390772fc000000000000000000000000000000000000000000000000000000008152fd5b90816020910312610426575161059d81612a92565b614c6082849395600080809781948294f11590565b614c6a5750505050565b73ffffffffffffffffffffffffffffffffffffffff16803b15614d7c57604051937fd0e30db0000000000000000000000000000000000000000000000000000000008552838560048186865af193841561199157614d2395602095614d69575b506040518096819582947fa9059cbb000000000000000000000000000000000000000000000000000000008452600484016020909392919373ffffffffffffffffffffffffffffffffffffffff60408201951681520152565b03925af1801561199157614d3a575b808080614740565b614d5b9060203d602011614d62575b614d538183610e66565b810190614c36565b5038614d32565b503d614d49565b80611985614d7692610e36565b38614cca565b8280fd5b80600052600e602052604060002091614da661293b60135464ffffffffff9060501c1690565b83549064ffffffffff8260081c169181831490811591614e95575b50614e545750507f546aca7b2683440b8f02fa95faeb8efc79dd0f16af3d815a002742ea6f76116c92614df6614e339261431f565b51600182015580547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001660021781555460081c64ffffffffff1690565b6040805164ffffffffff90921682526020820192909252908190810161469a565b60408051948552602085019290925290830152507fea18705d978143c83c4009ada26bdca3246bfd37055c03a17f85d3210cbf85999150806060810161469a565b6001915060ff16614ea5816111bb565b141538614dc1565b73ffffffffffffffffffffffffffffffffffffffff600054163303614ece57565b60046040517f30cd7471000000000000000000000000000000000000000000000000000000008152fd5b614f23907f000000000000000000000000000000000000000000000000000000000000000090613ddc565b3403614f2b57565b60046040517f2a12a0cc000000000000000000000000000000000000000000000000000000008152fd5b60025460035490037fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff01908101809111613971577f000000000000000000000000000000000000000000000000000000000000000010614fb157565b60046040517f5d20e856000000000000000000000000000000000000000000000000000000008152fd5b64ffffffffff60135460501c16614fee57565b60046040517fab6ecc53000000000000000000000000000000000000000000000000000000008152fd5b6002549073ffffffffffffffffffffffffffffffffffffffff811690811561517e57831561515457611388841161512a57613e58936150b48261507d60009473ffffffffffffffffffffffffffffffffffffffff166000526007602052604060002090565b805468010000000000000001850201905573ffffffffffffffffffffffffffffffffffffffff164260a01b6001841460e11b171790565b6150c8856000526006602052604060002090565b558301927fdeaa91b6123d068f5821d0fb0678463d1a8a6079fe8af5de3ce5e896dcf9133d604051806151227fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8801829190602083019252565b0390a4600255565b60046040517f3db1f9af000000000000000000000000000000000000000000000000000000008152fd5b60046040517fb562e8dd000000000000000000000000000000000000000000000000000000008152fd5b60046040517f2e076300000000000000000000000000000000000000000000000000000000008152fd5b600260ff600a5460b81c16146151ba57565b60046040517f2e98fd9a000000000000000000000000000000000000000000000000000000008152fd5b156151eb57565b60046040517fd8ba85a4000000000000000000000000000000000000000000000000000000008152fd5b60ff811161397157600161059d911b7f0000000000000000000000000000000000000000000000000000000000000000613ddc565b3d15615275573d9061525b82612be4565b916152696040519384610e66565b82523d6000602084013e565b606090565b90813b15615332576000918291826040516152d08161317260208201957fa9059cbb0000000000000000000000000000000000000000000000000000000087526024830191906020604084019361dead81520152565b51925af16152dc61524a565b9015615308578051806152ed575050565b81602080613f5a936153029501019101614c36565b61530857565b60046040517ff1568f95000000000000000000000000000000000000000000000000000000008152fd5b60046040517f09ee12d5000000000000000000000000000000000000000000000000000000008152fd5b919091803b15615332576040517fa9059cbb000000000000000000000000000000000000000000000000000000006020820190815273ffffffffffffffffffffffffffffffffffffffff90941660248201526044810192909252600092839283906152d08160648101613172565b8080600111156153ff575b60046040517fdf2d9b42000000000000000000000000000000000000000000000000000000008152fd5b6002548110156153d5576000526006602052604060002054907c010000000000000000000000000000000000000000000000000000000082166153d5575b8115615447575090565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff91500161547f816000526006602052604060002090565b549061543d565b9061ffff9182815416615498816142d0565b9360005b8281106154a95750505050565b60018101906154cb836154bc8488614289565b90549060031b1c16918861432c565b5261549c565b906154db82610ea7565b60406154ea6040519283610e66565b8382527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe06155188395610ea7565b01906000805b83811061552c575050505050565b8251908382019180831067ffffffffffffffff841117610e3157602092855283815282848183015282880101520161551e565b90604091604081019181526020606081926040838201528651809552019401926000905b83821061559257505050505090565b90919293948386518051835201519060028210156111c55784810191909152810194830193929160010190615583565b9290916000936000936155df826000526012602052604060002090565b6155ee611343825461ffff1690565b90816155fc575b5050505090565b91939296508061560c87926154d1565b926000955b82871061565b5750507ff0c0bd04f09c5b4c03d28f7311833e44f9fe752809264f87607a694d218993de939450039561564f6040519283928361555f565b0390a1388080806155f5565b919380959193506001808801978b6156876113436156798c8a614289565b905461ffff9160031b1c1690565b916156d261569484614852565b92846156b4846156ae87600052600f602052604060002090565b9961432c565b515286546156cb9060181c64ffffffffff1661293b565b90036143b5565b6402540be40087061161570e575050505090613d1361570392805461ffff6001818360401c160160401b9116179055565b939290918792615611565b615703959c93945090615732602061572a61574295948d61432c565b510160019052565b61573c8488613d4d565b9061574f565b0197600052602060002090565b9162040000916157a9615798600095838752600f60205280604061577586828b20614bd2565b98878152601060205286828220558981522055600052600f602052604060002090565b91600052600f602052604060002090565b938454179055179055565b9162030000916157a9615798600095838752600f60205280604061577586828b20614bd2565b6001146157e45750565b6001146157ed57565b6013546001600052600f6020527f169f97de0d9a84d840042b17d3c6b9638b3d6fd9024c9eb0c7a306a17b49f88f547f3c6f6a06cfd9c0c95090713d31b06691fff09d08efa09dfe81b5f4fcd0db2c349160501c64ffffffffff169061ffff168061587257506001905b6040805164ffffffffff9290921682526020820192909252a1565b90615857565b929093916108516158aa917f000000000000000000000000000000000000000000000000000000000000000090613ddc565b92600384106159ec575b6158c0849592956142d0565b916158d5826000526011602052604060002090565b956000905b86821061594c5750505061593d849561ffff7fe740435bd797b3f29ea5e91b18d424d5418e497bd3a2267dfba548e842c1f4fa95961661ffff167fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0000825416179055565b61469a6040519283928361450d565b61599c9060018061595d8684614503565b019061597382600052600f602052604060002090565b9182549060ff8260101c1661598781611215565b156159a1575b50505050600052602060002090565b6158da565b6159e393620100006159c79369ffff000000000000ffff8c60181b911617178155614bd2565b94856159d3828b61432c565b52019361ffff611789868d614289565b3880808061598d565b600393506158b4565b919290600092615a0f826000526011602052604060002090565b94615a1f611343875461ffff1690565b90615a29826142d0565b9360005b838110615a6c57505050507f671c98e1063255ef19ccc962aca12d122b0043de83631fac15be1cb076e9f7b29293945061469a6040519283928361450d565b600180820191615a82611343615679858e614289565b90615a8c82614852565b9085615aa283600052600f602052604060002090565b548560ff8260101c16615ab481611215565b14615ac5575b505050505050615a2d565b60181c64ffffffffff1614615adc575b8581615aba565b9082615af0615afb94938c9e96979e61432c565b5261573c8488613d4d565b019638808080615ad5565b8015908115615b41575b50615b1757565b60046040517f297146a9000000000000000000000000000000000000000000000000000000008152fd5b61012c91501138615b10565b90816020910312610426575161059d816103fc565b909261059d949360809373ffffffffffffffffffffffffffffffffffffffff809216845216602083015260408201528160608201520190610549565b92602091615bf593600073ffffffffffffffffffffffffffffffffffffffff6040518097819682957f150b7a02000000000000000000000000000000000000000000000000000000009b8c85523360048601615b62565b0393165af160009181615c6d575b50615c4757615c1061524a565b80519081615c425760046040517fd1a57ed6000000000000000000000000000000000000000000000000000000008152fd5b602001fd5b7fffffffff00000000000000000000000000000000000000000000000000000000161490565b615c9091925060203d602011615c97575b615c888183610e66565b810190615b4d565b9038615c03565b503d615c7e565b64ffffffffff60135460781c16014210615cb457565b60046040517fa9d9eca0000000000000000000000000000000000000000000000000000000008152fd5b6040517f5d3b1d300000000000000000000000000000000000000000000000000000000081527f000000000000000000000000000000000000000000000000000000000000000060048201527f000000000000000000000000000000000000000000000000000000000000000067ffffffffffffffff16602482015260036044820152622625a060648201526001608482015260208160a48160007f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff165af190811561199157600091615ee5575b50615dd961416e82600052600e602052604060002090565b615de2816111bb565b615ebb576013547f3d94fecedaa4f90b8bd459797adb95f5bb11426025c5541390d9ccc1ad1b60a1919060501c64ffffffffff16601380547fffffffffffffff0000000000ffffffffffffffffffffffffffffffffffffffff164260a01b78ffffffffff00000000000000000000000000000000000000001617905581600052600e6020528060081b600117604060002055614e33770200000000000000000000000000000000000000000000007fffffffffffffffff00ffffffffffffffffffffffffffffffffffffffffffffff600a541617600a55565b60046040517ff9012132000000000000000000000000000000000000000000000000000000008152fd5b615efe915060203d6020116136d8576136c98183610e66565b38615dc1565b9060405160a081016040527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff608082019360008552935b0192600a90818106603001855304928315615f77577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff90615f3b565b92506080837fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0920301920191825256fea26469706673582212204e836d7aff2e133dedffd65da7fe4d684cb5e44c412824c6e6690883c019fa2364736f6c63430008180033000000000000000000000000000000000000000000000000000000000000008000000000000000000000000043000000000000000000000000000000000000020000000000000000000000002536fe9ab3f511540f2f9e2ec2a805005c3dd8000000000000000000000000004066b9bd584b5fa88897194dabe3a37883ac35f70000000000000000000000003ab105f0e4a22ec4a96a9b0ca90c5c534d21f3a7000000000000000000000000000000000000000000000000000000000000026000000000000000000000000000000000000000000000000000000000000002a0000000000000000000000000000000000000000000000000000009184e72a00000000000000000000000000000000000000000000000000000000000000007d000000000000000000000000000000000000000000000000000000000000001f4000000000000000000000000000000000000000000000000000000000000003c000000000000000000000000000000000000000000000000000000000000001400000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000406f10d635be12ad33d6b133c6da89180f5b999e000000000000000000000000f145092fd2729352c519d70c1ba2aa3a7a99f20a000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001bc9fcb0dc87b6a4872a0b969617d844f851d6340000000000000000000000000000000000000000000000000de0b6b3a76400000000000000000000000000001d52b7c0ef56141998e99d65ee429a8ec24d23ea00000000000000000000000000000000000000000000000000000000000001f4000000000000000000000000430000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000002e00000000000000000000000000000000000000000000000000000000000000010496e766173696f6e204472696c6c203100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000e494e564153494f4e4452494c4c31000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003a68747470733a2f2f6170692e6c6f6f6b73726172652e6f72672f6170692f76312f696e66696c74726174696f6e2f626c6173742f6167656e742f000000000000
Deployed Bytecode
0x6080604052600436101561001257600080fd5b60003560e01c806301ffc9a7146103f757806306fdde03146103f25780630744f3d5146103ed578063081812fc146103e8578063095ea7b3146103e35780631613f92c146103de57806317d65508146103d957806318160ddd146103d45780631cecfca1146103cf5780631df47f80146103ca5780631fe543e3146103c557806323452b9c146103c057806323b872dd146103bb578063255e4685146103b65780632b5e3e26146103b15780632bb5a9e6146103ac5780632de5aaf7146103a7578063311b8d5c146103a257806332cb6b0c1461039d57806335a8bfca146103985780633acd6cb2146103935780633e5675391461038e57806342842e0e1461038957806349890e151461038457806352a43eed1461037f57806355b159091461037a5780635b6ac011146103755780635cb6dfff146103705780636352211e1461036b57806364df049e14610366578063703fd3f81461036157806370a082311461035c5780637200b829146103575780637762df25146103525780637c18f2b61461034d57806388c3ffb01461034857806388e01a98146103435780638d859f3e1461033e5780638da5cb5b1461033957806395d89b411461033457806398753c461461032f5780639c87e0a81461032a5780639feddaed14610325578063a0712d6814610320578063a1fb20151461031b578063a22cb46514610316578063b106857914610311578063b88d4fde1461030c578063bd85948c14610307578063c0b6f56114610302578063c87b56dd146102fd578063d580c87f146102f8578063d65ab5f2146102f3578063db2e21bc146102ee578063db73bfce146102e9578063e1c31530146102e4578063e67e1666146102df578063e9254d26146102da578063e985e9c5146102d5578063ea2b4ab2146102d0578063ee94cec9146102cb5763eedaaa8d146102c657600080fd5b613cd7565b613a7b565b613a10565b613976565b6138f5565b61389c565b61385b565b61379a565b613536565b613316565b6132b1565b6130ab565b612fc3565b612cc0565b612c1e565b612b8b565b612a9c565b612a51565b6128a6565b612816565b612573565b612530565b61244c565b6123fa565b6123a1565b611fca565b611f44565b611ebd565b611e6b565b611cfb565b611c5c565b611c20565b611bce565b611b74565b611b02565b611a26565b6119ea565b611600565b6115c5565b6115a2565b6114ad565b611454565b61141b565b6113c2565b61135c565b61126c565b6111ca565b61112c565b6110e6565b6110d4565b610f6c565b610ebf565b610d84565b610d2b565b610cc7565b610c6e565b610aa1565b610964565b610886565b61076f565b6105a0565b61042b565b7fffffffff0000000000000000000000000000000000000000000000000000000081160361042657565b600080fd5b346104265760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126104265760207fffffffff00000000000000000000000000000000000000000000000000000000600435610489816103fc565b167f01ffc9a70000000000000000000000000000000000000000000000000000000081149081156104f1575b81156104c7575b506040519015158152f35b7f5b5e139f00000000000000000000000000000000000000000000000000000000915014386104bc565b7f80ac58cd00000000000000000000000000000000000000000000000000000000811491506104b5565b600091031261042657565b60005b8381106105395750506000910152565b8181015183820152602001610529565b907fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f60209361058581518092818752878088019101610526565b0116010190565b90602061059d928181520190610549565b90565b34610426576000807ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc360112610701576040519080600454906001918060011c92600182169283156106f7575b6020926020861085146106ca57858852602088019490811561068b5750600114610632575b61062e8761062281890382610e66565b6040519182918261058c565b0390f35b600460005294509192917f8a35acfbc15ff81a39ae7d344fd709f28e8600b4aa8c65c6b64bfe7fe36bd19b5b83861061067a57505050910190506106228261062e3880610612565b80548587015294820194810161065e565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001685525050505090151560051b0190506106228261062e3880610612565b6024827f4e487b710000000000000000000000000000000000000000000000000000000081526022600452fd5b93607f16936105ed565b80fd5b9060207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc8301126104265760043567ffffffffffffffff9283821161042657806023830112156104265781600401359384116104265760248460051b83010111610426576024019190565b346104265761077d36610704565b6000916107a261079d8361079861ffff6013541661ffff1690565b613d4d565b614870565b6107aa614226565b91601454601554916000925b8184106107c857604051878152602090f35b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff60019161086261087661086f6108518b809d6108686108596108518f8f8f8f9061084061081e610845948b9461084b97613d89565b3561083b61082b82614852565b600052600f602052604060002090565b6148a3565b613dcd565b95614a0c565b85613ddc565b612710900490565b96878093613dff565b9e614a95565b9103613ddc565b8093613dff565b95030397019301929495916107b6565b346104265760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc360112610426576004356108c181614b11565b156108f4576000526008602052602073ffffffffffffffffffffffffffffffffffffffff60406000205416604051908152f35b60046040517fcf4700e4000000000000000000000000000000000000000000000000000000008152fd5b6004359073ffffffffffffffffffffffffffffffffffffffff8216820361042657565b6024359073ffffffffffffffffffffffffffffffffffffffff8216820361042657565b60407ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126104265761099661091e565b60243573ffffffffffffffffffffffffffffffffffffffff806109b8836153ca565b1690813303610a38575b600083815260086020526040812080547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff87161790559316907f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b9258480a480f35b81600052600960205260ff610a713360406000209073ffffffffffffffffffffffffffffffffffffffff16600052602052604060002090565b54166109c25760046040517fcfb3b942000000000000000000000000000000000000000000000000000000008152fd5b34610426576000807ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261070157600260ff600a5460b01c1614610c4457610b277602000000000000000000000000000000000000000000007fffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffffffff600a541617600a55565b610b2f614b65565b60018152600f602052604081205461ffff1680610c3f575060015b610b5381614be5565b6014548015610c15577f4aa95f981a8337cb337de335b965507da0879c3b49f799d20058e913f5ad2c2691610b886000601455565b610bb45a83337f0000000000000000000000004300000000000000000000000000000000000004614c4b565b6040805191825260006020830152810191909152606090a1610c127601000000000000000000000000000000000000000000007fffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffffffff600a541617600a55565b80f35b60046040517f969bf728000000000000000000000000000000000000000000000000000000008152fd5b610b4a565b60046040517f1bbee726000000000000000000000000000000000000000000000000000000008152fd5b346104265760007ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126104265760206040517f00000000000000000000000000000000000000000000000000000000000000a08152f35b346104265760007ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261042657600254600354602091037fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff015b604051908152f35b346104265760007ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126104265760206040517f000000000000000000000000000000000000000000000000000000000000003c8152f35b346104265760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261042657610dbb61091e565b5060046040517fbb7790e6000000000000000000000000000000000000000000000000000000008152fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b6080810190811067ffffffffffffffff821117610e3157604052565b610de6565b67ffffffffffffffff8111610e3157604052565b6020810190811067ffffffffffffffff821117610e3157604052565b90601f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0910116810190811067ffffffffffffffff821117610e3157604052565b67ffffffffffffffff8111610e315760051b60200190565b346104265760407ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126104265760243567ffffffffffffffff8111610426573660238201121561042657806004013590610f1a82610ea7565b90610f286040519283610e66565b8282526020926024602084019160051b8301019136831161042657602401905b828210610f5d57610f5b84600435613e0c565b005b81358152908401908401610f48565b34610426576000807ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261070157610fa4614ead565b60015460ff8160a01c16610fb7816111bb565b801561104a5780610fc96001926111bb565b1461101f575b507fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff600154166001557f8eca980489e87f7dba4f26917aa4bfc906eb3f2b4f7b4b9fd0ff2b8bb3e21ae38180a180f35b7fffffffffffffffffffffffff00000000000000000000000000000000000000001660015538610fcf565b60046040517fccf69db7000000000000000000000000000000000000000000000000000000008152fd5b7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc60609101126104265773ffffffffffffffffffffffffffffffffffffffff90600435828116810361042657916024359081168103610426579060443590565b610f5b6110e036611074565b91613ec1565b346104265760007ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261042657602064ffffffffff600a5460c01c16604051908152f35b60407ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261042657610f5b61116161091e565b6024359061116d614ead565b61117682614ef8565b61117f82614f55565b611187614fdb565b615018565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fd5b600311156111c557565b61118c565b346104265760007ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261042657602060ff60015460a01c1660405190611211816111bb565b8152f35b600511156111c557565b9060058210156111c55752565b919091606060808201938161ffff918281511685526112536020820151602087019061121f565b64ffffffffff6040820151166040860152015116910152565b346104265760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261042657600435604080606081516112ae81610e15565b600091818380935282602082015282858201520152838152600f60205220908051916112d983610e15565b5461ffff808216845260ff8260101c169160058310156111c55761062e9561132a61134a93611343936113529660208a015264ffffffffff8160181c16888a0152871c16606088019061ffff169052565b61133e81600052600f602052604060002090565b614bd2565b61ffff1690565b61ffff168352565b519182918261122c565b346104265760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126104265760043561ffff8116036104265760046040517fbb7790e6000000000000000000000000000000000000000000000000000000008152fd5b346104265760007ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126104265760206040517f00000000000000000000000000000000000000000000000000000000000007d08152f35b346104265760007ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc360112610426576020610d23614226565b346104265760007ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126104265760206040517f00000000000000000000000000000000000000000000000000000000000001f48152f35b34610426576000807ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc360112610701576114e5614ead565b600154600260ff8260a01c166114fa816111bb565b03611578577fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff907fffffffffffffffffffffffff00000000000000000000000000000000000000008354168355166001557f3edd90e7770f06fafde38004653b33870066c33bfc923ff6102acd601f85dfbc6020604051838152a180f35b60046040517f045c5122000000000000000000000000000000000000000000000000000000008152fd5b610f5b6115ae36611074565b90604051926115bc84610e4a565b600084526147e0565b346104265760007ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126104265760206040516109c48152f35b346104265761160e36610704565b600260ff600a5460b01c1614610c44576116647602000000000000000000000000000000000000000000007fffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffffffff600a541617600a55565b61166c6151a8565b6013549161ffff9261012c84821611156119c05764ffffffffff90611690846151e4565b60501c16906116a9826000526012602052604060002090565b926116b9611343855461ffff1690565b90808201926096841161199657600094916116d3816142d0565b916000935b8497838610156117ad576117a5908b6117896117796116f88a8989613d89565b359361175d8461172761170a88614852565b61082b8961172283600052600f602052604060002090565b6148f2565b805490620200007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ffff831617905560401c16615215565b6117678c8c61432c565b526117728b8b61432c565b5190613dff565b9860018091019c8b01018d614289565b919092169061ffff8084549260031b9316831b921b1916179055565b9693966116d8565b89547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00001661ffff898d1616178a5592848b6013547fffffffffffffffffffffffffffffffffffffffffffffffffffff00000000ffff8480848460101c160360101b938360201c160160201b9116171760135573ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000001bc9fcb0dc87b6a4872a0b969617d844f851d63416917f000000000000000000000000406f10d635be12ad33d6b133c6da89180f5b999e833b15610426576040517fda3e8ce400000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff8216600482015233602482015230604482015260648101889052936000908590608490829084905af1908115611991577fc336583a12cbbd0e56a944ad6e644ea9b89b312ea7174f79e72f27e83d23c1889761192f9561192393611978575b5060011c9061527a565b60405194859485614389565b0390a1610f5b7601000000000000000000000000000000000000000000007fffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffffffff600a541617600a55565b8061198561198b92610e36565b8061051b565b89611919565b614340565b60046040517f943c39b6000000000000000000000000000000000000000000000000000000008152fd5b60046040517fc90c904e000000000000000000000000000000000000000000000000000000008152fd5b346104265760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc360112610426576020610d236004356143b5565b34610426576000807ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261070157611a5e614ead565b60015460ff8160a01c16611a71816111bb565b611ad8577fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1674020000000000000000000000000000000000000000176001557f3ff05a45e46337fa1cbf20996d2eeb927280bce099f37252bcca1040609604ec8180a180f35b60046040517f74ed79ae000000000000000000000000000000000000000000000000000000008152fd5b346104265760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261042657600435600052600e60205260606040600020805464ffffffffff600160ff83169301549160405193611b62816111bb565b845260081c1660208301526040820152f35b346104265760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261042657602073ffffffffffffffffffffffffffffffffffffffff611bc56004356153ca565b16604051908152f35b346104265760007ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261042657602073ffffffffffffffffffffffffffffffffffffffff600a5416604051908152f35b346104265760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc360112610426576020610d23600435614496565b346104265760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126104265773ffffffffffffffffffffffffffffffffffffffff611ca861091e565b168015611cd1576000526007602052602067ffffffffffffffff60406000205416604051908152f35b60046040517f8f4eb604000000000000000000000000000000000000000000000000000000008152fd5b346104265760007ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261042657600154600160ff8260a01c16611d3f816111bb565b03611e415773ffffffffffffffffffffffffffffffffffffffff163303611e1757600080547fffffffffffffffffffffffff00000000000000000000000000000000000000001633179055611db77fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff60015416600155565b611de47fffffffffffffffffffffffff000000000000000000000000000000000000000060015416600155565b6040513381527f3edd90e7770f06fafde38004653b33870066c33bfc923ff6102acd601f85dfbc9080602081015b0390a1005b60046040517fafdcfb92000000000000000000000000000000000000000000000000000000008152fd5b60046040517f5e4f2826000000000000000000000000000000000000000000000000000000008152fd5b346104265760007ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261042657602073ffffffffffffffffffffffffffffffffffffffff60015416604051908152f35b346104265760407ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc360112610426576020612710611f07611eff602435614496565b600435613ddc565b04604051908152f35b90815180825260208080930193019160005b828110611f30575050505090565b835185529381019392810192600101611f22565b346104265760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261042657611fbc600435806000526011602052611f8f6040600020615486565b90600052601260205261062e611fa86040600020615486565b604051938493604085526040850190611f10565b908382036020850152611f10565b346104265760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126104265760135464ffffffffff808260501c1661201e600435600052600e602052604060002090565b91818354918260081c161490811591612389575b5061235f577f33a701182892fd888ed152ca2ac23771a32e814469b7cd255965471e1af3a65992600180930154612067614226565b9161ffff91828083169260201c169060009180612301575b5061012c8311156121b057846120bb7fffffffffffffffffffffffffffffffffffffffffffffffff0000ffff000000009285612144988a615878565b906000907f00000000000000000000000000000000000000000000000000000000000000a0808a1161219c575b505081816013549501878660301c160160301b968560101c16010360101b9303911617171782907fffffffffffffff000000000000000000000000000000ffffffffffffffffffff60014260781b930160501b91161717601355565b61218b770100000000000000000000000000000000000000000000007fffffffffffffffff00ffffffffffffffffffffffffffffffffffffffffffffff600a541617600a55565b604051910181528060208101611e12565b6121a992508903896159f5565b38806120e8565b829187612237969411918261223c575b508293946121f27fffffffffffffffffffffffffffffffffffffffffffffffff0000ffffffff000094601354976157da565b8560301c16010160301b9216171782907fffffffffffffff000000000000000000000000000000ffffffffffffffffffff60014260781b930160501b91161717601355565b612144565b927f671c98e1063255ef19ccc962aca12d122b0043de83631fac15be1cb076e9f7b26122d2866122b28c612291867fffffffffffffffffffffffffffffffffffffffffffffffff0000ffffffff00009a614503565b016122aa8161133e81600052600f602052604060002090565b92839161574f565b6122ba6142a5565b906122c48261431f565b526040519182918c8361450d565b0390a17fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff9485019401926121c0565b92949150612359612314859284896155c2565b939180828097039901960303167fffffffffffffffffffffffffffffffffffffffffffffffffffff0000ffffffff65ffff000000006013549260201b16911617601355565b3861207f565b60046040517fe4c98f71000000000000000000000000000000000000000000000000000000008152fd5b6002915060ff16612399816111bb565b141538612032565b346104265760007ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126104265760206040517f000000000000000000000000000000000000000000000000000009184e72a0008152f35b346104265760007ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261042657602073ffffffffffffffffffffffffffffffffffffffff60005416604051908152f35b34610426576000807ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc360112610701576040519080600554906001918060011c9260018216928315612526575b6020926020861085146106ca57858852602088019490811561068b57506001146124cd5761062e8761062281890382610e66565b600560005294509192917f036b6384b5eca791c62761152d0c79bb0604c104a5fb6f4eb0703f3154bb3db05b83861061251557505050910190506106228261062e3880610612565b8054858701529482019481016124f9565b93607f1693612499565b346104265760007ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261042657602061ffff600a5460a01c16604051908152f35b346104265761258136610704565b90600260ff600a5460b01c1614610c44576125d87602000000000000000000000000000000000000000000007fffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffffffff600a541617600a55565b6125e06151a8565b6125e9826151e4565b6125fd8261079861134360135461ffff1690565b9061260782614870565b61260f614226565b9060145493601554946000612623836142d0565b9160005b8481106127395750916126d16126eb926126a86126f39a6126a37f537267dffdb0954f0c19f86e8ea73087f7db51b35dc6bea8a9df9b42b86c53d39998976013548d7fffffffffffffffffffffffffffffffffffffffffffff0000ffffffffffff00008b61ffff8460401c160160401b92161717601355601455565b601555565b5a90337f0000000000000000000000004300000000000000000000000000000000000004614c4b565b60135460501c64ffffffffff169260405194859485614524565b0390a16157da565b610f5b7601000000000000000000000000000000000000000000007fffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffffffff600a541617600a55565b958691819961274984888a613d89565b359061275482614be5565b61275d82614852565b928261277385600052600f602052604060002090565b9061277d916148a3565b6127878582613dcd565b9661279186614a0c565b61279b9089613ddc565b6127109004806127ac81998c61432c565b526127b691613dff565b96866127c187614a95565b9103906127cd91613ddc565b61271090049586910303946127e191613dff565b9a6127eb926157b4565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0195600101612627565b346104265760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261042657600260ff600a5460b01c1614610c445761289b7602000000000000000000000000000000000000000000007fffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffffffff600a541617600a55565b6126f3600435614558565b60207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261042657600435600260ff600a5460b01c1614610c44576129297602000000000000000000000000000000000000000000007fffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffffffff600a541617600a55565b600a546129459060c01c64ffffffffff165b64ffffffffff1690565b42108015612a36575b612a0c5761295a614fdb565b61298e816129883373ffffffffffffffffffffffffffffffffffffffff16600052600d602052604060002090565b54613dff565b907f00000000000000000000000000000000000000000000000000000000000001f482116129e2576126f3916129c382614ef8565b6129cc82614f55565b336000908152600d602052604090205533615018565b60046040517fdb815ecd000000000000000000000000000000000000000000000000000000008152fd5b60046040517ffa073358000000000000000000000000000000000000000000000000000000008152fd5b50612a4a61293b600b5464ffffffffff1690565b421161294e565b346104265760007ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc360112610426576020610d23612a8d614226565b614a95565b8015150361042657565b346104265760407ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261042657612ad361091e565b73ffffffffffffffffffffffffffffffffffffffff60243591612af583612a92565b336000526009602052612b2c8160406000209073ffffffffffffffffffffffffffffffffffffffff16600052602052604060002090565b921515927fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0081541660ff851617905560405192835216907f17307eab39ab6107e8899845ad3d59bd9653f200f220920489ca2b5937696c3160203392a3005b346104265760007ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126104265760206040517f00000000000000000000000000000000000000000000000000000000000000148152f35b67ffffffffffffffff8111610e3157601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe01660200190565b60807ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261042657612c5061091e565b612c58610941565b6064359167ffffffffffffffff8311610426573660238401121561042657826004013591612c8583612be4565b92612c936040519485610e66565b8084523660248287010111610426576020816000926024610f5b98018388013785010152604435916147e0565b34610426576000807ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261070157600260ff600a5460b01c1614610c4457612d467602000000000000000000000000000000000000000000007fffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffffffff600a541617600a55565b60135464ffffffffff90818160501c16918215612f995762015180908260a01c16014210612f6f57612d76614226565b9161ffff80921691600191828514612f3e575b61012c8411612f08578290612dc060037f000000000000000000000000000000000000000000000000000000000000003c04615c9e565b601354612dd39060101c61ffff16611343565b612e40575b505050821115612e32575050612dec615cde565b610c127601000000000000000000000000000000000000000000007fffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffffffff600a541617600a55565b612e3b916157da565b612dec565b7f00000000000000000000000000000000000000000000000000000000000000a080821115612f015781035b9087925b612eb4575b50507fffffffffffffffffffffffffffffffffffffffffffffffff0000ffff0000ffff90601354928360301c160160301b911617601355388181612dd8565b909591612ed9611343612ed1896000526011602052604060002090565b5461ffff1690565b15612efa5790848092612eed858a856159f5565b8091019403970191612e70565b9195612e75565b5081612e6c565b5050505050612f367f000000000000000000000000000000000000000000000000000000000000003c615c9e565b612e3b615cde565b828403612d895760046040517fdf469ccb000000000000000000000000000000000000000000000000000000008152fd5b60046040517f9f0306e8000000000000000000000000000000000000000000000000000000008152fd5b60046040517fc1409a71000000000000000000000000000000000000000000000000000000008152fd5b346104265760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261042657612ffa61091e565b613002614ead565b60015460ff8160a01c16613015816111bb565b611ad8577fffffffffffffffffffffff0000000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff90911690811774010000000000000000000000000000000000000000176001556040805133815260208101929092527fb86c75c9bffca616b2d314cc914f7c3f1d174255b16b941c3f3ededee276d5ef919081908101611e12565b34610426576020807ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261042657600435906130e882614b11565b1561328757604051906000600c546001928160011c936001831692831561327d575b6020861084146132505785875286949360208601939291811561321257506001146131b0575b50505061313f92500382610e66565b80511561319e5761062261316c9161317261315c61062e95615f04565b604051948593602085019061483b565b9061483b565b037fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08101835282610e66565b505061062e6131ab614276565b610622565b9250936131df600c6000527fdf6966c971051c3d54ec59162606531493a51404a002842f56009d7e5cf4a8c790565b946000935b8285106131fc5750505061313f935001388080613130565b86548585015295860195879550938101936131e4565b91505061313f959293507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff009150168252151560051b01388080613130565b6024857f4e487b710000000000000000000000000000000000000000000000000000000081526022600452fd5b94607f169461310a565b60046040517fa14c4b50000000000000000000000000000000000000000000000000000000008152fd5b346104265760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126104265773ffffffffffffffffffffffffffffffffffffffff6132fd61091e565b16600052600d6020526020604060002054604051908152f35b346104265760007ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126104265761334d614ead565b60025460035490037fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff017f00000000000000000000000000000000000000000000000000000000000007d081106134f2575b61012c81106134c85761ffff613421916133b7614fdb565b6133f16a01000000000000000000007fffffffffffffffffffffffffffffffffff0000000000ffffffffffffffffffff6013541617601355565b1661ffff167fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00006013541617601355565b6134c04761345161344961343f611343600a5461ffff9060a01c1690565b8302612710900490565b809203601455565b604051600181527f33a701182892fd888ed152ca2ac23771a32e814469b7cd255965471e1af3a65990602090a1600a5473ffffffffffffffffffffffffffffffffffffffff16905a917f0000000000000000000000004300000000000000000000000000000000000004614c4b565b610f5b615cde565b60046040517f93c93e01000000000000000000000000000000000000000000000000000000008152fd5b61350561293b600b5464ffffffffff1690565b42101561339f5760046040517f532b23d7000000000000000000000000000000000000000000000000000000008152fd5b34610426576000807ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126107015761356e614ead565b60135461ffff908181169164ffffffffff808360501c161592831594859384613733575b5083613728575b5082613711575b5050816136ef575b82156136e7575b5081156136df575b506135bf5780f35b476135ec5a82337f0000000000000000000000004300000000000000000000000000000000000004614c4b565b6040517f70a08231000000000000000000000000000000000000000000000000000000008152306004820152907f000000000000000000000000406f10d635be12ad33d6b133c6da89180f5b999e9060208360248173ffffffffffffffffffffffffffffffffffffffff86165afa918215611991577f99010623e00d801536d5e2da7de373bda9592873b6d101d65738aa2582e645229385936136aa575b508261369791339061535c565b604080519182526020820192909252a180f35b6136979193506136d19060203d6020116136d8575b6136c98183610e66565b810190614549565b929061368a565b503d6136bf565b9050386135b7565b9150386135af565b90506201fa4061370861293b600b5464ffffffffff1690565b014211906135a8565b61371f925060781c16613def565b421138806135a0565b600110925038613599565b613767919650613762818460301c1691613762818660401c1691613762818860201c16918860101c168c613dff565b613dff565b60025460035490037fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0114159438613592565b346104265760007ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc360112610426576013546014546015546016546040805161ffff8087168252601087901c811660208084019190915287901c811682840152603087901c811660608301529186901c909116608082015264ffffffffff605086901c811660a080840191909152607887901c821660c08401529590951c90941660e085015261010084019290925261012083015261014082015261016090f35b346104265760007ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc360112610426576020610d23613897614226565b614a0c565b346104265760007ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126104265760206040517f0000000000000000000000000000000000000000000000000de0b6b3a76400008152f35b346104265761390336610704565b60009182915b80841061391b57602083604051908152f35b909161395a61ffff61392e868587613d89565b3561393881614852565b600052600f6020526040906139518260002091826148f2565b54901c16615215565b810180911161397157600193909301929190613909565b613d1e565b346104265760407ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261042657602060ff613a046139b461091e565b73ffffffffffffffffffffffffffffffffffffffff6139d1610941565b91166000526009845260406000209073ffffffffffffffffffffffffffffffffffffffff16600052602052604060002090565b54166040519015158152f35b346104265760007ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261042657602064ffffffffff600b5416604051908152f35b6004359064ffffffffff8216820361042657565b6024359064ffffffffff8216820361042657565b34610426576040807ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261042657613ab3613a53565b90613abc613a67565b90613ac5614ead565b64ffffffffff8381169390831680851015613cae578415948515613bd3575b50804211908115613bb7575b50613b8e577fde0225a54e6c9fb403aa996cb755cf686017f93bc6bc8e4f9f37e398e3e146bd93613b4d8464ffffffffff167fffffffffffffffffffffffffffffffffffffffffffffffffffffff0000000000600b541617600b55565b15613b845750600a54611e129060c01c64ffffffffff16915b5164ffffffffff928316815292909116602083015281906040820190565b611e129091613b66565b600482517fbe62021d000000000000000000000000000000000000000000000000000000008152fd5b9050613bcc61293b600b5464ffffffffff1690565b1138613af0565b4211613c8557600a54613bef9060c01c64ffffffffff1661293b565b80613c4f575b50613c49827fffffff0000000000ffffffffffffffffffffffffffffffffffffffffffffffff7cffffffffff000000000000000000000000000000000000000000000000600a549260c01b16911617600a55565b38613ae4565b421015613c5c5738613bf5565b600483517fd8aefac8000000000000000000000000000000000000000000000000000000008152fd5b600483517f0fcb8b7b000000000000000000000000000000000000000000000000000000008152fd5b600483517f3ad9580b000000000000000000000000000000000000000000000000000000008152fd5b346104265760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc360112610426576020610d23600435614852565b600052602060002090565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b9190820391821161397157565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b9190811015613d995760051b0190565b613d5a565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b8115613dd7570490565b613d9e565b8181029291811591840414171561397157565b906201fa40820180921161397157565b9190820180921161397157565b91907f000000000000000000000000f145092fd2729352c519d70c1ba2aa3a7a99f20a9273ffffffffffffffffffffffffffffffffffffffff84163303613e5a57613e58929350614d80565b565b6040517f1cf993f400000000000000000000000000000000000000000000000000000000815233600482015273ffffffffffffffffffffffffffffffffffffffff85166024820152604490fd5b0390fd5b908152604081019291613e58916020019061121f565b90613ecb83614852565b600052600f60205260ff60406000205460101c1660058110156111c5576001811180614204575b6141ce5750613f00836153ca565b73ffffffffffffffffffffffffffffffffffffffff8084169283828416036141a457600086815260086020526040902080549092613f5e73ffffffffffffffffffffffffffffffffffffffff881633908114908414171590565b1590565b614115575b82169586156140eb5761403493613fa0926140e1575b5073ffffffffffffffffffffffffffffffffffffffff166000526007602052604060002090565b80547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff019055613ff08173ffffffffffffffffffffffffffffffffffffffff166000526007602052604060002090565b8054600101905573ffffffffffffffffffffffffffffffffffffffff164260a01b177c02000000000000000000000000000000000000000000000000000000001790565b614048856000526006602052604060002090565b557c0200000000000000000000000000000000000000000000000000000000811615614097575b507fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef600080a4565b600184016140af816000526006602052604060002090565b54156140bc575b5061406f565b60025481146140b6576140d9906000526006602052604060002090565b5538806140b6565b6000905538613f79565b60046040517fea553b34000000000000000000000000000000000000000000000000000000008152fd5b614175613f5a61416e336141498b73ffffffffffffffffffffffffffffffffffffffff166000526009602052604060002090565b9073ffffffffffffffffffffffffffffffffffffffff16600052602052604060002090565b5460ff1690565b15613f635760046040517f59c896be000000000000000000000000000000000000000000000000000000008152fd5b60046040517fa1148100000000000000000000000000000000000000000000000000000000008152fd5b83613ea76040519283927f0d5323a900000000000000000000000000000000000000000000000000000000845260048401613eab565b5061dead73ffffffffffffffffffffffffffffffffffffffff83161415613ef2565b60025460035490037fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0160135461ffff90818160301c1683039283116139715760401c1681039081116139715790565b6040519061428382610e4a565b60008252565b9190916097831015613d9957601e908360041c019260011b1690565b604051906040820182811067ffffffffffffffff821117610e31576040526001825260203681840137565b906142da82610ea7565b6142e76040519182610e66565b8281527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe06143158294610ea7565b0190602036910137565b805115613d995760200190565b8051821015613d995760209160051b010190565b6040513d6000823e3d90fd5b90918281527f07ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff83116104265760209260051b809284830137010190565b929161059d94926143a792855260606020860152606085019161434c565b916040818403910152611f10565b801580801561446d575b614443577f00000000000000000000000000000000000000000000000000000002552bcad491601e810291818304601e1417156139715763b2d05e0002908082046305f5e1001490151715613971577f000000000000000000000000000000000000000000000000000000000000009f908115613dd7570481039081116139715790565b60046040517f04ea02d5000000000000000000000000000000000000000000000000000000008152fd5b507f00000000000000000000000000000000000000000000000000000000000000a082116143bf565b606481029080820460641490151715613971578015613dd7576425c8a44a00047ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffdb610810190811161397157620f4240900490565b6144ff906144f961271093614496565b90613ddc565b0490565b8115613dd7570690565b60409061059d939281528160208201520190611f10565b929161059d949264ffffffffff6143a79316855260606020860152606085019161434c565b90816020910312610426575190565b614560614b65565b61456981614be5565b61457281614852565b61457b81615b06565b600b5466ffffffffffffff9060281c811680831c600116610c15576145de916001841b16177fffffffffffffffffffffffffffffffffffffffff00000000000000ffffffffff6bffffffffffffff0000000000600b549260281b16911617600b55565b6145ea816015546144e9565b80614767575b50601654801561469f575b61460b906144f961271093614496565b0480614615575050565b7f4aa95f981a8337cb337de335b965507da0879c3b49f799d20058e913f5ad2c269161469a7f000000000000000000000000406f10d635be12ad33d6b133c6da89180f5b999e9261466781338661535c565b6040519384938473ffffffffffffffffffffffffffffffffffffffff604092959493606083019683521660208201520152565b0390a1565b506040517f70a08231000000000000000000000000000000000000000000000000000000008152306004820152906020826024817f000000000000000000000000406f10d635be12ad33d6b133c6da89180f5b999e73ffffffffffffffffffffffffffffffffffffffff165afa91821561199157600092614746575b50818215614740576144f961460b9261473661271095601655565b93505090506145fb565b50505050565b61476091925060203d6020116136d8576136c98183610e66565b903861471b565b6147d77f4aa95f981a8337cb337de335b965507da0879c3b49f799d20058e913f5ad2c26916147b85a82337f0000000000000000000000004300000000000000000000000000000000000004614c4b565b6040805186815260006020820152908101919091529081906060820190565b0390a1386145f0565b9291906147ee828286613ec1565b803b6147fa5750505050565b61480393615b9e565b156148115738808080614740565b60046040517fd1a57ed6000000000000000000000000000000000000000000000000000000008152fd5b9061484e60209282815194859201610526565b0190565b9081600052601060205260406000205491821561486c5750565b9150565b60011161487957565b60046040517f61df2a20000000000000000000000000000000000000000000000000000000008152fd5b5460101c60ff1660058110156111c5576148ba5750565b604490604051907f0d5323a9000000000000000000000000000000000000000000000000000000008252600482015260006024820152fd5b5460101c60ff1660058110156111c55760010361490c5750565b604490604051907f0d5323a9000000000000000000000000000000000000000000000000000000008252600482015260016024820152fd5b8015614a065780806001146149ff576002146149f9576001908161013382101682600b831016176149f157906002815b8082116149aa575050817fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff048111613971570290565b9092807fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff048111613971578184166149e8575b800292811c90614974565b809202916149dd565b600291500a90565b50600490565b5050600190565b50600090565b612710908181029181830414901517156139715760025460035490037fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff018015613dd757614a5a9104614944565b8060320290603282040361397157640218711a0081810391818311613971576064830292830460641491141715613971576305f5e100900490565b9061271091828102908082048414901517156139715760025460035490037fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff01908115613dd75704611f4090818102918183041490151715613971576063620f61d09104810390811161397157606490049180831161486c5750565b80600111159081614b59575b81614b26575090565b905060005260066020527c0100000000000000000000000000000000000000000000000000000000604060002054161590565b60025481109150614b1d565b60135461ffff60018183161491821592614bc2575b8215614bb3575b5050614b8957565b60046040517fc7284d0e000000000000000000000000000000000000000000000000000000008152fd5b60201c16151590503880614b81565b9150808260101c16151591614b7a565b5461ffff1680614be0575090565b905090565b614c0373ffffffffffffffffffffffffffffffffffffffff916153ca565b163303614c0c57565b60046040517f390772fc000000000000000000000000000000000000000000000000000000008152fd5b90816020910312610426575161059d81612a92565b614c6082849395600080809781948294f11590565b614c6a5750505050565b73ffffffffffffffffffffffffffffffffffffffff16803b15614d7c57604051937fd0e30db0000000000000000000000000000000000000000000000000000000008552838560048186865af193841561199157614d2395602095614d69575b506040518096819582947fa9059cbb000000000000000000000000000000000000000000000000000000008452600484016020909392919373ffffffffffffffffffffffffffffffffffffffff60408201951681520152565b03925af1801561199157614d3a575b808080614740565b614d5b9060203d602011614d62575b614d538183610e66565b810190614c36565b5038614d32565b503d614d49565b80611985614d7692610e36565b38614cca565b8280fd5b80600052600e602052604060002091614da661293b60135464ffffffffff9060501c1690565b83549064ffffffffff8260081c169181831490811591614e95575b50614e545750507f546aca7b2683440b8f02fa95faeb8efc79dd0f16af3d815a002742ea6f76116c92614df6614e339261431f565b51600182015580547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001660021781555460081c64ffffffffff1690565b6040805164ffffffffff90921682526020820192909252908190810161469a565b60408051948552602085019290925290830152507fea18705d978143c83c4009ada26bdca3246bfd37055c03a17f85d3210cbf85999150806060810161469a565b6001915060ff16614ea5816111bb565b141538614dc1565b73ffffffffffffffffffffffffffffffffffffffff600054163303614ece57565b60046040517f30cd7471000000000000000000000000000000000000000000000000000000008152fd5b614f23907f000000000000000000000000000000000000000000000000000009184e72a00090613ddc565b3403614f2b57565b60046040517f2a12a0cc000000000000000000000000000000000000000000000000000000008152fd5b60025460035490037fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff01908101809111613971577f00000000000000000000000000000000000000000000000000000000000007d010614fb157565b60046040517f5d20e856000000000000000000000000000000000000000000000000000000008152fd5b64ffffffffff60135460501c16614fee57565b60046040517fab6ecc53000000000000000000000000000000000000000000000000000000008152fd5b6002549073ffffffffffffffffffffffffffffffffffffffff811690811561517e57831561515457611388841161512a57613e58936150b48261507d60009473ffffffffffffffffffffffffffffffffffffffff166000526007602052604060002090565b805468010000000000000001850201905573ffffffffffffffffffffffffffffffffffffffff164260a01b6001841460e11b171790565b6150c8856000526006602052604060002090565b558301927fdeaa91b6123d068f5821d0fb0678463d1a8a6079fe8af5de3ce5e896dcf9133d604051806151227fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8801829190602083019252565b0390a4600255565b60046040517f3db1f9af000000000000000000000000000000000000000000000000000000008152fd5b60046040517fb562e8dd000000000000000000000000000000000000000000000000000000008152fd5b60046040517f2e076300000000000000000000000000000000000000000000000000000000008152fd5b600260ff600a5460b81c16146151ba57565b60046040517f2e98fd9a000000000000000000000000000000000000000000000000000000008152fd5b156151eb57565b60046040517fd8ba85a4000000000000000000000000000000000000000000000000000000008152fd5b60ff811161397157600161059d911b7f0000000000000000000000000000000000000000000000000de0b6b3a7640000613ddc565b3d15615275573d9061525b82612be4565b916152696040519384610e66565b82523d6000602084013e565b606090565b90813b15615332576000918291826040516152d08161317260208201957fa9059cbb0000000000000000000000000000000000000000000000000000000087526024830191906020604084019361dead81520152565b51925af16152dc61524a565b9015615308578051806152ed575050565b81602080613f5a936153029501019101614c36565b61530857565b60046040517ff1568f95000000000000000000000000000000000000000000000000000000008152fd5b60046040517f09ee12d5000000000000000000000000000000000000000000000000000000008152fd5b919091803b15615332576040517fa9059cbb000000000000000000000000000000000000000000000000000000006020820190815273ffffffffffffffffffffffffffffffffffffffff90941660248201526044810192909252600092839283906152d08160648101613172565b8080600111156153ff575b60046040517fdf2d9b42000000000000000000000000000000000000000000000000000000008152fd5b6002548110156153d5576000526006602052604060002054907c010000000000000000000000000000000000000000000000000000000082166153d5575b8115615447575090565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff91500161547f816000526006602052604060002090565b549061543d565b9061ffff9182815416615498816142d0565b9360005b8281106154a95750505050565b60018101906154cb836154bc8488614289565b90549060031b1c16918861432c565b5261549c565b906154db82610ea7565b60406154ea6040519283610e66565b8382527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe06155188395610ea7565b01906000805b83811061552c575050505050565b8251908382019180831067ffffffffffffffff841117610e3157602092855283815282848183015282880101520161551e565b90604091604081019181526020606081926040838201528651809552019401926000905b83821061559257505050505090565b90919293948386518051835201519060028210156111c55784810191909152810194830193929160010190615583565b9290916000936000936155df826000526012602052604060002090565b6155ee611343825461ffff1690565b90816155fc575b5050505090565b91939296508061560c87926154d1565b926000955b82871061565b5750507ff0c0bd04f09c5b4c03d28f7311833e44f9fe752809264f87607a694d218993de939450039561564f6040519283928361555f565b0390a1388080806155f5565b919380959193506001808801978b6156876113436156798c8a614289565b905461ffff9160031b1c1690565b916156d261569484614852565b92846156b4846156ae87600052600f602052604060002090565b9961432c565b515286546156cb9060181c64ffffffffff1661293b565b90036143b5565b6402540be40087061161570e575050505090613d1361570392805461ffff6001818360401c160160401b9116179055565b939290918792615611565b615703959c93945090615732602061572a61574295948d61432c565b510160019052565b61573c8488613d4d565b9061574f565b0197600052602060002090565b9162040000916157a9615798600095838752600f60205280604061577586828b20614bd2565b98878152601060205286828220558981522055600052600f602052604060002090565b91600052600f602052604060002090565b938454179055179055565b9162030000916157a9615798600095838752600f60205280604061577586828b20614bd2565b6001146157e45750565b6001146157ed57565b6013546001600052600f6020527f169f97de0d9a84d840042b17d3c6b9638b3d6fd9024c9eb0c7a306a17b49f88f547f3c6f6a06cfd9c0c95090713d31b06691fff09d08efa09dfe81b5f4fcd0db2c349160501c64ffffffffff169061ffff168061587257506001905b6040805164ffffffffff9290921682526020820192909252a1565b90615857565b929093916108516158aa917f000000000000000000000000000000000000000000000000000000000000001490613ddc565b92600384106159ec575b6158c0849592956142d0565b916158d5826000526011602052604060002090565b956000905b86821061594c5750505061593d849561ffff7fe740435bd797b3f29ea5e91b18d424d5418e497bd3a2267dfba548e842c1f4fa95961661ffff167fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0000825416179055565b61469a6040519283928361450d565b61599c9060018061595d8684614503565b019061597382600052600f602052604060002090565b9182549060ff8260101c1661598781611215565b156159a1575b50505050600052602060002090565b6158da565b6159e393620100006159c79369ffff000000000000ffff8c60181b911617178155614bd2565b94856159d3828b61432c565b52019361ffff611789868d614289565b3880808061598d565b600393506158b4565b919290600092615a0f826000526011602052604060002090565b94615a1f611343875461ffff1690565b90615a29826142d0565b9360005b838110615a6c57505050507f671c98e1063255ef19ccc962aca12d122b0043de83631fac15be1cb076e9f7b29293945061469a6040519283928361450d565b600180820191615a82611343615679858e614289565b90615a8c82614852565b9085615aa283600052600f602052604060002090565b548560ff8260101c16615ab481611215565b14615ac5575b505050505050615a2d565b60181c64ffffffffff1614615adc575b8581615aba565b9082615af0615afb94938c9e96979e61432c565b5261573c8488613d4d565b019638808080615ad5565b8015908115615b41575b50615b1757565b60046040517f297146a9000000000000000000000000000000000000000000000000000000008152fd5b61012c91501138615b10565b90816020910312610426575161059d816103fc565b909261059d949360809373ffffffffffffffffffffffffffffffffffffffff809216845216602083015260408201528160608201520190610549565b92602091615bf593600073ffffffffffffffffffffffffffffffffffffffff6040518097819682957f150b7a02000000000000000000000000000000000000000000000000000000009b8c85523360048601615b62565b0393165af160009181615c6d575b50615c4757615c1061524a565b80519081615c425760046040517fd1a57ed6000000000000000000000000000000000000000000000000000000008152fd5b602001fd5b7fffffffff00000000000000000000000000000000000000000000000000000000161490565b615c9091925060203d602011615c97575b615c888183610e66565b810190615b4d565b9038615c03565b503d615c7e565b64ffffffffff60135460781c16014210615cb457565b60046040517fa9d9eca0000000000000000000000000000000000000000000000000000000008152fd5b6040517f5d3b1d300000000000000000000000000000000000000000000000000000000081527f000000000000000000000000000000000000000000000000000000000000000060048201527f000000000000000000000000000000000000000000000000000000000000000067ffffffffffffffff16602482015260036044820152622625a060648201526001608482015260208160a48160007f000000000000000000000000f145092fd2729352c519d70c1ba2aa3a7a99f20a73ffffffffffffffffffffffffffffffffffffffff165af190811561199157600091615ee5575b50615dd961416e82600052600e602052604060002090565b615de2816111bb565b615ebb576013547f3d94fecedaa4f90b8bd459797adb95f5bb11426025c5541390d9ccc1ad1b60a1919060501c64ffffffffff16601380547fffffffffffffff0000000000ffffffffffffffffffffffffffffffffffffffff164260a01b78ffffffffff00000000000000000000000000000000000000001617905581600052600e6020528060081b600117604060002055614e33770200000000000000000000000000000000000000000000007fffffffffffffffff00ffffffffffffffffffffffffffffffffffffffffffffff600a541617600a55565b60046040517ff9012132000000000000000000000000000000000000000000000000000000008152fd5b615efe915060203d6020116136d8576136c98183610e66565b38615dc1565b9060405160a081016040527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff608082019360008552935b0192600a90818106603001855304928315615f77577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff90615f3b565b92506080837fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0920301920191825256fea26469706673582212204e836d7aff2e133dedffd65da7fe4d684cb5e44c412824c6e6690883c019fa2364736f6c63430008180033
Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)
000000000000000000000000000000000000000000000000000000000000008000000000000000000000000043000000000000000000000000000000000000020000000000000000000000002536fe9ab3f511540f2f9e2ec2a805005c3dd8000000000000000000000000004066b9bd584b5fa88897194dabe3a37883ac35f70000000000000000000000003ab105f0e4a22ec4a96a9b0ca90c5c534d21f3a7000000000000000000000000000000000000000000000000000000000000026000000000000000000000000000000000000000000000000000000000000002a0000000000000000000000000000000000000000000000000000009184e72a00000000000000000000000000000000000000000000000000000000000000007d000000000000000000000000000000000000000000000000000000000000001f4000000000000000000000000000000000000000000000000000000000000003c000000000000000000000000000000000000000000000000000000000000001400000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000406f10d635be12ad33d6b133c6da89180f5b999e000000000000000000000000f145092fd2729352c519d70c1ba2aa3a7a99f20a000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001bc9fcb0dc87b6a4872a0b969617d844f851d6340000000000000000000000000000000000000000000000000de0b6b3a76400000000000000000000000000001d52b7c0ef56141998e99d65ee429a8ec24d23ea00000000000000000000000000000000000000000000000000000000000001f4000000000000000000000000430000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000002e00000000000000000000000000000000000000000000000000000000000000010496e766173696f6e204472696c6c203100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000e494e564153494f4e4452494c4c31000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003a68747470733a2f2f6170692e6c6f6f6b73726172652e6f72672f6170692f76312f696e66696c74726174696f6e2f626c6173742f6167656e742f000000000000
-----Decoded View---------------
Arg [0] : constructorCalldata (tuple):
Arg [1] : owner (address): 0x3ab105F0e4A22ec4A96a9b0Ca90c5C534d21f3a7
Arg [2] : name (string): Invasion Drill 1
Arg [3] : symbol (string): INVASIONDRILL1
Arg [4] : price (uint256): 10000000000000
Arg [5] : maxSupply (uint256): 2000
Arg [6] : maxMintPerAddress (uint256): 500
Arg [7] : secondsPerRound (uint256): 60
Arg [8] : agentsToWoundPerRoundInBasisPoints (uint256): 20
Arg [9] : roundsToBeWoundedBeforeDead (uint256): 160
Arg [10] : looks (address): 0x406F10d635be12ad33D6B133C6DA89180f5B999e
Arg [11] : vrfCoordinator (address): 0xf145092FD2729352C519D70C1BA2AA3a7a99f20A
Arg [12] : keyHash (bytes32): 0x0000000000000000000000000000000000000000000000000000000000000000
Arg [13] : subscriptionId (uint64): 0
Arg [14] : transferManager (address): 0x1bC9fCB0dC87b6A4872A0b969617d844f851d634
Arg [15] : healBaseCost (uint256): 1000000000000000000
Arg [16] : protocolFeeRecipient (address): 0x1d52b7c0EF56141998E99d65eE429a8EC24d23Ea
Arg [17] : protocolFeeBp (uint16): 500
Arg [18] : weth (address): 0x4300000000000000000000000000000000000004
Arg [19] : baseURI (string): https://api.looksrare.org/api/v1/infiltration/blast/agent/
Arg [1] : blast (address): 0x4300000000000000000000000000000000000002
Arg [2] : blastPoints (address): 0x2536FE9ab3F511540F2f9e2eC2A805005C3Dd800
Arg [3] : blastPointsOperator (address): 0x4066b9BD584b5FA88897194dAbE3a37883AC35F7
-----Encoded View---------------
30 Constructor Arguments found :
Arg [0] : 0000000000000000000000000000000000000000000000000000000000000080
Arg [1] : 0000000000000000000000004300000000000000000000000000000000000002
Arg [2] : 0000000000000000000000002536fe9ab3f511540f2f9e2ec2a805005c3dd800
Arg [3] : 0000000000000000000000004066b9bd584b5fa88897194dabe3a37883ac35f7
Arg [4] : 0000000000000000000000003ab105f0e4a22ec4a96a9b0ca90c5c534d21f3a7
Arg [5] : 0000000000000000000000000000000000000000000000000000000000000260
Arg [6] : 00000000000000000000000000000000000000000000000000000000000002a0
Arg [7] : 000000000000000000000000000000000000000000000000000009184e72a000
Arg [8] : 00000000000000000000000000000000000000000000000000000000000007d0
Arg [9] : 00000000000000000000000000000000000000000000000000000000000001f4
Arg [10] : 000000000000000000000000000000000000000000000000000000000000003c
Arg [11] : 0000000000000000000000000000000000000000000000000000000000000014
Arg [12] : 00000000000000000000000000000000000000000000000000000000000000a0
Arg [13] : 000000000000000000000000406f10d635be12ad33d6b133c6da89180f5b999e
Arg [14] : 000000000000000000000000f145092fd2729352c519d70c1ba2aa3a7a99f20a
Arg [15] : 0000000000000000000000000000000000000000000000000000000000000000
Arg [16] : 0000000000000000000000000000000000000000000000000000000000000000
Arg [17] : 0000000000000000000000001bc9fcb0dc87b6a4872a0b969617d844f851d634
Arg [18] : 0000000000000000000000000000000000000000000000000de0b6b3a7640000
Arg [19] : 0000000000000000000000001d52b7c0ef56141998e99d65ee429a8ec24d23ea
Arg [20] : 00000000000000000000000000000000000000000000000000000000000001f4
Arg [21] : 0000000000000000000000004300000000000000000000000000000000000004
Arg [22] : 00000000000000000000000000000000000000000000000000000000000002e0
Arg [23] : 0000000000000000000000000000000000000000000000000000000000000010
Arg [24] : 496e766173696f6e204472696c6c203100000000000000000000000000000000
Arg [25] : 000000000000000000000000000000000000000000000000000000000000000e
Arg [26] : 494e564153494f4e4452494c4c31000000000000000000000000000000000000
Arg [27] : 000000000000000000000000000000000000000000000000000000000000003a
Arg [28] : 68747470733a2f2f6170692e6c6f6f6b73726172652e6f72672f6170692f7631
Arg [29] : 2f696e66696c74726174696f6e2f626c6173742f6167656e742f000000000000
Loading...
Loading
Loading...
Loading
Loading...
Loading
Loading...
Loading
[ Download: CSV Export ]
[ Download: CSV Export ]
A contract address hosts a smart contract, which is a set of code stored on the blockchain that runs when predetermined conditions are met. Learn more about addresses in our Knowledge Base.