Overview
ETH Balance
More Info
ContractCreator
Multichain Info
Latest 16 from a total of 16 transactions
| Transaction Hash |
Method
|
Block
|
From
|
To
|
Amount
|
||||
|---|---|---|---|---|---|---|---|---|---|
| Mint | 11015613 | 445 days ago | IN | 0.00501 ETH | 0.00047098 | ||||
| Mint | 11015412 | 445 days ago | IN | 0.05 ETH | 0.00036665 | ||||
| Mint | 11015357 | 445 days ago | IN | 0.035 ETH | 0.00043221 | ||||
| Mint | 10985715 | 446 days ago | IN | 0.005 ETH | 0.00000043 | ||||
| Mint | 10981402 | 446 days ago | IN | 0.0001 ETH | 0.00000062 | ||||
| Mint | 10981058 | 446 days ago | IN | 0.005 ETH | 0.00000068 | ||||
| Mint | 10980990 | 446 days ago | IN | 0.005 ETH | 0.00000072 | ||||
| Mint | 10980578 | 446 days ago | IN | 0.025 ETH | 0.00000066 | ||||
| Mint | 10978575 | 446 days ago | IN | 0.0001 ETH | 0.00000028 | ||||
| Mint | 10973788 | 446 days ago | IN | 0.005 ETH | 0.0000004 | ||||
| Mint | 10973669 | 446 days ago | IN | 0.05 ETH | 0.00000047 | ||||
| Mint | 10972333 | 446 days ago | IN | 0.0001 ETH | 0.00000034 | ||||
| Set Worker | 10972157 | 446 days ago | IN | 0 ETH | 0.00004656 | ||||
| Update Probabili... | 10972154 | 446 days ago | IN | 0 ETH | 0.00032456 | ||||
| Update Phase | 10972151 | 446 days ago | IN | 0 ETH | 0.00009251 | ||||
| Update Pyth | 10972149 | 446 days ago | IN | 0 ETH | 0.00004945 |
Latest 11 internal transactions
| Parent Transaction Hash | Block | From | To | Amount | ||
|---|---|---|---|---|---|---|
| 11015613 | 445 days ago | 0.00001 ETH | ||||
| 11015412 | 445 days ago | 0.00001 ETH | ||||
| 11015357 | 445 days ago | 0.00001 ETH | ||||
| 10985715 | 446 days ago | 0.00001 ETH | ||||
| 10981058 | 446 days ago | 0.00001 ETH | ||||
| 10980990 | 446 days ago | 0.00001 ETH | ||||
| 10980578 | 446 days ago | 0.00001 ETH | ||||
| 10978575 | 446 days ago | 0.00001 ETH | ||||
| 10973788 | 446 days ago | 0.00001 ETH | ||||
| 10973669 | 446 days ago | 0.00001 ETH | ||||
| 10972333 | 446 days ago | 0.00001 ETH |
Contract Source Code (Solidity Standard Json-Input format)
// SPDX-License-Identifier: MIT
// Compatible with OpenZeppelin Contracts ^5.0.0
pragma solidity ^0.8.20;
import {IEntropyConsumer} from '@pythnetwork/entropy-sdk-solidity/IEntropyConsumer.sol';
import {IEntropy} from '@pythnetwork/entropy-sdk-solidity/IEntropy.sol';
import '@openzeppelin/contracts/access/Ownable.sol';
import './libs/SignerLib.sol';
import './Gangster.sol';
import './interfaces/IBlast.sol';
contract Minter is Ownable, IEntropyConsumer {
using SignerLib for address;
struct Phase {
uint32 MAX_PER_BATCH;
uint256 BASE_PRICE;
bool status;
bool whitelistedOnly;
}
struct MintInfo {
address addr;
uint16 amount;
uint256[] values;
bytes32 randomNumber;
uint256 phaseId;
}
struct Probability {
uint probability;
uint gangsterReward;
}
IBlast public constant BLAST = IBlast(0x4300000000000000000000000000000000000002);
address private gasFeeOperator;
IEntropy entropy = IEntropy(0x98046Bd286715D3B0BC227Dd7a956b83D8978603);
address public provider;
Gangster gangster;
address private signer; // Signer address
address private worker; // Worker address
address private treasuryAddr; // Treasury address
mapping(uint256 => Phase) public mintPhase; // phaseId => phase info
mapping(uint64 => MintInfo) public mintData; // Pyth sequense number => MintInfo
mapping(bytes32 => uint64) public requestedRandomNumber; // userRequestRandom => Pyth sequense number
Probability[] public probabilities;
/**
***************************
*Public
***************************
*/
event RequestMint(address addr, uint256 amount, uint256 phaseId, uint64 sequenceNumber);
event RevealMint(address addr, uint256 amount, uint256 phaseId, uint64 sequenceNumber);
event EntropyResult(address entropy, uint64 sequence, address provider, bytes32 randomNumber);
constructor(address initialOwner, address _gangster, address _signer) Ownable(initialOwner) {
gangster = Gangster(_gangster);
signer = _signer;
BLAST.configureClaimableGas();
}
receive() external payable {}
fallback() external payable {}
/**
***************************
Public
***************************
*/
/**
* Claim gas
*/
function claimGas(bool _maxOnly) public {
require(gasFeeOperator != address(0), 'gasFee is not set');
if (_maxOnly) {
BLAST.claimMaxGas(address(this), gasFeeOperator);
} else {
BLAST.claimAllGas(address(this), gasFeeOperator);
}
}
/**
* @notice mint
* phaseId: Id of phase, which contains information of minting
* amount: number of nfts
* sig: signatire from application
*/
function mint(uint256 phaseId_, uint16 amount_, bytes32 userRandomNumber_, bytes memory sig_) public payable {
require(amount_ > 0, 'Invalid amount'); // check phase status
require(mintPhase[phaseId_].status, 'Mint phase is not available'); // check phase status
require(mintPhase[phaseId_].MAX_PER_BATCH >= amount_, 'Over max per batch'); // Limit max per batch
require(requestedRandomNumber[userRandomNumber_] == 0, 'Rad is used');
uint256 mintFee = amount_ * mintPhase[phaseId_].BASE_PRICE;
uint pythFee = entropy.getFee(provider);
uint totalFee = pythFee + mintFee;
require(msg.value >= totalFee, 'Send more eth');
if (mintPhase[phaseId_].whitelistedOnly) {
bytes32 message = SignerLib.prefixed(
keccak256(abi.encodePacked(msg.sender, phaseId_, amount_, userRandomNumber_, block.chainid))
);
require(signer.verifyAddressSigner(message, sig_), 'Invalid signature'); // validate signature
}
// pay the fees and request a random number from entropy
uint64 sequenceNumber = entropy.requestWithCallback{value: pythFee}(provider, userRandomNumber_);
requestedRandomNumber[userRandomNumber_] = sequenceNumber;
mintData[sequenceNumber].addr = msg.sender;
mintData[sequenceNumber].amount = amount_;
mintData[sequenceNumber].phaseId = phaseId_;
emit RequestMint(msg.sender, amount_, phaseId_, sequenceNumber);
}
// ============================== VIEW FUNCTION ==============================
// This method is required by the IEntropyConsumer interface
function getEntropy() internal view override returns (address) {
return address(entropy);
}
// Get the fee to flip a coin. See the comment above about fees.
function getFee() public view returns (uint256 fee) {
fee = entropy.getFee(provider);
}
function getMintValues(uint64 sequence) public view returns (uint[] memory) {
return mintData[sequence].values;
}
/**
***************************
DEFAULT_ADMIN_ROLE Function
***************************
*/
/**
* @notice withdraw
* withdraw to treasuryAddr_
*/
function withdraw() public onlyOwner {
require(address(this).balance > 0, 'Nothing to withdraw');
require(treasuryAddr != address(0), 'Treasury is not set');
address payable receiver = payable(treasuryAddr);
(bool sent, ) = receiver.call{value: address(this).balance}('');
require(sent, 'Failed to send Ether');
}
/**
* @notice emegencyWithdraw
* withdraw to owner address
*/
function emegencyWithdraw() public onlyOwner {
require(address(this).balance > 0, 'Nothing to withdraw');
address payable receiver = payable(msg.sender);
(bool sent, ) = receiver.call{value: address(this).balance}('');
require(sent, 'Failed to send Ether');
}
/**
* @dev Update Pyth address
*/
function updatePyth(address _entropy, address _provider) external onlyOwner {
require(_entropy != address(0), 'NOT_ALLOWED_ZERO_ADDRESS');
require(_provider != address(0), 'NOT_ALLOWED_ZERO_ADDRESS');
entropy = IEntropy(_entropy);
provider = _provider;
}
/**
* set GasFeeOperator
*/
function setGasFeeOperator(address _gasFeeOperator) public onlyOwner {
gasFeeOperator = _gasFeeOperator;
}
function setTreasuryAddress(address _addr) public onlyOwner {
treasuryAddr = _addr; // Max supply for presale
}
function setWorker(address _addr) public onlyOwner {
worker = _addr; // Max supply for presale
}
function setSigner(address _signer) public onlyOwner {
signer = _signer;
}
function updatePhase(
uint256 _phaseId,
uint32 _maxPerBatch,
uint256 _basePrice,
bool _status,
bool _whitelistedOnly
) public onlyOwner {
require(_maxPerBatch <= 20, 'Over limit');
mintPhase[_phaseId].MAX_PER_BATCH = _maxPerBatch;
mintPhase[_phaseId].BASE_PRICE = _basePrice;
mintPhase[_phaseId].status = _status;
mintPhase[_phaseId].whitelistedOnly = _whitelistedOnly;
}
function updateProbability(uint256[] memory _probability, uint256[] memory _gangsterReward) public onlyOwner {
require(sumOf(_probability) == 1000, 'Invalid input');
delete probabilities; //
// probabilities = new Probability[](0);
for (uint256 i = 0; i < _probability.length; i++) {
probabilities.push(Probability(_probability[i], _gangsterReward[i]));
}
}
function entropyCallback(uint64 _sequence, address _provider, bytes32 _randomNumber) internal override {
emit EntropyResult(msg.sender, _sequence, provider, _randomNumber);
require(_msgSender() == address(entropy) && provider == _provider, 'Caller is not entropy');
MintInfo storage mintInfo = mintData[_sequence];
address playerAddress = mintInfo.addr;
uint16 amount = mintInfo.amount;
uint256 phaseId = mintInfo.phaseId;
uint256 total = 0;
require(uint(mintInfo.randomNumber) == 0, 'Mint is revealed');
mintInfo.randomNumber = _randomNumber;
uint256[] memory arr = _calculateMintResult(uint256(_randomNumber), amount);
total = sumOf(arr);
mintInfo.values = arr;
gangster.mint(playerAddress, 1, total, '');
emit RevealMint(playerAddress, total, phaseId, _sequence);
}
function manualCallback(uint64 _sequence, bytes32 _randomNumber) public {
emit EntropyResult(msg.sender, _sequence, provider, _randomNumber);
require(_msgSender() == worker, 'Caller is not worker');
MintInfo storage mintInfo = mintData[_sequence];
address playerAddress = mintInfo.addr;
uint16 amount = mintInfo.amount;
uint256 phaseId = mintInfo.phaseId;
uint256 total = 0;
require(uint(mintInfo.randomNumber) == 0, 'Mint is revealed');
mintInfo.randomNumber = _randomNumber;
uint256[] memory arr = _calculateMintResult(uint256(_randomNumber), amount);
total = sumOf(arr);
mintInfo.values = arr;
gangster.mint(playerAddress, 1, total, '');
emit RevealMint(playerAddress, total, phaseId, _sequence);
}
function _calculateMintResult(uint256 randomNumber, uint256 amount) public view returns (uint256[] memory) {
uint256[] memory arr = new uint256[](amount);
for (uint16 i = 0; i < amount; i++) {
uint256 rad = uint256((randomNumber / (1000 ** i)) % 1000);
arr[i] = _calculateProbability(rad);
}
return arr;
}
function _calculateProbability(uint256 randomNumber) public view returns (uint256) {
uint256 currentProbability = 0;
for (uint256 i = 0; i < probabilities.length; i++) {
currentProbability += probabilities[i].probability;
if (randomNumber < currentProbability) return probabilities[i].gangsterReward;
}
return 0;
}
/**
* @notice sum of array
*/
function sumOf(uint[] memory arr) internal pure returns (uint256 result) {
for (uint256 i = 0; i < arr.length; i++) {
result += arr[i];
}
return result;
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (access/AccessControl.sol)
pragma solidity ^0.8.20;
import {IAccessControl} from "./IAccessControl.sol";
import {Context} from "../utils/Context.sol";
import {ERC165} from "../utils/introspection/ERC165.sol";
/**
* @dev Contract module that allows children to implement role-based access
* control mechanisms. This is a lightweight version that doesn't allow enumerating role
* members except through off-chain means by accessing the contract event logs. Some
* applications may benefit from on-chain enumerability, for those cases see
* {AccessControlEnumerable}.
*
* Roles are referred to by their `bytes32` identifier. These should be exposed
* in the external API and be unique. The best way to achieve this is by
* using `public constant` hash digests:
*
* ```solidity
* bytes32 public constant MY_ROLE = keccak256("MY_ROLE");
* ```
*
* Roles can be used to represent a set of permissions. To restrict access to a
* function call, use {hasRole}:
*
* ```solidity
* function foo() public {
* require(hasRole(MY_ROLE, msg.sender));
* ...
* }
* ```
*
* Roles can be granted and revoked dynamically via the {grantRole} and
* {revokeRole} functions. Each role has an associated admin role, and only
* accounts that have a role's admin role can call {grantRole} and {revokeRole}.
*
* By default, the admin role for all roles is `DEFAULT_ADMIN_ROLE`, which means
* that only accounts with this role will be able to grant or revoke other
* roles. More complex role relationships can be created by using
* {_setRoleAdmin}.
*
* WARNING: The `DEFAULT_ADMIN_ROLE` is also its own admin: it has permission to
* grant and revoke this role. Extra precautions should be taken to secure
* accounts that have been granted it. We recommend using {AccessControlDefaultAdminRules}
* to enforce additional security measures for this role.
*/
abstract contract AccessControl is Context, IAccessControl, ERC165 {
struct RoleData {
mapping(address account => bool) hasRole;
bytes32 adminRole;
}
mapping(bytes32 role => RoleData) private _roles;
bytes32 public constant DEFAULT_ADMIN_ROLE = 0x00;
/**
* @dev Modifier that checks that an account has a specific role. Reverts
* with an {AccessControlUnauthorizedAccount} error including the required role.
*/
modifier onlyRole(bytes32 role) {
_checkRole(role);
_;
}
/**
* @dev See {IERC165-supportsInterface}.
*/
function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {
return interfaceId == type(IAccessControl).interfaceId || super.supportsInterface(interfaceId);
}
/**
* @dev Returns `true` if `account` has been granted `role`.
*/
function hasRole(bytes32 role, address account) public view virtual returns (bool) {
return _roles[role].hasRole[account];
}
/**
* @dev Reverts with an {AccessControlUnauthorizedAccount} error if `_msgSender()`
* is missing `role`. Overriding this function changes the behavior of the {onlyRole} modifier.
*/
function _checkRole(bytes32 role) internal view virtual {
_checkRole(role, _msgSender());
}
/**
* @dev Reverts with an {AccessControlUnauthorizedAccount} error if `account`
* is missing `role`.
*/
function _checkRole(bytes32 role, address account) internal view virtual {
if (!hasRole(role, account)) {
revert AccessControlUnauthorizedAccount(account, role);
}
}
/**
* @dev Returns the admin role that controls `role`. See {grantRole} and
* {revokeRole}.
*
* To change a role's admin, use {_setRoleAdmin}.
*/
function getRoleAdmin(bytes32 role) public view virtual returns (bytes32) {
return _roles[role].adminRole;
}
/**
* @dev Grants `role` to `account`.
*
* If `account` had not been already granted `role`, emits a {RoleGranted}
* event.
*
* Requirements:
*
* - the caller must have ``role``'s admin role.
*
* May emit a {RoleGranted} event.
*/
function grantRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {
_grantRole(role, account);
}
/**
* @dev Revokes `role` from `account`.
*
* If `account` had been granted `role`, emits a {RoleRevoked} event.
*
* Requirements:
*
* - the caller must have ``role``'s admin role.
*
* May emit a {RoleRevoked} event.
*/
function revokeRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {
_revokeRole(role, account);
}
/**
* @dev Revokes `role` from the calling account.
*
* Roles are often managed via {grantRole} and {revokeRole}: this function's
* purpose is to provide a mechanism for accounts to lose their privileges
* if they are compromised (such as when a trusted device is misplaced).
*
* If the calling account had been revoked `role`, emits a {RoleRevoked}
* event.
*
* Requirements:
*
* - the caller must be `callerConfirmation`.
*
* May emit a {RoleRevoked} event.
*/
function renounceRole(bytes32 role, address callerConfirmation) public virtual {
if (callerConfirmation != _msgSender()) {
revert AccessControlBadConfirmation();
}
_revokeRole(role, callerConfirmation);
}
/**
* @dev Sets `adminRole` as ``role``'s admin role.
*
* Emits a {RoleAdminChanged} event.
*/
function _setRoleAdmin(bytes32 role, bytes32 adminRole) internal virtual {
bytes32 previousAdminRole = getRoleAdmin(role);
_roles[role].adminRole = adminRole;
emit RoleAdminChanged(role, previousAdminRole, adminRole);
}
/**
* @dev Attempts to grant `role` to `account` and returns a boolean indicating if `role` was granted.
*
* Internal function without access restriction.
*
* May emit a {RoleGranted} event.
*/
function _grantRole(bytes32 role, address account) internal virtual returns (bool) {
if (!hasRole(role, account)) {
_roles[role].hasRole[account] = true;
emit RoleGranted(role, account, _msgSender());
return true;
} else {
return false;
}
}
/**
* @dev Attempts to revoke `role` to `account` and returns a boolean indicating if `role` was revoked.
*
* Internal function without access restriction.
*
* May emit a {RoleRevoked} event.
*/
function _revokeRole(bytes32 role, address account) internal virtual returns (bool) {
if (hasRole(role, account)) {
_roles[role].hasRole[account] = false;
emit RoleRevoked(role, account, _msgSender());
return true;
} else {
return false;
}
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (access/IAccessControl.sol)
pragma solidity ^0.8.20;
/**
* @dev External interface of AccessControl declared to support ERC165 detection.
*/
interface IAccessControl {
/**
* @dev The `account` is missing a role.
*/
error AccessControlUnauthorizedAccount(address account, bytes32 neededRole);
/**
* @dev The caller of a function is not the expected one.
*
* NOTE: Don't confuse with {AccessControlUnauthorizedAccount}.
*/
error AccessControlBadConfirmation();
/**
* @dev Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole`
*
* `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite
* {RoleAdminChanged} not being emitted signaling this.
*/
event RoleAdminChanged(bytes32 indexed role, bytes32 indexed previousAdminRole, bytes32 indexed newAdminRole);
/**
* @dev Emitted when `account` is granted `role`.
*
* `sender` is the account that originated the contract call, an admin role
* bearer except when using {AccessControl-_setupRole}.
*/
event RoleGranted(bytes32 indexed role, address indexed account, address indexed sender);
/**
* @dev Emitted when `account` is revoked `role`.
*
* `sender` is the account that originated the contract call:
* - if using `revokeRole`, it is the admin role bearer
* - if using `renounceRole`, it is the role bearer (i.e. `account`)
*/
event RoleRevoked(bytes32 indexed role, address indexed account, address indexed sender);
/**
* @dev Returns `true` if `account` has been granted `role`.
*/
function hasRole(bytes32 role, address account) external view returns (bool);
/**
* @dev Returns the admin role that controls `role`. See {grantRole} and
* {revokeRole}.
*
* To change a role's admin, use {AccessControl-_setRoleAdmin}.
*/
function getRoleAdmin(bytes32 role) external view returns (bytes32);
/**
* @dev Grants `role` to `account`.
*
* If `account` had not been already granted `role`, emits a {RoleGranted}
* event.
*
* Requirements:
*
* - the caller must have ``role``'s admin role.
*/
function grantRole(bytes32 role, address account) external;
/**
* @dev Revokes `role` from `account`.
*
* If `account` had been granted `role`, emits a {RoleRevoked} event.
*
* Requirements:
*
* - the caller must have ``role``'s admin role.
*/
function revokeRole(bytes32 role, address account) external;
/**
* @dev Revokes `role` from the calling account.
*
* Roles are often managed via {grantRole} and {revokeRole}: this function's
* purpose is to provide a mechanism for accounts to lose their privileges
* if they are compromised (such as when a trusted device is misplaced).
*
* If the calling account had been granted `role`, emits a {RoleRevoked}
* event.
*
* Requirements:
*
* - the caller must be `callerConfirmation`.
*/
function renounceRole(bytes32 role, address callerConfirmation) external;
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (access/Ownable.sol)
pragma solidity ^0.8.20;
import {Context} from "../utils/Context.sol";
/**
* @dev Contract module which provides a basic access control mechanism, where
* there is an account (an owner) that can be granted exclusive access to
* specific functions.
*
* The initial owner is set to the address provided by the deployer. This can
* later be changed with {transferOwnership}.
*
* This module is used through inheritance. It will make available the modifier
* `onlyOwner`, which can be applied to your functions to restrict their use to
* the owner.
*/
abstract contract Ownable is Context {
address private _owner;
/**
* @dev The caller account is not authorized to perform an operation.
*/
error OwnableUnauthorizedAccount(address account);
/**
* @dev The owner is not a valid owner account. (eg. `address(0)`)
*/
error OwnableInvalidOwner(address owner);
event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);
/**
* @dev Initializes the contract setting the address provided by the deployer as the initial owner.
*/
constructor(address initialOwner) {
if (initialOwner == address(0)) {
revert OwnableInvalidOwner(address(0));
}
_transferOwnership(initialOwner);
}
/**
* @dev Throws if called by any account other than the owner.
*/
modifier onlyOwner() {
_checkOwner();
_;
}
/**
* @dev Returns the address of the current owner.
*/
function owner() public view virtual returns (address) {
return _owner;
}
/**
* @dev Throws if the sender is not the owner.
*/
function _checkOwner() internal view virtual {
if (owner() != _msgSender()) {
revert OwnableUnauthorizedAccount(_msgSender());
}
}
/**
* @dev Leaves the contract without owner. It will not be possible to call
* `onlyOwner` functions. Can only be called by the current owner.
*
* NOTE: Renouncing ownership will leave the contract without an owner,
* thereby disabling any functionality that is only available to the owner.
*/
function renounceOwnership() public virtual onlyOwner {
_transferOwnership(address(0));
}
/**
* @dev Transfers ownership of the contract to a new account (`newOwner`).
* Can only be called by the current owner.
*/
function transferOwnership(address newOwner) public virtual onlyOwner {
if (newOwner == address(0)) {
revert OwnableInvalidOwner(address(0));
}
_transferOwnership(newOwner);
}
/**
* @dev Transfers ownership of the contract to a new account (`newOwner`).
* Internal function without access restriction.
*/
function _transferOwnership(address newOwner) internal virtual {
address oldOwner = _owner;
_owner = newOwner;
emit OwnershipTransferred(oldOwner, newOwner);
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (interfaces/draft-IERC6093.sol)
pragma solidity ^0.8.20;
/**
* @dev Standard ERC20 Errors
* Interface of the https://eips.ethereum.org/EIPS/eip-6093[ERC-6093] custom errors for ERC20 tokens.
*/
interface IERC20Errors {
/**
* @dev Indicates an error related to the current `balance` of a `sender`. Used in transfers.
* @param sender Address whose tokens are being transferred.
* @param balance Current balance for the interacting account.
* @param needed Minimum amount required to perform a transfer.
*/
error ERC20InsufficientBalance(address sender, uint256 balance, uint256 needed);
/**
* @dev Indicates a failure with the token `sender`. Used in transfers.
* @param sender Address whose tokens are being transferred.
*/
error ERC20InvalidSender(address sender);
/**
* @dev Indicates a failure with the token `receiver`. Used in transfers.
* @param receiver Address to which tokens are being transferred.
*/
error ERC20InvalidReceiver(address receiver);
/**
* @dev Indicates a failure with the `spender`’s `allowance`. Used in transfers.
* @param spender Address that may be allowed to operate on tokens without being their owner.
* @param allowance Amount of tokens a `spender` is allowed to operate with.
* @param needed Minimum amount required to perform a transfer.
*/
error ERC20InsufficientAllowance(address spender, uint256 allowance, uint256 needed);
/**
* @dev Indicates a failure with the `approver` of a token to be approved. Used in approvals.
* @param approver Address initiating an approval operation.
*/
error ERC20InvalidApprover(address approver);
/**
* @dev Indicates a failure with the `spender` to be approved. Used in approvals.
* @param spender Address that may be allowed to operate on tokens without being their owner.
*/
error ERC20InvalidSpender(address spender);
}
/**
* @dev Standard ERC721 Errors
* Interface of the https://eips.ethereum.org/EIPS/eip-6093[ERC-6093] custom errors for ERC721 tokens.
*/
interface IERC721Errors {
/**
* @dev Indicates that an address can't be an owner. For example, `address(0)` is a forbidden owner in EIP-20.
* Used in balance queries.
* @param owner Address of the current owner of a token.
*/
error ERC721InvalidOwner(address owner);
/**
* @dev Indicates a `tokenId` whose `owner` is the zero address.
* @param tokenId Identifier number of a token.
*/
error ERC721NonexistentToken(uint256 tokenId);
/**
* @dev Indicates an error related to the ownership over a particular token. Used in transfers.
* @param sender Address whose tokens are being transferred.
* @param tokenId Identifier number of a token.
* @param owner Address of the current owner of a token.
*/
error ERC721IncorrectOwner(address sender, uint256 tokenId, address owner);
/**
* @dev Indicates a failure with the token `sender`. Used in transfers.
* @param sender Address whose tokens are being transferred.
*/
error ERC721InvalidSender(address sender);
/**
* @dev Indicates a failure with the token `receiver`. Used in transfers.
* @param receiver Address to which tokens are being transferred.
*/
error ERC721InvalidReceiver(address receiver);
/**
* @dev Indicates a failure with the `operator`’s approval. Used in transfers.
* @param operator Address that may be allowed to operate on tokens without being their owner.
* @param tokenId Identifier number of a token.
*/
error ERC721InsufficientApproval(address operator, uint256 tokenId);
/**
* @dev Indicates a failure with the `approver` of a token to be approved. Used in approvals.
* @param approver Address initiating an approval operation.
*/
error ERC721InvalidApprover(address approver);
/**
* @dev Indicates a failure with the `operator` to be approved. Used in approvals.
* @param operator Address that may be allowed to operate on tokens without being their owner.
*/
error ERC721InvalidOperator(address operator);
}
/**
* @dev Standard ERC1155 Errors
* Interface of the https://eips.ethereum.org/EIPS/eip-6093[ERC-6093] custom errors for ERC1155 tokens.
*/
interface IERC1155Errors {
/**
* @dev Indicates an error related to the current `balance` of a `sender`. Used in transfers.
* @param sender Address whose tokens are being transferred.
* @param balance Current balance for the interacting account.
* @param needed Minimum amount required to perform a transfer.
* @param tokenId Identifier number of a token.
*/
error ERC1155InsufficientBalance(address sender, uint256 balance, uint256 needed, uint256 tokenId);
/**
* @dev Indicates a failure with the token `sender`. Used in transfers.
* @param sender Address whose tokens are being transferred.
*/
error ERC1155InvalidSender(address sender);
/**
* @dev Indicates a failure with the token `receiver`. Used in transfers.
* @param receiver Address to which tokens are being transferred.
*/
error ERC1155InvalidReceiver(address receiver);
/**
* @dev Indicates a failure with the `operator`’s approval. Used in transfers.
* @param operator Address that may be allowed to operate on tokens without being their owner.
* @param owner Address of the current owner of a token.
*/
error ERC1155MissingApprovalForAll(address operator, address owner);
/**
* @dev Indicates a failure with the `approver` of a token to be approved. Used in approvals.
* @param approver Address initiating an approval operation.
*/
error ERC1155InvalidApprover(address approver);
/**
* @dev Indicates a failure with the `operator` to be approved. Used in approvals.
* @param operator Address that may be allowed to operate on tokens without being their owner.
*/
error ERC1155InvalidOperator(address operator);
/**
* @dev Indicates an array length mismatch between ids and values in a safeBatchTransferFrom operation.
* Used in batch transfers.
* @param idsLength Length of the array of token identifiers
* @param valuesLength Length of the array of token amounts
*/
error ERC1155InvalidArrayLength(uint256 idsLength, uint256 valuesLength);
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC1155/ERC1155.sol)
pragma solidity ^0.8.20;
import {IERC1155} from "./IERC1155.sol";
import {IERC1155Receiver} from "./IERC1155Receiver.sol";
import {IERC1155MetadataURI} from "./extensions/IERC1155MetadataURI.sol";
import {Context} from "../../utils/Context.sol";
import {IERC165, ERC165} from "../../utils/introspection/ERC165.sol";
import {Arrays} from "../../utils/Arrays.sol";
import {IERC1155Errors} from "../../interfaces/draft-IERC6093.sol";
/**
* @dev Implementation of the basic standard multi-token.
* See https://eips.ethereum.org/EIPS/eip-1155
* Originally based on code by Enjin: https://github.com/enjin/erc-1155
*/
abstract contract ERC1155 is Context, ERC165, IERC1155, IERC1155MetadataURI, IERC1155Errors {
using Arrays for uint256[];
using Arrays for address[];
mapping(uint256 id => mapping(address account => uint256)) private _balances;
mapping(address account => mapping(address operator => bool)) private _operatorApprovals;
// Used as the URI for all token types by relying on ID substitution, e.g. https://token-cdn-domain/{id}.json
string private _uri;
/**
* @dev See {_setURI}.
*/
constructor(string memory uri_) {
_setURI(uri_);
}
/**
* @dev See {IERC165-supportsInterface}.
*/
function supportsInterface(bytes4 interfaceId) public view virtual override(ERC165, IERC165) returns (bool) {
return
interfaceId == type(IERC1155).interfaceId ||
interfaceId == type(IERC1155MetadataURI).interfaceId ||
super.supportsInterface(interfaceId);
}
/**
* @dev See {IERC1155MetadataURI-uri}.
*
* This implementation returns the same URI for *all* token types. It relies
* on the token type ID substitution mechanism
* https://eips.ethereum.org/EIPS/eip-1155#metadata[defined in the EIP].
*
* Clients calling this function must replace the `\{id\}` substring with the
* actual token type ID.
*/
function uri(uint256 /* id */) public view virtual returns (string memory) {
return _uri;
}
/**
* @dev See {IERC1155-balanceOf}.
*/
function balanceOf(address account, uint256 id) public view virtual returns (uint256) {
return _balances[id][account];
}
/**
* @dev See {IERC1155-balanceOfBatch}.
*
* Requirements:
*
* - `accounts` and `ids` must have the same length.
*/
function balanceOfBatch(
address[] memory accounts,
uint256[] memory ids
) public view virtual returns (uint256[] memory) {
if (accounts.length != ids.length) {
revert ERC1155InvalidArrayLength(ids.length, accounts.length);
}
uint256[] memory batchBalances = new uint256[](accounts.length);
for (uint256 i = 0; i < accounts.length; ++i) {
batchBalances[i] = balanceOf(accounts.unsafeMemoryAccess(i), ids.unsafeMemoryAccess(i));
}
return batchBalances;
}
/**
* @dev See {IERC1155-setApprovalForAll}.
*/
function setApprovalForAll(address operator, bool approved) public virtual {
_setApprovalForAll(_msgSender(), operator, approved);
}
/**
* @dev See {IERC1155-isApprovedForAll}.
*/
function isApprovedForAll(address account, address operator) public view virtual returns (bool) {
return _operatorApprovals[account][operator];
}
/**
* @dev See {IERC1155-safeTransferFrom}.
*/
function safeTransferFrom(address from, address to, uint256 id, uint256 value, bytes memory data) public virtual {
address sender = _msgSender();
if (from != sender && !isApprovedForAll(from, sender)) {
revert ERC1155MissingApprovalForAll(sender, from);
}
_safeTransferFrom(from, to, id, value, data);
}
/**
* @dev See {IERC1155-safeBatchTransferFrom}.
*/
function safeBatchTransferFrom(
address from,
address to,
uint256[] memory ids,
uint256[] memory values,
bytes memory data
) public virtual {
address sender = _msgSender();
if (from != sender && !isApprovedForAll(from, sender)) {
revert ERC1155MissingApprovalForAll(sender, from);
}
_safeBatchTransferFrom(from, to, ids, values, data);
}
/**
* @dev Transfers a `value` amount of tokens of type `id` from `from` to `to`. Will mint (or burn) if `from`
* (or `to`) is the zero address.
*
* Emits a {TransferSingle} event if the arrays contain one element, and {TransferBatch} otherwise.
*
* Requirements:
*
* - If `to` refers to a smart contract, it must implement either {IERC1155Receiver-onERC1155Received}
* or {IERC1155Receiver-onERC1155BatchReceived} and return the acceptance magic value.
* - `ids` and `values` must have the same length.
*
* NOTE: The ERC-1155 acceptance check is not performed in this function. See {_updateWithAcceptanceCheck} instead.
*/
function _update(address from, address to, uint256[] memory ids, uint256[] memory values) internal virtual {
if (ids.length != values.length) {
revert ERC1155InvalidArrayLength(ids.length, values.length);
}
address operator = _msgSender();
for (uint256 i = 0; i < ids.length; ++i) {
uint256 id = ids.unsafeMemoryAccess(i);
uint256 value = values.unsafeMemoryAccess(i);
if (from != address(0)) {
uint256 fromBalance = _balances[id][from];
if (fromBalance < value) {
revert ERC1155InsufficientBalance(from, fromBalance, value, id);
}
unchecked {
// Overflow not possible: value <= fromBalance
_balances[id][from] = fromBalance - value;
}
}
if (to != address(0)) {
_balances[id][to] += value;
}
}
if (ids.length == 1) {
uint256 id = ids.unsafeMemoryAccess(0);
uint256 value = values.unsafeMemoryAccess(0);
emit TransferSingle(operator, from, to, id, value);
} else {
emit TransferBatch(operator, from, to, ids, values);
}
}
/**
* @dev Version of {_update} that performs the token acceptance check by calling
* {IERC1155Receiver-onERC1155Received} or {IERC1155Receiver-onERC1155BatchReceived} on the receiver address if it
* contains code (eg. is a smart contract at the moment of execution).
*
* IMPORTANT: Overriding this function is discouraged because it poses a reentrancy risk from the receiver. So any
* update to the contract state after this function would break the check-effect-interaction pattern. Consider
* overriding {_update} instead.
*/
function _updateWithAcceptanceCheck(
address from,
address to,
uint256[] memory ids,
uint256[] memory values,
bytes memory data
) internal virtual {
_update(from, to, ids, values);
if (to != address(0)) {
address operator = _msgSender();
if (ids.length == 1) {
uint256 id = ids.unsafeMemoryAccess(0);
uint256 value = values.unsafeMemoryAccess(0);
_doSafeTransferAcceptanceCheck(operator, from, to, id, value, data);
} else {
_doSafeBatchTransferAcceptanceCheck(operator, from, to, ids, values, data);
}
}
}
/**
* @dev Transfers a `value` tokens of token type `id` from `from` to `to`.
*
* Emits a {TransferSingle} event.
*
* Requirements:
*
* - `to` cannot be the zero address.
* - `from` must have a balance of tokens of type `id` of at least `value` amount.
* - If `to` refers to a smart contract, it must implement {IERC1155Receiver-onERC1155Received} and return the
* acceptance magic value.
*/
function _safeTransferFrom(address from, address to, uint256 id, uint256 value, bytes memory data) internal {
if (to == address(0)) {
revert ERC1155InvalidReceiver(address(0));
}
if (from == address(0)) {
revert ERC1155InvalidSender(address(0));
}
(uint256[] memory ids, uint256[] memory values) = _asSingletonArrays(id, value);
_updateWithAcceptanceCheck(from, to, ids, values, data);
}
/**
* @dev xref:ROOT:erc1155.adoc#batch-operations[Batched] version of {_safeTransferFrom}.
*
* Emits a {TransferBatch} event.
*
* Requirements:
*
* - If `to` refers to a smart contract, it must implement {IERC1155Receiver-onERC1155BatchReceived} and return the
* acceptance magic value.
* - `ids` and `values` must have the same length.
*/
function _safeBatchTransferFrom(
address from,
address to,
uint256[] memory ids,
uint256[] memory values,
bytes memory data
) internal {
if (to == address(0)) {
revert ERC1155InvalidReceiver(address(0));
}
if (from == address(0)) {
revert ERC1155InvalidSender(address(0));
}
_updateWithAcceptanceCheck(from, to, ids, values, data);
}
/**
* @dev Sets a new URI for all token types, by relying on the token type ID
* substitution mechanism
* https://eips.ethereum.org/EIPS/eip-1155#metadata[defined in the EIP].
*
* By this mechanism, any occurrence of the `\{id\}` substring in either the
* URI or any of the values in the JSON file at said URI will be replaced by
* clients with the token type ID.
*
* For example, the `https://token-cdn-domain/\{id\}.json` URI would be
* interpreted by clients as
* `https://token-cdn-domain/000000000000000000000000000000000000000000000000000000000004cce0.json`
* for token type ID 0x4cce0.
*
* See {uri}.
*
* Because these URIs cannot be meaningfully represented by the {URI} event,
* this function emits no events.
*/
function _setURI(string memory newuri) internal virtual {
_uri = newuri;
}
/**
* @dev Creates a `value` amount of tokens of type `id`, and assigns them to `to`.
*
* Emits a {TransferSingle} event.
*
* Requirements:
*
* - `to` cannot be the zero address.
* - If `to` refers to a smart contract, it must implement {IERC1155Receiver-onERC1155Received} and return the
* acceptance magic value.
*/
function _mint(address to, uint256 id, uint256 value, bytes memory data) internal {
if (to == address(0)) {
revert ERC1155InvalidReceiver(address(0));
}
(uint256[] memory ids, uint256[] memory values) = _asSingletonArrays(id, value);
_updateWithAcceptanceCheck(address(0), to, ids, values, data);
}
/**
* @dev xref:ROOT:erc1155.adoc#batch-operations[Batched] version of {_mint}.
*
* Emits a {TransferBatch} event.
*
* Requirements:
*
* - `ids` and `values` must have the same length.
* - `to` cannot be the zero address.
* - If `to` refers to a smart contract, it must implement {IERC1155Receiver-onERC1155BatchReceived} and return the
* acceptance magic value.
*/
function _mintBatch(address to, uint256[] memory ids, uint256[] memory values, bytes memory data) internal {
if (to == address(0)) {
revert ERC1155InvalidReceiver(address(0));
}
_updateWithAcceptanceCheck(address(0), to, ids, values, data);
}
/**
* @dev Destroys a `value` amount of tokens of type `id` from `from`
*
* Emits a {TransferSingle} event.
*
* Requirements:
*
* - `from` cannot be the zero address.
* - `from` must have at least `value` amount of tokens of type `id`.
*/
function _burn(address from, uint256 id, uint256 value) internal {
if (from == address(0)) {
revert ERC1155InvalidSender(address(0));
}
(uint256[] memory ids, uint256[] memory values) = _asSingletonArrays(id, value);
_updateWithAcceptanceCheck(from, address(0), ids, values, "");
}
/**
* @dev xref:ROOT:erc1155.adoc#batch-operations[Batched] version of {_burn}.
*
* Emits a {TransferBatch} event.
*
* Requirements:
*
* - `from` cannot be the zero address.
* - `from` must have at least `value` amount of tokens of type `id`.
* - `ids` and `values` must have the same length.
*/
function _burnBatch(address from, uint256[] memory ids, uint256[] memory values) internal {
if (from == address(0)) {
revert ERC1155InvalidSender(address(0));
}
_updateWithAcceptanceCheck(from, address(0), ids, values, "");
}
/**
* @dev Approve `operator` to operate on all of `owner` tokens
*
* Emits an {ApprovalForAll} event.
*
* Requirements:
*
* - `operator` cannot be the zero address.
*/
function _setApprovalForAll(address owner, address operator, bool approved) internal virtual {
if (operator == address(0)) {
revert ERC1155InvalidOperator(address(0));
}
_operatorApprovals[owner][operator] = approved;
emit ApprovalForAll(owner, operator, approved);
}
/**
* @dev Performs an acceptance check by calling {IERC1155-onERC1155Received} on the `to` address
* if it contains code at the moment of execution.
*/
function _doSafeTransferAcceptanceCheck(
address operator,
address from,
address to,
uint256 id,
uint256 value,
bytes memory data
) private {
if (to.code.length > 0) {
try IERC1155Receiver(to).onERC1155Received(operator, from, id, value, data) returns (bytes4 response) {
if (response != IERC1155Receiver.onERC1155Received.selector) {
// Tokens rejected
revert ERC1155InvalidReceiver(to);
}
} catch (bytes memory reason) {
if (reason.length == 0) {
// non-ERC1155Receiver implementer
revert ERC1155InvalidReceiver(to);
} else {
/// @solidity memory-safe-assembly
assembly {
revert(add(32, reason), mload(reason))
}
}
}
}
}
/**
* @dev Performs a batch acceptance check by calling {IERC1155-onERC1155BatchReceived} on the `to` address
* if it contains code at the moment of execution.
*/
function _doSafeBatchTransferAcceptanceCheck(
address operator,
address from,
address to,
uint256[] memory ids,
uint256[] memory values,
bytes memory data
) private {
if (to.code.length > 0) {
try IERC1155Receiver(to).onERC1155BatchReceived(operator, from, ids, values, data) returns (
bytes4 response
) {
if (response != IERC1155Receiver.onERC1155BatchReceived.selector) {
// Tokens rejected
revert ERC1155InvalidReceiver(to);
}
} catch (bytes memory reason) {
if (reason.length == 0) {
// non-ERC1155Receiver implementer
revert ERC1155InvalidReceiver(to);
} else {
/// @solidity memory-safe-assembly
assembly {
revert(add(32, reason), mload(reason))
}
}
}
}
}
/**
* @dev Creates an array in memory with only one value for each of the elements provided.
*/
function _asSingletonArrays(
uint256 element1,
uint256 element2
) private pure returns (uint256[] memory array1, uint256[] memory array2) {
/// @solidity memory-safe-assembly
assembly {
// Load the free memory pointer
array1 := mload(0x40)
// Set array length to 1
mstore(array1, 1)
// Store the single element at the next word after the length (where content starts)
mstore(add(array1, 0x20), element1)
// Repeat for next array locating it right after the first array
array2 := add(array1, 0x40)
mstore(array2, 1)
mstore(add(array2, 0x20), element2)
// Update the free memory pointer by pointing after the second array
mstore(0x40, add(array2, 0x40))
}
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC1155/extensions/ERC1155Burnable.sol)
pragma solidity ^0.8.20;
import {ERC1155} from "../ERC1155.sol";
/**
* @dev Extension of {ERC1155} that allows token holders to destroy both their
* own tokens and those that they have been approved to use.
*/
abstract contract ERC1155Burnable is ERC1155 {
function burn(address account, uint256 id, uint256 value) public virtual {
if (account != _msgSender() && !isApprovedForAll(account, _msgSender())) {
revert ERC1155MissingApprovalForAll(_msgSender(), account);
}
_burn(account, id, value);
}
function burnBatch(address account, uint256[] memory ids, uint256[] memory values) public virtual {
if (account != _msgSender() && !isApprovedForAll(account, _msgSender())) {
revert ERC1155MissingApprovalForAll(_msgSender(), account);
}
_burnBatch(account, ids, values);
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC1155/extensions/ERC1155Supply.sol)
pragma solidity ^0.8.20;
import {ERC1155} from "../ERC1155.sol";
/**
* @dev Extension of ERC1155 that adds tracking of total supply per id.
*
* Useful for scenarios where Fungible and Non-fungible tokens have to be
* clearly identified. Note: While a totalSupply of 1 might mean the
* corresponding is an NFT, there is no guarantees that no other token with the
* same id are not going to be minted.
*
* NOTE: This contract implies a global limit of 2**256 - 1 to the number of tokens
* that can be minted.
*
* CAUTION: This extension should not be added in an upgrade to an already deployed contract.
*/
abstract contract ERC1155Supply is ERC1155 {
mapping(uint256 id => uint256) private _totalSupply;
uint256 private _totalSupplyAll;
/**
* @dev Total value of tokens in with a given id.
*/
function totalSupply(uint256 id) public view virtual returns (uint256) {
return _totalSupply[id];
}
/**
* @dev Total value of tokens.
*/
function totalSupply() public view virtual returns (uint256) {
return _totalSupplyAll;
}
/**
* @dev Indicates whether any token exist with a given id, or not.
*/
function exists(uint256 id) public view virtual returns (bool) {
return totalSupply(id) > 0;
}
/**
* @dev See {ERC1155-_update}.
*/
function _update(
address from,
address to,
uint256[] memory ids,
uint256[] memory values
) internal virtual override {
super._update(from, to, ids, values);
if (from == address(0)) {
uint256 totalMintValue = 0;
for (uint256 i = 0; i < ids.length; ++i) {
uint256 value = values[i];
// Overflow check required: The rest of the code assumes that totalSupply never overflows
_totalSupply[ids[i]] += value;
totalMintValue += value;
}
// Overflow check required: The rest of the code assumes that totalSupplyAll never overflows
_totalSupplyAll += totalMintValue;
}
if (to == address(0)) {
uint256 totalBurnValue = 0;
for (uint256 i = 0; i < ids.length; ++i) {
uint256 value = values[i];
unchecked {
// Overflow not possible: values[i] <= balanceOf(from, ids[i]) <= totalSupply(ids[i])
_totalSupply[ids[i]] -= value;
// Overflow not possible: sum_i(values[i]) <= sum_i(totalSupply(ids[i])) <= totalSupplyAll
totalBurnValue += value;
}
}
unchecked {
// Overflow not possible: totalBurnValue = sum_i(values[i]) <= sum_i(totalSupply(ids[i])) <= totalSupplyAll
_totalSupplyAll -= totalBurnValue;
}
}
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC1155/extensions/IERC1155MetadataURI.sol)
pragma solidity ^0.8.20;
import {IERC1155} from "../IERC1155.sol";
/**
* @dev Interface of the optional ERC1155MetadataExtension interface, as defined
* in the https://eips.ethereum.org/EIPS/eip-1155#metadata-extensions[EIP].
*/
interface IERC1155MetadataURI is IERC1155 {
/**
* @dev Returns the URI for token type `id`.
*
* If the `\{id\}` substring is present in the URI, it must be replaced by
* clients with the actual token type ID.
*/
function uri(uint256 id) external view returns (string memory);
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.1) (token/ERC1155/IERC1155.sol)
pragma solidity ^0.8.20;
import {IERC165} from "../../utils/introspection/IERC165.sol";
/**
* @dev Required interface of an ERC1155 compliant contract, as defined in the
* https://eips.ethereum.org/EIPS/eip-1155[EIP].
*/
interface IERC1155 is IERC165 {
/**
* @dev Emitted when `value` amount of tokens of type `id` are transferred from `from` to `to` by `operator`.
*/
event TransferSingle(address indexed operator, address indexed from, address indexed to, uint256 id, uint256 value);
/**
* @dev Equivalent to multiple {TransferSingle} events, where `operator`, `from` and `to` are the same for all
* transfers.
*/
event TransferBatch(
address indexed operator,
address indexed from,
address indexed to,
uint256[] ids,
uint256[] values
);
/**
* @dev Emitted when `account` grants or revokes permission to `operator` to transfer their tokens, according to
* `approved`.
*/
event ApprovalForAll(address indexed account, address indexed operator, bool approved);
/**
* @dev Emitted when the URI for token type `id` changes to `value`, if it is a non-programmatic URI.
*
* If an {URI} event was emitted for `id`, the standard
* https://eips.ethereum.org/EIPS/eip-1155#metadata-extensions[guarantees] that `value` will equal the value
* returned by {IERC1155MetadataURI-uri}.
*/
event URI(string value, uint256 indexed id);
/**
* @dev Returns the value of tokens of token type `id` owned by `account`.
*
* Requirements:
*
* - `account` cannot be the zero address.
*/
function balanceOf(address account, uint256 id) external view returns (uint256);
/**
* @dev xref:ROOT:erc1155.adoc#batch-operations[Batched] version of {balanceOf}.
*
* Requirements:
*
* - `accounts` and `ids` must have the same length.
*/
function balanceOfBatch(
address[] calldata accounts,
uint256[] calldata ids
) external view returns (uint256[] memory);
/**
* @dev Grants or revokes permission to `operator` to transfer the caller's tokens, according to `approved`,
*
* Emits an {ApprovalForAll} event.
*
* Requirements:
*
* - `operator` cannot be the caller.
*/
function setApprovalForAll(address operator, bool approved) external;
/**
* @dev Returns true if `operator` is approved to transfer ``account``'s tokens.
*
* See {setApprovalForAll}.
*/
function isApprovedForAll(address account, address operator) external view returns (bool);
/**
* @dev Transfers a `value` amount of tokens of type `id` from `from` to `to`.
*
* WARNING: This function can potentially allow a reentrancy attack when transferring tokens
* to an untrusted contract, when invoking {onERC1155Received} on the receiver.
* Ensure to follow the checks-effects-interactions pattern and consider employing
* reentrancy guards when interacting with untrusted contracts.
*
* Emits a {TransferSingle} event.
*
* Requirements:
*
* - `to` cannot be the zero address.
* - If the caller is not `from`, it must have been approved to spend ``from``'s tokens via {setApprovalForAll}.
* - `from` must have a balance of tokens of type `id` of at least `value` amount.
* - If `to` refers to a smart contract, it must implement {IERC1155Receiver-onERC1155Received} and return the
* acceptance magic value.
*/
function safeTransferFrom(address from, address to, uint256 id, uint256 value, bytes calldata data) external;
/**
* @dev xref:ROOT:erc1155.adoc#batch-operations[Batched] version of {safeTransferFrom}.
*
* WARNING: This function can potentially allow a reentrancy attack when transferring tokens
* to an untrusted contract, when invoking {onERC1155BatchReceived} on the receiver.
* Ensure to follow the checks-effects-interactions pattern and consider employing
* reentrancy guards when interacting with untrusted contracts.
*
* Emits either a {TransferSingle} or a {TransferBatch} event, depending on the length of the array arguments.
*
* Requirements:
*
* - `ids` and `values` must have the same length.
* - If `to` refers to a smart contract, it must implement {IERC1155Receiver-onERC1155BatchReceived} and return the
* acceptance magic value.
*/
function safeBatchTransferFrom(
address from,
address to,
uint256[] calldata ids,
uint256[] calldata values,
bytes calldata data
) external;
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC1155/IERC1155Receiver.sol)
pragma solidity ^0.8.20;
import {IERC165} from "../../utils/introspection/IERC165.sol";
/**
* @dev Interface that must be implemented by smart contracts in order to receive
* ERC-1155 token transfers.
*/
interface IERC1155Receiver is IERC165 {
/**
* @dev Handles the receipt of a single ERC1155 token type. This function is
* called at the end of a `safeTransferFrom` after the balance has been updated.
*
* NOTE: To accept the transfer, this must return
* `bytes4(keccak256("onERC1155Received(address,address,uint256,uint256,bytes)"))`
* (i.e. 0xf23a6e61, or its own function selector).
*
* @param operator The address which initiated the transfer (i.e. msg.sender)
* @param from The address which previously owned the token
* @param id The ID of the token being transferred
* @param value The amount of tokens being transferred
* @param data Additional data with no specified format
* @return `bytes4(keccak256("onERC1155Received(address,address,uint256,uint256,bytes)"))` if transfer is allowed
*/
function onERC1155Received(
address operator,
address from,
uint256 id,
uint256 value,
bytes calldata data
) external returns (bytes4);
/**
* @dev Handles the receipt of a multiple ERC1155 token types. This function
* is called at the end of a `safeBatchTransferFrom` after the balances have
* been updated.
*
* NOTE: To accept the transfer(s), this must return
* `bytes4(keccak256("onERC1155BatchReceived(address,address,uint256[],uint256[],bytes)"))`
* (i.e. 0xbc197c81, or its own function selector).
*
* @param operator The address which initiated the batch transfer (i.e. msg.sender)
* @param from The address which previously owned the token
* @param ids An array containing ids of each token being transferred (order and length must match values array)
* @param values An array containing amounts of each token being transferred (order and length must match ids array)
* @param data Additional data with no specified format
* @return `bytes4(keccak256("onERC1155BatchReceived(address,address,uint256[],uint256[],bytes)"))` if transfer is allowed
*/
function onERC1155BatchReceived(
address operator,
address from,
uint256[] calldata ids,
uint256[] calldata values,
bytes calldata data
) external returns (bytes4);
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (utils/Arrays.sol)
pragma solidity ^0.8.20;
import {StorageSlot} from "./StorageSlot.sol";
import {Math} from "./math/Math.sol";
/**
* @dev Collection of functions related to array types.
*/
library Arrays {
using StorageSlot for bytes32;
/**
* @dev Searches a sorted `array` and returns the first index that contains
* a value greater or equal to `element`. If no such index exists (i.e. all
* values in the array are strictly less than `element`), the array length is
* returned. Time complexity O(log n).
*
* `array` is expected to be sorted in ascending order, and to contain no
* repeated elements.
*/
function findUpperBound(uint256[] storage array, uint256 element) internal view returns (uint256) {
uint256 low = 0;
uint256 high = array.length;
if (high == 0) {
return 0;
}
while (low < high) {
uint256 mid = Math.average(low, high);
// Note that mid will always be strictly less than high (i.e. it will be a valid array index)
// because Math.average rounds towards zero (it does integer division with truncation).
if (unsafeAccess(array, mid).value > element) {
high = mid;
} else {
low = mid + 1;
}
}
// At this point `low` is the exclusive upper bound. We will return the inclusive upper bound.
if (low > 0 && unsafeAccess(array, low - 1).value == element) {
return low - 1;
} else {
return low;
}
}
/**
* @dev Access an array in an "unsafe" way. Skips solidity "index-out-of-range" check.
*
* WARNING: Only use if you are certain `pos` is lower than the array length.
*/
function unsafeAccess(address[] storage arr, uint256 pos) internal pure returns (StorageSlot.AddressSlot storage) {
bytes32 slot;
// We use assembly to calculate the storage slot of the element at index `pos` of the dynamic array `arr`
// following https://docs.soliditylang.org/en/v0.8.20/internals/layout_in_storage.html#mappings-and-dynamic-arrays.
/// @solidity memory-safe-assembly
assembly {
mstore(0, arr.slot)
slot := add(keccak256(0, 0x20), pos)
}
return slot.getAddressSlot();
}
/**
* @dev Access an array in an "unsafe" way. Skips solidity "index-out-of-range" check.
*
* WARNING: Only use if you are certain `pos` is lower than the array length.
*/
function unsafeAccess(bytes32[] storage arr, uint256 pos) internal pure returns (StorageSlot.Bytes32Slot storage) {
bytes32 slot;
// We use assembly to calculate the storage slot of the element at index `pos` of the dynamic array `arr`
// following https://docs.soliditylang.org/en/v0.8.20/internals/layout_in_storage.html#mappings-and-dynamic-arrays.
/// @solidity memory-safe-assembly
assembly {
mstore(0, arr.slot)
slot := add(keccak256(0, 0x20), pos)
}
return slot.getBytes32Slot();
}
/**
* @dev Access an array in an "unsafe" way. Skips solidity "index-out-of-range" check.
*
* WARNING: Only use if you are certain `pos` is lower than the array length.
*/
function unsafeAccess(uint256[] storage arr, uint256 pos) internal pure returns (StorageSlot.Uint256Slot storage) {
bytes32 slot;
// We use assembly to calculate the storage slot of the element at index `pos` of the dynamic array `arr`
// following https://docs.soliditylang.org/en/v0.8.20/internals/layout_in_storage.html#mappings-and-dynamic-arrays.
/// @solidity memory-safe-assembly
assembly {
mstore(0, arr.slot)
slot := add(keccak256(0, 0x20), pos)
}
return slot.getUint256Slot();
}
/**
* @dev Access an array in an "unsafe" way. Skips solidity "index-out-of-range" check.
*
* WARNING: Only use if you are certain `pos` is lower than the array length.
*/
function unsafeMemoryAccess(uint256[] memory arr, uint256 pos) internal pure returns (uint256 res) {
assembly {
res := mload(add(add(arr, 0x20), mul(pos, 0x20)))
}
}
/**
* @dev Access an array in an "unsafe" way. Skips solidity "index-out-of-range" check.
*
* WARNING: Only use if you are certain `pos` is lower than the array length.
*/
function unsafeMemoryAccess(address[] memory arr, uint256 pos) internal pure returns (address res) {
assembly {
res := mload(add(add(arr, 0x20), mul(pos, 0x20)))
}
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.1) (utils/Context.sol)
pragma solidity ^0.8.20;
/**
* @dev Provides information about the current execution context, including the
* sender of the transaction and its data. While these are generally available
* via msg.sender and msg.data, they should not be accessed in such a direct
* manner, since when dealing with meta-transactions the account sending and
* paying for execution may not be the actual sender (as far as an application
* is concerned).
*
* This contract is only required for intermediate, library-like contracts.
*/
abstract contract Context {
function _msgSender() internal view virtual returns (address) {
return msg.sender;
}
function _msgData() internal view virtual returns (bytes calldata) {
return msg.data;
}
function _contextSuffixLength() internal view virtual returns (uint256) {
return 0;
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/ERC165.sol)
pragma solidity ^0.8.20;
import {IERC165} from "./IERC165.sol";
/**
* @dev Implementation of the {IERC165} interface.
*
* Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check
* for the additional interface id that will be supported. For example:
*
* ```solidity
* function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {
* return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId);
* }
* ```
*/
abstract contract ERC165 is IERC165 {
/**
* @dev See {IERC165-supportsInterface}.
*/
function supportsInterface(bytes4 interfaceId) public view virtual returns (bool) {
return interfaceId == type(IERC165).interfaceId;
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/IERC165.sol)
pragma solidity ^0.8.20;
/**
* @dev Interface of the ERC165 standard, as defined in the
* https://eips.ethereum.org/EIPS/eip-165[EIP].
*
* Implementers can declare support of contract interfaces, which can then be
* queried by others ({ERC165Checker}).
*
* For an implementation, see {ERC165}.
*/
interface IERC165 {
/**
* @dev Returns true if this contract implements the interface defined by
* `interfaceId`. See the corresponding
* https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]
* to learn more about how these ids are created.
*
* This function call must use less than 30 000 gas.
*/
function supportsInterface(bytes4 interfaceId) external view returns (bool);
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (utils/math/Math.sol)
pragma solidity ^0.8.20;
/**
* @dev Standard math utilities missing in the Solidity language.
*/
library Math {
/**
* @dev Muldiv operation overflow.
*/
error MathOverflowedMulDiv();
enum Rounding {
Floor, // Toward negative infinity
Ceil, // Toward positive infinity
Trunc, // Toward zero
Expand // Away from zero
}
/**
* @dev Returns the addition of two unsigned integers, with an overflow flag.
*/
function tryAdd(uint256 a, uint256 b) internal pure returns (bool, uint256) {
unchecked {
uint256 c = a + b;
if (c < a) return (false, 0);
return (true, c);
}
}
/**
* @dev Returns the subtraction of two unsigned integers, with an overflow flag.
*/
function trySub(uint256 a, uint256 b) internal pure returns (bool, uint256) {
unchecked {
if (b > a) return (false, 0);
return (true, a - b);
}
}
/**
* @dev Returns the multiplication of two unsigned integers, with an overflow flag.
*/
function tryMul(uint256 a, uint256 b) internal pure returns (bool, uint256) {
unchecked {
// Gas optimization: this is cheaper than requiring 'a' not being zero, but the
// benefit is lost if 'b' is also tested.
// See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522
if (a == 0) return (true, 0);
uint256 c = a * b;
if (c / a != b) return (false, 0);
return (true, c);
}
}
/**
* @dev Returns the division of two unsigned integers, with a division by zero flag.
*/
function tryDiv(uint256 a, uint256 b) internal pure returns (bool, uint256) {
unchecked {
if (b == 0) return (false, 0);
return (true, a / b);
}
}
/**
* @dev Returns the remainder of dividing two unsigned integers, with a division by zero flag.
*/
function tryMod(uint256 a, uint256 b) internal pure returns (bool, uint256) {
unchecked {
if (b == 0) return (false, 0);
return (true, a % b);
}
}
/**
* @dev Returns the largest of two numbers.
*/
function max(uint256 a, uint256 b) internal pure returns (uint256) {
return a > b ? a : b;
}
/**
* @dev Returns the smallest of two numbers.
*/
function min(uint256 a, uint256 b) internal pure returns (uint256) {
return a < b ? a : b;
}
/**
* @dev Returns the average of two numbers. The result is rounded towards
* zero.
*/
function average(uint256 a, uint256 b) internal pure returns (uint256) {
// (a + b) / 2 can overflow.
return (a & b) + (a ^ b) / 2;
}
/**
* @dev Returns the ceiling of the division of two numbers.
*
* This differs from standard division with `/` in that it rounds towards infinity instead
* of rounding towards zero.
*/
function ceilDiv(uint256 a, uint256 b) internal pure returns (uint256) {
if (b == 0) {
// Guarantee the same behavior as in a regular Solidity division.
return a / b;
}
// (a + b - 1) / b can overflow on addition, so we distribute.
return a == 0 ? 0 : (a - 1) / b + 1;
}
/**
* @notice Calculates floor(x * y / denominator) with full precision. Throws if result overflows a uint256 or
* denominator == 0.
* @dev Original credit to Remco Bloemen under MIT license (https://xn--2-umb.com/21/muldiv) with further edits by
* Uniswap Labs also under MIT license.
*/
function mulDiv(uint256 x, uint256 y, uint256 denominator) internal pure returns (uint256 result) {
unchecked {
// 512-bit multiply [prod1 prod0] = x * y. Compute the product mod 2^256 and mod 2^256 - 1, then use
// use the Chinese Remainder Theorem to reconstruct the 512 bit result. The result is stored in two 256
// variables such that product = prod1 * 2^256 + prod0.
uint256 prod0 = x * y; // Least significant 256 bits of the product
uint256 prod1; // Most significant 256 bits of the product
assembly {
let mm := mulmod(x, y, not(0))
prod1 := sub(sub(mm, prod0), lt(mm, prod0))
}
// Handle non-overflow cases, 256 by 256 division.
if (prod1 == 0) {
// Solidity will revert if denominator == 0, unlike the div opcode on its own.
// The surrounding unchecked block does not change this fact.
// See https://docs.soliditylang.org/en/latest/control-structures.html#checked-or-unchecked-arithmetic.
return prod0 / denominator;
}
// Make sure the result is less than 2^256. Also prevents denominator == 0.
if (denominator <= prod1) {
revert MathOverflowedMulDiv();
}
///////////////////////////////////////////////
// 512 by 256 division.
///////////////////////////////////////////////
// Make division exact by subtracting the remainder from [prod1 prod0].
uint256 remainder;
assembly {
// Compute remainder using mulmod.
remainder := mulmod(x, y, denominator)
// Subtract 256 bit number from 512 bit number.
prod1 := sub(prod1, gt(remainder, prod0))
prod0 := sub(prod0, remainder)
}
// Factor powers of two out of denominator and compute largest power of two divisor of denominator.
// Always >= 1. See https://cs.stackexchange.com/q/138556/92363.
uint256 twos = denominator & (0 - denominator);
assembly {
// Divide denominator by twos.
denominator := div(denominator, twos)
// Divide [prod1 prod0] by twos.
prod0 := div(prod0, twos)
// Flip twos such that it is 2^256 / twos. If twos is zero, then it becomes one.
twos := add(div(sub(0, twos), twos), 1)
}
// Shift in bits from prod1 into prod0.
prod0 |= prod1 * twos;
// Invert denominator mod 2^256. Now that denominator is an odd number, it has an inverse modulo 2^256 such
// that denominator * inv = 1 mod 2^256. Compute the inverse by starting with a seed that is correct for
// four bits. That is, denominator * inv = 1 mod 2^4.
uint256 inverse = (3 * denominator) ^ 2;
// Use the Newton-Raphson iteration to improve the precision. Thanks to Hensel's lifting lemma, this also
// works in modular arithmetic, doubling the correct bits in each step.
inverse *= 2 - denominator * inverse; // inverse mod 2^8
inverse *= 2 - denominator * inverse; // inverse mod 2^16
inverse *= 2 - denominator * inverse; // inverse mod 2^32
inverse *= 2 - denominator * inverse; // inverse mod 2^64
inverse *= 2 - denominator * inverse; // inverse mod 2^128
inverse *= 2 - denominator * inverse; // inverse mod 2^256
// Because the division is now exact we can divide by multiplying with the modular inverse of denominator.
// This will give us the correct result modulo 2^256. Since the preconditions guarantee that the outcome is
// less than 2^256, this is the final result. We don't need to compute the high bits of the result and prod1
// is no longer required.
result = prod0 * inverse;
return result;
}
}
/**
* @notice Calculates x * y / denominator with full precision, following the selected rounding direction.
*/
function mulDiv(uint256 x, uint256 y, uint256 denominator, Rounding rounding) internal pure returns (uint256) {
uint256 result = mulDiv(x, y, denominator);
if (unsignedRoundsUp(rounding) && mulmod(x, y, denominator) > 0) {
result += 1;
}
return result;
}
/**
* @dev Returns the square root of a number. If the number is not a perfect square, the value is rounded
* towards zero.
*
* Inspired by Henry S. Warren, Jr.'s "Hacker's Delight" (Chapter 11).
*/
function sqrt(uint256 a) internal pure returns (uint256) {
if (a == 0) {
return 0;
}
// For our first guess, we get the biggest power of 2 which is smaller than the square root of the target.
//
// We know that the "msb" (most significant bit) of our target number `a` is a power of 2 such that we have
// `msb(a) <= a < 2*msb(a)`. This value can be written `msb(a)=2**k` with `k=log2(a)`.
//
// This can be rewritten `2**log2(a) <= a < 2**(log2(a) + 1)`
// → `sqrt(2**k) <= sqrt(a) < sqrt(2**(k+1))`
// → `2**(k/2) <= sqrt(a) < 2**((k+1)/2) <= 2**(k/2 + 1)`
//
// Consequently, `2**(log2(a) / 2)` is a good first approximation of `sqrt(a)` with at least 1 correct bit.
uint256 result = 1 << (log2(a) >> 1);
// At this point `result` is an estimation with one bit of precision. We know the true value is a uint128,
// since it is the square root of a uint256. Newton's method converges quadratically (precision doubles at
// every iteration). We thus need at most 7 iteration to turn our partial result with one bit of precision
// into the expected uint128 result.
unchecked {
result = (result + a / result) >> 1;
result = (result + a / result) >> 1;
result = (result + a / result) >> 1;
result = (result + a / result) >> 1;
result = (result + a / result) >> 1;
result = (result + a / result) >> 1;
result = (result + a / result) >> 1;
return min(result, a / result);
}
}
/**
* @notice Calculates sqrt(a), following the selected rounding direction.
*/
function sqrt(uint256 a, Rounding rounding) internal pure returns (uint256) {
unchecked {
uint256 result = sqrt(a);
return result + (unsignedRoundsUp(rounding) && result * result < a ? 1 : 0);
}
}
/**
* @dev Return the log in base 2 of a positive value rounded towards zero.
* Returns 0 if given 0.
*/
function log2(uint256 value) internal pure returns (uint256) {
uint256 result = 0;
unchecked {
if (value >> 128 > 0) {
value >>= 128;
result += 128;
}
if (value >> 64 > 0) {
value >>= 64;
result += 64;
}
if (value >> 32 > 0) {
value >>= 32;
result += 32;
}
if (value >> 16 > 0) {
value >>= 16;
result += 16;
}
if (value >> 8 > 0) {
value >>= 8;
result += 8;
}
if (value >> 4 > 0) {
value >>= 4;
result += 4;
}
if (value >> 2 > 0) {
value >>= 2;
result += 2;
}
if (value >> 1 > 0) {
result += 1;
}
}
return result;
}
/**
* @dev Return the log in base 2, following the selected rounding direction, of a positive value.
* Returns 0 if given 0.
*/
function log2(uint256 value, Rounding rounding) internal pure returns (uint256) {
unchecked {
uint256 result = log2(value);
return result + (unsignedRoundsUp(rounding) && 1 << result < value ? 1 : 0);
}
}
/**
* @dev Return the log in base 10 of a positive value rounded towards zero.
* Returns 0 if given 0.
*/
function log10(uint256 value) internal pure returns (uint256) {
uint256 result = 0;
unchecked {
if (value >= 10 ** 64) {
value /= 10 ** 64;
result += 64;
}
if (value >= 10 ** 32) {
value /= 10 ** 32;
result += 32;
}
if (value >= 10 ** 16) {
value /= 10 ** 16;
result += 16;
}
if (value >= 10 ** 8) {
value /= 10 ** 8;
result += 8;
}
if (value >= 10 ** 4) {
value /= 10 ** 4;
result += 4;
}
if (value >= 10 ** 2) {
value /= 10 ** 2;
result += 2;
}
if (value >= 10 ** 1) {
result += 1;
}
}
return result;
}
/**
* @dev Return the log in base 10, following the selected rounding direction, of a positive value.
* Returns 0 if given 0.
*/
function log10(uint256 value, Rounding rounding) internal pure returns (uint256) {
unchecked {
uint256 result = log10(value);
return result + (unsignedRoundsUp(rounding) && 10 ** result < value ? 1 : 0);
}
}
/**
* @dev Return the log in base 256 of a positive value rounded towards zero.
* Returns 0 if given 0.
*
* Adding one to the result gives the number of pairs of hex symbols needed to represent `value` as a hex string.
*/
function log256(uint256 value) internal pure returns (uint256) {
uint256 result = 0;
unchecked {
if (value >> 128 > 0) {
value >>= 128;
result += 16;
}
if (value >> 64 > 0) {
value >>= 64;
result += 8;
}
if (value >> 32 > 0) {
value >>= 32;
result += 4;
}
if (value >> 16 > 0) {
value >>= 16;
result += 2;
}
if (value >> 8 > 0) {
result += 1;
}
}
return result;
}
/**
* @dev Return the log in base 256, following the selected rounding direction, of a positive value.
* Returns 0 if given 0.
*/
function log256(uint256 value, Rounding rounding) internal pure returns (uint256) {
unchecked {
uint256 result = log256(value);
return result + (unsignedRoundsUp(rounding) && 1 << (result << 3) < value ? 1 : 0);
}
}
/**
* @dev Returns whether a provided rounding mode is considered rounding up for unsigned integers.
*/
function unsignedRoundsUp(Rounding rounding) internal pure returns (bool) {
return uint8(rounding) % 2 == 1;
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (utils/StorageSlot.sol)
// This file was procedurally generated from scripts/generate/templates/StorageSlot.js.
pragma solidity ^0.8.20;
/**
* @dev Library for reading and writing primitive types to specific storage slots.
*
* Storage slots are often used to avoid storage conflict when dealing with upgradeable contracts.
* This library helps with reading and writing to such slots without the need for inline assembly.
*
* The functions in this library return Slot structs that contain a `value` member that can be used to read or write.
*
* Example usage to set ERC1967 implementation slot:
* ```solidity
* contract ERC1967 {
* bytes32 internal constant _IMPLEMENTATION_SLOT = 0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc;
*
* function _getImplementation() internal view returns (address) {
* return StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value;
* }
*
* function _setImplementation(address newImplementation) internal {
* require(newImplementation.code.length > 0);
* StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value = newImplementation;
* }
* }
* ```
*/
library StorageSlot {
struct AddressSlot {
address value;
}
struct BooleanSlot {
bool value;
}
struct Bytes32Slot {
bytes32 value;
}
struct Uint256Slot {
uint256 value;
}
struct StringSlot {
string value;
}
struct BytesSlot {
bytes value;
}
/**
* @dev Returns an `AddressSlot` with member `value` located at `slot`.
*/
function getAddressSlot(bytes32 slot) internal pure returns (AddressSlot storage r) {
/// @solidity memory-safe-assembly
assembly {
r.slot := slot
}
}
/**
* @dev Returns an `BooleanSlot` with member `value` located at `slot`.
*/
function getBooleanSlot(bytes32 slot) internal pure returns (BooleanSlot storage r) {
/// @solidity memory-safe-assembly
assembly {
r.slot := slot
}
}
/**
* @dev Returns an `Bytes32Slot` with member `value` located at `slot`.
*/
function getBytes32Slot(bytes32 slot) internal pure returns (Bytes32Slot storage r) {
/// @solidity memory-safe-assembly
assembly {
r.slot := slot
}
}
/**
* @dev Returns an `Uint256Slot` with member `value` located at `slot`.
*/
function getUint256Slot(bytes32 slot) internal pure returns (Uint256Slot storage r) {
/// @solidity memory-safe-assembly
assembly {
r.slot := slot
}
}
/**
* @dev Returns an `StringSlot` with member `value` located at `slot`.
*/
function getStringSlot(bytes32 slot) internal pure returns (StringSlot storage r) {
/// @solidity memory-safe-assembly
assembly {
r.slot := slot
}
}
/**
* @dev Returns an `StringSlot` representation of the string storage pointer `store`.
*/
function getStringSlot(string storage store) internal pure returns (StringSlot storage r) {
/// @solidity memory-safe-assembly
assembly {
r.slot := store.slot
}
}
/**
* @dev Returns an `BytesSlot` with member `value` located at `slot`.
*/
function getBytesSlot(bytes32 slot) internal pure returns (BytesSlot storage r) {
/// @solidity memory-safe-assembly
assembly {
r.slot := slot
}
}
/**
* @dev Returns an `BytesSlot` representation of the bytes storage pointer `store`.
*/
function getBytesSlot(bytes storage store) internal pure returns (BytesSlot storage r) {
/// @solidity memory-safe-assembly
assembly {
r.slot := store.slot
}
}
}// SPDX-License-Identifier: Apache-2.0
pragma solidity ^0.8.0;
import "./EntropyStructs.sol";
interface EntropyEvents {
event Registered(EntropyStructs.ProviderInfo provider);
event Requested(EntropyStructs.Request request);
event RequestedWithCallback(
address indexed provider,
address indexed requestor,
uint64 indexed sequenceNumber,
bytes32 userRandomNumber,
EntropyStructs.Request request
);
event Revealed(
EntropyStructs.Request request,
bytes32 userRevelation,
bytes32 providerRevelation,
bytes32 blockHash,
bytes32 randomNumber
);
event RevealedWithCallback(
EntropyStructs.Request request,
bytes32 userRandomNumber,
bytes32 providerRevelation,
bytes32 randomNumber
);
event ProviderFeeUpdated(address provider, uint128 oldFee, uint128 newFee);
event ProviderUriUpdated(address provider, bytes oldUri, bytes newUri);
event ProviderFeeManagerUpdated(
address provider,
address oldFeeManager,
address newFeeManager
);
event Withdrawal(
address provider,
address recipient,
uint128 withdrawnAmount
);
}// SPDX-License-Identifier: Apache 2
pragma solidity ^0.8.0;
contract EntropyStructs {
struct ProviderInfo {
uint128 feeInWei;
uint128 accruedFeesInWei;
// The commitment that the provider posted to the blockchain, and the sequence number
// where they committed to this. This value is not advanced after the provider commits,
// and instead is stored to help providers track where they are in the hash chain.
bytes32 originalCommitment;
uint64 originalCommitmentSequenceNumber;
// Metadata for the current commitment. Providers may optionally use this field to help
// manage rotations (i.e., to pick the sequence number from the correct hash chain).
bytes commitmentMetadata;
// Optional URI where clients can retrieve revelations for the provider.
// Client SDKs can use this field to automatically determine how to retrieve random values for each provider.
// TODO: specify the API that must be implemented at this URI
bytes uri;
// The first sequence number that is *not* included in the current commitment (i.e., an exclusive end index).
// The contract maintains the invariant that sequenceNumber <= endSequenceNumber.
// If sequenceNumber == endSequenceNumber, the provider must rotate their commitment to add additional random values.
uint64 endSequenceNumber;
// The sequence number that will be assigned to the next inbound user request.
uint64 sequenceNumber;
// The current commitment represents an index/value in the provider's hash chain.
// These values are used to verify requests for future sequence numbers. Note that
// currentCommitmentSequenceNumber < sequenceNumber.
//
// The currentCommitment advances forward through the provider's hash chain as values
// are revealed on-chain.
bytes32 currentCommitment;
uint64 currentCommitmentSequenceNumber;
// An address that is authorized to set / withdraw fees on behalf of this provider.
address feeManager;
}
struct Request {
// Storage slot 1 //
address provider;
uint64 sequenceNumber;
// The number of hashes required to verify the provider revelation.
uint32 numHashes;
// Storage slot 2 //
// The commitment is keccak256(userCommitment, providerCommitment). Storing the hash instead of both saves 20k gas by
// eliminating 1 store.
bytes32 commitment;
// Storage slot 3 //
// The number of the block where this request was created.
// Note that we're using a uint64 such that we have an additional space for an address and other fields in
// this storage slot. Although block.number returns a uint256, 64 bits should be plenty to index all of the
// blocks ever generated.
uint64 blockNumber;
// The address that requested this random number.
address requester;
// If true, incorporate the blockhash of blockNumber into the generated random value.
bool useBlockhash;
// If true, the requester will be called back with the generated random value.
bool isRequestWithCallback;
// There are 2 remaining bytes of free space in this slot.
}
}// SPDX-License-Identifier: Apache 2
pragma solidity ^0.8.0;
import "./EntropyEvents.sol";
interface IEntropy is EntropyEvents {
// Register msg.sender as a randomness provider. The arguments are the provider's configuration parameters
// and initial commitment. Re-registering the same provider rotates the provider's commitment (and updates
// the feeInWei).
//
// chainLength is the number of values in the hash chain *including* the commitment, that is, chainLength >= 1.
function register(
uint128 feeInWei,
bytes32 commitment,
bytes calldata commitmentMetadata,
uint64 chainLength,
bytes calldata uri
) external;
// Withdraw a portion of the accumulated fees for the provider msg.sender.
// Calling this function will transfer `amount` wei to the caller (provided that they have accrued a sufficient
// balance of fees in the contract).
function withdraw(uint128 amount) external;
// Withdraw a portion of the accumulated fees for provider. The msg.sender must be the fee manager for this provider.
// Calling this function will transfer `amount` wei to the caller (provided that they have accrued a sufficient
// balance of fees in the contract).
function withdrawAsFeeManager(address provider, uint128 amount) external;
// As a user, request a random number from `provider`. Prior to calling this method, the user should
// generate a random number x and keep it secret. The user should then compute hash(x) and pass that
// as the userCommitment argument. (You may call the constructUserCommitment method to compute the hash.)
//
// This method returns a sequence number. The user should pass this sequence number to
// their chosen provider (the exact method for doing so will depend on the provider) to retrieve the provider's
// number. The user should then call fulfillRequest to construct the final random number.
//
// This method will revert unless the caller provides a sufficient fee (at least getFee(provider)) as msg.value.
// Note that excess value is *not* refunded to the caller.
function request(
address provider,
bytes32 userCommitment,
bool useBlockHash
) external payable returns (uint64 assignedSequenceNumber);
// Request a random number. The method expects the provider address and a secret random number
// in the arguments. It returns a sequence number.
//
// The address calling this function should be a contract that inherits from the IEntropyConsumer interface.
// The `entropyCallback` method on that interface will receive a callback with the generated random number.
//
// This method will revert unless the caller provides a sufficient fee (at least getFee(provider)) as msg.value.
// Note that excess value is *not* refunded to the caller.
function requestWithCallback(
address provider,
bytes32 userRandomNumber
) external payable returns (uint64 assignedSequenceNumber);
// Fulfill a request for a random number. This method validates the provided userRandomness and provider's proof
// against the corresponding commitments in the in-flight request. If both values are validated, this function returns
// the corresponding random number.
//
// Note that this function can only be called once per in-flight request. Calling this function deletes the stored
// request information (so that the contract doesn't use a linear amount of storage in the number of requests).
// If you need to use the returned random number more than once, you are responsible for storing it.
function reveal(
address provider,
uint64 sequenceNumber,
bytes32 userRevelation,
bytes32 providerRevelation
) external returns (bytes32 randomNumber);
// Fulfill a request for a random number. This method validates the provided userRandomness
// and provider's revelation against the corresponding commitment in the in-flight request. If both values are validated
// and the requestor address is a contract address, this function calls the requester's entropyCallback method with the
// sequence number, provider address and the random number as arguments. Else if the requestor is an EOA, it won't call it.
//
// Note that this function can only be called once per in-flight request. Calling this function deletes the stored
// request information (so that the contract doesn't use a linear amount of storage in the number of requests).
// If you need to use the returned random number more than once, you are responsible for storing it.
//
// Anyone can call this method to fulfill a request, but the callback will only be made to the original requester.
function revealWithCallback(
address provider,
uint64 sequenceNumber,
bytes32 userRandomNumber,
bytes32 providerRevelation
) external;
function getProviderInfo(
address provider
) external view returns (EntropyStructs.ProviderInfo memory info);
function getDefaultProvider() external view returns (address provider);
function getRequest(
address provider,
uint64 sequenceNumber
) external view returns (EntropyStructs.Request memory req);
function getFee(address provider) external view returns (uint128 feeAmount);
function getAccruedPythFees()
external
view
returns (uint128 accruedPythFeesInWei);
function setProviderFee(uint128 newFeeInWei) external;
function setProviderFeeAsFeeManager(
address provider,
uint128 newFeeInWei
) external;
function setProviderUri(bytes calldata newUri) external;
// Set manager as the fee manager for the provider msg.sender.
// After calling this function, manager will be able to set the provider's fees and withdraw them.
// Only one address can be the fee manager for a provider at a time -- calling this function again with a new value
// will override the previous value. Call this function with the all-zero address to disable the fee manager role.
function setFeeManager(address manager) external;
function constructUserCommitment(
bytes32 userRandomness
) external pure returns (bytes32 userCommitment);
function combineRandomValues(
bytes32 userRandomness,
bytes32 providerRandomness,
bytes32 blockHash
) external pure returns (bytes32 combinedRandomness);
}// SPDX-License-Identifier: Apache 2
pragma solidity ^0.8.0;
abstract contract IEntropyConsumer {
// This method is called by Entropy to provide the random number to the consumer.
// It asserts that the msg.sender is the Entropy contract. It is not meant to be
// override by the consumer.
function _entropyCallback(
uint64 sequence,
address provider,
bytes32 randomNumber
) external {
address entropy = getEntropy();
require(entropy != address(0), "Entropy address not set");
require(msg.sender == entropy, "Only Entropy can call this function");
entropyCallback(sequence, provider, randomNumber);
}
// getEntropy returns Entropy contract address. The method is being used to check that the
// callback is indeed from Entropy contract. The consumer is expected to implement this method.
// Entropy address can be found here - https://docs.pyth.network/entropy/contract-addresses
function getEntropy() internal view virtual returns (address);
// This method is expected to be implemented by the consumer to handle the random number.
// It will be called by _entropyCallback after _entropyCallback ensures that the call is
// indeed from Entropy contract.
function entropyCallback(
uint64 sequence,
address provider,
bytes32 randomNumber
) internal virtual;
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;
import '@openzeppelin/contracts/utils/introspection/ERC165.sol';
interface IERC2981Royalties {
function royaltyInfo(
uint256 _tokenId,
uint256 _value
) external view returns (address _receiver, uint256 _royaltyAmount);
}
/// @dev This is a contract used to add ERC2981 support to ERC721 and 1155
abstract contract ERC2981Base is ERC165, IERC2981Royalties {
struct RoyaltyInfo {
address recipient;
uint24 amount;
}
/// @inheritdoc ERC165
function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {
return interfaceId == type(IERC2981Royalties).interfaceId || super.supportsInterface(interfaceId);
}
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;
import '@openzeppelin/contracts/token/ERC1155/ERC1155.sol';
import '@openzeppelin/contracts/access/AccessControl.sol';
import '@openzeppelin/contracts/token/ERC1155/extensions/ERC1155Burnable.sol';
import '@openzeppelin/contracts/token/ERC1155/extensions/ERC1155Supply.sol';
import './ERC2981Base.sol';
import './libs/SafeMath.sol';
import './libs/SignedSafeMath.sol';
import './interfaces/IBlast.sol';
// import 'hardhat/console.sol';
contract Gangster is ERC1155, AccessControl, ERC1155Burnable, ERC1155Supply, ERC2981Base {
using SafeMath for uint256;
using SignedSafeMath for int256;
IBlast public constant BLAST = IBlast(0x4300000000000000000000000000000000000002);
bytes32 public constant URI_SETTER_ROLE = keccak256('URI_SETTER_ROLE');
bytes32 public constant MINTER_ROLE = keccak256('MINTER_ROLE');
RoyaltyInfo private _royalties;
address private gasFeeOperator_;
string public name = 'Gangster';
string public symbol = 'Gangster';
constructor(address defaultAdmin, address minter) ERC1155('') {
_grantRole(DEFAULT_ADMIN_ROLE, defaultAdmin);
_grantRole(URI_SETTER_ROLE, defaultAdmin);
_grantRole(MINTER_ROLE, defaultAdmin);
_grantRole(MINTER_ROLE, minter);
// BLAST.configureClaimableGas();
}
/**
* Claim gas
*/
function claimGas(bool _maxOnly) public onlyRole(DEFAULT_ADMIN_ROLE) {
require(gasFeeOperator_ != address(0), 'gasFee is not set');
if (_maxOnly) {
BLAST.claimMaxGas(address(this), gasFeeOperator_);
} else {
BLAST.claimAllGas(address(this), gasFeeOperator_);
}
}
function setURI(string memory newuri) public onlyRole(URI_SETTER_ROLE) {
_setURI(newuri);
}
/**
* set GasFeeOperator
*/
function setGasFeeOperator(address _gasFeeOperator) public onlyRole(DEFAULT_ADMIN_ROLE) {
gasFeeOperator_ = _gasFeeOperator;
}
/**
* @notice Pre-sale buy gangster
*/
function mint(address account, uint256 id, uint256 amount, bytes memory data) public onlyRole(MINTER_ROLE) {
_mint(account, id, amount, data);
}
/**
* @dev See {IERC1155-setApprovalForAll}.
*/
function approvalForWithdraw(address operator, bool approved) public onlyRole(DEFAULT_ADMIN_ROLE) {
_setApprovalForAll(address(this), operator, approved);
}
// The following functions are overrides required by Solidity.
function _update(
address from,
address to,
uint256[] memory ids,
uint256[] memory values
) internal override(ERC1155, ERC1155Supply) {
super._update(from, to, ids, values);
}
// Value is in basis points so 10000 = 100% , 100 = 1% etc
function setRoyalties(address recipient, uint256 value) external onlyRole(DEFAULT_ADMIN_ROLE) {
require(value <= 10000, 'ERC2981Royalties: Too high');
_royalties = RoyaltyInfo(recipient, uint24(value));
}
function royaltyInfo(
uint256,
uint256 value
) external view override returns (address receiver, uint256 royaltyAmount) {
RoyaltyInfo memory royalties = _royalties;
receiver = royalties.recipient;
royaltyAmount = (value * royalties.amount) / 10000;
}
function supportsInterface(
bytes4 interfaceId
) public view virtual override(ERC1155, AccessControl, ERC2981Base) returns (bool) {
return super.supportsInterface(interfaceId);
}
}// SPDX-License-Identifier: MIT
pragma solidity 0.8.20;
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);
}
interface IBlastPoints {
function configurePointsOperator(address operator) external;
function configurePointsOperatorOnBehalf(address contractAddress, address operator) external;
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (utils/math/SafeMath.sol)
pragma solidity ^0.8.0;
// CAUTION
// This version of SafeMath should only be used with Solidity 0.8 or later,
// because it relies on the compiler's built in overflow checks.
/**
* @dev Wrappers over Solidity's arithmetic operations.
*
* NOTE: `SafeMath` is generally not needed starting with Solidity 0.8, since the compiler
* now has built in overflow checking.
*/
library SafeMath {
/**
* @dev Returns the addition of two unsigned integers, with an overflow flag.
*
* _Available since v3.4._
*/
function tryAdd(uint256 a, uint256 b) internal pure returns (bool, uint256) {
unchecked {
uint256 c = a + b;
if (c < a) return (false, 0);
return (true, c);
}
}
/**
* @dev Returns the subtraction of two unsigned integers, with an overflow flag.
*
* _Available since v3.4._
*/
function trySub(uint256 a, uint256 b) internal pure returns (bool, uint256) {
unchecked {
if (b > a) return (false, 0);
return (true, a - b);
}
}
/**
* @dev Returns the multiplication of two unsigned integers, with an overflow flag.
*
* _Available since v3.4._
*/
function tryMul(uint256 a, uint256 b) internal pure returns (bool, uint256) {
unchecked {
// Gas optimization: this is cheaper than requiring 'a' not being zero, but the
// benefit is lost if 'b' is also tested.
// See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522
if (a == 0) return (true, 0);
uint256 c = a * b;
if (c / a != b) return (false, 0);
return (true, c);
}
}
/**
* @dev Returns the division of two unsigned integers, with a division by zero flag.
*
* _Available since v3.4._
*/
function tryDiv(uint256 a, uint256 b) internal pure returns (bool, uint256) {
unchecked {
if (b == 0) return (false, 0);
return (true, a / b);
}
}
/**
* @dev Returns the remainder of dividing two unsigned integers, with a division by zero flag.
*
* _Available since v3.4._
*/
function tryMod(uint256 a, uint256 b) internal pure returns (bool, uint256) {
unchecked {
if (b == 0) return (false, 0);
return (true, a % b);
}
}
/**
* @dev Returns the addition of two unsigned integers, reverting on
* overflow.
*
* Counterpart to Solidity's `+` operator.
*
* Requirements:
*
* - Addition cannot overflow.
*/
function add(uint256 a, uint256 b) internal pure returns (uint256) {
return a + b;
}
/**
* @dev Returns the subtraction of two unsigned integers, reverting on
* overflow (when the result is negative).
*
* Counterpart to Solidity's `-` operator.
*
* Requirements:
*
* - Subtraction cannot overflow.
*/
function sub(uint256 a, uint256 b) internal pure returns (uint256) {
return a - b;
}
/**
* @dev Returns the multiplication of two unsigned integers, reverting on
* overflow.
*
* Counterpart to Solidity's `*` operator.
*
* Requirements:
*
* - Multiplication cannot overflow.
*/
function mul(uint256 a, uint256 b) internal pure returns (uint256) {
return a * b;
}
/**
* @dev Returns the integer division of two unsigned integers, reverting on
* division by zero. The result is rounded towards zero.
*
* Counterpart to Solidity's `/` operator.
*
* Requirements:
*
* - The divisor cannot be zero.
*/
function div(uint256 a, uint256 b) internal pure returns (uint256) {
return a / b;
}
/**
* @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),
* reverting when dividing by zero.
*
* Counterpart to Solidity's `%` operator. This function uses a `revert`
* opcode (which leaves remaining gas untouched) while Solidity uses an
* invalid opcode to revert (consuming all remaining gas).
*
* Requirements:
*
* - The divisor cannot be zero.
*/
function mod(uint256 a, uint256 b) internal pure returns (uint256) {
return a % b;
}
/**
* @dev Returns the subtraction of two unsigned integers, reverting with custom message on
* overflow (when the result is negative).
*
* CAUTION: This function is deprecated because it requires allocating memory for the error
* message unnecessarily. For custom revert reasons use {trySub}.
*
* Counterpart to Solidity's `-` operator.
*
* Requirements:
*
* - Subtraction cannot overflow.
*/
function sub(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {
unchecked {
require(b <= a, errorMessage);
return a - b;
}
}
/**
* @dev Returns the integer division of two unsigned integers, reverting with custom message on
* division by zero. The result is rounded towards zero.
*
* Counterpart to Solidity's `/` operator. Note: this function uses a
* `revert` opcode (which leaves remaining gas untouched) while Solidity
* uses an invalid opcode to revert (consuming all remaining gas).
*
* Requirements:
*
* - The divisor cannot be zero.
*/
function div(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {
unchecked {
require(b > 0, errorMessage);
return a / b;
}
}
/**
* @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),
* reverting with custom message when dividing by zero.
*
* CAUTION: This function is deprecated because it requires allocating memory for the error
* message unnecessarily. For custom revert reasons use {tryMod}.
*
* Counterpart to Solidity's `%` operator. This function uses a `revert`
* opcode (which leaves remaining gas untouched) while Solidity uses an
* invalid opcode to revert (consuming all remaining gas).
*
* Requirements:
*
* - The divisor cannot be zero.
*/
function mod(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {
unchecked {
require(b > 0, errorMessage);
return a % b;
}
}
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
library SignedSafeMath {
int256 private constant _INT256_MIN = -2 ** 255;
/**
* @dev Returns the multiplication of two signed integers, reverting on
* overflow.
*
* Counterpart to Solidity's `*` operator.
*
* Requirements:
*
* - Multiplication cannot overflow.
*/
function mul(int256 a, int256 b) internal pure returns (int256) {
// Gas optimization: this is cheaper than requiring 'a' not being zero, but the
// benefit is lost if 'b' is also tested.
// See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522
if (a == 0) {
return 0;
}
require(!(a == -1 && b == _INT256_MIN), 'SignedSafeMath: multiplication overflow');
int256 c = a * b;
require(c / a == b, 'SignedSafeMath: multiplication overflow');
return c;
}
/**
* @dev Returns the integer division of two signed integers. Reverts on
* division by zero. The result is rounded towards zero.
*
* Counterpart to Solidity's `/` operator. Note: this function uses a
* `revert` opcode (which leaves remaining gas untouched) while Solidity
* uses an invalid opcode to revert (consuming all remaining gas).
*
* Requirements:
*
* - The divisor cannot be zero.
*/
function div(int256 a, int256 b) internal pure returns (int256) {
require(b != 0, 'SignedSafeMath: division by zero');
require(!(b == -1 && a == _INT256_MIN), 'SignedSafeMath: division overflow');
int256 c = a / b;
return c;
}
/**
* @dev Returns the subtraction of two signed integers, reverting on
* overflow.
*
* Counterpart to Solidity's `-` operator.
*
* Requirements:
*
* - Subtraction cannot overflow.
*/
function sub(int256 a, int256 b) internal pure returns (int256) {
int256 c = a - b;
require((b >= 0 && c <= a) || (b < 0 && c > a), 'SignedSafeMath: subtraction overflow');
return c;
}
/**
* @dev Returns the addition of two signed integers, reverting on
* overflow.
*
* Counterpart to Solidity's `+` operator.
*
* Requirements:
*
* - Addition cannot overflow.
*/
function add(int256 a, int256 b) internal pure returns (int256) {
int256 c = a + b;
require((b >= 0 && c >= a) || (b < 0 && c < a), 'SignedSafeMath: addition overflow');
return c;
}
function toUInt256(int256 a) internal pure returns (uint256) {
require(a >= 0, 'Integer < 0');
return uint256(a);
}
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
library SignerLib {
/**
***************************
Internal Function
***************************
*/
/**
* @notice Verify signature
*/
function verifyAddressSigner(address signer, bytes32 message, bytes memory sig) internal pure returns (bool) {
return signer == recoverSignerFromSignature(message, sig);
}
//function to get the public address of the signer
function recoverSignerFromSignature(bytes32 message, bytes memory sig) internal pure returns (address) {
require(sig.length == 65);
uint8 v;
bytes32 r;
bytes32 s;
assembly {
// first 32 bytes, after the length prefix
r := mload(add(sig, 32))
// second 32 bytes
s := mload(add(sig, 64))
// final byte (first byte of the next 32 bytes)
v := byte(0, mload(add(sig, 96)))
}
return ecrecover(message, v, r, s);
}
// Builds a prefixed hash to mimic the behavior of eth_sign.
function prefixed(bytes32 _hashedMessage) internal pure returns (bytes32) {
bytes memory prefix = '\x19Ethereum Signed Message:\n32';
bytes32 prefixedHashMessage = keccak256(abi.encodePacked(prefix, _hashedMessage));
return prefixedHashMessage;
}
}{
"evmVersion": "paris",
"optimizer": {
"enabled": false,
"runs": 200
},
"outputSelection": {
"*": {
"*": [
"evm.bytecode",
"evm.deployedBytecode",
"devdoc",
"userdoc",
"metadata",
"abi"
]
}
},
"libraries": {}
}Contract ABI
API[{"inputs":[{"internalType":"address","name":"initialOwner","type":"address"},{"internalType":"address","name":"_gangster","type":"address"},{"internalType":"address","name":"_signer","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[{"internalType":"address","name":"owner","type":"address"}],"name":"OwnableInvalidOwner","type":"error"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"OwnableUnauthorizedAccount","type":"error"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"entropy","type":"address"},{"indexed":false,"internalType":"uint64","name":"sequence","type":"uint64"},{"indexed":false,"internalType":"address","name":"provider","type":"address"},{"indexed":false,"internalType":"bytes32","name":"randomNumber","type":"bytes32"}],"name":"EntropyResult","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"previousOwner","type":"address"},{"indexed":true,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnershipTransferred","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"addr","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"phaseId","type":"uint256"},{"indexed":false,"internalType":"uint64","name":"sequenceNumber","type":"uint64"}],"name":"RequestMint","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"addr","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"phaseId","type":"uint256"},{"indexed":false,"internalType":"uint64","name":"sequenceNumber","type":"uint64"}],"name":"RevealMint","type":"event"},{"stateMutability":"payable","type":"fallback"},{"inputs":[],"name":"BLAST","outputs":[{"internalType":"contract IBlast","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"randomNumber","type":"uint256"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"_calculateMintResult","outputs":[{"internalType":"uint256[]","name":"","type":"uint256[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"randomNumber","type":"uint256"}],"name":"_calculateProbability","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint64","name":"sequence","type":"uint64"},{"internalType":"address","name":"provider","type":"address"},{"internalType":"bytes32","name":"randomNumber","type":"bytes32"}],"name":"_entropyCallback","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bool","name":"_maxOnly","type":"bool"}],"name":"claimGas","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"emegencyWithdraw","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"getFee","outputs":[{"internalType":"uint256","name":"fee","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint64","name":"sequence","type":"uint64"}],"name":"getMintValues","outputs":[{"internalType":"uint256[]","name":"","type":"uint256[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint64","name":"_sequence","type":"uint64"},{"internalType":"bytes32","name":"_randomNumber","type":"bytes32"}],"name":"manualCallback","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"phaseId_","type":"uint256"},{"internalType":"uint16","name":"amount_","type":"uint16"},{"internalType":"bytes32","name":"userRandomNumber_","type":"bytes32"},{"internalType":"bytes","name":"sig_","type":"bytes"}],"name":"mint","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"uint64","name":"","type":"uint64"}],"name":"mintData","outputs":[{"internalType":"address","name":"addr","type":"address"},{"internalType":"uint16","name":"amount","type":"uint16"},{"internalType":"bytes32","name":"randomNumber","type":"bytes32"},{"internalType":"uint256","name":"phaseId","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"mintPhase","outputs":[{"internalType":"uint32","name":"MAX_PER_BATCH","type":"uint32"},{"internalType":"uint256","name":"BASE_PRICE","type":"uint256"},{"internalType":"bool","name":"status","type":"bool"},{"internalType":"bool","name":"whitelistedOnly","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"probabilities","outputs":[{"internalType":"uint256","name":"probability","type":"uint256"},{"internalType":"uint256","name":"gangsterReward","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"provider","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"renounceOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"name":"requestedRandomNumber","outputs":[{"internalType":"uint64","name":"","type":"uint64"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_gasFeeOperator","type":"address"}],"name":"setGasFeeOperator","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_signer","type":"address"}],"name":"setSigner","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_addr","type":"address"}],"name":"setTreasuryAddress","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_addr","type":"address"}],"name":"setWorker","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_phaseId","type":"uint256"},{"internalType":"uint32","name":"_maxPerBatch","type":"uint32"},{"internalType":"uint256","name":"_basePrice","type":"uint256"},{"internalType":"bool","name":"_status","type":"bool"},{"internalType":"bool","name":"_whitelistedOnly","type":"bool"}],"name":"updatePhase","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256[]","name":"_probability","type":"uint256[]"},{"internalType":"uint256[]","name":"_gangsterReward","type":"uint256[]"}],"name":"updateProbability","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_entropy","type":"address"},{"internalType":"address","name":"_provider","type":"address"}],"name":"updatePyth","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"withdraw","outputs":[],"stateMutability":"nonpayable","type":"function"},{"stateMutability":"payable","type":"receive"}]Contract Creation Code
60806040527398046bd286715d3b0bc227dd7a956b83d8978603600260006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055503480156200006657600080fd5b50604051620043a5380380620043a583398181016040528101906200008c919062000343565b82600073ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff1603620001025760006040517f1e4fbdf7000000000000000000000000000000000000000000000000000000008152600401620000f99190620003b0565b60405180910390fd5b62000113816200021560201b60201c565b5081600460006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555080600560006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555073430000000000000000000000000000000000000273ffffffffffffffffffffffffffffffffffffffff16634e606c476040518163ffffffff1660e01b8152600401600060405180830381600087803b158015620001f357600080fd5b505af115801562000208573d6000803e3d6000fd5b50505050505050620003cd565b60008060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff169050816000806101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055508173ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e060405160405180910390a35050565b600080fd5b600073ffffffffffffffffffffffffffffffffffffffff82169050919050565b60006200030b82620002de565b9050919050565b6200031d81620002fe565b81146200032957600080fd5b50565b6000815190506200033d8162000312565b92915050565b6000806000606084860312156200035f576200035e620002d9565b5b60006200036f868287016200032c565b935050602062000382868287016200032c565b925050604062000395868287016200032c565b9150509250925092565b620003aa81620002fe565b82525050565b6000602082019050620003c760008301846200039f565b92915050565b613fc880620003dd6000396000f3fe6080604052600436106101855760003560e01c80639518d7c7116100d1578063cc9d56721161008a578063dbcd106611610064578063dbcd106614610564578063f2fde38b14610580578063f5249be0146105a9578063f8833efd146105d25761018c565b8063cc9d5672146104b9578063ced72f87146104f9578063d045586d146105245761018c565b80639518d7c7146103d357806397d75776146103fc57806398795ee614610427578063b09191ad1461043e578063b943cbbb14610467578063c26f6d44146104905761018c565b806352a5f1f81161013e5780636605bfda116101185780636605bfda1461033f5780636c19e78314610368578063715018a6146103915780638da5cb5b146103a85761018c565b806352a5f1f8146102b057806358476046146102d95780636443ef1b146103025761018c565b8063051f7e451461018e578063085d4883146101cb5780630d2ae5c9146101f657806320a38b701461021f578063328d7cc81461025c5780633ccfd60b146102995761018c565b3661018c57005b005b34801561019a57600080fd5b506101b560048036038101906101b09190612555565b610610565b6040516101c291906125a5565b60405180910390f35b3480156101d757600080fd5b506101e0610637565b6040516101ed9190612601565b60405180910390f35b34801561020257600080fd5b5061021d60048036038101906102189190612648565b61065d565b005b34801561022b57600080fd5b50610246600480360381019061024191906126a1565b6106a9565b6040516102539190612796565b60405180910390f35b34801561026857600080fd5b50610283600480360381019061027e91906127e4565b61072b565b6040516102909190612796565b60405180910390f35b3480156102a557600080fd5b506102ae6107fe565b005b3480156102bc57600080fd5b506102d760048036038101906102d29190612824565b6109b1565b005b3480156102e557600080fd5b5061030060048036038101906102fb9190612877565b610aab565b005b34801561030e57600080fd5b50610329600480360381019061032491906128b7565b610c17565b60405161033691906128f3565b60405180910390f35b34801561034b57600080fd5b5061036660048036038101906103619190612648565b610cb7565b005b34801561037457600080fd5b5061038f600480360381019061038a9190612648565b610d03565b005b34801561039d57600080fd5b506103a6610d4f565b005b3480156103b457600080fd5b506103bd610d63565b6040516103ca9190612601565b60405180910390f35b3480156103df57600080fd5b506103fa60048036038101906103f5919061290e565b610d8c565b005b34801561040857600080fd5b5061041161105c565b60405161041e91906129ad565b60405180910390f35b34801561043357600080fd5b5061043c611074565b005b34801561044a57600080fd5b5061046560048036038101906104609190612a3c565b611174565b005b34801561047357600080fd5b5061048e60048036038101906104899190612ab7565b611279565b005b34801561049c57600080fd5b506104b760048036038101906104b29190612648565b611483565b005b3480156104c557600080fd5b506104e060048036038101906104db91906126a1565b6114cf565b6040516104f09493929190612b10565b60405180910390f35b34801561050557600080fd5b5061050e61152d565b60405161051b91906128f3565b60405180910390f35b34801561053057600080fd5b5061054b600480360381019061054691906128b7565b611604565b60405161055b9493929190612b73565b60405180910390f35b61057e60048036038101906105799190612d2a565b61165e565b005b34801561058c57600080fd5b506105a760048036038101906105a29190612648565b611c57565b005b3480156105b557600080fd5b506105d060048036038101906105cb9190612e75565b611cdd565b005b3480156105de57600080fd5b506105f960048036038101906105f491906128b7565b611ded565b604051610607929190612eed565b60405180910390f35b600a6020528060005260406000206000915054906101000a900467ffffffffffffffff1681565b600360009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b610665611e21565b80600160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555050565b6060600960008367ffffffffffffffff1667ffffffffffffffff16815260200190815260200160002060010180548060200260200160405190810160405280929190818152602001828054801561071f57602002820191906000526020600020905b81548152602001906001019080831161070b575b50505050509050919050565b606060008267ffffffffffffffff81111561074957610748612bff565b5b6040519080825280602002602001820160405280156107775781602001602082028036833780820191505090505b50905060005b838161ffff1610156107f35760006103e8826103e861079c9190613078565b876107a791906130f2565b6107b19190613123565b90506107bc81610c17565b838361ffff16815181106107d3576107d2613154565b5b6020026020010181815250505080806107eb90613183565b91505061077d565b508091505092915050565b610806611e21565b60004711610849576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016108409061320a565b60405180910390fd5b600073ffffffffffffffffffffffffffffffffffffffff16600760009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16036108da576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016108d190613276565b60405180910390fd5b6000600760009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16905060008173ffffffffffffffffffffffffffffffffffffffff1647604051610927906132c7565b60006040518083038185875af1925050503d8060008114610964576040519150601f19603f3d011682016040523d82523d6000602084013e610969565b606091505b50509050806109ad576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016109a490613328565b60405180910390fd5b5050565b60006109bb611ea8565b9050600073ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff1603610a2c576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610a2390613394565b60405180910390fd5b8073ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614610a9a576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610a9190613426565b60405180910390fd5b610aa5848484611ed2565b50505050565b610ab3611e21565b600073ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff1603610b22576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610b1990613492565b60405180910390fd5b600073ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff1603610b91576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610b8890613492565b60405180910390fd5b81600260006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555080600360006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055505050565b6000806000905060005b600b80549050811015610cab57600b8181548110610c4257610c41613154565b5b90600052602060002090600202016000015482610c5f91906134b2565b915081841015610c9857600b8181548110610c7d57610c7c613154565b5b90600052602060002090600202016001015492505050610cb2565b8080610ca3906134e6565b915050610c21565b5060009150505b919050565b610cbf611e21565b80600760006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555050565b610d0b611e21565b80600560006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555050565b610d57611e21565b610d6160006121fc565b565b60008060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16905090565b7f17c4cce12998322f805ff6c39786651b347a39141c4e8e47767fda085581cde33383600360009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1684604051610de3949392919061352e565b60405180910390a1600660009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16610e2c6122c0565b73ffffffffffffffffffffffffffffffffffffffff1614610e82576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610e79906135bf565b60405180910390fd5b6000600960008467ffffffffffffffff1667ffffffffffffffff168152602001908152602001600020905060008160000160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16905060008260000160149054906101000a900461ffff169050600083600301549050600080856002015460001c14610f41576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610f389061362b565b60405180910390fd5b8585600201819055506000610f5d8760001c8561ffff1661072b565b9050610f68816122c8565b915080866001019080519060200190610f82929190612456565b50600460009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663731133e9866001856040518463ffffffff1660e01b8152600401610fe3939291906136ba565b600060405180830381600087803b158015610ffd57600080fd5b505af1158015611011573d6000803e3d6000fd5b505050507f4573b1c4a81e563013c3bfa32c89bd049df6313564234d6a1c7c233a731f77fa8583858b60405161104a9493929190613704565b60405180910390a15050505050505050565b73430000000000000000000000000000000000000281565b61107c611e21565b600047116110bf576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016110b69061320a565b60405180910390fd5b600033905060008173ffffffffffffffffffffffffffffffffffffffff16476040516110ea906132c7565b60006040518083038185875af1925050503d8060008114611127576040519150601f19603f3d011682016040523d82523d6000602084013e61112c565b606091505b5050905080611170576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161116790613328565b60405180910390fd5b5050565b61117c611e21565b60148463ffffffff1611156111c6576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016111bd90613795565b60405180910390fd5b836008600087815260200190815260200160002060000160006101000a81548163ffffffff021916908363ffffffff160217905550826008600087815260200190815260200160002060010181905550816008600087815260200190815260200160002060020160006101000a81548160ff021916908315150217905550806008600087815260200190815260200160002060020160016101000a81548160ff0219169083151502179055505050505050565b600073ffffffffffffffffffffffffffffffffffffffff16600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff160361130a576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161130190613801565b60405180910390fd5b80156113ca5773430000000000000000000000000000000000000273ffffffffffffffffffffffffffffffffffffffff1663662aa11d30600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff166040518363ffffffff1660e01b8152600401611381929190613821565b6020604051808303816000875af11580156113a0573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906113c4919061385f565b50611480565b73430000000000000000000000000000000000000273ffffffffffffffffffffffffffffffffffffffff1663954fa5ee30600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff166040518363ffffffff1660e01b815260040161143b929190613821565b6020604051808303816000875af115801561145a573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061147e919061385f565b505b50565b61148b611e21565b80600660006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555050565b60096020528060005260406000206000915090508060000160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16908060000160149054906101000a900461ffff16908060020154908060030154905084565b6000600260009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663b88c9148600360009054906101000a900473ffffffffffffffffffffffffffffffffffffffff166040518263ffffffff1660e01b81526004016115ac9190612601565b602060405180830381865afa1580156115c9573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906115ed91906138d4565b6fffffffffffffffffffffffffffffffff16905090565b60086020528060005260406000206000915090508060000160009054906101000a900463ffffffff16908060010154908060020160009054906101000a900460ff16908060020160019054906101000a900460ff16905084565b60008361ffff16116116a5576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161169c9061394d565b60405180910390fd5b6008600085815260200190815260200160002060020160009054906101000a900460ff16611708576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016116ff906139b9565b60405180910390fd5b8261ffff166008600086815260200190815260200160002060000160009054906101000a900463ffffffff1663ffffffff16101561177b576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161177290613a25565b60405180910390fd5b6000600a600084815260200190815260200160002060009054906101000a900467ffffffffffffffff1667ffffffffffffffff16146117ef576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016117e690613a91565b60405180910390fd5b600060086000868152602001908152602001600020600101548461ffff166118179190613ab1565b90506000600260009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663b88c9148600360009054906101000a900473ffffffffffffffffffffffffffffffffffffffff166040518263ffffffff1660e01b81526004016118989190612601565b602060405180830381865afa1580156118b5573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906118d991906138d4565b6fffffffffffffffffffffffffffffffff169050600082826118fb91906134b2565b905080341015611940576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161193790613b3f565b60405180910390fd5b6008600088815260200190815260200160002060020160019054906101000a900460ff1615611a325760006119a23389898946604051602001611987959493929190613c1f565b6040516020818303038152906040528051906020012061231a565b90506119f18186600560009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1661238c9092919063ffffffff16565b611a30576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401611a2790613cca565b60405180910390fd5b505b6000600260009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166319cb825f84600360009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16896040518463ffffffff1660e01b8152600401611ab4929190613cea565b60206040518083038185885af1158015611ad2573d6000803e3d6000fd5b50505050506040513d601f19601f82011682018060405250810190611af79190613d28565b905080600a600088815260200190815260200160002060006101000a81548167ffffffffffffffff021916908367ffffffffffffffff16021790555033600960008367ffffffffffffffff1667ffffffffffffffff16815260200190815260200160002060000160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555086600960008367ffffffffffffffff1667ffffffffffffffff16815260200190815260200160002060000160146101000a81548161ffff021916908361ffff16021790555087600960008367ffffffffffffffff1667ffffffffffffffff168152602001908152602001600020600301819055507fc332ce7c560e1184b0358aa14014f7fbbbf083aa8611e28d4812bafb7b30861933888a84604051611c459493929190613d86565b60405180910390a15050505050505050565b611c5f611e21565b600073ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff1603611cd15760006040517f1e4fbdf7000000000000000000000000000000000000000000000000000000008152600401611cc89190612601565b60405180910390fd5b611cda816121fc565b50565b611ce5611e21565b6103e8611cf1836122c8565b14611d31576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401611d2890613e17565b60405180910390fd5b600b6000611d3f91906124a3565b60005b8251811015611de857600b6040518060400160405280858481518110611d6b57611d6a613154565b5b60200260200101518152602001848481518110611d8b57611d8a613154565b5b60200260200101518152509080600181540180825580915050600190039060005260206000209060020201600090919091909150600082015181600001556020820151816001015550508080611de0906134e6565b915050611d42565b505050565b600b8181548110611dfd57600080fd5b90600052602060002090600202016000915090508060000154908060010154905082565b611e296122c0565b73ffffffffffffffffffffffffffffffffffffffff16611e47610d63565b73ffffffffffffffffffffffffffffffffffffffff1614611ea657611e6a6122c0565b6040517f118cdaa7000000000000000000000000000000000000000000000000000000008152600401611e9d9190612601565b60405180910390fd5b565b6000600260009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16905090565b7f17c4cce12998322f805ff6c39786651b347a39141c4e8e47767fda085581cde33384600360009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1684604051611f29949392919061352e565b60405180910390a1600260009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16611f726122c0565b73ffffffffffffffffffffffffffffffffffffffff16148015611fe257508173ffffffffffffffffffffffffffffffffffffffff16600360009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16145b612021576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161201890613e83565b60405180910390fd5b6000600960008567ffffffffffffffff1667ffffffffffffffff168152602001908152602001600020905060008160000160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16905060008260000160149054906101000a900461ffff169050600083600301549050600080856002015460001c146120e0576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016120d79061362b565b60405180910390fd5b85856002018190555060006120fc8760001c8561ffff1661072b565b9050612107816122c8565b915080866001019080519060200190612121929190612456565b50600460009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663731133e9866001856040518463ffffffff1660e01b8152600401612182939291906136ba565b600060405180830381600087803b15801561219c57600080fd5b505af11580156121b0573d6000803e3d6000fd5b505050507f4573b1c4a81e563013c3bfa32c89bd049df6313564234d6a1c7c233a731f77fa8583858c6040516121e99493929190613704565b60405180910390a1505050505050505050565b60008060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff169050816000806101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055508173ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e060405160405180910390a35050565b600033905090565b600080600090505b8251811015612314578281815181106122ec576122eb613154565b5b6020026020010151826122ff91906134b2565b9150808061230c906134e6565b9150506122d0565b50919050565b6000806040518060400160405280601c81526020017f19457468657265756d205369676e6564204d6573736167653a0a33320000000081525090506000818460405160200161236a929190613f09565b6040516020818303038152906040528051906020012090508092505050919050565b600061239883836123cf565b73ffffffffffffffffffffffffffffffffffffffff168473ffffffffffffffffffffffffffffffffffffffff161490509392505050565b600060418251146123df57600080fd5b60008060006020850151915060408501519050606085015160001a92506001868484846040516000815260200160405260405161241f9493929190613f4d565b6020604051602081039080840390855afa158015612441573d6000803e3d6000fd5b50505060206040510351935050505092915050565b828054828255906000526020600020908101928215612492579160200282015b82811115612491578251825591602001919060010190612476565b5b50905061249f91906124c7565b5090565b50805460008255600202906000526020600020908101906124c491906124e4565b50565b5b808211156124e05760008160009055506001016124c8565b5090565b5b80821115612507576000808201600090556001820160009055506002016124e5565b5090565b6000604051905090565b600080fd5b600080fd5b6000819050919050565b6125328161251f565b811461253d57600080fd5b50565b60008135905061254f81612529565b92915050565b60006020828403121561256b5761256a612515565b5b600061257984828501612540565b91505092915050565b600067ffffffffffffffff82169050919050565b61259f81612582565b82525050565b60006020820190506125ba6000830184612596565b92915050565b600073ffffffffffffffffffffffffffffffffffffffff82169050919050565b60006125eb826125c0565b9050919050565b6125fb816125e0565b82525050565b600060208201905061261660008301846125f2565b92915050565b612625816125e0565b811461263057600080fd5b50565b6000813590506126428161261c565b92915050565b60006020828403121561265e5761265d612515565b5b600061266c84828501612633565b91505092915050565b61267e81612582565b811461268957600080fd5b50565b60008135905061269b81612675565b92915050565b6000602082840312156126b7576126b6612515565b5b60006126c58482850161268c565b91505092915050565b600081519050919050565b600082825260208201905092915050565b6000819050602082019050919050565b6000819050919050565b61270d816126fa565b82525050565b600061271f8383612704565b60208301905092915050565b6000602082019050919050565b6000612743826126ce565b61274d81856126d9565b9350612758836126ea565b8060005b838110156127895781516127708882612713565b975061277b8361272b565b92505060018101905061275c565b5085935050505092915050565b600060208201905081810360008301526127b08184612738565b905092915050565b6127c1816126fa565b81146127cc57600080fd5b50565b6000813590506127de816127b8565b92915050565b600080604083850312156127fb576127fa612515565b5b6000612809858286016127cf565b925050602061281a858286016127cf565b9150509250929050565b60008060006060848603121561283d5761283c612515565b5b600061284b8682870161268c565b935050602061285c86828701612633565b925050604061286d86828701612540565b9150509250925092565b6000806040838503121561288e5761288d612515565b5b600061289c85828601612633565b92505060206128ad85828601612633565b9150509250929050565b6000602082840312156128cd576128cc612515565b5b60006128db848285016127cf565b91505092915050565b6128ed816126fa565b82525050565b600060208201905061290860008301846128e4565b92915050565b6000806040838503121561292557612924612515565b5b60006129338582860161268c565b925050602061294485828601612540565b9150509250929050565b6000819050919050565b600061297361296e612969846125c0565b61294e565b6125c0565b9050919050565b600061298582612958565b9050919050565b60006129978261297a565b9050919050565b6129a78161298c565b82525050565b60006020820190506129c2600083018461299e565b92915050565b600063ffffffff82169050919050565b6129e1816129c8565b81146129ec57600080fd5b50565b6000813590506129fe816129d8565b92915050565b60008115159050919050565b612a1981612a04565b8114612a2457600080fd5b50565b600081359050612a3681612a10565b92915050565b600080600080600060a08688031215612a5857612a57612515565b5b6000612a66888289016127cf565b9550506020612a77888289016129ef565b9450506040612a88888289016127cf565b9350506060612a9988828901612a27565b9250506080612aaa88828901612a27565b9150509295509295909350565b600060208284031215612acd57612acc612515565b5b6000612adb84828501612a27565b91505092915050565b600061ffff82169050919050565b612afb81612ae4565b82525050565b612b0a8161251f565b82525050565b6000608082019050612b2560008301876125f2565b612b326020830186612af2565b612b3f6040830185612b01565b612b4c60608301846128e4565b95945050505050565b612b5e816129c8565b82525050565b612b6d81612a04565b82525050565b6000608082019050612b886000830187612b55565b612b9560208301866128e4565b612ba26040830185612b64565b612baf6060830184612b64565b95945050505050565b612bc181612ae4565b8114612bcc57600080fd5b50565b600081359050612bde81612bb8565b92915050565b600080fd5b600080fd5b6000601f19601f8301169050919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b612c3782612bee565b810181811067ffffffffffffffff82111715612c5657612c55612bff565b5b80604052505050565b6000612c6961250b565b9050612c758282612c2e565b919050565b600067ffffffffffffffff821115612c9557612c94612bff565b5b612c9e82612bee565b9050602081019050919050565b82818337600083830152505050565b6000612ccd612cc884612c7a565b612c5f565b905082815260208101848484011115612ce957612ce8612be9565b5b612cf4848285612cab565b509392505050565b600082601f830112612d1157612d10612be4565b5b8135612d21848260208601612cba565b91505092915050565b60008060008060808587031215612d4457612d43612515565b5b6000612d52878288016127cf565b9450506020612d6387828801612bcf565b9350506040612d7487828801612540565b925050606085013567ffffffffffffffff811115612d9557612d9461251a565b5b612da187828801612cfc565b91505092959194509250565b600067ffffffffffffffff821115612dc857612dc7612bff565b5b602082029050602081019050919050565b600080fd5b6000612df1612dec84612dad565b612c5f565b90508083825260208201905060208402830185811115612e1457612e13612dd9565b5b835b81811015612e3d5780612e2988826127cf565b845260208401935050602081019050612e16565b5050509392505050565b600082601f830112612e5c57612e5b612be4565b5b8135612e6c848260208601612dde565b91505092915050565b60008060408385031215612e8c57612e8b612515565b5b600083013567ffffffffffffffff811115612eaa57612ea961251a565b5b612eb685828601612e47565b925050602083013567ffffffffffffffff811115612ed757612ed661251a565b5b612ee385828601612e47565b9150509250929050565b6000604082019050612f0260008301856128e4565b612f0f60208301846128e4565b9392505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b60008160011c9050919050565b6000808291508390505b6001851115612f9c57808604811115612f7857612f77612f16565b5b6001851615612f875780820291505b8081029050612f9585612f45565b9450612f5c565b94509492505050565b600082612fb55760019050613071565b81612fc35760009050613071565b8160018114612fd95760028114612fe357613012565b6001915050613071565b60ff841115612ff557612ff4612f16565b5b8360020a91508482111561300c5761300b612f16565b5b50613071565b5060208310610133831016604e8410600b84101617156130475782820a90508381111561304257613041612f16565b5b613071565b6130548484846001612f52565b9250905081840481111561306b5761306a612f16565b5b81810290505b9392505050565b6000613083826126fa565b915061308e83612ae4565b92506130bb7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8484612fa5565b905092915050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b60006130fd826126fa565b9150613108836126fa565b925082613118576131176130c3565b5b828204905092915050565b600061312e826126fa565b9150613139836126fa565b925082613149576131486130c3565b5b828206905092915050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b600061318e82612ae4565b915061ffff82036131a2576131a1612f16565b5b600182019050919050565b600082825260208201905092915050565b7f4e6f7468696e6720746f20776974686472617700000000000000000000000000600082015250565b60006131f46013836131ad565b91506131ff826131be565b602082019050919050565b60006020820190508181036000830152613223816131e7565b9050919050565b7f5472656173757279206973206e6f742073657400000000000000000000000000600082015250565b60006132606013836131ad565b915061326b8261322a565b602082019050919050565b6000602082019050818103600083015261328f81613253565b9050919050565b600081905092915050565b50565b60006132b1600083613296565b91506132bc826132a1565b600082019050919050565b60006132d2826132a4565b9150819050919050565b7f4661696c656420746f2073656e64204574686572000000000000000000000000600082015250565b60006133126014836131ad565b915061331d826132dc565b602082019050919050565b6000602082019050818103600083015261334181613305565b9050919050565b7f456e74726f70792061646472657373206e6f7420736574000000000000000000600082015250565b600061337e6017836131ad565b915061338982613348565b602082019050919050565b600060208201905081810360008301526133ad81613371565b9050919050565b7f4f6e6c7920456e74726f70792063616e2063616c6c20746869732066756e637460008201527f696f6e0000000000000000000000000000000000000000000000000000000000602082015250565b60006134106023836131ad565b915061341b826133b4565b604082019050919050565b6000602082019050818103600083015261343f81613403565b9050919050565b7f4e4f545f414c4c4f5745445f5a45524f5f414444524553530000000000000000600082015250565b600061347c6018836131ad565b915061348782613446565b602082019050919050565b600060208201905081810360008301526134ab8161346f565b9050919050565b60006134bd826126fa565b91506134c8836126fa565b92508282019050808211156134e0576134df612f16565b5b92915050565b60006134f1826126fa565b91507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff820361352357613522612f16565b5b600182019050919050565b600060808201905061354360008301876125f2565b6135506020830186612596565b61355d60408301856125f2565b61356a6060830184612b01565b95945050505050565b7f43616c6c6572206973206e6f7420776f726b6572000000000000000000000000600082015250565b60006135a96014836131ad565b91506135b482613573565b602082019050919050565b600060208201905081810360008301526135d88161359c565b9050919050565b7f4d696e742069732072657665616c656400000000000000000000000000000000600082015250565b60006136156010836131ad565b9150613620826135df565b602082019050919050565b6000602082019050818103600083015261364481613608565b9050919050565b6000819050919050565b600061367061366b6136668461364b565b61294e565b6126fa565b9050919050565b61368081613655565b82525050565b600082825260208201905092915050565b60006136a4600083613686565b91506136af826132a1565b600082019050919050565b60006080820190506136cf60008301866125f2565b6136dc6020830185613677565b6136e960408301846128e4565b81810360608301526136fa81613697565b9050949350505050565b600060808201905061371960008301876125f2565b61372660208301866128e4565b61373360408301856128e4565b6137406060830184612596565b95945050505050565b7f4f766572206c696d697400000000000000000000000000000000000000000000600082015250565b600061377f600a836131ad565b915061378a82613749565b602082019050919050565b600060208201905081810360008301526137ae81613772565b9050919050565b7f676173466565206973206e6f7420736574000000000000000000000000000000600082015250565b60006137eb6011836131ad565b91506137f6826137b5565b602082019050919050565b6000602082019050818103600083015261381a816137de565b9050919050565b600060408201905061383660008301856125f2565b61384360208301846125f2565b9392505050565b600081519050613859816127b8565b92915050565b60006020828403121561387557613874612515565b5b60006138838482850161384a565b91505092915050565b60006fffffffffffffffffffffffffffffffff82169050919050565b6138b18161388c565b81146138bc57600080fd5b50565b6000815190506138ce816138a8565b92915050565b6000602082840312156138ea576138e9612515565b5b60006138f8848285016138bf565b91505092915050565b7f496e76616c696420616d6f756e74000000000000000000000000000000000000600082015250565b6000613937600e836131ad565b915061394282613901565b602082019050919050565b600060208201905081810360008301526139668161392a565b9050919050565b7f4d696e74207068617365206973206e6f7420617661696c61626c650000000000600082015250565b60006139a3601b836131ad565b91506139ae8261396d565b602082019050919050565b600060208201905081810360008301526139d281613996565b9050919050565b7f4f766572206d6178207065722062617463680000000000000000000000000000600082015250565b6000613a0f6012836131ad565b9150613a1a826139d9565b602082019050919050565b60006020820190508181036000830152613a3e81613a02565b9050919050565b7f5261642069732075736564000000000000000000000000000000000000000000600082015250565b6000613a7b600b836131ad565b9150613a8682613a45565b602082019050919050565b60006020820190508181036000830152613aaa81613a6e565b9050919050565b6000613abc826126fa565b9150613ac7836126fa565b9250828202613ad5816126fa565b91508282048414831517613aec57613aeb612f16565b5b5092915050565b7f53656e64206d6f72652065746800000000000000000000000000000000000000600082015250565b6000613b29600d836131ad565b9150613b3482613af3565b602082019050919050565b60006020820190508181036000830152613b5881613b1c565b9050919050565b60008160601b9050919050565b6000613b7782613b5f565b9050919050565b6000613b8982613b6c565b9050919050565b613ba1613b9c826125e0565b613b7e565b82525050565b6000819050919050565b613bc2613bbd826126fa565b613ba7565b82525050565b60008160f01b9050919050565b6000613be082613bc8565b9050919050565b613bf8613bf382612ae4565b613bd5565b82525050565b6000819050919050565b613c19613c148261251f565b613bfe565b82525050565b6000613c2b8288613b90565b601482019150613c3b8287613bb1565b602082019150613c4b8286613be7565b600282019150613c5b8285613c08565b602082019150613c6b8284613bb1565b6020820191508190509695505050505050565b7f496e76616c6964207369676e6174757265000000000000000000000000000000600082015250565b6000613cb46011836131ad565b9150613cbf82613c7e565b602082019050919050565b60006020820190508181036000830152613ce381613ca7565b9050919050565b6000604082019050613cff60008301856125f2565b613d0c6020830184612b01565b9392505050565b600081519050613d2281612675565b92915050565b600060208284031215613d3e57613d3d612515565b5b6000613d4c84828501613d13565b91505092915050565b6000613d70613d6b613d6684612ae4565b61294e565b6126fa565b9050919050565b613d8081613d55565b82525050565b6000608082019050613d9b60008301876125f2565b613da86020830186613d77565b613db560408301856128e4565b613dc26060830184612596565b95945050505050565b7f496e76616c696420696e70757400000000000000000000000000000000000000600082015250565b6000613e01600d836131ad565b9150613e0c82613dcb565b602082019050919050565b60006020820190508181036000830152613e3081613df4565b9050919050565b7f43616c6c6572206973206e6f7420656e74726f70790000000000000000000000600082015250565b6000613e6d6015836131ad565b9150613e7882613e37565b602082019050919050565b60006020820190508181036000830152613e9c81613e60565b9050919050565b600081519050919050565b60005b83811015613ecc578082015181840152602081019050613eb1565b60008484015250505050565b6000613ee382613ea3565b613eed8185613296565b9350613efd818560208601613eae565b80840191505092915050565b6000613f158285613ed8565b9150613f218284613c08565b6020820191508190509392505050565b600060ff82169050919050565b613f4781613f31565b82525050565b6000608082019050613f626000830187612b01565b613f6f6020830186613f3e565b613f7c6040830185612b01565b613f896060830184612b01565b9594505050505056fea2646970667358221220c2a437109b78956caabedc33890a317d4d33810e1fd4d8880cdca4c826f8f0f364736f6c634300081400330000000000000000000000007866ac3933dca99b2e9a80f8948344a387a7bf6200000000000000000000000093a0dffee73b365c1c8237571783732137b19397000000000000000000000000ec6d0c755c255f2ecb400f716a557270cead7d8f
Deployed Bytecode
0x6080604052600436106101855760003560e01c80639518d7c7116100d1578063cc9d56721161008a578063dbcd106611610064578063dbcd106614610564578063f2fde38b14610580578063f5249be0146105a9578063f8833efd146105d25761018c565b8063cc9d5672146104b9578063ced72f87146104f9578063d045586d146105245761018c565b80639518d7c7146103d357806397d75776146103fc57806398795ee614610427578063b09191ad1461043e578063b943cbbb14610467578063c26f6d44146104905761018c565b806352a5f1f81161013e5780636605bfda116101185780636605bfda1461033f5780636c19e78314610368578063715018a6146103915780638da5cb5b146103a85761018c565b806352a5f1f8146102b057806358476046146102d95780636443ef1b146103025761018c565b8063051f7e451461018e578063085d4883146101cb5780630d2ae5c9146101f657806320a38b701461021f578063328d7cc81461025c5780633ccfd60b146102995761018c565b3661018c57005b005b34801561019a57600080fd5b506101b560048036038101906101b09190612555565b610610565b6040516101c291906125a5565b60405180910390f35b3480156101d757600080fd5b506101e0610637565b6040516101ed9190612601565b60405180910390f35b34801561020257600080fd5b5061021d60048036038101906102189190612648565b61065d565b005b34801561022b57600080fd5b50610246600480360381019061024191906126a1565b6106a9565b6040516102539190612796565b60405180910390f35b34801561026857600080fd5b50610283600480360381019061027e91906127e4565b61072b565b6040516102909190612796565b60405180910390f35b3480156102a557600080fd5b506102ae6107fe565b005b3480156102bc57600080fd5b506102d760048036038101906102d29190612824565b6109b1565b005b3480156102e557600080fd5b5061030060048036038101906102fb9190612877565b610aab565b005b34801561030e57600080fd5b50610329600480360381019061032491906128b7565b610c17565b60405161033691906128f3565b60405180910390f35b34801561034b57600080fd5b5061036660048036038101906103619190612648565b610cb7565b005b34801561037457600080fd5b5061038f600480360381019061038a9190612648565b610d03565b005b34801561039d57600080fd5b506103a6610d4f565b005b3480156103b457600080fd5b506103bd610d63565b6040516103ca9190612601565b60405180910390f35b3480156103df57600080fd5b506103fa60048036038101906103f5919061290e565b610d8c565b005b34801561040857600080fd5b5061041161105c565b60405161041e91906129ad565b60405180910390f35b34801561043357600080fd5b5061043c611074565b005b34801561044a57600080fd5b5061046560048036038101906104609190612a3c565b611174565b005b34801561047357600080fd5b5061048e60048036038101906104899190612ab7565b611279565b005b34801561049c57600080fd5b506104b760048036038101906104b29190612648565b611483565b005b3480156104c557600080fd5b506104e060048036038101906104db91906126a1565b6114cf565b6040516104f09493929190612b10565b60405180910390f35b34801561050557600080fd5b5061050e61152d565b60405161051b91906128f3565b60405180910390f35b34801561053057600080fd5b5061054b600480360381019061054691906128b7565b611604565b60405161055b9493929190612b73565b60405180910390f35b61057e60048036038101906105799190612d2a565b61165e565b005b34801561058c57600080fd5b506105a760048036038101906105a29190612648565b611c57565b005b3480156105b557600080fd5b506105d060048036038101906105cb9190612e75565b611cdd565b005b3480156105de57600080fd5b506105f960048036038101906105f491906128b7565b611ded565b604051610607929190612eed565b60405180910390f35b600a6020528060005260406000206000915054906101000a900467ffffffffffffffff1681565b600360009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b610665611e21565b80600160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555050565b6060600960008367ffffffffffffffff1667ffffffffffffffff16815260200190815260200160002060010180548060200260200160405190810160405280929190818152602001828054801561071f57602002820191906000526020600020905b81548152602001906001019080831161070b575b50505050509050919050565b606060008267ffffffffffffffff81111561074957610748612bff565b5b6040519080825280602002602001820160405280156107775781602001602082028036833780820191505090505b50905060005b838161ffff1610156107f35760006103e8826103e861079c9190613078565b876107a791906130f2565b6107b19190613123565b90506107bc81610c17565b838361ffff16815181106107d3576107d2613154565b5b6020026020010181815250505080806107eb90613183565b91505061077d565b508091505092915050565b610806611e21565b60004711610849576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016108409061320a565b60405180910390fd5b600073ffffffffffffffffffffffffffffffffffffffff16600760009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16036108da576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016108d190613276565b60405180910390fd5b6000600760009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16905060008173ffffffffffffffffffffffffffffffffffffffff1647604051610927906132c7565b60006040518083038185875af1925050503d8060008114610964576040519150601f19603f3d011682016040523d82523d6000602084013e610969565b606091505b50509050806109ad576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016109a490613328565b60405180910390fd5b5050565b60006109bb611ea8565b9050600073ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff1603610a2c576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610a2390613394565b60405180910390fd5b8073ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614610a9a576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610a9190613426565b60405180910390fd5b610aa5848484611ed2565b50505050565b610ab3611e21565b600073ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff1603610b22576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610b1990613492565b60405180910390fd5b600073ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff1603610b91576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610b8890613492565b60405180910390fd5b81600260006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555080600360006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055505050565b6000806000905060005b600b80549050811015610cab57600b8181548110610c4257610c41613154565b5b90600052602060002090600202016000015482610c5f91906134b2565b915081841015610c9857600b8181548110610c7d57610c7c613154565b5b90600052602060002090600202016001015492505050610cb2565b8080610ca3906134e6565b915050610c21565b5060009150505b919050565b610cbf611e21565b80600760006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555050565b610d0b611e21565b80600560006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555050565b610d57611e21565b610d6160006121fc565b565b60008060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16905090565b7f17c4cce12998322f805ff6c39786651b347a39141c4e8e47767fda085581cde33383600360009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1684604051610de3949392919061352e565b60405180910390a1600660009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16610e2c6122c0565b73ffffffffffffffffffffffffffffffffffffffff1614610e82576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610e79906135bf565b60405180910390fd5b6000600960008467ffffffffffffffff1667ffffffffffffffff168152602001908152602001600020905060008160000160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16905060008260000160149054906101000a900461ffff169050600083600301549050600080856002015460001c14610f41576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610f389061362b565b60405180910390fd5b8585600201819055506000610f5d8760001c8561ffff1661072b565b9050610f68816122c8565b915080866001019080519060200190610f82929190612456565b50600460009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663731133e9866001856040518463ffffffff1660e01b8152600401610fe3939291906136ba565b600060405180830381600087803b158015610ffd57600080fd5b505af1158015611011573d6000803e3d6000fd5b505050507f4573b1c4a81e563013c3bfa32c89bd049df6313564234d6a1c7c233a731f77fa8583858b60405161104a9493929190613704565b60405180910390a15050505050505050565b73430000000000000000000000000000000000000281565b61107c611e21565b600047116110bf576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016110b69061320a565b60405180910390fd5b600033905060008173ffffffffffffffffffffffffffffffffffffffff16476040516110ea906132c7565b60006040518083038185875af1925050503d8060008114611127576040519150601f19603f3d011682016040523d82523d6000602084013e61112c565b606091505b5050905080611170576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161116790613328565b60405180910390fd5b5050565b61117c611e21565b60148463ffffffff1611156111c6576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016111bd90613795565b60405180910390fd5b836008600087815260200190815260200160002060000160006101000a81548163ffffffff021916908363ffffffff160217905550826008600087815260200190815260200160002060010181905550816008600087815260200190815260200160002060020160006101000a81548160ff021916908315150217905550806008600087815260200190815260200160002060020160016101000a81548160ff0219169083151502179055505050505050565b600073ffffffffffffffffffffffffffffffffffffffff16600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff160361130a576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161130190613801565b60405180910390fd5b80156113ca5773430000000000000000000000000000000000000273ffffffffffffffffffffffffffffffffffffffff1663662aa11d30600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff166040518363ffffffff1660e01b8152600401611381929190613821565b6020604051808303816000875af11580156113a0573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906113c4919061385f565b50611480565b73430000000000000000000000000000000000000273ffffffffffffffffffffffffffffffffffffffff1663954fa5ee30600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff166040518363ffffffff1660e01b815260040161143b929190613821565b6020604051808303816000875af115801561145a573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061147e919061385f565b505b50565b61148b611e21565b80600660006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555050565b60096020528060005260406000206000915090508060000160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16908060000160149054906101000a900461ffff16908060020154908060030154905084565b6000600260009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663b88c9148600360009054906101000a900473ffffffffffffffffffffffffffffffffffffffff166040518263ffffffff1660e01b81526004016115ac9190612601565b602060405180830381865afa1580156115c9573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906115ed91906138d4565b6fffffffffffffffffffffffffffffffff16905090565b60086020528060005260406000206000915090508060000160009054906101000a900463ffffffff16908060010154908060020160009054906101000a900460ff16908060020160019054906101000a900460ff16905084565b60008361ffff16116116a5576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161169c9061394d565b60405180910390fd5b6008600085815260200190815260200160002060020160009054906101000a900460ff16611708576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016116ff906139b9565b60405180910390fd5b8261ffff166008600086815260200190815260200160002060000160009054906101000a900463ffffffff1663ffffffff16101561177b576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161177290613a25565b60405180910390fd5b6000600a600084815260200190815260200160002060009054906101000a900467ffffffffffffffff1667ffffffffffffffff16146117ef576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016117e690613a91565b60405180910390fd5b600060086000868152602001908152602001600020600101548461ffff166118179190613ab1565b90506000600260009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663b88c9148600360009054906101000a900473ffffffffffffffffffffffffffffffffffffffff166040518263ffffffff1660e01b81526004016118989190612601565b602060405180830381865afa1580156118b5573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906118d991906138d4565b6fffffffffffffffffffffffffffffffff169050600082826118fb91906134b2565b905080341015611940576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161193790613b3f565b60405180910390fd5b6008600088815260200190815260200160002060020160019054906101000a900460ff1615611a325760006119a23389898946604051602001611987959493929190613c1f565b6040516020818303038152906040528051906020012061231a565b90506119f18186600560009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1661238c9092919063ffffffff16565b611a30576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401611a2790613cca565b60405180910390fd5b505b6000600260009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166319cb825f84600360009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16896040518463ffffffff1660e01b8152600401611ab4929190613cea565b60206040518083038185885af1158015611ad2573d6000803e3d6000fd5b50505050506040513d601f19601f82011682018060405250810190611af79190613d28565b905080600a600088815260200190815260200160002060006101000a81548167ffffffffffffffff021916908367ffffffffffffffff16021790555033600960008367ffffffffffffffff1667ffffffffffffffff16815260200190815260200160002060000160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555086600960008367ffffffffffffffff1667ffffffffffffffff16815260200190815260200160002060000160146101000a81548161ffff021916908361ffff16021790555087600960008367ffffffffffffffff1667ffffffffffffffff168152602001908152602001600020600301819055507fc332ce7c560e1184b0358aa14014f7fbbbf083aa8611e28d4812bafb7b30861933888a84604051611c459493929190613d86565b60405180910390a15050505050505050565b611c5f611e21565b600073ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff1603611cd15760006040517f1e4fbdf7000000000000000000000000000000000000000000000000000000008152600401611cc89190612601565b60405180910390fd5b611cda816121fc565b50565b611ce5611e21565b6103e8611cf1836122c8565b14611d31576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401611d2890613e17565b60405180910390fd5b600b6000611d3f91906124a3565b60005b8251811015611de857600b6040518060400160405280858481518110611d6b57611d6a613154565b5b60200260200101518152602001848481518110611d8b57611d8a613154565b5b60200260200101518152509080600181540180825580915050600190039060005260206000209060020201600090919091909150600082015181600001556020820151816001015550508080611de0906134e6565b915050611d42565b505050565b600b8181548110611dfd57600080fd5b90600052602060002090600202016000915090508060000154908060010154905082565b611e296122c0565b73ffffffffffffffffffffffffffffffffffffffff16611e47610d63565b73ffffffffffffffffffffffffffffffffffffffff1614611ea657611e6a6122c0565b6040517f118cdaa7000000000000000000000000000000000000000000000000000000008152600401611e9d9190612601565b60405180910390fd5b565b6000600260009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16905090565b7f17c4cce12998322f805ff6c39786651b347a39141c4e8e47767fda085581cde33384600360009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1684604051611f29949392919061352e565b60405180910390a1600260009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16611f726122c0565b73ffffffffffffffffffffffffffffffffffffffff16148015611fe257508173ffffffffffffffffffffffffffffffffffffffff16600360009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16145b612021576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161201890613e83565b60405180910390fd5b6000600960008567ffffffffffffffff1667ffffffffffffffff168152602001908152602001600020905060008160000160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16905060008260000160149054906101000a900461ffff169050600083600301549050600080856002015460001c146120e0576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016120d79061362b565b60405180910390fd5b85856002018190555060006120fc8760001c8561ffff1661072b565b9050612107816122c8565b915080866001019080519060200190612121929190612456565b50600460009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663731133e9866001856040518463ffffffff1660e01b8152600401612182939291906136ba565b600060405180830381600087803b15801561219c57600080fd5b505af11580156121b0573d6000803e3d6000fd5b505050507f4573b1c4a81e563013c3bfa32c89bd049df6313564234d6a1c7c233a731f77fa8583858c6040516121e99493929190613704565b60405180910390a1505050505050505050565b60008060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff169050816000806101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055508173ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e060405160405180910390a35050565b600033905090565b600080600090505b8251811015612314578281815181106122ec576122eb613154565b5b6020026020010151826122ff91906134b2565b9150808061230c906134e6565b9150506122d0565b50919050565b6000806040518060400160405280601c81526020017f19457468657265756d205369676e6564204d6573736167653a0a33320000000081525090506000818460405160200161236a929190613f09565b6040516020818303038152906040528051906020012090508092505050919050565b600061239883836123cf565b73ffffffffffffffffffffffffffffffffffffffff168473ffffffffffffffffffffffffffffffffffffffff161490509392505050565b600060418251146123df57600080fd5b60008060006020850151915060408501519050606085015160001a92506001868484846040516000815260200160405260405161241f9493929190613f4d565b6020604051602081039080840390855afa158015612441573d6000803e3d6000fd5b50505060206040510351935050505092915050565b828054828255906000526020600020908101928215612492579160200282015b82811115612491578251825591602001919060010190612476565b5b50905061249f91906124c7565b5090565b50805460008255600202906000526020600020908101906124c491906124e4565b50565b5b808211156124e05760008160009055506001016124c8565b5090565b5b80821115612507576000808201600090556001820160009055506002016124e5565b5090565b6000604051905090565b600080fd5b600080fd5b6000819050919050565b6125328161251f565b811461253d57600080fd5b50565b60008135905061254f81612529565b92915050565b60006020828403121561256b5761256a612515565b5b600061257984828501612540565b91505092915050565b600067ffffffffffffffff82169050919050565b61259f81612582565b82525050565b60006020820190506125ba6000830184612596565b92915050565b600073ffffffffffffffffffffffffffffffffffffffff82169050919050565b60006125eb826125c0565b9050919050565b6125fb816125e0565b82525050565b600060208201905061261660008301846125f2565b92915050565b612625816125e0565b811461263057600080fd5b50565b6000813590506126428161261c565b92915050565b60006020828403121561265e5761265d612515565b5b600061266c84828501612633565b91505092915050565b61267e81612582565b811461268957600080fd5b50565b60008135905061269b81612675565b92915050565b6000602082840312156126b7576126b6612515565b5b60006126c58482850161268c565b91505092915050565b600081519050919050565b600082825260208201905092915050565b6000819050602082019050919050565b6000819050919050565b61270d816126fa565b82525050565b600061271f8383612704565b60208301905092915050565b6000602082019050919050565b6000612743826126ce565b61274d81856126d9565b9350612758836126ea565b8060005b838110156127895781516127708882612713565b975061277b8361272b565b92505060018101905061275c565b5085935050505092915050565b600060208201905081810360008301526127b08184612738565b905092915050565b6127c1816126fa565b81146127cc57600080fd5b50565b6000813590506127de816127b8565b92915050565b600080604083850312156127fb576127fa612515565b5b6000612809858286016127cf565b925050602061281a858286016127cf565b9150509250929050565b60008060006060848603121561283d5761283c612515565b5b600061284b8682870161268c565b935050602061285c86828701612633565b925050604061286d86828701612540565b9150509250925092565b6000806040838503121561288e5761288d612515565b5b600061289c85828601612633565b92505060206128ad85828601612633565b9150509250929050565b6000602082840312156128cd576128cc612515565b5b60006128db848285016127cf565b91505092915050565b6128ed816126fa565b82525050565b600060208201905061290860008301846128e4565b92915050565b6000806040838503121561292557612924612515565b5b60006129338582860161268c565b925050602061294485828601612540565b9150509250929050565b6000819050919050565b600061297361296e612969846125c0565b61294e565b6125c0565b9050919050565b600061298582612958565b9050919050565b60006129978261297a565b9050919050565b6129a78161298c565b82525050565b60006020820190506129c2600083018461299e565b92915050565b600063ffffffff82169050919050565b6129e1816129c8565b81146129ec57600080fd5b50565b6000813590506129fe816129d8565b92915050565b60008115159050919050565b612a1981612a04565b8114612a2457600080fd5b50565b600081359050612a3681612a10565b92915050565b600080600080600060a08688031215612a5857612a57612515565b5b6000612a66888289016127cf565b9550506020612a77888289016129ef565b9450506040612a88888289016127cf565b9350506060612a9988828901612a27565b9250506080612aaa88828901612a27565b9150509295509295909350565b600060208284031215612acd57612acc612515565b5b6000612adb84828501612a27565b91505092915050565b600061ffff82169050919050565b612afb81612ae4565b82525050565b612b0a8161251f565b82525050565b6000608082019050612b2560008301876125f2565b612b326020830186612af2565b612b3f6040830185612b01565b612b4c60608301846128e4565b95945050505050565b612b5e816129c8565b82525050565b612b6d81612a04565b82525050565b6000608082019050612b886000830187612b55565b612b9560208301866128e4565b612ba26040830185612b64565b612baf6060830184612b64565b95945050505050565b612bc181612ae4565b8114612bcc57600080fd5b50565b600081359050612bde81612bb8565b92915050565b600080fd5b600080fd5b6000601f19601f8301169050919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b612c3782612bee565b810181811067ffffffffffffffff82111715612c5657612c55612bff565b5b80604052505050565b6000612c6961250b565b9050612c758282612c2e565b919050565b600067ffffffffffffffff821115612c9557612c94612bff565b5b612c9e82612bee565b9050602081019050919050565b82818337600083830152505050565b6000612ccd612cc884612c7a565b612c5f565b905082815260208101848484011115612ce957612ce8612be9565b5b612cf4848285612cab565b509392505050565b600082601f830112612d1157612d10612be4565b5b8135612d21848260208601612cba565b91505092915050565b60008060008060808587031215612d4457612d43612515565b5b6000612d52878288016127cf565b9450506020612d6387828801612bcf565b9350506040612d7487828801612540565b925050606085013567ffffffffffffffff811115612d9557612d9461251a565b5b612da187828801612cfc565b91505092959194509250565b600067ffffffffffffffff821115612dc857612dc7612bff565b5b602082029050602081019050919050565b600080fd5b6000612df1612dec84612dad565b612c5f565b90508083825260208201905060208402830185811115612e1457612e13612dd9565b5b835b81811015612e3d5780612e2988826127cf565b845260208401935050602081019050612e16565b5050509392505050565b600082601f830112612e5c57612e5b612be4565b5b8135612e6c848260208601612dde565b91505092915050565b60008060408385031215612e8c57612e8b612515565b5b600083013567ffffffffffffffff811115612eaa57612ea961251a565b5b612eb685828601612e47565b925050602083013567ffffffffffffffff811115612ed757612ed661251a565b5b612ee385828601612e47565b9150509250929050565b6000604082019050612f0260008301856128e4565b612f0f60208301846128e4565b9392505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b60008160011c9050919050565b6000808291508390505b6001851115612f9c57808604811115612f7857612f77612f16565b5b6001851615612f875780820291505b8081029050612f9585612f45565b9450612f5c565b94509492505050565b600082612fb55760019050613071565b81612fc35760009050613071565b8160018114612fd95760028114612fe357613012565b6001915050613071565b60ff841115612ff557612ff4612f16565b5b8360020a91508482111561300c5761300b612f16565b5b50613071565b5060208310610133831016604e8410600b84101617156130475782820a90508381111561304257613041612f16565b5b613071565b6130548484846001612f52565b9250905081840481111561306b5761306a612f16565b5b81810290505b9392505050565b6000613083826126fa565b915061308e83612ae4565b92506130bb7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8484612fa5565b905092915050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b60006130fd826126fa565b9150613108836126fa565b925082613118576131176130c3565b5b828204905092915050565b600061312e826126fa565b9150613139836126fa565b925082613149576131486130c3565b5b828206905092915050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b600061318e82612ae4565b915061ffff82036131a2576131a1612f16565b5b600182019050919050565b600082825260208201905092915050565b7f4e6f7468696e6720746f20776974686472617700000000000000000000000000600082015250565b60006131f46013836131ad565b91506131ff826131be565b602082019050919050565b60006020820190508181036000830152613223816131e7565b9050919050565b7f5472656173757279206973206e6f742073657400000000000000000000000000600082015250565b60006132606013836131ad565b915061326b8261322a565b602082019050919050565b6000602082019050818103600083015261328f81613253565b9050919050565b600081905092915050565b50565b60006132b1600083613296565b91506132bc826132a1565b600082019050919050565b60006132d2826132a4565b9150819050919050565b7f4661696c656420746f2073656e64204574686572000000000000000000000000600082015250565b60006133126014836131ad565b915061331d826132dc565b602082019050919050565b6000602082019050818103600083015261334181613305565b9050919050565b7f456e74726f70792061646472657373206e6f7420736574000000000000000000600082015250565b600061337e6017836131ad565b915061338982613348565b602082019050919050565b600060208201905081810360008301526133ad81613371565b9050919050565b7f4f6e6c7920456e74726f70792063616e2063616c6c20746869732066756e637460008201527f696f6e0000000000000000000000000000000000000000000000000000000000602082015250565b60006134106023836131ad565b915061341b826133b4565b604082019050919050565b6000602082019050818103600083015261343f81613403565b9050919050565b7f4e4f545f414c4c4f5745445f5a45524f5f414444524553530000000000000000600082015250565b600061347c6018836131ad565b915061348782613446565b602082019050919050565b600060208201905081810360008301526134ab8161346f565b9050919050565b60006134bd826126fa565b91506134c8836126fa565b92508282019050808211156134e0576134df612f16565b5b92915050565b60006134f1826126fa565b91507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff820361352357613522612f16565b5b600182019050919050565b600060808201905061354360008301876125f2565b6135506020830186612596565b61355d60408301856125f2565b61356a6060830184612b01565b95945050505050565b7f43616c6c6572206973206e6f7420776f726b6572000000000000000000000000600082015250565b60006135a96014836131ad565b91506135b482613573565b602082019050919050565b600060208201905081810360008301526135d88161359c565b9050919050565b7f4d696e742069732072657665616c656400000000000000000000000000000000600082015250565b60006136156010836131ad565b9150613620826135df565b602082019050919050565b6000602082019050818103600083015261364481613608565b9050919050565b6000819050919050565b600061367061366b6136668461364b565b61294e565b6126fa565b9050919050565b61368081613655565b82525050565b600082825260208201905092915050565b60006136a4600083613686565b91506136af826132a1565b600082019050919050565b60006080820190506136cf60008301866125f2565b6136dc6020830185613677565b6136e960408301846128e4565b81810360608301526136fa81613697565b9050949350505050565b600060808201905061371960008301876125f2565b61372660208301866128e4565b61373360408301856128e4565b6137406060830184612596565b95945050505050565b7f4f766572206c696d697400000000000000000000000000000000000000000000600082015250565b600061377f600a836131ad565b915061378a82613749565b602082019050919050565b600060208201905081810360008301526137ae81613772565b9050919050565b7f676173466565206973206e6f7420736574000000000000000000000000000000600082015250565b60006137eb6011836131ad565b91506137f6826137b5565b602082019050919050565b6000602082019050818103600083015261381a816137de565b9050919050565b600060408201905061383660008301856125f2565b61384360208301846125f2565b9392505050565b600081519050613859816127b8565b92915050565b60006020828403121561387557613874612515565b5b60006138838482850161384a565b91505092915050565b60006fffffffffffffffffffffffffffffffff82169050919050565b6138b18161388c565b81146138bc57600080fd5b50565b6000815190506138ce816138a8565b92915050565b6000602082840312156138ea576138e9612515565b5b60006138f8848285016138bf565b91505092915050565b7f496e76616c696420616d6f756e74000000000000000000000000000000000000600082015250565b6000613937600e836131ad565b915061394282613901565b602082019050919050565b600060208201905081810360008301526139668161392a565b9050919050565b7f4d696e74207068617365206973206e6f7420617661696c61626c650000000000600082015250565b60006139a3601b836131ad565b91506139ae8261396d565b602082019050919050565b600060208201905081810360008301526139d281613996565b9050919050565b7f4f766572206d6178207065722062617463680000000000000000000000000000600082015250565b6000613a0f6012836131ad565b9150613a1a826139d9565b602082019050919050565b60006020820190508181036000830152613a3e81613a02565b9050919050565b7f5261642069732075736564000000000000000000000000000000000000000000600082015250565b6000613a7b600b836131ad565b9150613a8682613a45565b602082019050919050565b60006020820190508181036000830152613aaa81613a6e565b9050919050565b6000613abc826126fa565b9150613ac7836126fa565b9250828202613ad5816126fa565b91508282048414831517613aec57613aeb612f16565b5b5092915050565b7f53656e64206d6f72652065746800000000000000000000000000000000000000600082015250565b6000613b29600d836131ad565b9150613b3482613af3565b602082019050919050565b60006020820190508181036000830152613b5881613b1c565b9050919050565b60008160601b9050919050565b6000613b7782613b5f565b9050919050565b6000613b8982613b6c565b9050919050565b613ba1613b9c826125e0565b613b7e565b82525050565b6000819050919050565b613bc2613bbd826126fa565b613ba7565b82525050565b60008160f01b9050919050565b6000613be082613bc8565b9050919050565b613bf8613bf382612ae4565b613bd5565b82525050565b6000819050919050565b613c19613c148261251f565b613bfe565b82525050565b6000613c2b8288613b90565b601482019150613c3b8287613bb1565b602082019150613c4b8286613be7565b600282019150613c5b8285613c08565b602082019150613c6b8284613bb1565b6020820191508190509695505050505050565b7f496e76616c6964207369676e6174757265000000000000000000000000000000600082015250565b6000613cb46011836131ad565b9150613cbf82613c7e565b602082019050919050565b60006020820190508181036000830152613ce381613ca7565b9050919050565b6000604082019050613cff60008301856125f2565b613d0c6020830184612b01565b9392505050565b600081519050613d2281612675565b92915050565b600060208284031215613d3e57613d3d612515565b5b6000613d4c84828501613d13565b91505092915050565b6000613d70613d6b613d6684612ae4565b61294e565b6126fa565b9050919050565b613d8081613d55565b82525050565b6000608082019050613d9b60008301876125f2565b613da86020830186613d77565b613db560408301856128e4565b613dc26060830184612596565b95945050505050565b7f496e76616c696420696e70757400000000000000000000000000000000000000600082015250565b6000613e01600d836131ad565b9150613e0c82613dcb565b602082019050919050565b60006020820190508181036000830152613e3081613df4565b9050919050565b7f43616c6c6572206973206e6f7420656e74726f70790000000000000000000000600082015250565b6000613e6d6015836131ad565b9150613e7882613e37565b602082019050919050565b60006020820190508181036000830152613e9c81613e60565b9050919050565b600081519050919050565b60005b83811015613ecc578082015181840152602081019050613eb1565b60008484015250505050565b6000613ee382613ea3565b613eed8185613296565b9350613efd818560208601613eae565b80840191505092915050565b6000613f158285613ed8565b9150613f218284613c08565b6020820191508190509392505050565b600060ff82169050919050565b613f4781613f31565b82525050565b6000608082019050613f626000830187612b01565b613f6f6020830186613f3e565b613f7c6040830185612b01565b613f896060830184612b01565b9594505050505056fea2646970667358221220c2a437109b78956caabedc33890a317d4d33810e1fd4d8880cdca4c826f8f0f364736f6c63430008140033
Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)
0000000000000000000000007866ac3933dca99b2e9a80f8948344a387a7bf6200000000000000000000000093a0dffee73b365c1c8237571783732137b19397000000000000000000000000ec6d0c755c255f2ecb400f716a557270cead7d8f
-----Decoded View---------------
Arg [0] : initialOwner (address): 0x7866Ac3933dCA99b2e9a80F8948344a387a7BF62
Arg [1] : _gangster (address): 0x93A0dFFee73b365c1c8237571783732137B19397
Arg [2] : _signer (address): 0xEc6D0c755C255f2eCB400F716a557270cEAd7D8F
-----Encoded View---------------
3 Constructor Arguments found :
Arg [0] : 0000000000000000000000007866ac3933dca99b2e9a80f8948344a387a7bf62
Arg [1] : 00000000000000000000000093a0dffee73b365c1c8237571783732137b19397
Arg [2] : 000000000000000000000000ec6d0c755c255f2ecb400f716a557270cead7d8f
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.