Overview
ETH Balance
ETH Value
$150.04 (@ $3,000.78/ETH)Latest 25 from a total of 32 transactions
| Transaction Hash |
|
Block
|
From
|
To
|
|||||
|---|---|---|---|---|---|---|---|---|---|
| Create | 5347468 | 580 days ago | IN | 0.002 ETH | 0.00002915 | ||||
| Create | 5338984 | 580 days ago | IN | 0.002 ETH | 0.00000995 | ||||
| Create | 5250501 | 582 days ago | IN | 0.002 ETH | 0.00001265 | ||||
| Create | 5233765 | 582 days ago | IN | 0.002 ETH | 0.00002881 | ||||
| Create | 5213481 | 583 days ago | IN | 0.002 ETH | 0.00011149 | ||||
| Create | 5190589 | 583 days ago | IN | 0.002 ETH | 0.00007511 | ||||
| Create | 4797330 | 593 days ago | IN | 0.002 ETH | 0.00002003 | ||||
| Create | 4519686 | 599 days ago | IN | 0.002 ETH | 0.00000639 | ||||
| Create | 4476159 | 600 days ago | IN | 0.002 ETH | 0.00000638 | ||||
| Create | 4449960 | 601 days ago | IN | 0.002 ETH | 0.00000636 | ||||
| Create | 4408817 | 602 days ago | IN | 0.002 ETH | 0.0000061 | ||||
| Create | 4349595 | 603 days ago | IN | 0.002 ETH | 0.0000069 | ||||
| Create | 4261856 | 605 days ago | IN | 0.002 ETH | 0.00000749 | ||||
| Create | 4086054 | 609 days ago | IN | 0.002 ETH | 0.00000644 | ||||
| Create | 3998119 | 611 days ago | IN | 0.002 ETH | 0.00005694 | ||||
| Create | 3543536 | 622 days ago | IN | 0.002 ETH | 0.00002085 | ||||
| Create | 3541294 | 622 days ago | IN | 0.002 ETH | 0.00002327 | ||||
| Create | 3529937 | 622 days ago | IN | 0.002 ETH | 0.00004426 | ||||
| Create | 3396179 | 625 days ago | IN | 0.002 ETH | 0.00003192 | ||||
| Create | 3315709 | 627 days ago | IN | 0.002 ETH | 0.00003297 | ||||
| Create | 3245893 | 628 days ago | IN | 0.002 ETH | 0.00002255 | ||||
| Create | 3132827 | 631 days ago | IN | 0.002 ETH | 0.00003792 | ||||
| Create | 3098832 | 632 days ago | IN | 0.002 ETH | 0.00004823 | ||||
| Set Platform Fee | 3050990 | 633 days ago | IN | 0 ETH | 0.00000918 | ||||
| Create | 3047055 | 633 days ago | IN | 0.002 ETH | 0.00002679 |
Latest 25 internal transactions (View All)
Cross-Chain Transactions
Contract Source Code (Solidity Standard Json-Input format)
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
// Clone Factory
import "@openzeppelin/contracts/proxy/Clones.sol";
import "@openzeppelin/contracts/security/Pausable.sol";
import "./Artgene721Implementation.sol";
import "../../blast/BlastConfiguration.sol";
import "../ArtgenePlatform.sol";
/**
* @title contract by artgene.xyz
*/
//////////////////////////////////////////////////////////////////////////////////////////////////////
// //
// //
// @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ //
// @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ //
// @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ //
// @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ //
// @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ //
// @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ //
// @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ //
// @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ //
// @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ //
// @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ //
// @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ //
// @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@#S%??%S#@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ //
// @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@%***++***S@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ //
// @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@?+***%?**+*#@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ //
// @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@S+*+*#@@?+*+?@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ //
// @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@*+++%@@@#*+++S@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ //
// @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@S+++*#@@@@%+++*#@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ //
// @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@*+++%@@@@@#*+++%@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ //
// @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@S+++*#@@@@@@%+++*@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ //
// @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@?+++%@@@@@@@#++++S@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ //
// @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@S++++#@@@@@@@@?+++*@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ //
// @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@?+++?@@@@@@@@@S++++S@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ //
// @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@#++++S@@@@@@@@@@*+++*%???#@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ //
// @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@S+++*#@@@@@#S%?*+++++++++S@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ //
// @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@?+++?@@@@#?+++;+++++++%%S@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ //
// @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@#++++S@@@#*;+++?%S%++++@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ //
// @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@%;+++@@@@#+++;%@@@#+++;S@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ //
// @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@*;+;?@@@@@%;+;+#@@@*;+;?@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ //
// @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@#+;;;S@@@@@@?;;;+S@@%;;;+@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ //
// @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@%;;;+@@@@@@@@?;;;;?#%;;;+#@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ //
// @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@*;;;?@@@@@@@@@%+;;;+;;;;?@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ //
// @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@#;;;;#@@@@@@@@@@#%*+;;;+%@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ //
// @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@#?+*%@@@@@@@@@@@@@@#SS#@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ //
// @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ //
// @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ //
// @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ //
// @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ //
// @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ //
// @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ //
// @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ //
// @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ //
// @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ //
// @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ //
// @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ //
// @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ //
// //
// //
//////////////////////////////////////////////////////////////////////////////////////////////////////
contract Artgene721Factory is ArtgenePlatform, Pausable {
Artgene721Implementation public implementation =
new Artgene721Implementation();
event ContractDeployed(
address indexed contractAddress,
address indexed creator,
string name,
uint256 platformFee,
uint256 mintFee
);
function configureBlast() public onlyOwner {
if (!_BLAST_isBlast()) {
return;
}
// This sets the Gas Mode to claimable
BLAST.configureClaimableGas();
// contract balance will grow automatically
// HACK: this fails in simulation, but works on-chain
// BLAST.configureAutomaticYield()
// Configure Blast Points API and Governor
_BLAST_configureGovernor(owner());
_BLAST_configurePointsOperator(BLAST_ARTGENE_OPERATOR);
}
function create(
string memory _name,
string memory _symbol,
uint256 _maxSupply,
uint256 _nReserved,
bool _startAtOne,
string memory _uri,
MintConfig memory _config
) external payable whenNotPaused returns (Artgene721Implementation) {
require(
msg.value >= getCreationFee(),
"ArtgeneFactory: Not enough ether sent to deploy contract"
);
address instance = Clones.clone(address(implementation));
Artgene721Implementation collection = Artgene721Implementation(
payable(instance)
);
collection.initialize(
_name,
_symbol,
_maxSupply,
_nReserved,
_startAtOne,
_uri,
_config
);
collection.transferOwnership(msg.sender);
if (_BLAST_isBlast()) {
// Governor was transferred to the address(this) in the constructor
// Sets the Gas Mode to claimable
BLAST.configureClaimableGasOnBehalf(instance);
// contract balance will grow automatically
// HACK: this fails in simulation, but works on-chain
// try BLAST.configureAutomaticYieldOnBehalf(instance) {} catch {}
// pass control to the owner
_BLAST_configureGovernor(owner(), instance);
}
emit ContractDeployed(
address(collection),
msg.sender,
_name,
this.getPlatformFee(),
getMintFee()
);
return collection;
}
/**
* @dev Drains the balance of the contract to the owner's address.
* Can only be called by the contract owner.
*/
function drain() public onlyOwner {
payable(this.getPlatformAddress()).transfer(address(this).balance);
_pause();
}
/**
* @dev Pauses the contract.
* Can only be called by the contract owner.
*/
function pause() public onlyOwner {
_pause();
}
/**
* @dev Unpauses the contract.
* Can only be called by the contract owner.
*/
function unpause() public onlyOwner {
_unpause();
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (proxy/Clones.sol)
pragma solidity ^0.8.0;
/**
* @dev https://eips.ethereum.org/EIPS/eip-1167[EIP 1167] is a standard for
* deploying minimal proxy contracts, also known as "clones".
*
* > To simply and cheaply clone contract functionality in an immutable way, this standard specifies
* > a minimal bytecode implementation that delegates all calls to a known, fixed address.
*
* The library includes functions to deploy a proxy using either `create` (traditional deployment) or `create2`
* (salted deterministic deployment). It also includes functions to predict the addresses of clones deployed using the
* deterministic method.
*
* _Available since v3.4._
*/
library Clones {
/**
* @dev Deploys and returns the address of a clone that mimics the behaviour of `implementation`.
*
* This function uses the create opcode, which should never revert.
*/
function clone(address implementation) internal returns (address instance) {
/// @solidity memory-safe-assembly
assembly {
// Cleans the upper 96 bits of the `implementation` word, then packs the first 3 bytes
// of the `implementation` address with the bytecode before the address.
mstore(0x00, or(shr(0xe8, shl(0x60, implementation)), 0x3d602d80600a3d3981f3363d3d373d3d3d363d73000000))
// Packs the remaining 17 bytes of `implementation` with the bytecode after the address.
mstore(0x20, or(shl(0x78, implementation), 0x5af43d82803e903d91602b57fd5bf3))
instance := create(0, 0x09, 0x37)
}
require(instance != address(0), "ERC1167: create failed");
}
/**
* @dev Deploys and returns the address of a clone that mimics the behaviour of `implementation`.
*
* This function uses the create2 opcode and a `salt` to deterministically deploy
* the clone. Using the same `implementation` and `salt` multiple time will revert, since
* the clones cannot be deployed twice at the same address.
*/
function cloneDeterministic(address implementation, bytes32 salt) internal returns (address instance) {
/// @solidity memory-safe-assembly
assembly {
// Cleans the upper 96 bits of the `implementation` word, then packs the first 3 bytes
// of the `implementation` address with the bytecode before the address.
mstore(0x00, or(shr(0xe8, shl(0x60, implementation)), 0x3d602d80600a3d3981f3363d3d373d3d3d363d73000000))
// Packs the remaining 17 bytes of `implementation` with the bytecode after the address.
mstore(0x20, or(shl(0x78, implementation), 0x5af43d82803e903d91602b57fd5bf3))
instance := create2(0, 0x09, 0x37, salt)
}
require(instance != address(0), "ERC1167: create2 failed");
}
/**
* @dev Computes the address of a clone deployed using {Clones-cloneDeterministic}.
*/
function predictDeterministicAddress(
address implementation,
bytes32 salt,
address deployer
) internal pure returns (address predicted) {
/// @solidity memory-safe-assembly
assembly {
let ptr := mload(0x40)
mstore(add(ptr, 0x38), deployer)
mstore(add(ptr, 0x24), 0x5af43d82803e903d91602b57fd5bf3ff)
mstore(add(ptr, 0x14), implementation)
mstore(ptr, 0x3d602d80600a3d3981f3363d3d373d3d3d363d73)
mstore(add(ptr, 0x58), salt)
mstore(add(ptr, 0x78), keccak256(add(ptr, 0x0c), 0x37))
predicted := keccak256(add(ptr, 0x43), 0x55)
}
}
/**
* @dev Computes the address of a clone deployed using {Clones-cloneDeterministic}.
*/
function predictDeterministicAddress(
address implementation,
bytes32 salt
) internal view returns (address predicted) {
return predictDeterministicAddress(implementation, salt, address(this));
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.7.0) (security/Pausable.sol)
pragma solidity ^0.8.0;
import "../utils/Context.sol";
/**
* @dev Contract module which allows children to implement an emergency stop
* mechanism that can be triggered by an authorized account.
*
* This module is used through inheritance. It will make available the
* modifiers `whenNotPaused` and `whenPaused`, which can be applied to
* the functions of your contract. Note that they will not be pausable by
* simply including this module, only once the modifiers are put in place.
*/
abstract contract Pausable is Context {
/**
* @dev Emitted when the pause is triggered by `account`.
*/
event Paused(address account);
/**
* @dev Emitted when the pause is lifted by `account`.
*/
event Unpaused(address account);
bool private _paused;
/**
* @dev Initializes the contract in unpaused state.
*/
constructor() {
_paused = false;
}
/**
* @dev Modifier to make a function callable only when the contract is not paused.
*
* Requirements:
*
* - The contract must not be paused.
*/
modifier whenNotPaused() {
_requireNotPaused();
_;
}
/**
* @dev Modifier to make a function callable only when the contract is paused.
*
* Requirements:
*
* - The contract must be paused.
*/
modifier whenPaused() {
_requirePaused();
_;
}
/**
* @dev Returns true if the contract is paused, and false otherwise.
*/
function paused() public view virtual returns (bool) {
return _paused;
}
/**
* @dev Throws if the contract is paused.
*/
function _requireNotPaused() internal view virtual {
require(!paused(), "Pausable: paused");
}
/**
* @dev Throws if the contract is not paused.
*/
function _requirePaused() internal view virtual {
require(paused(), "Pausable: not paused");
}
/**
* @dev Triggers stopped state.
*
* Requirements:
*
* - The contract must not be paused.
*/
function _pause() internal virtual whenNotPaused {
_paused = true;
emit Paused(_msgSender());
}
/**
* @dev Returns to normal state.
*
* Requirements:
*
* - The contract must be paused.
*/
function _unpause() internal virtual whenPaused {
_paused = false;
emit Unpaused(_msgSender());
}
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
import "./Artgene721.sol";
/**
* @title contract by artgene.xyz
*/
//////////////////////////////////////////////////////////////////////////////////////////////////////
// //
// //
// @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ //
// @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ //
// @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ //
// @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ //
// @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ //
// @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ //
// @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ //
// @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ //
// @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ //
// @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ //
// @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ //
// @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@#S%??%S#@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ //
// @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@%***++***S@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ //
// @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@?+***%?**+*#@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ //
// @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@S+*+*#@@?+*+?@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ //
// @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@*+++%@@@#*+++S@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ //
// @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@S+++*#@@@@%+++*#@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ //
// @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@*+++%@@@@@#*+++%@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ //
// @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@S+++*#@@@@@@%+++*@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ //
// @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@?+++%@@@@@@@#++++S@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ //
// @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@S++++#@@@@@@@@?+++*@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ //
// @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@?+++?@@@@@@@@@S++++S@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ //
// @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@#++++S@@@@@@@@@@*+++*%???#@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ //
// @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@S+++*#@@@@@#S%?*+++++++++S@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ //
// @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@?+++?@@@@#?+++;+++++++%%S@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ //
// @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@#++++S@@@#*;+++?%S%++++@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ //
// @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@%;+++@@@@#+++;%@@@#+++;S@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ //
// @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@*;+;?@@@@@%;+;+#@@@*;+;?@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ //
// @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@#+;;;S@@@@@@?;;;+S@@%;;;+@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ //
// @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@%;;;+@@@@@@@@?;;;;?#%;;;+#@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ //
// @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@*;;;?@@@@@@@@@%+;;;+;;;;?@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ //
// @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@#;;;;#@@@@@@@@@@#%*+;;;+%@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ //
// @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@#?+*%@@@@@@@@@@@@@@#SS#@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ //
// @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ //
// @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ //
// @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ //
// @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ //
// @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ //
// @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ //
// @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ //
// @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ //
// @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ //
// @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ //
// @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ //
// @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ //
// //
// //
//////////////////////////////////////////////////////////////////////////////////////////////////////
contract Artgene721Implementation is Artgene721 {
// This constructor ensures that this contract can only be used as a master copy
// Marking constructor as initializer makes sure that real initializer cannot be called
// Thus, as the owner of the contract is 0x0, no one can do anything with the contract
// on the other hand, it's impossible to call this function in proxy,
// so the real initializer is the only initializer
/// @custom:oz-upgrades-unsafe-allow constructor
constructor() initializer {}
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
import "./IBlast.sol";
/// @dev https://docs.blast.io/building/guides/eth-yield
/**
* @dev This constant represents the address of the Blast System Contract.
* Reference: https://docs.blast.io/building/guides/gas-fees
*/
address constant BLAST_SYSTEM_CONTRACT = 0x4300000000000000000000000000000000000002;
// https://docs.blast.io/building/network-information
// Mainnet Chain ID 81457
// Testnet Chain ID 168587773
uint256 constant BLAST_MAINNET_CHAIN_ID = 81457;
uint256 constant BLAST_TESTNET_CHAIN_ID = 168587773;
// BlastPoints Mainnet address: 0x2536FE9ab3F511540F2f9e2eC2A805005C3Dd800
// BlastPoints Testnet address: 0x2fc95838c71e76ec69ff817983BFf17c710F34E0
address constant BLAST_MAINNET_POINTS = 0x2536FE9ab3F511540F2f9e2eC2A805005C3Dd800;
address constant BLAST_TESTNET_POINTS = 0x2fc95838c71e76ec69ff817983BFf17c710F34E0;
/// @dev This constant represents the address of the BLAST_ARTGENE_OPERATOR. Stored in `cast wallet`
address constant BLAST_ARTGENE_OPERATOR = 0x9b1419cd4b86C6c44146276A9A5c34A91872d841;
/**
* @dev This constant represents the interface to the BLAST contract.
* It is initialized with the address of the BLAST_SYSTEM_CONTRACT.
*/
IBlast constant BLAST = IBlast(BLAST_SYSTEM_CONTRACT);
/**
* @dev Retrieves the current chain ID.
* @return The chain ID as an unsigned integer.
*/
function chainId() view returns (uint) {
uint _chainId;
assembly {
_chainId := chainid()
}
return _chainId;
}
/**
* @dev Checks whether current chain is Blast by verifying the BLAST contract address.
* @return A boolean value indicating whether the current chain is Blast.
*/
function _BLAST_isBlast() view returns (bool) {
return address(BLAST).code.length > 0;
}
/**
* @dev Returns the address of the Blast Points contract.
*/
function _BLAST_getBlastPointsAddress() view returns (IBlastPoints) {
if (chainId() == BLAST_MAINNET_CHAIN_ID) {
return IBlastPoints(BLAST_MAINNET_POINTS);
} else if (chainId() == BLAST_TESTNET_CHAIN_ID) {
return IBlastPoints(BLAST_TESTNET_POINTS);
} else {
revert("Chain ID is not Blast");
}
}
/**
* @dev Configures the governor for the BLAST contract.
* @param _newGovernor The address of the new governor.
*/
function _BLAST_configureGovernor(address _newGovernor) {
BLAST.configureGovernor(_newGovernor);
}
/**
* @dev Configures the governor for the BLAST contract on behalf of a specific contract.
* @param _newGovernor The address of the new governor.
* @param _contractAddress The address of the contract on whose behalf the governor is being configured.
*/
function _BLAST_configureGovernor(
address _newGovernor,
address _contractAddress
) {
BLAST.configureGovernorOnBehalf(_newGovernor, _contractAddress);
}
/**
* @dev Configures the points operator for the Blast Points API.
* @param _newOperator The address of the new points operator.
*/
function _BLAST_configurePointsOperator(address _newOperator) {
// Configure Blast Points API https://docs.blast.io/airdrop/mainnet-points-api/how-to-integrate-api
IBlastPoints BLAST_POINTS = _BLAST_getBlastPointsAddress();
BLAST_POINTS.configurePointsOperator(_newOperator);
}
/**
* @dev Configures the points operator for the Blast Points API on behalf of a specific contract.
* @param _newOperator The address of the new points operator.
* @param _contractAddress The address of the contract on whose behalf the points operator is being configured.
*/
function _BLAST_configurePointsOperator(
address _newOperator,
address _contractAddress
) {
// Configure Blast Points API https://docs.blast.io/airdrop/mainnet-points-api/how-to-integrate-api
IBlastPoints BLAST_POINTS = _BLAST_getBlastPointsAddress();
BLAST_POINTS.configurePointsOperatorOnBehalf(
_contractAddress,
_newOperator
);
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
import "@openzeppelin/contracts/utils/Address.sol";
import "@openzeppelin/contracts/access/Ownable.sol";
import "./interfaces/IArtgenePlatform.sol";
contract ArtgenePlatform is Ownable, IArtgenePlatform {
/**
* @dev The creationFee variable represents the fee required to create a new collection on the Artgene platform.
*/
uint256 creationFee;
/**
* @dev The flat fee Artgene charges per each mint on top of artists' price.
*/
uint256 mintFee;
/**
* @dev Represents the platform revenue share fee in basis points (bps).
*/
uint256 platformFee; // in bps
/**
* @dev The address of the platform contract.
*/
address payable platformAddress;
uint256 constant MAX_PLATFORM_FEE = 5000; // 50%
event PlatformInfoUpdated(
address payable platformAddress,
uint256 platformFee,
uint256 creationFee,
uint256 mintFee
);
event Withdraw(address indexed to, uint256 amount);
constructor() {
platformFee = 1000;
platformAddress = payable(0x3087c429ed4e7e5Cec78D006fCC772ceeaa67f00);
creationFee = 0.002 ether;
mintFee = 0.000721 ether;
emit PlatformInfoUpdated(
platformAddress,
platformFee,
creationFee,
mintFee
);
}
function setCreationFee(uint256 _fee) public onlyOwner {
creationFee = _fee;
emit PlatformInfoUpdated(
platformAddress,
platformFee,
creationFee,
mintFee
);
}
function setMintFee(uint256 _fee) public onlyOwner {
mintFee = _fee;
emit PlatformInfoUpdated(
platformAddress,
platformFee,
creationFee,
mintFee
);
}
function setPlatformFee(uint256 _platformFee) public onlyOwner {
require(
_platformFee <= MAX_PLATFORM_FEE,
"ArtgenePlatformConfig: platform fee cannot be more than 10%"
);
platformFee = _platformFee;
emit PlatformInfoUpdated(
platformAddress,
platformFee,
creationFee,
mintFee
);
}
function setPlatformAddress(
address payable _platformAddress
) public onlyOwner {
platformAddress = _platformAddress;
emit PlatformInfoUpdated(
platformAddress,
platformFee,
creationFee,
mintFee
);
}
function withdraw() public onlyOwner {
address payable receiver = platformAddress;
uint256 amount = address(this).balance;
Address.sendValue(receiver, amount);
emit Withdraw(receiver, amount);
}
function getCreationFee() public view returns (uint256) {
return creationFee;
}
function getMintFee() public view returns (uint256) {
return mintFee;
}
function getPlatformFee() external view override returns (uint256) {
return platformFee;
}
function getPlatformAddress()
external
view
override
returns (address payable)
{
return platformAddress;
}
function getPlatformInfo()
external
view
returns (address payable, uint256, uint256, uint256)
{
return (platformAddress, platformFee, mintFee, creationFee);
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.4) (utils/Context.sol)
pragma solidity ^0.8.0;
/**
* @dev Provides information about the current execution context, including the
* sender of the transaction and its data. While these are generally available
* via msg.sender and msg.data, they should not be accessed in such a direct
* manner, since when dealing with meta-transactions the account sending and
* paying for execution may not be the actual sender (as far as an application
* is concerned).
*
* This contract is only required for intermediate, library-like contracts.
*/
abstract contract Context {
function _msgSender() internal view virtual returns (address) {
return msg.sender;
}
function _msgData() internal view virtual returns (bytes calldata) {
return msg.data;
}
function _contextSuffixLength() internal view virtual returns (uint256) {
return 0;
}
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
/**
* @title LICENSE REQUIREMENT
* @dev This contract is licensed under the MIT license.
* @dev You're not allowed to remove PLATFORM() from contract
*/
import "erc721a-upgradeable/contracts/ERC721AUpgradeable.sol";
import "erc721a-upgradeable/contracts/extensions/ERC721ABurnableUpgradeable.sol";
import "@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol";
import "@openzeppelin/contracts-upgradeable/security/ReentrancyGuardUpgradeable.sol";
import "@openzeppelin/contracts/utils/Address.sol";
import "@openzeppelin/contracts/utils/introspection/ERC165Checker.sol";
import "@openzeppelin/contracts/interfaces/IERC2981.sol";
import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
import "../interfaces/IERC4906.sol";
import "../interfaces/INFTExtension.sol";
import "../interfaces/IRenderer.sol";
import "../interfaces/IArtgene721.sol";
import "../interfaces/IArtgenePlatform.sol";
import "../../blast/BlastConfiguration.sol";
/**
* @title contract by artgene.xyz
*/
//////////////////////////////////////////////////////////////////////////////////////////////////////
// //
// //
// @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ //
// @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ //
// @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ //
// @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ //
// @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ //
// @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ //
// @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ //
// @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ //
// @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ //
// @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ //
// @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ //
// @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@#S%??%S#@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ //
// @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@%***++***S@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ //
// @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@?+***%?**+*#@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ //
// @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@S+*+*#@@?+*+?@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ //
// @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@*+++%@@@#*+++S@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ //
// @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@S+++*#@@@@%+++*#@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ //
// @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@*+++%@@@@@#*+++%@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ //
// @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@S+++*#@@@@@@%+++*@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ //
// @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@?+++%@@@@@@@#++++S@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ //
// @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@S++++#@@@@@@@@?+++*@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ //
// @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@?+++?@@@@@@@@@S++++S@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ //
// @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@#++++S@@@@@@@@@@*+++*%???#@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ //
// @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@S+++*#@@@@@#S%?*+++++++++S@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ //
// @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@?+++?@@@@#?+++;+++++++%%S@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ //
// @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@#++++S@@@#*;+++?%S%++++@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ //
// @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@%;+++@@@@#+++;%@@@#+++;S@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ //
// @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@*;+;?@@@@@%;+;+#@@@*;+;?@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ //
// @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@#+;;;S@@@@@@?;;;+S@@%;;;+@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ //
// @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@%;;;+@@@@@@@@?;;;;?#%;;;+#@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ //
// @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@*;;;?@@@@@@@@@%+;;;+;;;;?@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ //
// @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@#;;;;#@@@@@@@@@@#%*+;;;+%@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ //
// @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@#?+*%@@@@@@@@@@@@@@#SS#@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ //
// @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ //
// @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ //
// @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ //
// @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ //
// @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ //
// @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ //
// @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ //
// @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ //
// @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ //
// @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ //
// @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ //
// @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ //
// //
// //
//////////////////////////////////////////////////////////////////////////////////////////////////////
contract Artgene721 is
ERC721AUpgradeable,
ERC721ABurnableUpgradeable,
ReentrancyGuardUpgradeable,
OwnableUpgradeable,
IArtgene721Implementation,
IArtgene721 // implements IERC2981, IERC4906
{
using Address for address;
using SafeERC20 for IERC20;
uint32 internal constant TIMESTAMP_INFINITY = type(uint32).max; // 4 294 967 295 is 136 years, which is year 2106
uint256 internal constant MAX_PER_MINT_LIMIT = 50; // based on ERC721A limitations
uint256 public constant VERSION = 5;
uint256 public PLATFORM_FEE; // of 10,000
uint256 public MINT_FEE; // marketplace minting fixed fee
address payable private PLATFORM_TREASURY;
uint32 public startTimestamp;
uint32 public endTimestamp;
uint256 public reserved;
uint256 public maxSupply;
uint256 public maxPerMint;
uint256 public maxPerWallet;
uint256 public price;
uint256 public royaltyFee;
address public royaltyReceiver;
address public payoutReceiver;
address public renderer;
bool public isPayoutChangeLocked;
bool public isBurningAllowed;
bool private startAtOne;
/**
* @dev Additional data for each token that needs to be stored and accessed on-chain
*/
mapping(uint256 => bytes32) public data;
/**
* @dev Storing how many tokens each address has minted in public sale
*/
mapping(address => uint256) public mintedBy;
/**
* @dev List of connected extensions
*/
INFTExtension[] public extensions;
string private baseURI;
event ExtensionAdded(address indexed extensionAddress);
event ExtensionRevoked(address indexed extensionAddress);
event RendererAdded(address indexed extensionAddress);
event BurningAllowedUpdated(bool isBurningAllowed);
event PayoutChangeLocked(address payoutReceiver);
event Withdraw(address indexed to, uint256 amount);
event Evolution(uint256 indexed tokenId, bytes32 dna);
function initialize(
string memory _name,
string memory _symbol,
uint256 _maxSupply,
uint256 _nReserved,
bool _startAtOne,
string memory _uri,
MintConfig memory _config
) public initializerERC721A initializer {
// CHECK INPUTS
// either open edition or limited edition
if (_maxSupply == ARTGENE_MAX_SUPPLY_OPEN_EDITION) {
require(
_config.startTimestamp != 0 && _config.endTimestamp != 0,
"OpenEdition requires start and end timestamp"
);
require(
_config.startTimestamp < _config.endTimestamp,
"OpenEdition requires startTimestamp < endTimestamp"
);
require(
_config.maxTokensPerWallet != 0,
"OpenEdition requires maxPerWallet != 0"
);
} else {
// limited edition doesn't require start and end timestamp
// you can provide them optionally
}
reserved = _nReserved;
maxSupply = _maxSupply;
// should be set before calling ERC721A_init !
startAtOne = _startAtOne;
baseURI = _uri;
maxPerMint = MAX_PER_MINT_LIMIT;
// test if platform is deployed, platform is factory that deployed us
IArtgenePlatform platform = IArtgenePlatform(msg.sender);
require(
address(platform).code.length != 0,
"Platform not deployed"
);
(PLATFORM_TREASURY, PLATFORM_FEE, MINT_FEE,) = platform.getPlatformInfo();
__ERC721A_init(_name, _symbol);
__ERC721ABurnable_init();
__ReentrancyGuard_init();
__Ownable_init();
_configure(
_config.publicPrice,
_config.maxTokensPerMint,
_config.maxTokensPerWallet,
_config.royaltyFee,
_config.payoutReceiver,
_config.shouldLockPayoutReceiver,
_config.startTimestamp,
_config.endTimestamp
);
// Configure the contract with the BLAST system
if (_BLAST_isBlast()) {
// only include this configuration if we're on Blast chain
_BLAST_configurePointsOperator(BLAST_ARTGENE_OPERATOR);
// Passing control to the deployer
_BLAST_configureGovernor(msg.sender);
}
}
function _configure(
uint256 publicPrice,
uint256 maxTokensPerMint,
uint256 maxTokensPerWallet,
uint256 _royaltyFee,
address _payoutReceiver,
bool shouldLockPayoutReceiver,
uint32 _startTimestamp,
uint32 _endTimestamp
) internal {
if (_startTimestamp != 0) {
startTimestamp = _startTimestamp;
}
if (_endTimestamp != 0) {
endTimestamp = _endTimestamp;
}
if (publicPrice != 0) {
price = publicPrice;
}
if (maxTokensPerMint > 0) {
maxPerMint = maxTokensPerMint;
}
if (maxTokensPerWallet > 0) {
maxPerWallet = maxTokensPerWallet;
}
if (_royaltyFee > 0) {
royaltyFee = _royaltyFee;
}
if (_payoutReceiver != address(0)) {
payoutReceiver = _payoutReceiver;
}
if (shouldLockPayoutReceiver) {
isPayoutChangeLocked = true;
}
}
function _baseURI() internal view override returns (string memory) {
return baseURI;
}
function _startTokenId() internal view virtual override returns (uint256) {
return startAtOne ? 1 : 0;
}
function isOpenEdition() internal view returns (bool) {
return maxSupply == ARTGENE_MAX_SUPPLY_OPEN_EDITION;
}
// @dev used on Opensea to show collection-level metadata
function contractURI() external view returns (string memory uri) {
uri = _baseURI();
}
function tokenHTML(
uint256 tokenId,
bytes32 dna,
bytes calldata _data
) external view returns (string memory) {
if (renderer != address(0)) {
return IRenderer(renderer).tokenHTML(tokenId, dna, _data);
}
return "";
}
function tokenURI(
uint256 tokenId
)
public
view
override(ERC721AUpgradeable, IERC721AUpgradeable)
returns (string memory)
{
if (renderer != address(0)) {
string memory uri = IRenderer(renderer).tokenURI(tokenId);
if (bytes(uri).length > 0) {
return uri;
}
}
return super.tokenURI(tokenId);
}
function startTokenId() public view returns (uint256) {
return _startTokenId();
}
// ----- Admin functions -----
function setBaseURI(string calldata uri) public onlyOwner {
baseURI = uri;
// update metadata for all tokens
if (_totalMinted() == 0) return;
uint256 fromTokenId = _startTokenId();
uint256 toTokenId = _startTokenId() + _totalMinted() - 1;
emit BatchMetadataUpdate(fromTokenId, toTokenId);
}
function setPrice(uint256 _price) public onlyOwner {
price = _price;
}
function allowBurning(bool _isAllowed) public whenSaleNotStarted onlyOwner {
isBurningAllowed = _isAllowed;
emit BurningAllowedUpdated(_isAllowed);
}
function reduceMaxSupply(
uint256 _maxSupply
) public whenSaleNotStarted onlyOwner {
require(
_totalMinted() + reserved <= _maxSupply,
"Max supply is too low, already minted more (+ reserved)"
);
require(
_maxSupply < maxSupply,
"Cannot set higher than the current maxSupply"
);
maxSupply = _maxSupply;
}
// Lock changing withdraw address
function lockPayoutReceiver() public onlyOwner {
isPayoutChangeLocked = true;
emit PayoutChangeLocked(getPayoutReceiver());
}
function isExtensionAdded(address _extension) public view returns (bool) {
for (uint256 index = 0; index < extensions.length; index++) {
if (address(extensions[index]) == _extension) {
return true;
}
}
return false;
}
function extensionsLength() external view returns (uint256) {
return extensions.length;
}
function extensionList() external view returns (INFTExtension[] memory) {
// @dev this is O(N), don't use this on-chain
return extensions;
}
// Extensions are allowed to mint
function addExtension(address _extension) public onlyOwner {
require(_extension != address(this), "Cannot add self as extension");
require(!isExtensionAdded(_extension), "Extension already added");
extensions.push(INFTExtension(_extension));
emit ExtensionAdded(_extension);
}
function revokeExtension(address _extension) public onlyOwner {
uint256 index = 0;
for (; index < extensions.length; index++) {
if (extensions[index] == INFTExtension(_extension)) {
break;
}
}
extensions[index] = extensions[extensions.length - 1];
extensions.pop();
emit ExtensionRevoked(_extension);
}
function revokeAllExtensions() public onlyOwner {
for (uint256 index = 0; index < extensions.length; index++) {
emit ExtensionRevoked(address(extensions[index]));
}
delete extensions;
}
function setRenderer(address _renderer) public onlyOwner {
require(_renderer != address(this), "Cannot add self as renderer");
require(
_renderer == address(0) ||
ERC165Checker.supportsInterface(
_renderer,
type(IRenderer).interfaceId
),
"Not conforms to renderer interface"
);
renderer = _renderer;
emit RendererAdded(_renderer);
}
// ---- Minting ----
function _mintConsecutive(uint256 nTokens, address to) internal {
if (isOpenEdition()) {
// unlimited minting
} else {
require(
_totalMinted() + nTokens + reserved <= maxSupply,
"Not enough Tokens left."
);
}
uint256 nextTokenId = _nextTokenId();
_safeMint(to, nTokens, "");
for (uint256 i; i < nTokens; i++) {
uint256 tokenId = nextTokenId + i;
bytes32 dna = _createDNA(tokenId);
emit Evolution(tokenId, dna);
}
}
// @dev depends on the current block, so it's not possible to know the DNA in advance
function _createDNA(uint256 tokenId) internal view returns (bytes32) {
return
keccak256(
abi.encodePacked(
bytes32(block.prevrandao),
blockhash(block.number - 1),
bytes32(tokenId)
)
);
}
// ---- Mint control ----
modifier whenSaleActive() {
require(saleStarted(), "Sale not active");
_;
}
modifier whenSaleNotStarted() {
require(!saleStarted(), "Sale should not be active");
_;
}
modifier whenNotPayoutChangeLocked() {
require(!isPayoutChangeLocked, "Payout change is locked");
_;
}
modifier whenBurnAllowed() {
require(isBurningAllowed, "Burning is not allowed");
_;
}
modifier onlyExtension() {
require(
isExtensionAdded(msg.sender),
"Extension should be added to contract before minting"
);
_;
}
// ---- Mint public ----
// Contract can sell tokens
function mint(
uint256 nTokens
) external payable nonReentrant whenSaleActive {
// setting it to 0 means no limit
if (maxPerWallet > 0) {
require(
mintedBy[msg.sender] + nTokens <= maxPerWallet,
"You cannot mint more than maxPerWallet tokens for one address!"
);
// only store minted amounts after limit is enabled to save gas
mintedBy[msg.sender] += nTokens;
}
require(
nTokens <= maxPerMint,
"You cannot mint more than MAX_TOKENS_PER_MINT tokens at once!"
);
require(nTokens * price + _calculateMintFee(nTokens) <= msg.value, "Inconsistent amount sent!");
_transferMintFee(nTokens);
_mintConsecutive(nTokens, msg.sender);
}
// Owner can claim free tokens without paying mint fee
function claim(
uint256 nTokens,
address to
) external nonReentrant onlyOwner {
require(nTokens <= reserved, "That would exceed the max reserved.");
reserved = reserved - nTokens;
_mintConsecutive(nTokens, to);
}
// ---- Mint via extension
function mintExternal(
uint256 nTokens,
address to,
bytes32
) external payable onlyExtension nonReentrant {
require(msg.value >= _calculateMintFee(nTokens), "Mint Fee is required");
_transferMintFee(nTokens);
_mintConsecutive(nTokens, to);
}
// ---- Burn
function burn(
uint256 tokenId
) public override whenBurnAllowed nonReentrant {
// The caller must own `tokenId` or be an approved operator.
_burn(tokenId, true);
}
// ---- Mint configuration
function updateMaxPerMint(
uint256 _maxPerMint
) public onlyOwner nonReentrant {
require(_maxPerMint <= MAX_PER_MINT_LIMIT, "Too many tokens per mint");
maxPerMint = _maxPerMint;
}
// set to 0 to save gas, mintedBy is not used
function updateMaxPerWallet(
uint256 _maxPerWallet
) public onlyOwner nonReentrant {
maxPerWallet = _maxPerWallet;
}
// ---- Sale control ----
function updateStartTimestamp(uint32 _startTimestamp) public onlyOwner {
startTimestamp = _startTimestamp;
}
function updateMintStartEnd(
uint32 _startTimestamp,
uint32 _endTimestamp
) public onlyOwner {
startTimestamp = _startTimestamp;
endTimestamp = _endTimestamp;
}
function startSale() public onlyOwner {
startTimestamp = uint32(block.timestamp);
if (endTimestamp < startTimestamp) {
// if endTimestamp is not set, reset it to infinity
endTimestamp = TIMESTAMP_INFINITY;
}
}
function stopSale() public onlyOwner {
startTimestamp = 0;
}
function saleStarted() public view returns (bool) {
if (startTimestamp == 0) {
// this is default value, means sale wasn't initilized
// set startTimestamp to now to start sale
return false;
}
if (endTimestamp == 0) {
// if endTimestamp is not set, sale starts as usual
return block.timestamp >= startTimestamp;
}
// otherwise check if sale is active
return
block.timestamp >= startTimestamp &&
block.timestamp <= endTimestamp;
}
// ---- Offchain Info ----
function setRoyaltyFee(uint256 _royaltyFee) public onlyOwner {
royaltyFee = _royaltyFee;
}
function setRoyaltyReceiver(address _receiver) public onlyOwner {
royaltyReceiver = _receiver;
}
function setPayoutReceiver(
address _receiver
) public onlyOwner whenNotPayoutChangeLocked {
payoutReceiver = payable(_receiver);
}
function royaltyInfo(
uint256,
uint256 salePrice
) external view returns (address receiver, uint256 royaltyAmount) {
receiver = getRoyaltyReceiver();
royaltyAmount = (salePrice * royaltyFee) / 10000;
}
function getPayoutReceiver()
public
view
returns (address payable receiver)
{
receiver = payoutReceiver != address(0x0)
? payable(payoutReceiver)
: payable(owner());
}
function getRoyaltyReceiver()
public
view
returns (address payable receiver)
{
receiver = royaltyReceiver != address(0x0)
? payable(royaltyReceiver)
: getPayoutReceiver();
}
// ---- Allow royalty deposits from Opensea -----
receive() external payable {}
// ---- Withdraw -----
modifier onlyPlatform() {
require(
payable(msg.sender) == PLATFORM_TREASURY,
"Caller is not Platform"
);
_;
}
function _calculateMintFee(uint256 amount) private view returns (uint256) {
return MINT_FEE * amount;
}
function _transferMintFee(uint256 amount) private {
Address.sendValue(PLATFORM_TREASURY, MINT_FEE * amount);
}
function _withdraw() private {
uint256 balance = address(this).balance;
uint256 amount = (balance * (10000 - PLATFORM_FEE)) / 10000;
address payable receiver = getPayoutReceiver();
address payable platform = PLATFORM_TREASURY;
Address.sendValue(receiver, amount);
Address.sendValue(platform, balance - amount);
emit Withdraw(receiver, amount);
}
function withdraw() public virtual onlyOwner {
_withdraw();
}
function forceWithdrawPlatform() public virtual onlyPlatform {
_withdraw();
}
function withdrawToken(IERC20 token) public virtual onlyOwner {
uint256 balance = token.balanceOf(address(this));
uint256 amount = (balance * (10000 - PLATFORM_FEE)) / 10000;
address payable receiver = getPayoutReceiver();
address payable platform = PLATFORM_TREASURY;
token.safeTransfer(receiver, amount);
token.safeTransfer(platform, balance - amount);
}
function PLATFORM() public pure returns (string memory _url) {
_url = "https://artgene.xyz";
}
// -------- ERC721 overrides --------
function supportsInterface(
bytes4 interfaceId
)
public
view
override(ERC721AUpgradeable, IERC721AUpgradeable)
returns (bool)
{
return
interfaceId == type(IERC2981).interfaceId ||
interfaceId == type(IERC4906).interfaceId ||
interfaceId == type(IArtgene721).interfaceId ||
super.supportsInterface(interfaceId);
}
// @dev from openzeppelin-contracts/contracts/interfaces/IERC4906.sol
function forceMetadataUpdate(
uint256 _fromTokenId,
uint256 _toTokenId
) public onlyOwner {
require(_fromTokenId <= _toTokenId, "Invalid range");
/// @dev This event emits when the metadata of a range of tokens is changed.
/// So that the third-party platforms such as NFT market could
/// timely update the images and related attributes of the NFTs.
emit BatchMetadataUpdate(_fromTokenId, _toTokenId);
}
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
enum YieldMode {
AUTOMATIC,
VOID,
CLAIMABLE
}
enum GasMode {
VOID,
CLAIMABLE
}
interface IBlastPoints {
// configure
function configurePointsOperator(address operator) external;
function configurePointsOperatorOnBehalf(
address contractAddress,
address operator
) external;
// read
function readStatus(
address contractAddress
)
external
view
returns (address operatorAddress, bool isBanned, uint256 codeLength);
}
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 IGovernorInfo {
function governorMap(address) external view returns (address);
function isAuthorized(address contractAddress) external view returns (bool);
function isGovernor(address contractAddress) external view returns (bool);
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (utils/Address.sol)
pragma solidity ^0.8.1;
/**
* @dev Collection of functions related to the address type
*/
library Address {
/**
* @dev Returns true if `account` is a contract.
*
* [IMPORTANT]
* ====
* It is unsafe to assume that an address for which this function returns
* false is an externally-owned account (EOA) and not a contract.
*
* Among others, `isContract` will return false for the following
* types of addresses:
*
* - an externally-owned account
* - a contract in construction
* - an address where a contract will be created
* - an address where a contract lived, but was destroyed
*
* Furthermore, `isContract` will also return true if the target contract within
* the same transaction is already scheduled for destruction by `SELFDESTRUCT`,
* which only has an effect at the end of a transaction.
* ====
*
* [IMPORTANT]
* ====
* You shouldn't rely on `isContract` to protect against flash loan attacks!
*
* Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets
* like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract
* constructor.
* ====
*/
function isContract(address account) internal view returns (bool) {
// This method relies on extcodesize/address.code.length, which returns 0
// for contracts in construction, since the code is only stored at the end
// of the constructor execution.
return account.code.length > 0;
}
/**
* @dev Replacement for Solidity's `transfer`: sends `amount` wei to
* `recipient`, forwarding all available gas and reverting on errors.
*
* https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost
* of certain opcodes, possibly making contracts go over the 2300 gas limit
* imposed by `transfer`, making them unable to receive funds via
* `transfer`. {sendValue} removes this limitation.
*
* https://consensys.net/diligence/blog/2019/09/stop-using-soliditys-transfer-now/[Learn more].
*
* IMPORTANT: because control is transferred to `recipient`, care must be
* taken to not create reentrancy vulnerabilities. Consider using
* {ReentrancyGuard} or the
* https://solidity.readthedocs.io/en/v0.8.0/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].
*/
function sendValue(address payable recipient, uint256 amount) internal {
require(address(this).balance >= amount, "Address: insufficient balance");
(bool success, ) = recipient.call{value: amount}("");
require(success, "Address: unable to send value, recipient may have reverted");
}
/**
* @dev Performs a Solidity function call using a low level `call`. A
* plain `call` is an unsafe replacement for a function call: use this
* function instead.
*
* If `target` reverts with a revert reason, it is bubbled up by this
* function (like regular Solidity function calls).
*
* Returns the raw returned data. To convert to the expected return value,
* use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].
*
* Requirements:
*
* - `target` must be a contract.
* - calling `target` with `data` must not revert.
*
* _Available since v3.1._
*/
function functionCall(address target, bytes memory data) internal returns (bytes memory) {
return functionCallWithValue(target, data, 0, "Address: low-level call failed");
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with
* `errorMessage` as a fallback revert reason when `target` reverts.
*
* _Available since v3.1._
*/
function functionCall(
address target,
bytes memory data,
string memory errorMessage
) internal returns (bytes memory) {
return functionCallWithValue(target, data, 0, errorMessage);
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
* but also transferring `value` wei to `target`.
*
* Requirements:
*
* - the calling contract must have an ETH balance of at least `value`.
* - the called Solidity function must be `payable`.
*
* _Available since v3.1._
*/
function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) {
return functionCallWithValue(target, data, value, "Address: low-level call with value failed");
}
/**
* @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but
* with `errorMessage` as a fallback revert reason when `target` reverts.
*
* _Available since v3.1._
*/
function functionCallWithValue(
address target,
bytes memory data,
uint256 value,
string memory errorMessage
) internal returns (bytes memory) {
require(address(this).balance >= value, "Address: insufficient balance for call");
(bool success, bytes memory returndata) = target.call{value: value}(data);
return verifyCallResultFromTarget(target, success, returndata, errorMessage);
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
* but performing a static call.
*
* _Available since v3.3._
*/
function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {
return functionStaticCall(target, data, "Address: low-level static call failed");
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],
* but performing a static call.
*
* _Available since v3.3._
*/
function functionStaticCall(
address target,
bytes memory data,
string memory errorMessage
) internal view returns (bytes memory) {
(bool success, bytes memory returndata) = target.staticcall(data);
return verifyCallResultFromTarget(target, success, returndata, errorMessage);
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
* but performing a delegate call.
*
* _Available since v3.4._
*/
function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {
return functionDelegateCall(target, data, "Address: low-level delegate call failed");
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],
* but performing a delegate call.
*
* _Available since v3.4._
*/
function functionDelegateCall(
address target,
bytes memory data,
string memory errorMessage
) internal returns (bytes memory) {
(bool success, bytes memory returndata) = target.delegatecall(data);
return verifyCallResultFromTarget(target, success, returndata, errorMessage);
}
/**
* @dev Tool to verify that a low level call to smart-contract was successful, and revert (either by bubbling
* the revert reason or using the provided one) in case of unsuccessful call or if target was not a contract.
*
* _Available since v4.8._
*/
function verifyCallResultFromTarget(
address target,
bool success,
bytes memory returndata,
string memory errorMessage
) internal view returns (bytes memory) {
if (success) {
if (returndata.length == 0) {
// only check isContract if the call was successful and the return data is empty
// otherwise we already know that it was a contract
require(isContract(target), "Address: call to non-contract");
}
return returndata;
} else {
_revert(returndata, errorMessage);
}
}
/**
* @dev Tool to verify that a low level call was successful, and revert if it wasn't, either by bubbling the
* revert reason or using the provided one.
*
* _Available since v4.3._
*/
function verifyCallResult(
bool success,
bytes memory returndata,
string memory errorMessage
) internal pure returns (bytes memory) {
if (success) {
return returndata;
} else {
_revert(returndata, errorMessage);
}
}
function _revert(bytes memory returndata, string memory errorMessage) private pure {
// Look for revert reason and bubble it up if present
if (returndata.length > 0) {
// The easiest way to bubble the revert reason is using memory via assembly
/// @solidity memory-safe-assembly
assembly {
let returndata_size := mload(returndata)
revert(add(32, returndata), returndata_size)
}
} else {
revert(errorMessage);
}
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (access/Ownable.sol)
pragma solidity ^0.8.0;
import "../utils/Context.sol";
/**
* @dev Contract module which provides a basic access control mechanism, where
* there is an account (an owner) that can be granted exclusive access to
* specific functions.
*
* By default, the owner account will be the one that deploys the contract. This
* can later be changed with {transferOwnership}.
*
* This module is used through inheritance. It will make available the modifier
* `onlyOwner`, which can be applied to your functions to restrict their use to
* the owner.
*/
abstract contract Ownable is Context {
address private _owner;
event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);
/**
* @dev Initializes the contract setting the deployer as the initial owner.
*/
constructor() {
_transferOwnership(_msgSender());
}
/**
* @dev Throws if called by any account other than the owner.
*/
modifier onlyOwner() {
_checkOwner();
_;
}
/**
* @dev Returns the address of the current owner.
*/
function owner() public view virtual returns (address) {
return _owner;
}
/**
* @dev Throws if the sender is not the owner.
*/
function _checkOwner() internal view virtual {
require(owner() == _msgSender(), "Ownable: caller is not the owner");
}
/**
* @dev Leaves the contract without owner. It will not be possible to call
* `onlyOwner` functions. 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 {
require(newOwner != address(0), "Ownable: new owner is the zero address");
_transferOwnership(newOwner);
}
/**
* @dev Transfers ownership of the contract to a new account (`newOwner`).
* Internal function without access restriction.
*/
function _transferOwnership(address newOwner) internal virtual {
address oldOwner = _owner;
_owner = newOwner;
emit OwnershipTransferred(oldOwner, newOwner);
}
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
address constant ARTGENE_PLATFORM_ADDRESS = 0xAaaeEee77ED0D0ffCc2813333b796E367f1E12d9;
address constant ARTGENE_PLATFORM_ADDRESS_ZKSYNC = 0x983A23615aC3ECdeBe7d1438251403d57956Ccba;
function getChainID() view returns (uint256) {
uint256 id;
assembly {
id := chainid()
}
return id;
}
function getArtgenePlatformAddress() view returns (address) {
uint256 chainID = getChainID();
if (chainID == 1) {
// mainnet
return ARTGENE_PLATFORM_ADDRESS;
} else if (chainID == 5) {
// goerli
return ARTGENE_PLATFORM_ADDRESS;
} else if (chainID == 280) {
// zksync testnet
return ARTGENE_PLATFORM_ADDRESS_ZKSYNC;
} else if (chainID == 324) {
// zksync era
return ARTGENE_PLATFORM_ADDRESS_ZKSYNC;
} else {
return address(0);
}
}
interface IArtgenePlatform {
function getPlatformFee() external view returns (uint256);
function getPlatformAddress() external view returns (address payable);
function getCreationFee() external view returns (uint256);
function getMintFee() external view returns (uint256);
function getPlatformInfo() external view returns (address payable, uint256, uint256, uint256);
function setPlatformFee(uint256 _platformFee) external;
function setPlatformAddress(address payable _platformAddress) external;
function setCreationFee(uint256 _creationFee) external;
function setMintFee(uint256 _mintFee) external;
}
interface IArtgeneMarketplace {
function getRateFee() external view returns (uint256);
function getFlatFee() external view returns (uint256);
function getCreationFee() external view returns (uint256);
function getAddress() external view returns (address payable);
function setRateFee(uint256 _platformFee) external;
function setFlatFee(uint256 _platformFee) external;
function setCreationFee(uint256 _platformFee) external;
function setAddress(address payable _platformAddress) external;
}// SPDX-License-Identifier: MIT
// ERC721A Contracts v4.3.0
// Creator: Chiru Labs
pragma solidity ^0.8.4;
import './IERC721AUpgradeable.sol';
import {ERC721AStorage} from './ERC721AStorage.sol';
import './ERC721A__Initializable.sol';
/**
* @dev Interface of ERC721 token receiver.
*/
interface ERC721A__IERC721ReceiverUpgradeable {
function onERC721Received(
address operator,
address from,
uint256 tokenId,
bytes calldata data
) external returns (bytes4);
}
/**
* @title ERC721A
*
* @dev Implementation of the [ERC721](https://eips.ethereum.org/EIPS/eip-721)
* Non-Fungible Token Standard, including the Metadata extension.
* Optimized for lower gas during batch mints.
*
* Token IDs are minted in sequential order (e.g. 0, 1, 2, 3, ...)
* starting from `_startTokenId()`.
*
* The `_sequentialUpTo()` function can be overriden to enable spot mints
* (i.e. non-consecutive mints) for `tokenId`s greater than `_sequentialUpTo()`.
*
* Assumptions:
*
* - An owner cannot have more than 2**64 - 1 (max value of uint64) of supply.
* - The maximum token ID cannot exceed 2**256 - 1 (max value of uint256).
*/
contract ERC721AUpgradeable is ERC721A__Initializable, IERC721AUpgradeable {
using ERC721AStorage for ERC721AStorage.Layout;
// =============================================================
// CONSTANTS
// =============================================================
// Mask of an entry in packed address data.
uint256 private constant _BITMASK_ADDRESS_DATA_ENTRY = (1 << 64) - 1;
// The bit position of `numberMinted` in packed address data.
uint256 private constant _BITPOS_NUMBER_MINTED = 64;
// The bit position of `numberBurned` in packed address data.
uint256 private constant _BITPOS_NUMBER_BURNED = 128;
// The bit position of `aux` in packed address data.
uint256 private constant _BITPOS_AUX = 192;
// Mask of all 256 bits in packed address data except the 64 bits for `aux`.
uint256 private constant _BITMASK_AUX_COMPLEMENT = (1 << 192) - 1;
// The bit position of `startTimestamp` in packed ownership.
uint256 private constant _BITPOS_START_TIMESTAMP = 160;
// The bit mask of the `burned` bit in packed ownership.
uint256 private constant _BITMASK_BURNED = 1 << 224;
// The bit position of the `nextInitialized` bit in packed ownership.
uint256 private constant _BITPOS_NEXT_INITIALIZED = 225;
// The bit mask of the `nextInitialized` bit in packed ownership.
uint256 private constant _BITMASK_NEXT_INITIALIZED = 1 << 225;
// The bit position of `extraData` in packed ownership.
uint256 private constant _BITPOS_EXTRA_DATA = 232;
// Mask of all 256 bits in a packed ownership except the 24 bits for `extraData`.
uint256 private constant _BITMASK_EXTRA_DATA_COMPLEMENT = (1 << 232) - 1;
// The mask of the lower 160 bits for addresses.
uint256 private constant _BITMASK_ADDRESS = (1 << 160) - 1;
// The maximum `quantity` that can be minted with {_mintERC2309}.
// This limit is to prevent overflows on the address data entries.
// For a limit of 5000, a total of 3.689e15 calls to {_mintERC2309}
// is required to cause an overflow, which is unrealistic.
uint256 private constant _MAX_MINT_ERC2309_QUANTITY_LIMIT = 5000;
// The `Transfer` event signature is given by:
// `keccak256(bytes("Transfer(address,address,uint256)"))`.
bytes32 private constant _TRANSFER_EVENT_SIGNATURE =
0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef;
// =============================================================
// CONSTRUCTOR
// =============================================================
function __ERC721A_init(string memory name_, string memory symbol_) internal onlyInitializingERC721A {
__ERC721A_init_unchained(name_, symbol_);
}
function __ERC721A_init_unchained(string memory name_, string memory symbol_) internal onlyInitializingERC721A {
ERC721AStorage.layout()._name = name_;
ERC721AStorage.layout()._symbol = symbol_;
ERC721AStorage.layout()._currentIndex = _startTokenId();
if (_sequentialUpTo() < _startTokenId()) _revert(SequentialUpToTooSmall.selector);
}
// =============================================================
// TOKEN COUNTING OPERATIONS
// =============================================================
/**
* @dev Returns the starting token ID for sequential mints.
*
* Override this function to change the starting token ID for sequential mints.
*
* Note: The value returned must never change after any tokens have been minted.
*/
function _startTokenId() internal view virtual returns (uint256) {
return 0;
}
/**
* @dev Returns the maximum token ID (inclusive) for sequential mints.
*
* Override this function to return a value less than 2**256 - 1,
* but greater than `_startTokenId()`, to enable spot (non-sequential) mints.
*
* Note: The value returned must never change after any tokens have been minted.
*/
function _sequentialUpTo() internal view virtual returns (uint256) {
return type(uint256).max;
}
/**
* @dev Returns the next token ID to be minted.
*/
function _nextTokenId() internal view virtual returns (uint256) {
return ERC721AStorage.layout()._currentIndex;
}
/**
* @dev Returns the total number of tokens in existence.
* Burned tokens will reduce the count.
* To get the total number of tokens minted, please see {_totalMinted}.
*/
function totalSupply() public view virtual override returns (uint256 result) {
// Counter underflow is impossible as `_burnCounter` cannot be incremented
// more than `_currentIndex + _spotMinted - _startTokenId()` times.
unchecked {
// With spot minting, the intermediate `result` can be temporarily negative,
// and the computation must be unchecked.
result = ERC721AStorage.layout()._currentIndex - ERC721AStorage.layout()._burnCounter - _startTokenId();
if (_sequentialUpTo() != type(uint256).max) result += ERC721AStorage.layout()._spotMinted;
}
}
/**
* @dev Returns the total amount of tokens minted in the contract.
*/
function _totalMinted() internal view virtual returns (uint256 result) {
// Counter underflow is impossible as `_currentIndex` does not decrement,
// and it is initialized to `_startTokenId()`.
unchecked {
result = ERC721AStorage.layout()._currentIndex - _startTokenId();
if (_sequentialUpTo() != type(uint256).max) result += ERC721AStorage.layout()._spotMinted;
}
}
/**
* @dev Returns the total number of tokens burned.
*/
function _totalBurned() internal view virtual returns (uint256) {
return ERC721AStorage.layout()._burnCounter;
}
/**
* @dev Returns the total number of tokens that are spot-minted.
*/
function _totalSpotMinted() internal view virtual returns (uint256) {
return ERC721AStorage.layout()._spotMinted;
}
// =============================================================
// ADDRESS DATA OPERATIONS
// =============================================================
/**
* @dev Returns the number of tokens in `owner`'s account.
*/
function balanceOf(address owner) public view virtual override returns (uint256) {
if (owner == address(0)) _revert(BalanceQueryForZeroAddress.selector);
return ERC721AStorage.layout()._packedAddressData[owner] & _BITMASK_ADDRESS_DATA_ENTRY;
}
/**
* Returns the number of tokens minted by `owner`.
*/
function _numberMinted(address owner) internal view returns (uint256) {
return
(ERC721AStorage.layout()._packedAddressData[owner] >> _BITPOS_NUMBER_MINTED) & _BITMASK_ADDRESS_DATA_ENTRY;
}
/**
* Returns the number of tokens burned by or on behalf of `owner`.
*/
function _numberBurned(address owner) internal view returns (uint256) {
return
(ERC721AStorage.layout()._packedAddressData[owner] >> _BITPOS_NUMBER_BURNED) & _BITMASK_ADDRESS_DATA_ENTRY;
}
/**
* Returns the auxiliary data for `owner`. (e.g. number of whitelist mint slots used).
*/
function _getAux(address owner) internal view returns (uint64) {
return uint64(ERC721AStorage.layout()._packedAddressData[owner] >> _BITPOS_AUX);
}
/**
* Sets the auxiliary data for `owner`. (e.g. number of whitelist mint slots used).
* If there are multiple variables, please pack them into a uint64.
*/
function _setAux(address owner, uint64 aux) internal virtual {
uint256 packed = ERC721AStorage.layout()._packedAddressData[owner];
uint256 auxCasted;
// Cast `aux` with assembly to avoid redundant masking.
assembly {
auxCasted := aux
}
packed = (packed & _BITMASK_AUX_COMPLEMENT) | (auxCasted << _BITPOS_AUX);
ERC721AStorage.layout()._packedAddressData[owner] = packed;
}
// =============================================================
// IERC165
// =============================================================
/**
* @dev Returns true if this contract implements the interface defined by
* `interfaceId`. See the corresponding
* [EIP section](https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified)
* to learn more about how these ids are created.
*
* This function call must use less than 30000 gas.
*/
function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {
// The interface IDs are constants representing the first 4 bytes
// of the XOR of all function selectors in the interface.
// See: [ERC165](https://eips.ethereum.org/EIPS/eip-165)
// (e.g. `bytes4(i.functionA.selector ^ i.functionB.selector ^ ...)`)
return
interfaceId == 0x01ffc9a7 || // ERC165 interface ID for ERC165.
interfaceId == 0x80ac58cd || // ERC165 interface ID for ERC721.
interfaceId == 0x5b5e139f; // ERC165 interface ID for ERC721Metadata.
}
// =============================================================
// IERC721Metadata
// =============================================================
/**
* @dev Returns the token collection name.
*/
function name() public view virtual override returns (string memory) {
return ERC721AStorage.layout()._name;
}
/**
* @dev Returns the token collection symbol.
*/
function symbol() public view virtual override returns (string memory) {
return ERC721AStorage.layout()._symbol;
}
/**
* @dev Returns the Uniform Resource Identifier (URI) for `tokenId` token.
*/
function tokenURI(uint256 tokenId) public view virtual override returns (string memory) {
if (!_exists(tokenId)) _revert(URIQueryForNonexistentToken.selector);
string memory baseURI = _baseURI();
return bytes(baseURI).length != 0 ? string(abi.encodePacked(baseURI, _toString(tokenId))) : '';
}
/**
* @dev Base URI for computing {tokenURI}. If set, the resulting URI for each
* token will be the concatenation of the `baseURI` and the `tokenId`. Empty
* by default, it can be overridden in child contracts.
*/
function _baseURI() internal view virtual returns (string memory) {
return '';
}
// =============================================================
// OWNERSHIPS OPERATIONS
// =============================================================
/**
* @dev Returns the owner of the `tokenId` token.
*
* Requirements:
*
* - `tokenId` must exist.
*/
function ownerOf(uint256 tokenId) public view virtual override returns (address) {
return address(uint160(_packedOwnershipOf(tokenId)));
}
/**
* @dev Gas spent here starts off proportional to the maximum mint batch size.
* It gradually moves to O(1) as tokens get transferred around over time.
*/
function _ownershipOf(uint256 tokenId) internal view virtual returns (TokenOwnership memory) {
return _unpackedOwnership(_packedOwnershipOf(tokenId));
}
/**
* @dev Returns the unpacked `TokenOwnership` struct at `index`.
*/
function _ownershipAt(uint256 index) internal view virtual returns (TokenOwnership memory) {
return _unpackedOwnership(ERC721AStorage.layout()._packedOwnerships[index]);
}
/**
* @dev Returns whether the ownership slot at `index` is initialized.
* An uninitialized slot does not necessarily mean that the slot has no owner.
*/
function _ownershipIsInitialized(uint256 index) internal view virtual returns (bool) {
return ERC721AStorage.layout()._packedOwnerships[index] != 0;
}
/**
* @dev Initializes the ownership slot minted at `index` for efficiency purposes.
*/
function _initializeOwnershipAt(uint256 index) internal virtual {
if (ERC721AStorage.layout()._packedOwnerships[index] == 0) {
ERC721AStorage.layout()._packedOwnerships[index] = _packedOwnershipOf(index);
}
}
/**
* @dev Returns the packed ownership data of `tokenId`.
*/
function _packedOwnershipOf(uint256 tokenId) private view returns (uint256 packed) {
if (_startTokenId() <= tokenId) {
packed = ERC721AStorage.layout()._packedOwnerships[tokenId];
if (tokenId > _sequentialUpTo()) {
if (_packedOwnershipExists(packed)) return packed;
_revert(OwnerQueryForNonexistentToken.selector);
}
// If the data at the starting slot does not exist, start the scan.
if (packed == 0) {
if (tokenId >= ERC721AStorage.layout()._currentIndex) _revert(OwnerQueryForNonexistentToken.selector);
// Invariant:
// There will always be an initialized ownership slot
// (i.e. `ownership.addr != address(0) && ownership.burned == false`)
// before an unintialized ownership slot
// (i.e. `ownership.addr == address(0) && ownership.burned == false`)
// Hence, `tokenId` will not underflow.
//
// We can directly compare the packed value.
// If the address is zero, packed will be zero.
for (;;) {
unchecked {
packed = ERC721AStorage.layout()._packedOwnerships[--tokenId];
}
if (packed == 0) continue;
if (packed & _BITMASK_BURNED == 0) return packed;
// Otherwise, the token is burned, and we must revert.
// This handles the case of batch burned tokens, where only the burned bit
// of the starting slot is set, and remaining slots are left uninitialized.
_revert(OwnerQueryForNonexistentToken.selector);
}
}
// Otherwise, the data exists and we can skip the scan.
// This is possible because we have already achieved the target condition.
// This saves 2143 gas on transfers of initialized tokens.
// If the token is not burned, return `packed`. Otherwise, revert.
if (packed & _BITMASK_BURNED == 0) return packed;
}
_revert(OwnerQueryForNonexistentToken.selector);
}
/**
* @dev Returns the unpacked `TokenOwnership` struct from `packed`.
*/
function _unpackedOwnership(uint256 packed) private pure returns (TokenOwnership memory ownership) {
ownership.addr = address(uint160(packed));
ownership.startTimestamp = uint64(packed >> _BITPOS_START_TIMESTAMP);
ownership.burned = packed & _BITMASK_BURNED != 0;
ownership.extraData = uint24(packed >> _BITPOS_EXTRA_DATA);
}
/**
* @dev Packs ownership data into a single uint256.
*/
function _packOwnershipData(address owner, uint256 flags) private view returns (uint256 result) {
assembly {
// Mask `owner` to the lower 160 bits, in case the upper bits somehow aren't clean.
owner := and(owner, _BITMASK_ADDRESS)
// `owner | (block.timestamp << _BITPOS_START_TIMESTAMP) | flags`.
result := or(owner, or(shl(_BITPOS_START_TIMESTAMP, timestamp()), flags))
}
}
/**
* @dev Returns the `nextInitialized` flag set if `quantity` equals 1.
*/
function _nextInitializedFlag(uint256 quantity) private pure returns (uint256 result) {
// For branchless setting of the `nextInitialized` flag.
assembly {
// `(quantity == 1) << _BITPOS_NEXT_INITIALIZED`.
result := shl(_BITPOS_NEXT_INITIALIZED, eq(quantity, 1))
}
}
// =============================================================
// APPROVAL OPERATIONS
// =============================================================
/**
* @dev Gives permission to `to` to transfer `tokenId` token to another account. See {ERC721A-_approve}.
*
* Requirements:
*
* - The caller must own the token or be an approved operator.
*/
function approve(address to, uint256 tokenId) public payable virtual override {
_approve(to, tokenId, true);
}
/**
* @dev Returns the account approved for `tokenId` token.
*
* Requirements:
*
* - `tokenId` must exist.
*/
function getApproved(uint256 tokenId) public view virtual override returns (address) {
if (!_exists(tokenId)) _revert(ApprovalQueryForNonexistentToken.selector);
return ERC721AStorage.layout()._tokenApprovals[tokenId].value;
}
/**
* @dev Approve or remove `operator` as an operator for the caller.
* Operators can call {transferFrom} or {safeTransferFrom}
* for any token owned by the caller.
*
* Requirements:
*
* - The `operator` cannot be the caller.
*
* Emits an {ApprovalForAll} event.
*/
function setApprovalForAll(address operator, bool approved) public virtual override {
ERC721AStorage.layout()._operatorApprovals[_msgSenderERC721A()][operator] = approved;
emit ApprovalForAll(_msgSenderERC721A(), operator, approved);
}
/**
* @dev Returns if the `operator` is allowed to manage all of the assets of `owner`.
*
* See {setApprovalForAll}.
*/
function isApprovedForAll(address owner, address operator) public view virtual override returns (bool) {
return ERC721AStorage.layout()._operatorApprovals[owner][operator];
}
/**
* @dev Returns whether `tokenId` exists.
*
* Tokens can be managed by their owner or approved accounts via {approve} or {setApprovalForAll}.
*
* Tokens start existing when they are minted. See {_mint}.
*/
function _exists(uint256 tokenId) internal view virtual returns (bool result) {
if (_startTokenId() <= tokenId) {
if (tokenId > _sequentialUpTo())
return _packedOwnershipExists(ERC721AStorage.layout()._packedOwnerships[tokenId]);
if (tokenId < ERC721AStorage.layout()._currentIndex) {
uint256 packed;
while ((packed = ERC721AStorage.layout()._packedOwnerships[tokenId]) == 0) --tokenId;
result = packed & _BITMASK_BURNED == 0;
}
}
}
/**
* @dev Returns whether `packed` represents a token that exists.
*/
function _packedOwnershipExists(uint256 packed) private pure returns (bool result) {
assembly {
// The following is equivalent to `owner != address(0) && burned == false`.
// Symbolically tested.
result := gt(and(packed, _BITMASK_ADDRESS), and(packed, _BITMASK_BURNED))
}
}
/**
* @dev Returns whether `msgSender` is equal to `approvedAddress` or `owner`.
*/
function _isSenderApprovedOrOwner(
address approvedAddress,
address owner,
address msgSender
) private pure returns (bool result) {
assembly {
// Mask `owner` to the lower 160 bits, in case the upper bits somehow aren't clean.
owner := and(owner, _BITMASK_ADDRESS)
// Mask `msgSender` to the lower 160 bits, in case the upper bits somehow aren't clean.
msgSender := and(msgSender, _BITMASK_ADDRESS)
// `msgSender == owner || msgSender == approvedAddress`.
result := or(eq(msgSender, owner), eq(msgSender, approvedAddress))
}
}
/**
* @dev Returns the storage slot and value for the approved address of `tokenId`.
*/
function _getApprovedSlotAndAddress(uint256 tokenId)
private
view
returns (uint256 approvedAddressSlot, address approvedAddress)
{
ERC721AStorage.TokenApprovalRef storage tokenApproval = ERC721AStorage.layout()._tokenApprovals[tokenId];
// The following is equivalent to `approvedAddress = _tokenApprovals[tokenId].value`.
assembly {
approvedAddressSlot := tokenApproval.slot
approvedAddress := sload(approvedAddressSlot)
}
}
// =============================================================
// TRANSFER OPERATIONS
// =============================================================
/**
* @dev Transfers `tokenId` from `from` to `to`.
*
* Requirements:
*
* - `from` cannot be the zero address.
* - `to` cannot be the zero address.
* - `tokenId` token must be owned by `from`.
* - If the caller is not `from`, it must be approved to move this token
* by either {approve} or {setApprovalForAll}.
*
* Emits a {Transfer} event.
*/
function transferFrom(
address from,
address to,
uint256 tokenId
) public payable virtual override {
uint256 prevOwnershipPacked = _packedOwnershipOf(tokenId);
// Mask `from` to the lower 160 bits, in case the upper bits somehow aren't clean.
from = address(uint160(uint256(uint160(from)) & _BITMASK_ADDRESS));
if (address(uint160(prevOwnershipPacked)) != from) _revert(TransferFromIncorrectOwner.selector);
(uint256 approvedAddressSlot, address approvedAddress) = _getApprovedSlotAndAddress(tokenId);
// The nested ifs save around 20+ gas over a compound boolean condition.
if (!_isSenderApprovedOrOwner(approvedAddress, from, _msgSenderERC721A()))
if (!isApprovedForAll(from, _msgSenderERC721A())) _revert(TransferCallerNotOwnerNorApproved.selector);
_beforeTokenTransfers(from, to, tokenId, 1);
// Clear approvals from the previous owner.
assembly {
if approvedAddress {
// This is equivalent to `delete _tokenApprovals[tokenId]`.
sstore(approvedAddressSlot, 0)
}
}
// Underflow of the sender's balance is impossible because we check for
// ownership above and the recipient's balance can't realistically overflow.
// Counter overflow is incredibly unrealistic as `tokenId` would have to be 2**256.
unchecked {
// We can directly increment and decrement the balances.
--ERC721AStorage.layout()._packedAddressData[from]; // Updates: `balance -= 1`.
++ERC721AStorage.layout()._packedAddressData[to]; // Updates: `balance += 1`.
// Updates:
// - `address` to the next owner.
// - `startTimestamp` to the timestamp of transfering.
// - `burned` to `false`.
// - `nextInitialized` to `true`.
ERC721AStorage.layout()._packedOwnerships[tokenId] = _packOwnershipData(
to,
_BITMASK_NEXT_INITIALIZED | _nextExtraData(from, to, prevOwnershipPacked)
);
// If the next slot may not have been initialized (i.e. `nextInitialized == false`) .
if (prevOwnershipPacked & _BITMASK_NEXT_INITIALIZED == 0) {
uint256 nextTokenId = tokenId + 1;
// If the next slot's address is zero and not burned (i.e. packed value is zero).
if (ERC721AStorage.layout()._packedOwnerships[nextTokenId] == 0) {
// If the next slot is within bounds.
if (nextTokenId != ERC721AStorage.layout()._currentIndex) {
// Initialize the next slot to maintain correctness for `ownerOf(tokenId + 1)`.
ERC721AStorage.layout()._packedOwnerships[nextTokenId] = prevOwnershipPacked;
}
}
}
}
// Mask `to` to the lower 160 bits, in case the upper bits somehow aren't clean.
uint256 toMasked = uint256(uint160(to)) & _BITMASK_ADDRESS;
assembly {
// Emit the `Transfer` event.
log4(
0, // Start of data (0, since no data).
0, // End of data (0, since no data).
_TRANSFER_EVENT_SIGNATURE, // Signature.
from, // `from`.
toMasked, // `to`.
tokenId // `tokenId`.
)
}
if (toMasked == 0) _revert(TransferToZeroAddress.selector);
_afterTokenTransfers(from, to, tokenId, 1);
}
/**
* @dev Equivalent to `safeTransferFrom(from, to, tokenId, '')`.
*/
function safeTransferFrom(
address from,
address to,
uint256 tokenId
) public payable virtual override {
safeTransferFrom(from, to, tokenId, '');
}
/**
* @dev Safely transfers `tokenId` token from `from` to `to`.
*
* Requirements:
*
* - `from` cannot be the zero address.
* - `to` cannot be the zero address.
* - `tokenId` token must exist and be owned by `from`.
* - If the caller is not `from`, it must be approved to move this token
* by either {approve} or {setApprovalForAll}.
* - If `to` refers to a smart contract, it must implement
* {IERC721Receiver-onERC721Received}, which is called upon a safe transfer.
*
* Emits a {Transfer} event.
*/
function safeTransferFrom(
address from,
address to,
uint256 tokenId,
bytes memory _data
) public payable virtual override {
transferFrom(from, to, tokenId);
if (to.code.length != 0)
if (!_checkContractOnERC721Received(from, to, tokenId, _data)) {
_revert(TransferToNonERC721ReceiverImplementer.selector);
}
}
/**
* @dev Hook that is called before a set of serially-ordered token IDs
* are about to be transferred. This includes minting.
* And also called before burning one token.
*
* `startTokenId` - the first token ID to be transferred.
* `quantity` - the amount to be transferred.
*
* Calling conditions:
*
* - When `from` and `to` are both non-zero, `from`'s `tokenId` will be
* transferred to `to`.
* - When `from` is zero, `tokenId` will be minted for `to`.
* - When `to` is zero, `tokenId` will be burned by `from`.
* - `from` and `to` are never both zero.
*/
function _beforeTokenTransfers(
address from,
address to,
uint256 startTokenId,
uint256 quantity
) internal virtual {}
/**
* @dev Hook that is called after a set of serially-ordered token IDs
* have been transferred. This includes minting.
* And also called after one token has been burned.
*
* `startTokenId` - the first token ID to be transferred.
* `quantity` - the amount to be transferred.
*
* Calling conditions:
*
* - When `from` and `to` are both non-zero, `from`'s `tokenId` has been
* transferred to `to`.
* - When `from` is zero, `tokenId` has been minted for `to`.
* - When `to` is zero, `tokenId` has been burned by `from`.
* - `from` and `to` are never both zero.
*/
function _afterTokenTransfers(
address from,
address to,
uint256 startTokenId,
uint256 quantity
) internal virtual {}
/**
* @dev Private function to invoke {IERC721Receiver-onERC721Received} on a target contract.
*
* `from` - Previous owner of the given token ID.
* `to` - Target address that will receive the token.
* `tokenId` - Token ID to be transferred.
* `_data` - Optional data to send along with the call.
*
* Returns whether the call correctly returned the expected magic value.
*/
function _checkContractOnERC721Received(
address from,
address to,
uint256 tokenId,
bytes memory _data
) private returns (bool) {
try
ERC721A__IERC721ReceiverUpgradeable(to).onERC721Received(_msgSenderERC721A(), from, tokenId, _data)
returns (bytes4 retval) {
return retval == ERC721A__IERC721ReceiverUpgradeable(to).onERC721Received.selector;
} catch (bytes memory reason) {
if (reason.length == 0) {
_revert(TransferToNonERC721ReceiverImplementer.selector);
}
assembly {
revert(add(32, reason), mload(reason))
}
}
}
// =============================================================
// MINT OPERATIONS
// =============================================================
/**
* @dev Mints `quantity` tokens and transfers them to `to`.
*
* Requirements:
*
* - `to` cannot be the zero address.
* - `quantity` must be greater than 0.
*
* Emits a {Transfer} event for each mint.
*/
function _mint(address to, uint256 quantity) internal virtual {
uint256 startTokenId = ERC721AStorage.layout()._currentIndex;
if (quantity == 0) _revert(MintZeroQuantity.selector);
_beforeTokenTransfers(address(0), to, startTokenId, quantity);
// Overflows are incredibly unrealistic.
// `balance` and `numberMinted` have a maximum limit of 2**64.
// `tokenId` has a maximum limit of 2**256.
unchecked {
// Updates:
// - `address` to the owner.
// - `startTimestamp` to the timestamp of minting.
// - `burned` to `false`.
// - `nextInitialized` to `quantity == 1`.
ERC721AStorage.layout()._packedOwnerships[startTokenId] = _packOwnershipData(
to,
_nextInitializedFlag(quantity) | _nextExtraData(address(0), to, 0)
);
// Updates:
// - `balance += quantity`.
// - `numberMinted += quantity`.
//
// We can directly add to the `balance` and `numberMinted`.
ERC721AStorage.layout()._packedAddressData[to] += quantity * ((1 << _BITPOS_NUMBER_MINTED) | 1);
// Mask `to` to the lower 160 bits, in case the upper bits somehow aren't clean.
uint256 toMasked = uint256(uint160(to)) & _BITMASK_ADDRESS;
if (toMasked == 0) _revert(MintToZeroAddress.selector);
uint256 end = startTokenId + quantity;
uint256 tokenId = startTokenId;
if (end - 1 > _sequentialUpTo()) _revert(SequentialMintExceedsLimit.selector);
do {
assembly {
// Emit the `Transfer` event.
log4(
0, // Start of data (0, since no data).
0, // End of data (0, since no data).
_TRANSFER_EVENT_SIGNATURE, // Signature.
0, // `address(0)`.
toMasked, // `to`.
tokenId // `tokenId`.
)
}
// The `!=` check ensures that large values of `quantity`
// that overflows uint256 will make the loop run out of gas.
} while (++tokenId != end);
ERC721AStorage.layout()._currentIndex = end;
}
_afterTokenTransfers(address(0), to, startTokenId, quantity);
}
/**
* @dev Mints `quantity` tokens and transfers them to `to`.
*
* This function is intended for efficient minting only during contract creation.
*
* It emits only one {ConsecutiveTransfer} as defined in
* [ERC2309](https://eips.ethereum.org/EIPS/eip-2309),
* instead of a sequence of {Transfer} event(s).
*
* Calling this function outside of contract creation WILL make your contract
* non-compliant with the ERC721 standard.
* For full ERC721 compliance, substituting ERC721 {Transfer} event(s) with the ERC2309
* {ConsecutiveTransfer} event is only permissible during contract creation.
*
* Requirements:
*
* - `to` cannot be the zero address.
* - `quantity` must be greater than 0.
*
* Emits a {ConsecutiveTransfer} event.
*/
function _mintERC2309(address to, uint256 quantity) internal virtual {
uint256 startTokenId = ERC721AStorage.layout()._currentIndex;
if (to == address(0)) _revert(MintToZeroAddress.selector);
if (quantity == 0) _revert(MintZeroQuantity.selector);
if (quantity > _MAX_MINT_ERC2309_QUANTITY_LIMIT) _revert(MintERC2309QuantityExceedsLimit.selector);
_beforeTokenTransfers(address(0), to, startTokenId, quantity);
// Overflows are unrealistic due to the above check for `quantity` to be below the limit.
unchecked {
// Updates:
// - `balance += quantity`.
// - `numberMinted += quantity`.
//
// We can directly add to the `balance` and `numberMinted`.
ERC721AStorage.layout()._packedAddressData[to] += quantity * ((1 << _BITPOS_NUMBER_MINTED) | 1);
// Updates:
// - `address` to the owner.
// - `startTimestamp` to the timestamp of minting.
// - `burned` to `false`.
// - `nextInitialized` to `quantity == 1`.
ERC721AStorage.layout()._packedOwnerships[startTokenId] = _packOwnershipData(
to,
_nextInitializedFlag(quantity) | _nextExtraData(address(0), to, 0)
);
if (startTokenId + quantity - 1 > _sequentialUpTo()) _revert(SequentialMintExceedsLimit.selector);
emit ConsecutiveTransfer(startTokenId, startTokenId + quantity - 1, address(0), to);
ERC721AStorage.layout()._currentIndex = startTokenId + quantity;
}
_afterTokenTransfers(address(0), to, startTokenId, quantity);
}
/**
* @dev Safely mints `quantity` tokens and transfers them to `to`.
*
* Requirements:
*
* - If `to` refers to a smart contract, it must implement
* {IERC721Receiver-onERC721Received}, which is called for each safe transfer.
* - `quantity` must be greater than 0.
*
* See {_mint}.
*
* Emits a {Transfer} event for each mint.
*/
function _safeMint(
address to,
uint256 quantity,
bytes memory _data
) internal virtual {
_mint(to, quantity);
unchecked {
if (to.code.length != 0) {
uint256 end = ERC721AStorage.layout()._currentIndex;
uint256 index = end - quantity;
do {
if (!_checkContractOnERC721Received(address(0), to, index++, _data)) {
_revert(TransferToNonERC721ReceiverImplementer.selector);
}
} while (index < end);
// This prevents reentrancy to `_safeMint`.
// It does not prevent reentrancy to `_safeMintSpot`.
if (ERC721AStorage.layout()._currentIndex != end) revert();
}
}
}
/**
* @dev Equivalent to `_safeMint(to, quantity, '')`.
*/
function _safeMint(address to, uint256 quantity) internal virtual {
_safeMint(to, quantity, '');
}
/**
* @dev Mints a single token at `tokenId`.
*
* Note: A spot-minted `tokenId` that has been burned can be re-minted again.
*
* Requirements:
*
* - `to` cannot be the zero address.
* - `tokenId` must be greater than `_sequentialUpTo()`.
* - `tokenId` must not exist.
*
* Emits a {Transfer} event for each mint.
*/
function _mintSpot(address to, uint256 tokenId) internal virtual {
if (tokenId <= _sequentialUpTo()) _revert(SpotMintTokenIdTooSmall.selector);
uint256 prevOwnershipPacked = ERC721AStorage.layout()._packedOwnerships[tokenId];
if (_packedOwnershipExists(prevOwnershipPacked)) _revert(TokenAlreadyExists.selector);
_beforeTokenTransfers(address(0), to, tokenId, 1);
// Overflows are incredibly unrealistic.
// The `numberMinted` for `to` is incremented by 1, and has a max limit of 2**64 - 1.
// `_spotMinted` is incremented by 1, and has a max limit of 2**256 - 1.
unchecked {
// Updates:
// - `address` to the owner.
// - `startTimestamp` to the timestamp of minting.
// - `burned` to `false`.
// - `nextInitialized` to `true` (as `quantity == 1`).
ERC721AStorage.layout()._packedOwnerships[tokenId] = _packOwnershipData(
to,
_nextInitializedFlag(1) | _nextExtraData(address(0), to, prevOwnershipPacked)
);
// Updates:
// - `balance += 1`.
// - `numberMinted += 1`.
//
// We can directly add to the `balance` and `numberMinted`.
ERC721AStorage.layout()._packedAddressData[to] += (1 << _BITPOS_NUMBER_MINTED) | 1;
// Mask `to` to the lower 160 bits, in case the upper bits somehow aren't clean.
uint256 toMasked = uint256(uint160(to)) & _BITMASK_ADDRESS;
if (toMasked == 0) _revert(MintToZeroAddress.selector);
assembly {
// Emit the `Transfer` event.
log4(
0, // Start of data (0, since no data).
0, // End of data (0, since no data).
_TRANSFER_EVENT_SIGNATURE, // Signature.
0, // `address(0)`.
toMasked, // `to`.
tokenId // `tokenId`.
)
}
++ERC721AStorage.layout()._spotMinted;
}
_afterTokenTransfers(address(0), to, tokenId, 1);
}
/**
* @dev Safely mints a single token at `tokenId`.
*
* Note: A spot-minted `tokenId` that has been burned can be re-minted again.
*
* Requirements:
*
* - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}.
* - `tokenId` must be greater than `_sequentialUpTo()`.
* - `tokenId` must not exist.
*
* See {_mintSpot}.
*
* Emits a {Transfer} event.
*/
function _safeMintSpot(
address to,
uint256 tokenId,
bytes memory _data
) internal virtual {
_mintSpot(to, tokenId);
unchecked {
if (to.code.length != 0) {
uint256 currentSpotMinted = ERC721AStorage.layout()._spotMinted;
if (!_checkContractOnERC721Received(address(0), to, tokenId, _data)) {
_revert(TransferToNonERC721ReceiverImplementer.selector);
}
// This prevents reentrancy to `_safeMintSpot`.
// It does not prevent reentrancy to `_safeMint`.
if (ERC721AStorage.layout()._spotMinted != currentSpotMinted) revert();
}
}
}
/**
* @dev Equivalent to `_safeMintSpot(to, tokenId, '')`.
*/
function _safeMintSpot(address to, uint256 tokenId) internal virtual {
_safeMintSpot(to, tokenId, '');
}
// =============================================================
// APPROVAL OPERATIONS
// =============================================================
/**
* @dev Equivalent to `_approve(to, tokenId, false)`.
*/
function _approve(address to, uint256 tokenId) internal virtual {
_approve(to, tokenId, false);
}
/**
* @dev Gives permission to `to` to transfer `tokenId` token to another account.
* The approval is cleared when the token is transferred.
*
* Only a single account can be approved at a time, so approving the
* zero address clears previous approvals.
*
* Requirements:
*
* - `tokenId` must exist.
*
* Emits an {Approval} event.
*/
function _approve(
address to,
uint256 tokenId,
bool approvalCheck
) internal virtual {
address owner = ownerOf(tokenId);
if (approvalCheck && _msgSenderERC721A() != owner)
if (!isApprovedForAll(owner, _msgSenderERC721A())) {
_revert(ApprovalCallerNotOwnerNorApproved.selector);
}
ERC721AStorage.layout()._tokenApprovals[tokenId].value = to;
emit Approval(owner, to, tokenId);
}
// =============================================================
// BURN OPERATIONS
// =============================================================
/**
* @dev Equivalent to `_burn(tokenId, false)`.
*/
function _burn(uint256 tokenId) internal virtual {
_burn(tokenId, false);
}
/**
* @dev Destroys `tokenId`.
* The approval is cleared when the token is burned.
*
* Requirements:
*
* - `tokenId` must exist.
*
* Emits a {Transfer} event.
*/
function _burn(uint256 tokenId, bool approvalCheck) internal virtual {
uint256 prevOwnershipPacked = _packedOwnershipOf(tokenId);
address from = address(uint160(prevOwnershipPacked));
(uint256 approvedAddressSlot, address approvedAddress) = _getApprovedSlotAndAddress(tokenId);
if (approvalCheck) {
// The nested ifs save around 20+ gas over a compound boolean condition.
if (!_isSenderApprovedOrOwner(approvedAddress, from, _msgSenderERC721A()))
if (!isApprovedForAll(from, _msgSenderERC721A())) _revert(TransferCallerNotOwnerNorApproved.selector);
}
_beforeTokenTransfers(from, address(0), tokenId, 1);
// Clear approvals from the previous owner.
assembly {
if approvedAddress {
// This is equivalent to `delete _tokenApprovals[tokenId]`.
sstore(approvedAddressSlot, 0)
}
}
// Underflow of the sender's balance is impossible because we check for
// ownership above and the recipient's balance can't realistically overflow.
// Counter overflow is incredibly unrealistic as `tokenId` would have to be 2**256.
unchecked {
// Updates:
// - `balance -= 1`.
// - `numberBurned += 1`.
//
// We can directly decrement the balance, and increment the number burned.
// This is equivalent to `packed -= 1; packed += 1 << _BITPOS_NUMBER_BURNED;`.
ERC721AStorage.layout()._packedAddressData[from] += (1 << _BITPOS_NUMBER_BURNED) - 1;
// Updates:
// - `address` to the last owner.
// - `startTimestamp` to the timestamp of burning.
// - `burned` to `true`.
// - `nextInitialized` to `true`.
ERC721AStorage.layout()._packedOwnerships[tokenId] = _packOwnershipData(
from,
(_BITMASK_BURNED | _BITMASK_NEXT_INITIALIZED) | _nextExtraData(from, address(0), prevOwnershipPacked)
);
// If the next slot may not have been initialized (i.e. `nextInitialized == false`) .
if (prevOwnershipPacked & _BITMASK_NEXT_INITIALIZED == 0) {
uint256 nextTokenId = tokenId + 1;
// If the next slot's address is zero and not burned (i.e. packed value is zero).
if (ERC721AStorage.layout()._packedOwnerships[nextTokenId] == 0) {
// If the next slot is within bounds.
if (nextTokenId != ERC721AStorage.layout()._currentIndex) {
// Initialize the next slot to maintain correctness for `ownerOf(tokenId + 1)`.
ERC721AStorage.layout()._packedOwnerships[nextTokenId] = prevOwnershipPacked;
}
}
}
}
emit Transfer(from, address(0), tokenId);
_afterTokenTransfers(from, address(0), tokenId, 1);
// Overflow not possible, as `_burnCounter` cannot be exceed `_currentIndex + _spotMinted` times.
unchecked {
ERC721AStorage.layout()._burnCounter++;
}
}
// =============================================================
// EXTRA DATA OPERATIONS
// =============================================================
/**
* @dev Directly sets the extra data for the ownership data `index`.
*/
function _setExtraDataAt(uint256 index, uint24 extraData) internal virtual {
uint256 packed = ERC721AStorage.layout()._packedOwnerships[index];
if (packed == 0) _revert(OwnershipNotInitializedForExtraData.selector);
uint256 extraDataCasted;
// Cast `extraData` with assembly to avoid redundant masking.
assembly {
extraDataCasted := extraData
}
packed = (packed & _BITMASK_EXTRA_DATA_COMPLEMENT) | (extraDataCasted << _BITPOS_EXTRA_DATA);
ERC721AStorage.layout()._packedOwnerships[index] = packed;
}
/**
* @dev Called during each token transfer to set the 24bit `extraData` field.
* Intended to be overridden by the cosumer contract.
*
* `previousExtraData` - the value of `extraData` before transfer.
*
* Calling conditions:
*
* - When `from` and `to` are both non-zero, `from`'s `tokenId` will be
* transferred to `to`.
* - When `from` is zero, `tokenId` will be minted for `to`.
* - When `to` is zero, `tokenId` will be burned by `from`.
* - `from` and `to` are never both zero.
*/
function _extraData(
address from,
address to,
uint24 previousExtraData
) internal view virtual returns (uint24) {}
/**
* @dev Returns the next extra data for the packed ownership data.
* The returned result is shifted into position.
*/
function _nextExtraData(
address from,
address to,
uint256 prevOwnershipPacked
) private view returns (uint256) {
uint24 extraData = uint24(prevOwnershipPacked >> _BITPOS_EXTRA_DATA);
return uint256(_extraData(from, to, extraData)) << _BITPOS_EXTRA_DATA;
}
// =============================================================
// OTHER OPERATIONS
// =============================================================
/**
* @dev Returns the message sender (defaults to `msg.sender`).
*
* If you are writing GSN compatible contracts, you need to override this function.
*/
function _msgSenderERC721A() internal view virtual returns (address) {
return msg.sender;
}
/**
* @dev Converts a uint256 to its ASCII string decimal representation.
*/
function _toString(uint256 value) internal pure virtual returns (string memory str) {
assembly {
// The maximum value of a uint256 contains 78 digits (1 byte per digit), but
// we allocate 0xa0 bytes to keep the free memory pointer 32-byte word aligned.
// We will need 1 word for the trailing zeros padding, 1 word for the length,
// and 3 words for a maximum of 78 digits. Total: 5 * 0x20 = 0xa0.
let m := add(mload(0x40), 0xa0)
// Update the free memory pointer to allocate.
mstore(0x40, m)
// Assign the `str` to the end.
str := sub(m, 0x20)
// Zeroize the slot after the string.
mstore(str, 0)
// Cache the end of the memory to calculate the length later.
let end := str
// We write the string from rightmost digit to leftmost digit.
// The following is essentially a do-while loop that also handles the zero case.
// prettier-ignore
for { let temp := value } 1 {} {
str := sub(str, 1)
// Write the character to the pointer.
// The ASCII index of the '0' character is 48.
mstore8(str, add(48, mod(temp, 10)))
// Keep dividing `temp` until zero.
temp := div(temp, 10)
// prettier-ignore
if iszero(temp) { break }
}
let length := sub(end, str)
// Move the pointer 32 bytes leftwards to make room for the length.
str := sub(str, 0x20)
// Store the length.
mstore(str, length)
}
}
/**
* @dev For more efficient reverts.
*/
function _revert(bytes4 errorSelector) internal pure {
assembly {
mstore(0x00, errorSelector)
revert(0x00, 0x04)
}
}
}// SPDX-License-Identifier: MIT
// ERC721A Contracts v4.3.0
// Creator: Chiru Labs
pragma solidity ^0.8.4;
import './IERC721ABurnableUpgradeable.sol';
import '../ERC721AUpgradeable.sol';
import '../ERC721A__Initializable.sol';
/**
* @title ERC721ABurnable.
*
* @dev ERC721A token that can be irreversibly burned (destroyed).
*/
abstract contract ERC721ABurnableUpgradeable is
ERC721A__Initializable,
ERC721AUpgradeable,
IERC721ABurnableUpgradeable
{
function __ERC721ABurnable_init() internal onlyInitializingERC721A {
__ERC721ABurnable_init_unchained();
}
function __ERC721ABurnable_init_unchained() internal onlyInitializingERC721A {}
/**
* @dev Burns `tokenId`. See {ERC721A-_burn}.
*
* Requirements:
*
* - The caller must own `tokenId` or be an approved operator.
*/
function burn(uint256 tokenId) public virtual override {
_burn(tokenId, true);
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (access/Ownable.sol)
pragma solidity ^0.8.0;
import "../utils/ContextUpgradeable.sol";
import {Initializable} from "../proxy/utils/Initializable.sol";
/**
* @dev Contract module which provides a basic access control mechanism, where
* there is an account (an owner) that can be granted exclusive access to
* specific functions.
*
* By default, the owner account will be the one that deploys the contract. This
* can later be changed with {transferOwnership}.
*
* This module is used through inheritance. It will make available the modifier
* `onlyOwner`, which can be applied to your functions to restrict their use to
* the owner.
*/
abstract contract OwnableUpgradeable is Initializable, ContextUpgradeable {
address private _owner;
event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);
/**
* @dev Initializes the contract setting the deployer as the initial owner.
*/
function __Ownable_init() internal onlyInitializing {
__Ownable_init_unchained();
}
function __Ownable_init_unchained() internal onlyInitializing {
_transferOwnership(_msgSender());
}
/**
* @dev Throws if called by any account other than the owner.
*/
modifier onlyOwner() {
_checkOwner();
_;
}
/**
* @dev Returns the address of the current owner.
*/
function owner() public view virtual returns (address) {
return _owner;
}
/**
* @dev Throws if the sender is not the owner.
*/
function _checkOwner() internal view virtual {
require(owner() == _msgSender(), "Ownable: caller is not the owner");
}
/**
* @dev Leaves the contract without owner. It will not be possible to call
* `onlyOwner` functions. 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 {
require(newOwner != address(0), "Ownable: new owner is the zero address");
_transferOwnership(newOwner);
}
/**
* @dev Transfers ownership of the contract to a new account (`newOwner`).
* Internal function without access restriction.
*/
function _transferOwnership(address newOwner) internal virtual {
address oldOwner = _owner;
_owner = newOwner;
emit OwnershipTransferred(oldOwner, newOwner);
}
/**
* @dev This empty reserved space is put in place to allow future versions to add new
* variables without shifting down storage in the inheritance chain.
* See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps
*/
uint256[49] private __gap;
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (security/ReentrancyGuard.sol)
pragma solidity ^0.8.0;
import {Initializable} from "../proxy/utils/Initializable.sol";
/**
* @dev Contract module that helps prevent reentrant calls to a function.
*
* Inheriting from `ReentrancyGuard` will make the {nonReentrant} modifier
* available, which can be applied to functions to make sure there are no nested
* (reentrant) calls to them.
*
* Note that because there is a single `nonReentrant` guard, functions marked as
* `nonReentrant` may not call one another. This can be worked around by making
* those functions `private`, and then adding `external` `nonReentrant` entry
* points to them.
*
* TIP: If you would like to learn more about reentrancy and alternative ways
* to protect against it, check out our blog post
* https://blog.openzeppelin.com/reentrancy-after-istanbul/[Reentrancy After Istanbul].
*/
abstract contract ReentrancyGuardUpgradeable is Initializable {
// Booleans are more expensive than uint256 or any type that takes up a full
// word because each write operation emits an extra SLOAD to first read the
// slot's contents, replace the bits taken up by the boolean, and then write
// back. This is the compiler's defense against contract upgrades and
// pointer aliasing, and it cannot be disabled.
// The values being non-zero value makes deployment a bit more expensive,
// but in exchange the refund on every call to nonReentrant will be lower in
// amount. Since refunds are capped to a percentage of the total
// transaction's gas, it is best to keep them low in cases like this one, to
// increase the likelihood of the full refund coming into effect.
uint256 private constant _NOT_ENTERED = 1;
uint256 private constant _ENTERED = 2;
uint256 private _status;
function __ReentrancyGuard_init() internal onlyInitializing {
__ReentrancyGuard_init_unchained();
}
function __ReentrancyGuard_init_unchained() internal onlyInitializing {
_status = _NOT_ENTERED;
}
/**
* @dev Prevents a contract from calling itself, directly or indirectly.
* Calling a `nonReentrant` function from another `nonReentrant`
* function is not supported. It is possible to prevent this from happening
* by making the `nonReentrant` function external, and making it call a
* `private` function that does the actual work.
*/
modifier nonReentrant() {
_nonReentrantBefore();
_;
_nonReentrantAfter();
}
function _nonReentrantBefore() private {
// On the first call to nonReentrant, _status will be _NOT_ENTERED
require(_status != _ENTERED, "ReentrancyGuard: reentrant call");
// Any calls to nonReentrant after this point will fail
_status = _ENTERED;
}
function _nonReentrantAfter() private {
// By storing the original value once again, a refund is triggered (see
// https://eips.ethereum.org/EIPS/eip-2200)
_status = _NOT_ENTERED;
}
/**
* @dev Returns true if the reentrancy guard is currently set to "entered", which indicates there is a
* `nonReentrant` function in the call stack.
*/
function _reentrancyGuardEntered() internal view returns (bool) {
return _status == _ENTERED;
}
/**
* @dev This empty reserved space is put in place to allow future versions to add new
* variables without shifting down storage in the inheritance chain.
* See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps
*/
uint256[49] private __gap;
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (utils/introspection/ERC165Checker.sol)
pragma solidity ^0.8.0;
import "./IERC165.sol";
/**
* @dev Library used to query support of an interface declared via {IERC165}.
*
* Note that these functions return the actual result of the query: they do not
* `revert` if an interface is not supported. It is up to the caller to decide
* what to do in these cases.
*/
library ERC165Checker {
// As per the EIP-165 spec, no interface should ever match 0xffffffff
bytes4 private constant _INTERFACE_ID_INVALID = 0xffffffff;
/**
* @dev Returns true if `account` supports the {IERC165} interface.
*/
function supportsERC165(address account) internal view returns (bool) {
// Any contract that implements ERC165 must explicitly indicate support of
// InterfaceId_ERC165 and explicitly indicate non-support of InterfaceId_Invalid
return
supportsERC165InterfaceUnchecked(account, type(IERC165).interfaceId) &&
!supportsERC165InterfaceUnchecked(account, _INTERFACE_ID_INVALID);
}
/**
* @dev Returns true if `account` supports the interface defined by
* `interfaceId`. Support for {IERC165} itself is queried automatically.
*
* See {IERC165-supportsInterface}.
*/
function supportsInterface(address account, bytes4 interfaceId) internal view returns (bool) {
// query support of both ERC165 as per the spec and support of _interfaceId
return supportsERC165(account) && supportsERC165InterfaceUnchecked(account, interfaceId);
}
/**
* @dev Returns a boolean array where each value corresponds to the
* interfaces passed in and whether they're supported or not. This allows
* you to batch check interfaces for a contract where your expectation
* is that some interfaces may not be supported.
*
* See {IERC165-supportsInterface}.
*
* _Available since v3.4._
*/
function getSupportedInterfaces(
address account,
bytes4[] memory interfaceIds
) internal view returns (bool[] memory) {
// an array of booleans corresponding to interfaceIds and whether they're supported or not
bool[] memory interfaceIdsSupported = new bool[](interfaceIds.length);
// query support of ERC165 itself
if (supportsERC165(account)) {
// query support of each interface in interfaceIds
for (uint256 i = 0; i < interfaceIds.length; i++) {
interfaceIdsSupported[i] = supportsERC165InterfaceUnchecked(account, interfaceIds[i]);
}
}
return interfaceIdsSupported;
}
/**
* @dev Returns true if `account` supports all the interfaces defined in
* `interfaceIds`. Support for {IERC165} itself is queried automatically.
*
* Batch-querying can lead to gas savings by skipping repeated checks for
* {IERC165} support.
*
* See {IERC165-supportsInterface}.
*/
function supportsAllInterfaces(address account, bytes4[] memory interfaceIds) internal view returns (bool) {
// query support of ERC165 itself
if (!supportsERC165(account)) {
return false;
}
// query support of each interface in interfaceIds
for (uint256 i = 0; i < interfaceIds.length; i++) {
if (!supportsERC165InterfaceUnchecked(account, interfaceIds[i])) {
return false;
}
}
// all interfaces supported
return true;
}
/**
* @notice Query if a contract implements an interface, does not check ERC165 support
* @param account The address of the contract to query for support of an interface
* @param interfaceId The interface identifier, as specified in ERC-165
* @return true if the contract at account indicates support of the interface with
* identifier interfaceId, false otherwise
* @dev Assumes that account contains a contract that supports ERC165, otherwise
* the behavior of this method is undefined. This precondition can be checked
* with {supportsERC165}.
*
* Some precompiled contracts will falsely indicate support for a given interface, so caution
* should be exercised when using this function.
*
* Interface identification is specified in ERC-165.
*/
function supportsERC165InterfaceUnchecked(address account, bytes4 interfaceId) internal view returns (bool) {
// prepare call
bytes memory encodedParams = abi.encodeWithSelector(IERC165.supportsInterface.selector, interfaceId);
// perform static call
bool success;
uint256 returnSize;
uint256 returnValue;
assembly {
success := staticcall(30000, account, add(encodedParams, 0x20), mload(encodedParams), 0x00, 0x20)
returnSize := returndatasize()
returnValue := mload(0x00)
}
return success && returnSize >= 0x20 && returnValue > 0;
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (interfaces/IERC2981.sol)
pragma solidity ^0.8.0;
import "../utils/introspection/IERC165.sol";
/**
* @dev Interface for the NFT Royalty Standard.
*
* A standardized way to retrieve royalty payment information for non-fungible tokens (NFTs) to enable universal
* support for royalty payments across all NFT marketplaces and ecosystem participants.
*
* _Available since v4.5._
*/
interface IERC2981 is IERC165 {
/**
* @dev Returns how much royalty is owed and to whom, based on a sale price that may be denominated in any unit of
* exchange. The royalty amount is denominated and should be paid in that same unit of exchange.
*/
function royaltyInfo(
uint256 tokenId,
uint256 salePrice
) external view returns (address receiver, uint256 royaltyAmount);
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (token/ERC20/IERC20.sol)
pragma solidity ^0.8.0;
/**
* @dev Interface of the ERC20 standard as defined in the EIP.
*/
interface IERC20 {
/**
* @dev Emitted when `value` tokens are moved from one account (`from`) to
* another (`to`).
*
* Note that `value` may be zero.
*/
event Transfer(address indexed from, address indexed to, uint256 value);
/**
* @dev Emitted when the allowance of a `spender` for an `owner` is set by
* a call to {approve}. `value` is the new allowance.
*/
event Approval(address indexed owner, address indexed spender, uint256 value);
/**
* @dev Returns the amount of tokens in existence.
*/
function totalSupply() external view returns (uint256);
/**
* @dev Returns the amount of tokens owned by `account`.
*/
function balanceOf(address account) external view returns (uint256);
/**
* @dev Moves `amount` tokens from the caller's account to `to`.
*
* Returns a boolean value indicating whether the operation succeeded.
*
* Emits a {Transfer} event.
*/
function transfer(address to, uint256 amount) external returns (bool);
/**
* @dev Returns the remaining number of tokens that `spender` will be
* allowed to spend on behalf of `owner` through {transferFrom}. This is
* zero by default.
*
* This value changes when {approve} or {transferFrom} are called.
*/
function allowance(address owner, address spender) external view returns (uint256);
/**
* @dev Sets `amount` as the allowance of `spender` over the caller's tokens.
*
* Returns a boolean value indicating whether the operation succeeded.
*
* IMPORTANT: Beware that changing an allowance with this method brings the risk
* that someone may use both the old and the new allowance by unfortunate
* transaction ordering. One possible solution to mitigate this race
* condition is to first reduce the spender's allowance to 0 and set the
* desired value afterwards:
* https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729
*
* Emits an {Approval} event.
*/
function approve(address spender, uint256 amount) external returns (bool);
/**
* @dev Moves `amount` tokens from `from` to `to` using the
* allowance mechanism. `amount` is then deducted from the caller's
* allowance.
*
* Returns a boolean value indicating whether the operation succeeded.
*
* Emits a {Transfer} event.
*/
function transferFrom(address from, address to, uint256 amount) external returns (bool);
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.3) (token/ERC20/utils/SafeERC20.sol)
pragma solidity ^0.8.0;
import "../IERC20.sol";
import "../extensions/IERC20Permit.sol";
import "../../../utils/Address.sol";
/**
* @title SafeERC20
* @dev Wrappers around ERC20 operations that throw on failure (when the token
* contract returns false). Tokens that return no value (and instead revert or
* throw on failure) are also supported, non-reverting calls are assumed to be
* successful.
* To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,
* which allows you to call the safe operations as `token.safeTransfer(...)`, etc.
*/
library SafeERC20 {
using Address for address;
/**
* @dev Transfer `value` amount of `token` from the calling contract to `to`. If `token` returns no value,
* non-reverting calls are assumed to be successful.
*/
function safeTransfer(IERC20 token, address to, uint256 value) internal {
_callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value));
}
/**
* @dev Transfer `value` amount of `token` from `from` to `to`, spending the approval given by `from` to the
* calling contract. If `token` returns no value, non-reverting calls are assumed to be successful.
*/
function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal {
_callOptionalReturn(token, abi.encodeWithSelector(token.transferFrom.selector, from, to, value));
}
/**
* @dev Deprecated. This function has issues similar to the ones found in
* {IERC20-approve}, and its usage is discouraged.
*
* Whenever possible, use {safeIncreaseAllowance} and
* {safeDecreaseAllowance} instead.
*/
function safeApprove(IERC20 token, address spender, uint256 value) internal {
// safeApprove should only be called when setting an initial allowance,
// or when resetting it to zero. To increase and decrease it, use
// 'safeIncreaseAllowance' and 'safeDecreaseAllowance'
require(
(value == 0) || (token.allowance(address(this), spender) == 0),
"SafeERC20: approve from non-zero to non-zero allowance"
);
_callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, value));
}
/**
* @dev Increase the calling contract's allowance toward `spender` by `value`. If `token` returns no value,
* non-reverting calls are assumed to be successful.
*/
function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal {
uint256 oldAllowance = token.allowance(address(this), spender);
_callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, oldAllowance + value));
}
/**
* @dev Decrease the calling contract's allowance toward `spender` by `value`. If `token` returns no value,
* non-reverting calls are assumed to be successful.
*/
function safeDecreaseAllowance(IERC20 token, address spender, uint256 value) internal {
unchecked {
uint256 oldAllowance = token.allowance(address(this), spender);
require(oldAllowance >= value, "SafeERC20: decreased allowance below zero");
_callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, oldAllowance - value));
}
}
/**
* @dev Set the calling contract's allowance toward `spender` to `value`. If `token` returns no value,
* non-reverting calls are assumed to be successful. Meant to be used with tokens that require the approval
* to be set to zero before setting it to a non-zero value, such as USDT.
*/
function forceApprove(IERC20 token, address spender, uint256 value) internal {
bytes memory approvalCall = abi.encodeWithSelector(token.approve.selector, spender, value);
if (!_callOptionalReturnBool(token, approvalCall)) {
_callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, 0));
_callOptionalReturn(token, approvalCall);
}
}
/**
* @dev Use a ERC-2612 signature to set the `owner` approval toward `spender` on `token`.
* Revert on invalid signature.
*/
function safePermit(
IERC20Permit token,
address owner,
address spender,
uint256 value,
uint256 deadline,
uint8 v,
bytes32 r,
bytes32 s
) internal {
uint256 nonceBefore = token.nonces(owner);
token.permit(owner, spender, value, deadline, v, r, s);
uint256 nonceAfter = token.nonces(owner);
require(nonceAfter == nonceBefore + 1, "SafeERC20: permit did not succeed");
}
/**
* @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement
* on the return value: the return value is optional (but if data is returned, it must not be false).
* @param token The token targeted by the call.
* @param data The call data (encoded using abi.encode or one of its variants).
*/
function _callOptionalReturn(IERC20 token, bytes memory data) private {
// We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since
// we're implementing it ourselves. We use {Address-functionCall} to perform this call, which verifies that
// the target address contains contract code and also asserts for success in the low-level call.
bytes memory returndata = address(token).functionCall(data, "SafeERC20: low-level call failed");
require(returndata.length == 0 || abi.decode(returndata, (bool)), "SafeERC20: ERC20 operation did not succeed");
}
/**
* @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement
* on the return value: the return value is optional (but if data is returned, it must not be false).
* @param token The token targeted by the call.
* @param data The call data (encoded using abi.encode or one of its variants).
*
* This is a variant of {_callOptionalReturn} that silents catches all reverts and returns a bool instead.
*/
function _callOptionalReturnBool(IERC20 token, bytes memory data) private returns (bool) {
// We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since
// we're implementing it ourselves. We cannot use {Address-functionCall} here since this should return false
// and not revert is the subcall reverts.
(bool success, bytes memory returndata) = address(token).call(data);
return
success && (returndata.length == 0 || abi.decode(returndata, (bool))) && Address.isContract(address(token));
}
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
import "@openzeppelin/contracts/interfaces/IERC165.sol";
import "@openzeppelin/contracts/interfaces/IERC721.sol";
// from OpenZeppelin Contracts draft https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/interfaces/IERC4906.sol
/// @title EIP-721 Metadata Update Extension
interface IERC4906 is IERC165, IERC721 {
/// @dev This event emits when the metadata of a token is changed.
/// So that the third-party platforms such as NFT market could
/// timely update the images and related attributes of the NFT.
event MetadataUpdate(uint256 _tokenId);
/// @dev This event emits when the metadata of a range of tokens is changed.
/// So that the third-party platforms such as NFT market could
/// timely update the images and related attributes of the NFTs.
event BatchMetadataUpdate(uint256 _fromTokenId, uint256 _toTokenId);
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.9;
import "@openzeppelin/contracts/utils/introspection/IERC165.sol";
interface INFTExtension is IERC165 {}
interface INFTURIExtension is INFTExtension {
function tokenURI(uint256 tokenId) external view returns (string memory);
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.9;
import "@openzeppelin/contracts/utils/introspection/IERC165.sol";
interface IRenderer is IERC165 {
function render(uint256 tokenId, bytes memory optional) external view returns (string memory);
function tokenURI(uint256 tokenId) external view returns (string memory);
function tokenHTML(uint256 tokenId, bytes32 dna, bytes calldata optional) external view returns (string memory);
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.9;
address constant ARTGENE_PROXY_IMPLEMENTATION = 0x8A13A3ea74aC471dF04a1A04666059EF8F6e6be9;
uint256 constant ARTGENE_MAX_SUPPLY_OPEN_EDITION = 0;
struct MintConfig {
uint256 publicPrice;
uint256 maxTokensPerMint;
uint256 maxTokensPerWallet;
uint256 royaltyFee;
address payoutReceiver;
bool shouldLockPayoutReceiver;
uint32 startTimestamp;
uint32 endTimestamp;
}
interface IArtgene721 {
// ------ View functions ------
function saleStarted() external view returns (bool);
function isExtensionAdded(address extension) external view returns (bool);
function renderer() external view returns (address);
/**
Extra information stored for each tokenId. Optional, provided on mint
*/
function data(uint256 tokenId) external view returns (bytes32);
// ------ Mint functions ------
/**
Mint from NFTExtension contract. Optionally provide data parameter.
*/
function mintExternal(
uint256 amount,
address to,
bytes32 data
) external payable;
// ------ Admin functions ------
function addExtension(address extension) external;
function revokeExtension(address extension) external;
function withdraw() external;
// ------ View functions ------
/**
Recommended royalty for tokenId sale.
*/
function royaltyInfo(
uint256 tokenId,
uint256 salePrice
) external view returns (address receiver, uint256 royaltyAmount);
// ------ Admin functions ------
function setRoyaltyReceiver(address receiver) external;
function setRoyaltyFee(uint256 fee) external;
// ------ IERC4906 ------
/// @dev This event emits when the metadata of a token is changed.
/// So that the third-party platforms such as NFT market could
/// timely update the images and related attributes of the NFT.
event MetadataUpdate(uint256 _tokenId);
/// @dev This event emits when the metadata of a range of tokens is changed.
/// So that the third-party platforms such as NFT market could
/// timely update the images and related attributes of the NFTs.
event BatchMetadataUpdate(uint256 _fromTokenId, uint256 _toTokenId);
}
interface IArtgene721Implementation {
function initialize(
string memory _name,
string memory _symbol,
uint256 _maxSupply,
uint256 _nReserved,
bool _startAtOne,
string memory uri,
MintConfig memory config
) external;
}// SPDX-License-Identifier: MIT
// ERC721A Contracts v4.3.0
// Creator: Chiru Labs
pragma solidity ^0.8.4;
/**
* @dev Interface of ERC721A.
*/
interface IERC721AUpgradeable {
/**
* The caller must own the token or be an approved operator.
*/
error ApprovalCallerNotOwnerNorApproved();
/**
* The token does not exist.
*/
error ApprovalQueryForNonexistentToken();
/**
* Cannot query the balance for the zero address.
*/
error BalanceQueryForZeroAddress();
/**
* Cannot mint to the zero address.
*/
error MintToZeroAddress();
/**
* The quantity of tokens minted must be more than zero.
*/
error MintZeroQuantity();
/**
* The token does not exist.
*/
error OwnerQueryForNonexistentToken();
/**
* The caller must own the token or be an approved operator.
*/
error TransferCallerNotOwnerNorApproved();
/**
* The token must be owned by `from`.
*/
error TransferFromIncorrectOwner();
/**
* Cannot safely transfer to a contract that does not implement the
* ERC721Receiver interface.
*/
error TransferToNonERC721ReceiverImplementer();
/**
* Cannot transfer to the zero address.
*/
error TransferToZeroAddress();
/**
* The token does not exist.
*/
error URIQueryForNonexistentToken();
/**
* The `quantity` minted with ERC2309 exceeds the safety limit.
*/
error MintERC2309QuantityExceedsLimit();
/**
* The `extraData` cannot be set on an unintialized ownership slot.
*/
error OwnershipNotInitializedForExtraData();
/**
* `_sequentialUpTo()` must be greater than `_startTokenId()`.
*/
error SequentialUpToTooSmall();
/**
* The `tokenId` of a sequential mint exceeds `_sequentialUpTo()`.
*/
error SequentialMintExceedsLimit();
/**
* Spot minting requires a `tokenId` greater than `_sequentialUpTo()`.
*/
error SpotMintTokenIdTooSmall();
/**
* Cannot mint over a token that already exists.
*/
error TokenAlreadyExists();
/**
* The feature is not compatible with spot mints.
*/
error NotCompatibleWithSpotMints();
// =============================================================
// STRUCTS
// =============================================================
struct TokenOwnership {
// The address of the owner.
address addr;
// Stores the start time of ownership with minimal overhead for tokenomics.
uint64 startTimestamp;
// Whether the token has been burned.
bool burned;
// Arbitrary data similar to `startTimestamp` that can be set via {_extraData}.
uint24 extraData;
}
// =============================================================
// TOKEN COUNTERS
// =============================================================
/**
* @dev Returns the total number of tokens in existence.
* Burned tokens will reduce the count.
* To get the total number of tokens minted, please see {_totalMinted}.
*/
function totalSupply() external view returns (uint256);
// =============================================================
// IERC165
// =============================================================
/**
* @dev Returns true if this contract implements the interface defined by
* `interfaceId`. See the corresponding
* [EIP section](https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified)
* to learn more about how these ids are created.
*
* This function call must use less than 30000 gas.
*/
function supportsInterface(bytes4 interfaceId) external view returns (bool);
// =============================================================
// IERC721
// =============================================================
/**
* @dev Emitted when `tokenId` token is transferred from `from` to `to`.
*/
event Transfer(address indexed from, address indexed to, uint256 indexed tokenId);
/**
* @dev Emitted when `owner` enables `approved` to manage the `tokenId` token.
*/
event Approval(address indexed owner, address indexed approved, uint256 indexed tokenId);
/**
* @dev Emitted when `owner` enables or disables
* (`approved`) `operator` to manage all of its assets.
*/
event ApprovalForAll(address indexed owner, address indexed operator, bool approved);
/**
* @dev Returns the number of tokens in `owner`'s account.
*/
function balanceOf(address owner) external view returns (uint256 balance);
/**
* @dev Returns the owner of the `tokenId` token.
*
* Requirements:
*
* - `tokenId` must exist.
*/
function ownerOf(uint256 tokenId) external view returns (address owner);
/**
* @dev Safely transfers `tokenId` token from `from` to `to`,
* checking first that contract recipients are aware of the ERC721 protocol
* to prevent tokens from being forever locked.
*
* Requirements:
*
* - `from` cannot be the zero address.
* - `to` cannot be the zero address.
* - `tokenId` token must exist and be owned by `from`.
* - If the caller is not `from`, it must be have been allowed to move
* this token by either {approve} or {setApprovalForAll}.
* - If `to` refers to a smart contract, it must implement
* {IERC721Receiver-onERC721Received}, which is called upon a safe transfer.
*
* Emits a {Transfer} event.
*/
function safeTransferFrom(
address from,
address to,
uint256 tokenId,
bytes calldata data
) external payable;
/**
* @dev Equivalent to `safeTransferFrom(from, to, tokenId, '')`.
*/
function safeTransferFrom(
address from,
address to,
uint256 tokenId
) external payable;
/**
* @dev Transfers `tokenId` from `from` to `to`.
*
* WARNING: Usage of this method is discouraged, use {safeTransferFrom}
* whenever possible.
*
* Requirements:
*
* - `from` cannot be the zero address.
* - `to` cannot be the zero address.
* - `tokenId` token must be owned by `from`.
* - If the caller is not `from`, it must be approved to move this token
* by either {approve} or {setApprovalForAll}.
*
* Emits a {Transfer} event.
*/
function transferFrom(
address from,
address to,
uint256 tokenId
) external payable;
/**
* @dev Gives permission to `to` to transfer `tokenId` token to another account.
* The approval is cleared when the token is transferred.
*
* Only a single account can be approved at a time, so approving the
* zero address clears previous approvals.
*
* Requirements:
*
* - The caller must own the token or be an approved operator.
* - `tokenId` must exist.
*
* Emits an {Approval} event.
*/
function approve(address to, uint256 tokenId) external payable;
/**
* @dev Approve or remove `operator` as an operator for the caller.
* Operators can call {transferFrom} or {safeTransferFrom}
* for any token owned by the caller.
*
* Requirements:
*
* - The `operator` cannot be the caller.
*
* Emits an {ApprovalForAll} event.
*/
function setApprovalForAll(address operator, bool _approved) external;
/**
* @dev Returns the account approved for `tokenId` token.
*
* Requirements:
*
* - `tokenId` must exist.
*/
function getApproved(uint256 tokenId) external view returns (address operator);
/**
* @dev Returns if the `operator` is allowed to manage all of the assets of `owner`.
*
* See {setApprovalForAll}.
*/
function isApprovedForAll(address owner, address operator) external view returns (bool);
// =============================================================
// IERC721Metadata
// =============================================================
/**
* @dev Returns the token collection name.
*/
function name() external view returns (string memory);
/**
* @dev Returns the token collection symbol.
*/
function symbol() external view returns (string memory);
/**
* @dev Returns the Uniform Resource Identifier (URI) for `tokenId` token.
*/
function tokenURI(uint256 tokenId) external view returns (string memory);
// =============================================================
// IERC2309
// =============================================================
/**
* @dev Emitted when tokens in `fromTokenId` to `toTokenId`
* (inclusive) is transferred from `from` to `to`, as defined in the
* [ERC2309](https://eips.ethereum.org/EIPS/eip-2309) standard.
*
* See {_mintERC2309} for more details.
*/
event ConsecutiveTransfer(uint256 indexed fromTokenId, uint256 toTokenId, address indexed from, address indexed to);
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
library ERC721AStorage {
// Bypass for a `--via-ir` bug (https://github.com/chiru-labs/ERC721A/pull/364).
struct TokenApprovalRef {
address value;
}
struct Layout {
// =============================================================
// STORAGE
// =============================================================
// The next token ID to be minted.
uint256 _currentIndex;
// The number of tokens burned.
uint256 _burnCounter;
// Token name
string _name;
// Token symbol
string _symbol;
// Mapping from token ID to ownership details
// An empty struct value does not necessarily mean the token is unowned.
// See {_packedOwnershipOf} implementation for details.
//
// Bits Layout:
// - [0..159] `addr`
// - [160..223] `startTimestamp`
// - [224] `burned`
// - [225] `nextInitialized`
// - [232..255] `extraData`
mapping(uint256 => uint256) _packedOwnerships;
// Mapping owner address to address data.
//
// Bits Layout:
// - [0..63] `balance`
// - [64..127] `numberMinted`
// - [128..191] `numberBurned`
// - [192..255] `aux`
mapping(address => uint256) _packedAddressData;
// Mapping from token ID to approved address.
mapping(uint256 => ERC721AStorage.TokenApprovalRef) _tokenApprovals;
// Mapping from owner to operator approvals
mapping(address => mapping(address => bool)) _operatorApprovals;
// The amount of tokens minted above `_sequentialUpTo()`.
// We call these spot mints (i.e. non-sequential mints).
uint256 _spotMinted;
}
bytes32 internal constant STORAGE_SLOT = keccak256('ERC721A.contracts.storage.ERC721A');
function layout() internal pure returns (Layout storage l) {
bytes32 slot = STORAGE_SLOT;
assembly {
l.slot := slot
}
}
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
/**
* @dev This is a base contract to aid in writing upgradeable diamond facet contracts, or any kind of contract that will be deployed
* behind a proxy. Since proxied contracts do not make use of a constructor, it's common to move constructor logic to an
* external initializer function, usually called `initialize`. It then becomes necessary to protect this initializer
* function so it can only be called once. The {initializer} modifier provided by this contract will have this effect.
*
* TIP: To avoid leaving the proxy in an uninitialized state, the initializer function should be called as early as
* possible by providing the encoded function call as the `_data` argument to {ERC1967Proxy-constructor}.
*
* CAUTION: When used with inheritance, manual care must be taken to not invoke a parent initializer twice, or to ensure
* that all initializers are idempotent. This is not verified automatically as constructors are by Solidity.
*/
import {ERC721A__InitializableStorage} from './ERC721A__InitializableStorage.sol';
abstract contract ERC721A__Initializable {
using ERC721A__InitializableStorage for ERC721A__InitializableStorage.Layout;
/**
* @dev Modifier to protect an initializer function from being invoked twice.
*/
modifier initializerERC721A() {
// If the contract is initializing we ignore whether _initialized is set in order to support multiple
// inheritance patterns, but we only do this in the context of a constructor, because in other contexts the
// contract may have been reentered.
require(
ERC721A__InitializableStorage.layout()._initializing
? _isConstructor()
: !ERC721A__InitializableStorage.layout()._initialized,
'ERC721A__Initializable: contract is already initialized'
);
bool isTopLevelCall = !ERC721A__InitializableStorage.layout()._initializing;
if (isTopLevelCall) {
ERC721A__InitializableStorage.layout()._initializing = true;
ERC721A__InitializableStorage.layout()._initialized = true;
}
_;
if (isTopLevelCall) {
ERC721A__InitializableStorage.layout()._initializing = false;
}
}
/**
* @dev Modifier to protect an initialization function so that it can only be invoked by functions with the
* {initializer} modifier, directly or indirectly.
*/
modifier onlyInitializingERC721A() {
require(
ERC721A__InitializableStorage.layout()._initializing,
'ERC721A__Initializable: contract is not initializing'
);
_;
}
/// @dev Returns true if and only if the function is running in the constructor
function _isConstructor() private view returns (bool) {
// extcodesize checks the size of the code stored in an address, and
// address returns the current address. Since the code is still not
// deployed when running a constructor, any checks on its code size will
// yield zero, making it an effective way to detect if a contract is
// under construction or not.
address self = address(this);
uint256 cs;
assembly {
cs := extcodesize(self)
}
return cs == 0;
}
}// SPDX-License-Identifier: MIT
// ERC721A Contracts v4.3.0
// Creator: Chiru Labs
pragma solidity ^0.8.4;
import '../IERC721AUpgradeable.sol';
/**
* @dev Interface of ERC721ABurnable.
*/
interface IERC721ABurnableUpgradeable is IERC721AUpgradeable {
/**
* @dev Burns `tokenId`. See {ERC721A-_burn}.
*
* Requirements:
*
* - The caller must own `tokenId` or be an approved operator.
*/
function burn(uint256 tokenId) external;
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.4) (utils/Context.sol)
pragma solidity ^0.8.0;
import {Initializable} from "../proxy/utils/Initializable.sol";
/**
* @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 ContextUpgradeable is Initializable {
function __Context_init() internal onlyInitializing {
}
function __Context_init_unchained() internal onlyInitializing {
}
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;
}
/**
* @dev This empty reserved space is put in place to allow future versions to add new
* variables without shifting down storage in the inheritance chain.
* See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps
*/
uint256[50] private __gap;
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (proxy/utils/Initializable.sol)
pragma solidity ^0.8.2;
import "../../utils/AddressUpgradeable.sol";
/**
* @dev This is a base contract to aid in writing upgradeable contracts, or any kind of contract that will be deployed
* behind a proxy. Since proxied contracts do not make use of a constructor, it's common to move constructor logic to an
* external initializer function, usually called `initialize`. It then becomes necessary to protect this initializer
* function so it can only be called once. The {initializer} modifier provided by this contract will have this effect.
*
* The initialization functions use a version number. Once a version number is used, it is consumed and cannot be
* reused. This mechanism prevents re-execution of each "step" but allows the creation of new initialization steps in
* case an upgrade adds a module that needs to be initialized.
*
* For example:
*
* [.hljs-theme-light.nopadding]
* ```solidity
* contract MyToken is ERC20Upgradeable {
* function initialize() initializer public {
* __ERC20_init("MyToken", "MTK");
* }
* }
*
* contract MyTokenV2 is MyToken, ERC20PermitUpgradeable {
* function initializeV2() reinitializer(2) public {
* __ERC20Permit_init("MyToken");
* }
* }
* ```
*
* TIP: To avoid leaving the proxy in an uninitialized state, the initializer function should be called as early as
* possible by providing the encoded function call as the `_data` argument to {ERC1967Proxy-constructor}.
*
* CAUTION: When used with inheritance, manual care must be taken to not invoke a parent initializer twice, or to ensure
* that all initializers are idempotent. This is not verified automatically as constructors are by Solidity.
*
* [CAUTION]
* ====
* Avoid leaving a contract uninitialized.
*
* An uninitialized contract can be taken over by an attacker. This applies to both a proxy and its implementation
* contract, which may impact the proxy. To prevent the implementation contract from being used, you should invoke
* the {_disableInitializers} function in the constructor to automatically lock it when it is deployed:
*
* [.hljs-theme-light.nopadding]
* ```
* /// @custom:oz-upgrades-unsafe-allow constructor
* constructor() {
* _disableInitializers();
* }
* ```
* ====
*/
abstract contract Initializable {
/**
* @dev Indicates that the contract has been initialized.
* @custom:oz-retyped-from bool
*/
uint8 private _initialized;
/**
* @dev Indicates that the contract is in the process of being initialized.
*/
bool private _initializing;
/**
* @dev Triggered when the contract has been initialized or reinitialized.
*/
event Initialized(uint8 version);
/**
* @dev A modifier that defines a protected initializer function that can be invoked at most once. In its scope,
* `onlyInitializing` functions can be used to initialize parent contracts.
*
* Similar to `reinitializer(1)`, except that functions marked with `initializer` can be nested in the context of a
* constructor.
*
* Emits an {Initialized} event.
*/
modifier initializer() {
bool isTopLevelCall = !_initializing;
require(
(isTopLevelCall && _initialized < 1) || (!AddressUpgradeable.isContract(address(this)) && _initialized == 1),
"Initializable: contract is already initialized"
);
_initialized = 1;
if (isTopLevelCall) {
_initializing = true;
}
_;
if (isTopLevelCall) {
_initializing = false;
emit Initialized(1);
}
}
/**
* @dev A modifier that defines a protected reinitializer function that can be invoked at most once, and only if the
* contract hasn't been initialized to a greater version before. In its scope, `onlyInitializing` functions can be
* used to initialize parent contracts.
*
* A reinitializer may be used after the original initialization step. This is essential to configure modules that
* are added through upgrades and that require initialization.
*
* When `version` is 1, this modifier is similar to `initializer`, except that functions marked with `reinitializer`
* cannot be nested. If one is invoked in the context of another, execution will revert.
*
* Note that versions can jump in increments greater than 1; this implies that if multiple reinitializers coexist in
* a contract, executing them in the right order is up to the developer or operator.
*
* WARNING: setting the version to 255 will prevent any future reinitialization.
*
* Emits an {Initialized} event.
*/
modifier reinitializer(uint8 version) {
require(!_initializing && _initialized < version, "Initializable: contract is already initialized");
_initialized = version;
_initializing = true;
_;
_initializing = false;
emit Initialized(version);
}
/**
* @dev Modifier to protect an initialization function so that it can only be invoked by functions with the
* {initializer} and {reinitializer} modifiers, directly or indirectly.
*/
modifier onlyInitializing() {
require(_initializing, "Initializable: contract is not initializing");
_;
}
/**
* @dev Locks the contract, preventing any future reinitialization. This cannot be part of an initializer call.
* Calling this in the constructor of a contract will prevent that contract from being initialized or reinitialized
* to any version. It is recommended to use this to lock implementation contracts that are designed to be called
* through proxies.
*
* Emits an {Initialized} event the first time it is successfully executed.
*/
function _disableInitializers() internal virtual {
require(!_initializing, "Initializable: contract is initializing");
if (_initialized != type(uint8).max) {
_initialized = type(uint8).max;
emit Initialized(type(uint8).max);
}
}
/**
* @dev Returns the highest version that has been initialized. See {reinitializer}.
*/
function _getInitializedVersion() internal view returns (uint8) {
return _initialized;
}
/**
* @dev Returns `true` if the contract is currently initializing. See {onlyInitializing}.
*/
function _isInitializing() internal view returns (bool) {
return _initializing;
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (utils/introspection/IERC165.sol)
pragma solidity ^0.8.0;
/**
* @dev Interface of the ERC165 standard, as defined in the
* https://eips.ethereum.org/EIPS/eip-165[EIP].
*
* Implementers can declare support of contract interfaces, which can then be
* queried by others ({ERC165Checker}).
*
* For an implementation, see {ERC165}.
*/
interface IERC165 {
/**
* @dev Returns true if this contract implements the interface defined by
* `interfaceId`. See the corresponding
* https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]
* to learn more about how these ids are created.
*
* This function call must use less than 30 000 gas.
*/
function supportsInterface(bytes4 interfaceId) external view returns (bool);
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.4) (token/ERC20/extensions/IERC20Permit.sol)
pragma solidity ^0.8.0;
/**
* @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in
* https://eips.ethereum.org/EIPS/eip-2612[EIP-2612].
*
* Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by
* presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't
* need to send a transaction, and thus is not required to hold Ether at all.
*
* ==== Security Considerations
*
* There are two important considerations concerning the use of `permit`. The first is that a valid permit signature
* expresses an allowance, and it should not be assumed to convey additional meaning. In particular, it should not be
* considered as an intention to spend the allowance in any specific way. The second is that because permits have
* built-in replay protection and can be submitted by anyone, they can be frontrun. A protocol that uses permits should
* take this into consideration and allow a `permit` call to fail. Combining these two aspects, a pattern that may be
* generally recommended is:
*
* ```solidity
* function doThingWithPermit(..., uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s) public {
* try token.permit(msg.sender, address(this), value, deadline, v, r, s) {} catch {}
* doThing(..., value);
* }
*
* function doThing(..., uint256 value) public {
* token.safeTransferFrom(msg.sender, address(this), value);
* ...
* }
* ```
*
* Observe that: 1) `msg.sender` is used as the owner, leaving no ambiguity as to the signer intent, and 2) the use of
* `try/catch` allows the permit to fail and makes the code tolerant to frontrunning. (See also
* {SafeERC20-safeTransferFrom}).
*
* Additionally, note that smart contract wallets (such as Argent or Safe) are not able to produce permit signatures, so
* contracts should have entry points that don't rely on permit.
*/
interface IERC20Permit {
/**
* @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens,
* given ``owner``'s signed approval.
*
* IMPORTANT: The same issues {IERC20-approve} has related to transaction
* ordering also apply here.
*
* Emits an {Approval} event.
*
* Requirements:
*
* - `spender` cannot be the zero address.
* - `deadline` must be a timestamp in the future.
* - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner`
* over the EIP712-formatted function arguments.
* - the signature must use ``owner``'s current nonce (see {nonces}).
*
* For more information on the signature format, see the
* https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP
* section].
*
* CAUTION: See Security Considerations above.
*/
function permit(
address owner,
address spender,
uint256 value,
uint256 deadline,
uint8 v,
bytes32 r,
bytes32 s
) external;
/**
* @dev Returns the current nonce for `owner`. This value must be
* included whenever a signature is generated for {permit}.
*
* Every successful call to {permit} increases ``owner``'s nonce by one. This
* prevents a signature from being used multiple times.
*/
function nonces(address owner) external view returns (uint256);
/**
* @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}.
*/
// solhint-disable-next-line func-name-mixedcase
function DOMAIN_SEPARATOR() external view returns (bytes32);
}// SPDX-License-Identifier: MIT // OpenZeppelin Contracts v4.4.1 (interfaces/IERC165.sol) pragma solidity ^0.8.0; import "../utils/introspection/IERC165.sol";
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts v4.4.1 (interfaces/IERC721.sol) pragma solidity ^0.8.0; import "../token/ERC721/IERC721.sol";
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
/**
* @dev This is a base storage for the initialization function for upgradeable diamond facet contracts
**/
library ERC721A__InitializableStorage {
struct Layout {
/*
* Indicates that the contract has been initialized.
*/
bool _initialized;
/*
* Indicates that the contract is in the process of being initialized.
*/
bool _initializing;
}
bytes32 internal constant STORAGE_SLOT = keccak256('ERC721A.contracts.storage.initializable.facet');
function layout() internal pure returns (Layout storage l) {
bytes32 slot = STORAGE_SLOT;
assembly {
l.slot := slot
}
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (utils/Address.sol)
pragma solidity ^0.8.1;
/**
* @dev Collection of functions related to the address type
*/
library AddressUpgradeable {
/**
* @dev Returns true if `account` is a contract.
*
* [IMPORTANT]
* ====
* It is unsafe to assume that an address for which this function returns
* false is an externally-owned account (EOA) and not a contract.
*
* Among others, `isContract` will return false for the following
* types of addresses:
*
* - an externally-owned account
* - a contract in construction
* - an address where a contract will be created
* - an address where a contract lived, but was destroyed
*
* Furthermore, `isContract` will also return true if the target contract within
* the same transaction is already scheduled for destruction by `SELFDESTRUCT`,
* which only has an effect at the end of a transaction.
* ====
*
* [IMPORTANT]
* ====
* You shouldn't rely on `isContract` to protect against flash loan attacks!
*
* Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets
* like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract
* constructor.
* ====
*/
function isContract(address account) internal view returns (bool) {
// This method relies on extcodesize/address.code.length, which returns 0
// for contracts in construction, since the code is only stored at the end
// of the constructor execution.
return account.code.length > 0;
}
/**
* @dev Replacement for Solidity's `transfer`: sends `amount` wei to
* `recipient`, forwarding all available gas and reverting on errors.
*
* https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost
* of certain opcodes, possibly making contracts go over the 2300 gas limit
* imposed by `transfer`, making them unable to receive funds via
* `transfer`. {sendValue} removes this limitation.
*
* https://consensys.net/diligence/blog/2019/09/stop-using-soliditys-transfer-now/[Learn more].
*
* IMPORTANT: because control is transferred to `recipient`, care must be
* taken to not create reentrancy vulnerabilities. Consider using
* {ReentrancyGuard} or the
* https://solidity.readthedocs.io/en/v0.8.0/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].
*/
function sendValue(address payable recipient, uint256 amount) internal {
require(address(this).balance >= amount, "Address: insufficient balance");
(bool success, ) = recipient.call{value: amount}("");
require(success, "Address: unable to send value, recipient may have reverted");
}
/**
* @dev Performs a Solidity function call using a low level `call`. A
* plain `call` is an unsafe replacement for a function call: use this
* function instead.
*
* If `target` reverts with a revert reason, it is bubbled up by this
* function (like regular Solidity function calls).
*
* Returns the raw returned data. To convert to the expected return value,
* use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].
*
* Requirements:
*
* - `target` must be a contract.
* - calling `target` with `data` must not revert.
*
* _Available since v3.1._
*/
function functionCall(address target, bytes memory data) internal returns (bytes memory) {
return functionCallWithValue(target, data, 0, "Address: low-level call failed");
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with
* `errorMessage` as a fallback revert reason when `target` reverts.
*
* _Available since v3.1._
*/
function functionCall(
address target,
bytes memory data,
string memory errorMessage
) internal returns (bytes memory) {
return functionCallWithValue(target, data, 0, errorMessage);
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
* but also transferring `value` wei to `target`.
*
* Requirements:
*
* - the calling contract must have an ETH balance of at least `value`.
* - the called Solidity function must be `payable`.
*
* _Available since v3.1._
*/
function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) {
return functionCallWithValue(target, data, value, "Address: low-level call with value failed");
}
/**
* @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but
* with `errorMessage` as a fallback revert reason when `target` reverts.
*
* _Available since v3.1._
*/
function functionCallWithValue(
address target,
bytes memory data,
uint256 value,
string memory errorMessage
) internal returns (bytes memory) {
require(address(this).balance >= value, "Address: insufficient balance for call");
(bool success, bytes memory returndata) = target.call{value: value}(data);
return verifyCallResultFromTarget(target, success, returndata, errorMessage);
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
* but performing a static call.
*
* _Available since v3.3._
*/
function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {
return functionStaticCall(target, data, "Address: low-level static call failed");
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],
* but performing a static call.
*
* _Available since v3.3._
*/
function functionStaticCall(
address target,
bytes memory data,
string memory errorMessage
) internal view returns (bytes memory) {
(bool success, bytes memory returndata) = target.staticcall(data);
return verifyCallResultFromTarget(target, success, returndata, errorMessage);
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
* but performing a delegate call.
*
* _Available since v3.4._
*/
function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {
return functionDelegateCall(target, data, "Address: low-level delegate call failed");
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],
* but performing a delegate call.
*
* _Available since v3.4._
*/
function functionDelegateCall(
address target,
bytes memory data,
string memory errorMessage
) internal returns (bytes memory) {
(bool success, bytes memory returndata) = target.delegatecall(data);
return verifyCallResultFromTarget(target, success, returndata, errorMessage);
}
/**
* @dev Tool to verify that a low level call to smart-contract was successful, and revert (either by bubbling
* the revert reason or using the provided one) in case of unsuccessful call or if target was not a contract.
*
* _Available since v4.8._
*/
function verifyCallResultFromTarget(
address target,
bool success,
bytes memory returndata,
string memory errorMessage
) internal view returns (bytes memory) {
if (success) {
if (returndata.length == 0) {
// only check isContract if the call was successful and the return data is empty
// otherwise we already know that it was a contract
require(isContract(target), "Address: call to non-contract");
}
return returndata;
} else {
_revert(returndata, errorMessage);
}
}
/**
* @dev Tool to verify that a low level call was successful, and revert if it wasn't, either by bubbling the
* revert reason or using the provided one.
*
* _Available since v4.3._
*/
function verifyCallResult(
bool success,
bytes memory returndata,
string memory errorMessage
) internal pure returns (bytes memory) {
if (success) {
return returndata;
} else {
_revert(returndata, errorMessage);
}
}
function _revert(bytes memory returndata, string memory errorMessage) private pure {
// Look for revert reason and bubble it up if present
if (returndata.length > 0) {
// The easiest way to bubble the revert reason is using memory via assembly
/// @solidity memory-safe-assembly
assembly {
let returndata_size := mload(returndata)
revert(add(32, returndata), returndata_size)
}
} else {
revert(errorMessage);
}
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (token/ERC721/IERC721.sol)
pragma solidity ^0.8.0;
import "../../utils/introspection/IERC165.sol";
/**
* @dev Required interface of an ERC721 compliant contract.
*/
interface IERC721 is IERC165 {
/**
* @dev Emitted when `tokenId` token is transferred from `from` to `to`.
*/
event Transfer(address indexed from, address indexed to, uint256 indexed tokenId);
/**
* @dev Emitted when `owner` enables `approved` to manage the `tokenId` token.
*/
event Approval(address indexed owner, address indexed approved, uint256 indexed tokenId);
/**
* @dev Emitted when `owner` enables or disables (`approved`) `operator` to manage all of its assets.
*/
event ApprovalForAll(address indexed owner, address indexed operator, bool approved);
/**
* @dev Returns the number of tokens in ``owner``'s account.
*/
function balanceOf(address owner) external view returns (uint256 balance);
/**
* @dev Returns the owner of the `tokenId` token.
*
* Requirements:
*
* - `tokenId` must exist.
*/
function ownerOf(uint256 tokenId) external view returns (address owner);
/**
* @dev Safely transfers `tokenId` token from `from` to `to`.
*
* Requirements:
*
* - `from` cannot be the zero address.
* - `to` cannot be the zero address.
* - `tokenId` token must exist and be owned by `from`.
* - If the caller is not `from`, it must be approved to move this token by either {approve} or {setApprovalForAll}.
* - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon a safe transfer.
*
* Emits a {Transfer} event.
*/
function safeTransferFrom(address from, address to, uint256 tokenId, bytes calldata data) external;
/**
* @dev Safely transfers `tokenId` token from `from` to `to`, checking first that contract recipients
* are aware of the ERC721 protocol to prevent tokens from being forever locked.
*
* Requirements:
*
* - `from` cannot be the zero address.
* - `to` cannot be the zero address.
* - `tokenId` token must exist and be owned by `from`.
* - If the caller is not `from`, it must have been allowed to move this token by either {approve} or {setApprovalForAll}.
* - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon a safe transfer.
*
* Emits a {Transfer} event.
*/
function safeTransferFrom(address from, address to, uint256 tokenId) external;
/**
* @dev Transfers `tokenId` token from `from` to `to`.
*
* WARNING: Note that the caller is responsible to confirm that the recipient is capable of receiving ERC721
* or else they may be permanently lost. Usage of {safeTransferFrom} prevents loss, though the caller must
* understand this adds an external call which potentially creates a reentrancy vulnerability.
*
* Requirements:
*
* - `from` cannot be the zero address.
* - `to` cannot be the zero address.
* - `tokenId` token must be owned by `from`.
* - If the caller is not `from`, it must be approved to move this token by either {approve} or {setApprovalForAll}.
*
* Emits a {Transfer} event.
*/
function transferFrom(address from, address to, uint256 tokenId) external;
/**
* @dev Gives permission to `to` to transfer `tokenId` token to another account.
* The approval is cleared when the token is transferred.
*
* Only a single account can be approved at a time, so approving the zero address clears previous approvals.
*
* Requirements:
*
* - The caller must own the token or be an approved operator.
* - `tokenId` must exist.
*
* Emits an {Approval} event.
*/
function approve(address to, uint256 tokenId) external;
/**
* @dev Approve or remove `operator` as an operator for the caller.
* Operators can call {transferFrom} or {safeTransferFrom} for any token owned by the caller.
*
* Requirements:
*
* - The `operator` cannot be the caller.
*
* Emits an {ApprovalForAll} event.
*/
function setApprovalForAll(address operator, bool approved) external;
/**
* @dev Returns the account approved for `tokenId` token.
*
* Requirements:
*
* - `tokenId` must exist.
*/
function getApproved(uint256 tokenId) external view returns (address operator);
/**
* @dev Returns if the `operator` is allowed to manage all of the assets of `owner`.
*
* See {setApprovalForAll}
*/
function isApprovedForAll(address owner, address operator) external view returns (bool);
}{
"remappings": [
"@matterlabs/=../../node_modules/@matterlabs/",
"@openzeppelin/=../../node_modules/@openzeppelin/",
"erc721a-upgradeable/=../../node_modules/erc721a-upgradeable/",
"system-contracts/=../../node_modules/@matterlabs/zksync-contracts/l2/system-contracts/",
"scripty.sol/=../../node_modules/scripty.sol/",
"solady/=../../node_modules/solady/",
"ds-test/=lib/forge-std/lib/ds-test/src/",
"forge-std/=lib/forge-std/src/",
"hardhat/=../../node_modules/hardhat/",
"@ensdomains/=../../node_modules/@ensdomains/",
"backend/=../../node_modules/backend/"
],
"optimizer": {
"enabled": true,
"runs": 200
},
"metadata": {
"useLiteralContent": false,
"bytecodeHash": "ipfs",
"appendCBOR": true
},
"outputSelection": {
"*": {
"*": [
"evm.bytecode",
"evm.deployedBytecode",
"devdoc",
"userdoc",
"metadata",
"abi"
]
}
},
"evmVersion": "paris",
"viaIR": true,
"libraries": {}
}Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
Contract ABI
API[{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"contractAddress","type":"address"},{"indexed":true,"internalType":"address","name":"creator","type":"address"},{"indexed":false,"internalType":"string","name":"name","type":"string"},{"indexed":false,"internalType":"uint256","name":"platformFee","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"mintFee","type":"uint256"}],"name":"ContractDeployed","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":"account","type":"address"}],"name":"Paused","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address payable","name":"platformAddress","type":"address"},{"indexed":false,"internalType":"uint256","name":"platformFee","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"creationFee","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"mintFee","type":"uint256"}],"name":"PlatformInfoUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"account","type":"address"}],"name":"Unpaused","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"Withdraw","type":"event"},{"inputs":[],"name":"configureBlast","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"string","name":"_name","type":"string"},{"internalType":"string","name":"_symbol","type":"string"},{"internalType":"uint256","name":"_maxSupply","type":"uint256"},{"internalType":"uint256","name":"_nReserved","type":"uint256"},{"internalType":"bool","name":"_startAtOne","type":"bool"},{"internalType":"string","name":"_uri","type":"string"},{"components":[{"internalType":"uint256","name":"publicPrice","type":"uint256"},{"internalType":"uint256","name":"maxTokensPerMint","type":"uint256"},{"internalType":"uint256","name":"maxTokensPerWallet","type":"uint256"},{"internalType":"uint256","name":"royaltyFee","type":"uint256"},{"internalType":"address","name":"payoutReceiver","type":"address"},{"internalType":"bool","name":"shouldLockPayoutReceiver","type":"bool"},{"internalType":"uint32","name":"startTimestamp","type":"uint32"},{"internalType":"uint32","name":"endTimestamp","type":"uint32"}],"internalType":"struct MintConfig","name":"_config","type":"tuple"}],"name":"create","outputs":[{"internalType":"contract Artgene721Implementation","name":"","type":"address"}],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"drain","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"getCreationFee","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getMintFee","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getPlatformAddress","outputs":[{"internalType":"address payable","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getPlatformFee","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getPlatformInfo","outputs":[{"internalType":"address payable","name":"","type":"address"},{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"implementation","outputs":[{"internalType":"contract Artgene721Implementation","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"pause","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"paused","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"renounceOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_fee","type":"uint256"}],"name":"setCreationFee","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_fee","type":"uint256"}],"name":"setMintFee","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address payable","name":"_platformAddress","type":"address"}],"name":"setPlatformAddress","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_platformFee","type":"uint256"}],"name":"setPlatformFee","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"unpause","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"withdraw","outputs":[],"stateMutability":"nonpayable","type":"function"}]Contract Creation Code
6080806040523461013b5760008054336001600160a01b031980831682178455936001600160a01b03939290919084167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e08480a36103e890816003557f39238a073b5892b28a4255febc1e22eb63283b2fe52a8b98a3181e76c1dfaef760806004549266071afd498d00008060015566028fbee4e210009081600255733087c429ed4e7e5cec78d006fcc772ceeaa67f0096878452602084015260408301526060820152a16001600160a81b031916176004556040516149fc808201906001600160401b03821183831017610127579082916112e98339039082f090811561011b5750169060055416176005556040516111a890816101418239f35b604051903d90823e3d90fd5b634e487b7160e01b84526041600452602484fd5b600080fdfe6080604052600436101561001257600080fd5b6000803560e01c806312e8e2c314610d415780633c0c456614610d185780633ccfd60b14610bd35780633f4ba83a14610b365780635c60da1b14610b0d5780635c975abb14610ae757806367705fc5146105b15780636ea8bc1014610593578063715018a614610539578063776187ab146104f55780637a5caab3146104d75780638456cb59146104b65780638da5cb5b1461048f5780639890220b1461037d578063a51df9da14610359578063b7d86225146102ed578063cc03c34214610256578063db07b68e14610238578063eddd0d9c146101cd5763f2fde38b146100f957600080fd5b346101ca5760203660031901126101ca576004356001600160a01b03818116918290036101c557610128611031565b811561017157600054826bffffffffffffffffffffffff60a01b821617600055167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0600080a380f35b60405162461bcd60e51b815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201526564647265737360d01b6064820152608490fd5b600080fd5b80fd5b50346101ca5760203660031901126101ca576000805160206111538339815191526004356101f9611031565b6002819055600454600354600154604080516001600160a01b039094168452602084019290925290820152606081019190915280608081015b0390a180f35b50346101ca57806003193601126101ca576020600154604051908152f35b50346101ca5760203660031901126101ca576004356001600160a01b0381169082908290036101ca5760008051602061115383398151915291610297611031565b61023260045491806bffffffffffffffffffffffff60a01b841617600455600354600154906002549260405196879616178590949392606092608083019660018060a01b03168352602083015260408201520152565b50346101ca5760203660031901126101ca57600080516020611153833981519152600435610319611031565b6001819055600454600354600254604080516001600160a01b03909416845260208401929092529082019290925260608101919091528060808101610232565b50346101ca57806003193601126101ca57610372611031565b61037a610f0e565b80f35b50346101ca57806003193601126101ca57610396611031565b604051631e0622b360e11b81528190602081600481305afa8015610484578291829161043c575b50818091479082908215610432575b6001600160a01b031690f115610426576103e4611089565b6004805460ff60a01b1916600160a01b1790556040513381527f62e78cea01bee320cd4e420270b5ea74000d11b0c9f74754ebdbfc544b05a25890602090a180f35b604051903d90823e3d90fd5b6108fc91506103cc565b9150506020813d60201161047c575b8161045860209383610e49565b8101031261047957516001600160a01b0381168103610479578190816103bd565b50fd5b3d915061044b565b6040513d84823e3d90fd5b50346101ca57806003193601126101ca57546040516001600160a01b039091168152602090f35b50346101ca57806003193601126101ca576104cf611031565b6103e4611089565b50346101ca57806003193601126101ca576020600254604051908152f35b50346101ca57806003193601126101ca57600454600354600254600154604080516001600160a01b0390951685526020850193909352918301526060820152608090f35b50346101ca57806003193601126101ca57610552611031565b600080546001600160a01b0319811682556001600160a01b03167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e08280a380f35b50346101ca57806003193601126101ca576020600354604051908152f35b506101c03660031901126101ca5767ffffffffffffffff6004358181116109c1576105e0903690600401610e87565b602435828111610a1a576105f8903690600401610e87565b91608435908115158203610ae35760a435818111610ac75761061e903690600401610e87565b91610100918260c319360112610acb5760405192830190811183821017610acf57604090815260c435835260e43560208401526101043590830152610124356060830152610144356001600160a01b0381168103610acb576080830152610164358015158103610acb5760a08301526101843563ffffffff81168103610acb5760c083015263ffffffff6101a435166101a43503610ac7576101a43560e08301526106c7611089565b6001543410610a5c57600554608881901c62ffffff16763d602d80600a3d3981f3363d3d373d3d3d363d7300000017875260781b6effffffffffffffffffffffffffffff19166e5af43d82803e903d91602b57fd5bf3176020526001600160a01b036037600988f016948515610a1e578692863b15610a1a5763ffffffff60e06107b2610789956040519889978897636e9af8fb60e11b89526101c060048a01526107778d6101c48b0190610ece565b8981036003190160248b015290610ece565b9160443560448901526064356064890152151560848801526003198783030160a4880152610ece565b835160c4860152602084015160e48601526040840151610104860152606084015161012486015260808401516001600160a01b031661014486015260a0840151151561016486015260c08401518316610184860152920151166101a4830152038183875af18015610a0f576109fc575b50813b156109c15760405163f2fde38b60e01b81523360048201528390818160248183885af18015610484576109e8575b506002604360981b01803b610937575b50506040516306ea8bc160e41b8152602081600481305afa9384156104265780946108e0575b60208486817ffaa0b290e41b04e5ec48ceb48eb322e2bfdf7e3486580a20198dc1238b2991e1876002546108c860405192606084526060840190610ece565b948783015260408201528033940390a3604051908152f35b9093506020843d60201161092f575b816108fc60209383610e49565b810103126101ca5750915191817ffaa0b290e41b04e5ec48ceb48eb322e2bfdf7e3486580a20198dc1238b2991e1610889565b3d91506108ef565b803b156109d957604051634846428160e11b815260048101859052828160248183865af19081156109dd5783916109c5575b505081546001600160a01b0316813b156109c1578291604483926040519485938492630ca12c4b60e01b845260048401528960248401525af180156104845715610863576109b690610e1f565b6109c1578238610863565b8280fd5b6109ce90610e1f565b6109d9578138610969565b5080fd5b6040513d85823e3d90fd5b6109f190610e1f565b6109c1578238610853565b610a0890939193610e1f565b9138610822565b6040513d86823e3d90fd5b8380fd5b60405162461bcd60e51b8152602060048201526016602482015275115490cc4c4d8dce8818dc99585d194819985a5b195960521b6044820152606490fd5b60405162461bcd60e51b815260206004820152603860248201527f41727467656e65466163746f72793a204e6f7420656e6f75676820657468657260448201527f2073656e7420746f206465706c6f7920636f6e747261637400000000000000006064820152608490fd5b8580fd5b8680fd5b634e487b7160e01b87526041600452602487fd5b8480fd5b50346101ca57806003193601126101ca57602060ff60045460a01c166040519015158152f35b50346101ca57806003193601126101ca576005546040516001600160a01b039091168152602090f35b50346101ca57806003193601126101ca57610b4f611031565b60045460ff8160a01c1615610b975760ff60a01b19166004556040513381527f5db9ee0a495bf2e6ff9c91a7834c1ba4fdd244a5e8aa4e537bd38aeae4b073aa90602090a180f35b60405162461bcd60e51b815260206004820152601460248201527314185d5cd8589b194e881b9bdd081c185d5cd95960621b6044820152606490fd5b50346101ca57806003193601126101ca57610bec611031565b6004546001600160a01b031647478111610cd3578280808084865af13d15610cce573d610c1881610e6b565b90610c266040519283610e49565b81528460203d92013e5b15610c635760207f884edad9ce6fa2440d8a54cc123490eb96d2768479d49ff9c7366125a942436491604051908152a280f35b60405162461bcd60e51b815260206004820152603a60248201527f416464726573733a20756e61626c6520746f2073656e642076616c75652c207260448201527f6563697069656e74206d617920686176652072657665727465640000000000006064820152608490fd5b610c30565b60405162461bcd60e51b815260206004820152601d60248201527f416464726573733a20696e73756666696369656e742062616c616e63650000006044820152606490fd5b50346101ca57806003193601126101ca576004546040516001600160a01b039091168152602090f35b50346101ca5760203660031901126101ca57600435610d5e611031565b6113888111610db4576003819055600454600154600254604080516001600160a01b0390941684526020840194909452928201526060810191909152600080516020611153833981519152908060808101610232565b60405162461bcd60e51b815260206004820152603b60248201527f41727467656e65506c6174666f726d436f6e6669673a20706c6174666f726d2060448201527f6665652063616e6e6f74206265206d6f7265207468616e2031302500000000006064820152608490fd5b67ffffffffffffffff8111610e3357604052565b634e487b7160e01b600052604160045260246000fd5b90601f8019910116810190811067ffffffffffffffff821117610e3357604052565b67ffffffffffffffff8111610e3357601f01601f191660200190565b81601f820112156101c557803590610e9e82610e6b565b92610eac6040519485610e49565b828452602083830101116101c557816000926020809301838601378301015290565b919082519283825260005b848110610efa575050826000602080949584010152601f8019910116010190565b602081830181015184830182015201610ed9565b60006002604360981b01803b1561102d57803b156109d9576040908151634e606c4760e01b8152838160048183865af1801561100d5761101a575b5082546001600160a01b0391908216813b15610ae35784916024839286519485938492631d70c8d360e31b845260048401525af1801561100d57908491610ff9575b5050610f956110d0565b16803b156109c1579082809260248351809581936336b91f2b60e01b8352739b1419cd4b86c6c44146276a9a5c34a91872d84160048401525af1908115610ff05750610fdf575050565b610fe98291610e1f565b6101ca5750565b513d84823e3d90fd5b61100290610e1f565b6109c1578238610f8b565b50505051903d90823e3d90fd5b61102690939193610e1f565b9138610f49565b5050565b6000546001600160a01b0316330361104557565b606460405162461bcd60e51b815260206004820152602060248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65726044820152fd5b60ff60045460a01c1661109857565b60405162461bcd60e51b815260206004820152601060248201526f14185d5cd8589b194e881c185d5cd95960821b6044820152606490fd5b4662013e31036110f257732536fe9ab3f511540f2f9e2ec2a805005c3dd80090565b46630a0c71fd0361111557732fc95838c71e76ec69ff817983bff17c710f34e090565b60405162461bcd60e51b815260206004820152601560248201527410da185a5b881251081a5cc81b9bdd08109b185cdd605a1b6044820152606490fdfe39238a073b5892b28a4255febc1e22eb63283b2fe52a8b98a3181e76c1dfaef7a26469706673582212203e6414a235520c4118b0e6bf1af4b5319dce0431eb7baab2279c0b6b9f65f13764736f6c6343000818003360808060405234620001275760005460ff8160081c16159182809362000119575b801562000100575b15620000a7575060ff1981166001176000558162000094575b5062000058575b6040516148cf90816200012d8239f35b61ff0019600054166000557f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb3847402498602060405160018152a162000048565b61ffff1916610101176000553862000041565b62461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201526d191e481a5b9a5d1a585b1a5e995960921b6064820152608490fd5b50303b158015620000285750600160ff83161462000028565b50600160ff83161062000020565b600080fdfe6080604052600436101561001b575b361561001957600080fd5b005b60003560e01c806301582f00146104bb57806301ffc9a7146104b65780630563aae5146104b157806306fdde03146104ac578063081812fc146104a7578063095ea7b3146104a2578063170ff3e11461049d57806318160ddd1461049857806320b7b8df1461049357806323b872dd1461048e57806329406326146104895780632a30e4c2146104845780632a55205a1461047f57806334fbc9a11461047a5780633ccfd60b146104755780633cef28d2146104705780633e4086e51461046b57806342842e0e1461046657806342966c6814610461578063453c23101461045c5780634690521b14610457578063507e094f14610452578063513dc7e91461044d57806353c4b14a1461044857806355f804b31461044357806356d3163d1461043e5780635c474f9e146104395780636352211e146104345780636b0071761461042f5780636e878ffb1461042a57806370a0823114610425578063715018a614610420578063735328021461041b5780637efc77fa146104165780638589a1a014610411578063894760691461040c5780638ada6b0f146104075780638da5cb5b146104025780638dc251e3146103fd57806391b7f5ed146103f857806395d89b41146103f35780639fbc8713146103ee578063a035b1fe146103e9578063a0712d68146103e4578063a22cb465146103df578063a474935c146103da578063a4f6628d146103d5578063a5bd5235146103d0578063a769310a146103cb578063a85adeab146103c6578063b66a0e5d146103c1578063b88d4fde146103bc578063b8997a97146103b7578063b89a56ce146103b2578063c39c5a35146103ad578063c87b56dd146103a8578063d5abeb01146103a3578063d7bf81a31461039e578063db85d59c14610399578063dd35f1f614610394578063ddd5e1b21461038f578063e36b0b371461038a578063e6798baa14610385578063e6fd48bc14610380578063e76af32e1461037b578063e8a3d48514610376578063e985e9c514610371578063efbbd4671461036c578063f0ba844014610367578063f2fde38b14610362578063f867b7971461035d578063fe60d12c14610358578063fecfda49146103535763ffa1ad740361000e576125ae565b612581565b612563565b6124ec565b61245b565b61242f565b6123a3565b61235e565b612342565b61231c565b6122f5565b6122d2565b6122a7565b612205565b61217c565b612098565b61203a565b61201c565b611ffd565b611f83565b611edb565b611ebd565b611e5b565b611cfe565b611cd7565b611bcc565b611bb1565b611b8a565b611b64565b611ae5565b6119d1565b6119b3565b61198a565b6118d6565b6118b5565b61186e565b611845565b61181c565b61172f565b6116c5565b611671565b611556565b6114f8565b61149e565b611471565b6113e2565b6113b3565b61138e565b6112a4565b611263565b611189565b611140565b6110e7565b610fee565b610fd0565b610ddd565b610dba565b610d99565b610d5c565b610c4b565b610c2d565b610bdd565b610b44565b610aee565b610aaf565b610a5a565b610a02565b610904565b610832565b6107b1565b6106c1565b610647565b61058a565b346105735760008060031936011261057057604051809160a554908183526020809301809260a583526000805160206147ba83398151915290835b818110610553575050508461050c910385611de8565b60405193838594850191818652518092526040850193925b82811061053357505050500390f35b83516001600160a01b031685528695509381019392810192600101610524565b82546001600160a01b0316845292860192600192830192016104f6565b80fd5b600080fd5b6001600160e01b031981160361057357565b34610573576020366003190112610573576105e66004356105aa81610578565b63ffffffff60e01b1663152a902d60e11b811490811561063e575b811561062d575b81156105ea575b5060405190151581529081906020820190565b0390f35b6301ffc9a760e01b81149150811561061c575b811561060b575b50386105d3565b635b5e139f60e01b14905038610604565b6380ac58cd60e01b811491506105fd565b63d13f73fb60e01b811491506105cc565b801591506105c5565b3461057357600036600319011261057357602060a554604051908152f35b60005b8381106106785750506000910152565b8181015183820152602001610668565b906020916106a181518092818552858086019101610665565b601f01601f1916010190565b9060206106be928181520190610688565b90565b346105735760008060031936011261057057604051908060008051602061483a83398151915280546106f2816125ca565b80865292602092600192808416908115610782575060011461072b575b6105e68761071f81890382611de8565b604051918291826106ad565b815293507f933ecf8acb7824b680a8d16f3ff3db8864228d986aa4c2ebab1eeb2703b4beb35b83851061076f5750505050810160200161071f826105e6388061070f565b8054868601840152938201938101610751565b9150508695506105e69693506020925061071f94915060ff191682840152151560051b8201019293388061070f565b34610573576020366003190112610573576004356107ce81613887565b156108005760005260008051602061481a833981519152602052602060018060a01b0360406000205416604051908152f35b6333d1c03960e21b60005260046000fd5b6001600160a01b0381160361057357565b610144359061083082610811565b565b60403660031901126105735760043561084a81610811565b6024356001600160a01b038061085f836139b9565b16908133036108c7575b600083815260008051602061481a8339815191526020526040812080546001600160a01b0319166001600160a01b0387161790559316907f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b9258480a480f35b60ff6108ed336108d685610cea565b9060018060a01b0316600052602052604060002090565b5416610869576367d9dca160e11b60005260046000fd5b346105735760203660031901126105735760043561092181610811565b610929613949565b6001600160a01b038116903082146109bd5761094490612e94565b61097857610951816126b6565b7f99c6112dbaef85e57ac8ca86dd23e3c785162b58a6e810e5d5e7455b568d66b1600080a2005b60405162461bcd60e51b815260206004820152601760248201527f457874656e73696f6e20616c72656164792061646465640000000000000000006044820152606490fd5b60405162461bcd60e51b815260206004820152601c60248201527f43616e6e6f74206164642073656c6620617320657874656e73696f6e000000006044820152606490fd5b346105735760003660031901126105735760206000805160206147da833981519152547f2569078dfb4b0305704d3008e7403993ae9601b85f7ae5e742de3de8f8011c41549003610a516139a1565b60405191038152f35b346105735760003660031901126105735760a1546040516001600160a01b039091168152602090f35b606090600319011261057357600435610a9b81610811565b90602435610aa881610811565b9060443590565b610019610abb36610a83565b91612715565b9181601f84011215610573578235916001600160401b038311610573576020838186019501011161057357565b34610573576060366003190112610573576044356001600160401b03811161057357610b30610b246105e6923690600401610ac1565b906024356004356128e5565b604051918291602083526020830190610688565b3461057357602036600319011261057357600435610b6181610811565b610b69613949565b60ff60a25460a01c16610b985760a180546001600160a01b0319166001600160a01b0392909216919091179055005b60405162461bcd60e51b815260206004820152601760248201527f5061796f7574206368616e6765206973206c6f636b65640000000000000000006044820152606490fd5b34610573576040366003190112610573576001600160a01b03610bfe612ee8565b16612710610c10609f54602435612995565b604080516001600160a01b03949094168452919004602083015290f35b34610573576000366003190112610573576020609754604051908152f35b3461057357600036600319011261057357610c64613949565b47609754612710908103818111610ce557610c7f9083612995565b0490610c89612ce7565b6099546001600160a01b039081169291610ca385826143d3565b848303928311610ce557610cda6020937f884edad9ce6fa2440d8a54cc123490eb96d2768479d49ff9c7366125a9424364956143d3565b6040519485521692a2005b61297f565b6001600160a01b031660009081527f2569078dfb4b0305704d3008e7403993ae9601b85f7ae5e742de3de8f8011c476020526040902090565b6001600160a01b031660009081527f2569078dfb4b0305704d3008e7403993ae9601b85f7ae5e742de3de8f8011c456020526040902090565b3461057357602036600319011261057357600435610d7981610811565b60018060a01b031660005260a46020526020604060002054604051908152f35b3461057357602036600319011261057357610db2613949565b600435609f55005b610019610dc636610a83565b9060405192610dd484611d97565b60008452612f70565b346105735760203660031901126105735760043560ff60a25460a81c1615610f9257610e07613a31565b610e10816139b9565b600082815260008051602061481a833981519152602052604090208054916001600160a01b03811691338085149084141715610e4b565b1590565b610f6e575b600093610f65575b50610e6282610d23565b80546fffffffffffffffffffffffffffffffff0190556001600160a01b0382164260a01b17600360e01b17610e9685612400565b55600160e11b811615610f24575b507fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef8280a4610f1b610ef77f2569078dfb4b0305704d3008e7403993ae9601b85f7ae5e742de3de8f8011c415460010190565b7f2569078dfb4b0305704d3008e7403993ae9601b85f7ae5e742de3de8f8011c4155565b61001960018055565b60018401610f3181612400565b5415610f3e575b50610ea4565b6000805160206147da833981519152548114610f3857610f5d90612400565b553880610f38565b83905538610e58565b610f88610e47610f81336108d687610cea565b5460ff1690565b15610e50576138e5565b60405162461bcd60e51b8152602060048201526016602482015275109d5c9b9a5b99c81a5cc81b9bdd08185b1b1bddd95960521b6044820152606490fd5b34610573576000366003190112610573576020609d54604051908152f35b60603660031901126105735760043560243561100981610811565b61101233612e94565b156110855761101f613a31565b61102b82609854612995565b3410611049578161103e61104393613a87565b613af4565b60018055005b60405162461bcd60e51b8152602060048201526014602482015273135a5b9d08119959481a5cc81c995c5d5a5c995960621b6044820152606490fd5b60405162461bcd60e51b815260206004820152603460248201527f457874656e73696f6e2073686f756c6420626520616464656420746f20636f6e6044820152737472616374206265666f7265206d696e74696e6760601b6064820152608490fd5b34610573576000366003190112610573576020609c54604051908152f35b6004359063ffffffff8216820361057357565b610184359063ffffffff8216820361057357565b6101a4359063ffffffff8216820361057357565b346105735760203660031901126105735761001961115c611105565b611164613949565b6099805463ffffffff60a01b191660a09290921b63ffffffff60a01b16919091179055565b34610573576000366003190112610573576099546001600160a01b039081169033829003611225574790609754612710908103818111610ce5576111cd9084612995565b04926111d7612ce7565b906111e285836143d3565b848403938411610ce5577f884edad9ce6fa2440d8a54cc123490eb96d2768479d49ff9c7366125a942436493611217916143d3565b6040519384521691602090a2005b60405162461bcd60e51b815260206004820152601660248201527543616c6c6572206973206e6f7420506c6174666f726d60501b6044820152606490fd5b34610573576020366003190112610573576004356001600160401b03811161057357611296610019913690600401610ac1565b9061129f613949565b612b0d565b34610573576020366003190112610573576004356112c181610811565b6112c9613949565b6001600160a01b038116903082146113495761130e9082158015611335575b6112f190612c4b565b60018060a01b03166001600160601b0360a01b60a254161760a255565b7f9ecad07ead74f2fb52324485432408cf6261ad2454126bb85412492425a8b1d0600080a2005b506112f161134282613be3565b90506112e8565b60405162461bcd60e51b815260206004820152601b60248201527f43616e6e6f74206164642073656c662061732072656e646572657200000000006044820152606490fd5b346105735760003660031901126105735760206113a9612ca2565b6040519015158152f35b346105735760203660031901126105735760206001600160a01b036113d96004356139b9565b16604051908152f35b3461057357604036600319011261057357600435602435611401613949565b80821161143c576040805192835260208301919091527f6bd5c950a8d8df17f772f5af37cb3655737899cbf903264b9795592da439661c91a1005b60405162461bcd60e51b815260206004820152600d60248201526c496e76616c69642072616e676560981b6044820152606490fd5b3461057357600036600319011261057357602061148c612ce7565b6040516001600160a01b039091168152f35b34610573576020366003190112610573576004356114bb81610811565b6001600160a01b038116156114e7576001600160401b036114dd602092610d23565b5416604051908152f35b6323d3ad8160e21b60005260046000fd5b346105735760008060031936011261057057611512613949565b606580546001600160a01b0319811690915581906001600160a01b03167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e08280a380f35b346105735760203660031901126105735760043561157b611575612ca2565b15612d09565b611583613949565b61158b613bc6565b609a548101809111610ce557811061160657609b548110156115ac57609b55005b60405162461bcd60e51b815260206004820152602c60248201527f43616e6e6f742073657420686967686572207468616e2074686520637572726560448201526b6e74206d6178537570706c7960a01b6064820152608490fd5b60405162461bcd60e51b815260206004820152603760248201527f4d617820737570706c7920697320746f6f206c6f772c20616c7265616479206d60448201527f696e746564206d6f726520282b207265736572766564290000000000000000006064820152608490fd5b34610573576000366003190112610573576105e660405161169181611db2565b6013815272343a3a38399d1797b0b93a33b2b732973c3cbd60691b6020820152604051918291602083526020830190610688565b34610573576000366003190112610573576116de613949565b60a2805460ff60a01b1916600160a01b1790557f1ebea55c22e40654c702e9f441c6344fd8ab9edd3fd2bcd0275d1ba76cfc8472602061171c612ce7565b6040516001600160a01b039091168152a1005b346105735760203660031901126105735760043561174c81610811565b611754613949565b6040516370a0823160e01b8152306004820152906001600160a01b03906020836024818585165afa91821561181757610019936000936117e6575b506117de6117b26117aa6117a4609754612ae1565b86612995565b612710900490565b6117ba612ce7565b946117d982856117d160995460018060a01b031690565b981687613d07565b612b00565b921690613d07565b61180991935060203d602011611810575b6118018183611de8565b810190612d55565b913861178f565b503d6117f7565b6128c6565b346105735760003660031901126105735760a2546040516001600160a01b039091168152602090f35b34610573576000366003190112610573576065546040516001600160a01b039091168152602090f35b346105735760203660031901126105735760043561188b81610811565b611893613949565b60a080546001600160a01b0319166001600160a01b0392909216919091179055005b34610573576020366003190112610573576118ce613949565b600435609e55005b34610573576000806003193601126105705760405190806000805160206147fa8339815191528054611907816125ca565b808652926020926001928084169081156107825750600114611933576105e68761071f81890382611de8565b815293507f617167b76dcc8247761fd21f427ad8ec3be6b3be203aed34e3aac08b4d31817c5b8385106119775750505050810160200161071f826105e6388061070f565b8054868601840152938201938101611959565b346105735760003660031901126105735760a0546040516001600160a01b039091168152602090f35b34610573576000366003190112610573576020609e54604051908152f35b6020366003190112610573576004356119e8613a31565b6119f0612ca2565b15611a9657609d549081611a4d575b610f1b90611a11609c54821115612dd6565b611a3d611a35611a23609e5484612995565b611a2f84609854612995565b90612ad4565b341015612e48565b611a4681613a87565b3390613af4565b3360005260a4602052604060002054818101809111610ce557610f1b92611a75911115612d64565b33600090815260a460205260409020611a8f828254612ad4565b90556119ff565b60405162461bcd60e51b815260206004820152600f60248201526e53616c65206e6f742061637469766560881b6044820152606490fd5b8015150361057357565b610164359061083082611acd565b3461057357604036600319011261057357600435611b0281610811565b60243590611b0f82611acd565b611b1c816108d633610cea565b9115159160ff1981541660ff841617905560405191825260018060a01b0316907f17307eab39ab6107e8899845ad3d59bd9653f200f220920489ca2b5937696c3160203392a3005b3461057357600036600319011261057357602060ff60a25460a01c166040519015158152f35b346105735760203660031901126105735760206113a9600435611bac81610811565b612e94565b3461057357600036600319011261057357602061148c612ee8565b3461057357602036600319011261057357600435611be981610811565b611bf1613949565b60a580546001600160a01b03928316926000929084905b838510611c94575b50611c6584611c47611c41611c2c611c2788612af1565b61206e565b905460039190911b1c6001600160a01b031690565b9161206e565b90919060018060a01b038084549260031b9316831b921b1916179055565b611c6d612f06565b7fe056b30f86b962fc88925cb7559e4364707cab11d2c52e090e6c0db62eb91135600080a2005b909193846000528282611cbd836000805160206147ba833981519152015460018060a01b031690565b1614611cce57600101939190611c08565b93829150611c10565b3461057357600036600319011261057357602063ffffffff60995460c01c16604051908152f35b3461057357600036600319011261057357611d17613949565b6099805463ffffffff60a01b19164260a01b63ffffffff60a01b1617905563ffffffff60995490808260a01c16908260c01c1610611d5157005b63ffffffff60c01b191663ffffffff60c01b17609955005b634e487b7160e01b600052604160045260246000fd5b6001600160401b038111611d9257604052565b611d69565b602081019081106001600160401b03821117611d9257604052565b604081019081106001600160401b03821117611d9257604052565b606081019081106001600160401b03821117611d9257604052565b90601f801991011681019081106001600160401b03821117611d9257604052565b6001600160401b038111611d9257601f01601f191660200190565b929192611e3082611e09565b91611e3e6040519384611de8565b829481845281830111610573578281602093846000960137010152565b608036600319011261057357600435611e7381610811565b602435611e7f81610811565b606435916001600160401b038311610573573660238401121561057357611eb3610019933690602481600401359101611e24565b9160443591612f70565b34610573576000366003190112610573576020609f54604051908152f35b346105735760008060031936011261057057611ef5613949565b60a554815b818110611f3a57508160a55580611f0f575080f35b6000805160206147ba833981519152908101905b818110611f2f57505080f35b828155600101611f23565b6000805160206147ba833981519152810154600191906001600160a01b03167fe056b30f86b962fc88925cb7559e4364707cab11d2c52e090e6c0db62eb911358580a201611efa565b3461057357602036600319011261057357600435611f9f613949565b611fa7613a31565b60328111611fb857609c5560018055005b60405162461bcd60e51b815260206004820152601860248201527f546f6f206d616e7920746f6b656e7320706572206d696e7400000000000000006044820152606490fd5b34610573576020366003190112610573576105e6610b30600435612fb3565b34610573576000366003190112610573576020609b54604051908152f35b34610573576000366003190112610573576020609854604051908152f35b634e487b7160e01b600052603260045260246000fd5b60a5548110156120935760a56000526000805160206147ba8339815191520190600090565b612058565b346105735760203660031901126105735760043560a5548110156105735760a56000526000805160206147ba83398151915201546040516001600160a01b039091168152602090f35b9080601f83011215610573578160206106be93359101611e24565b90610100809260c3190112610573576040519182018281106001600160401b03821117611d92576040528160c435815260e435602082015261010435604082015261012435606082015261214e610822565b608082015261215b611ad7565b60a0820152612168611118565b60c082015260e061217761112c565b910152565b34610573576101c0366003190112610573576001600160401b03600435818111610573576121ae9036906004016120e1565b602435828111610573576121c69036906004016120e1565b6084356121d281611acd565b60a435938411610573576121ed6100199436906004016120e1565b916121f7366120fc565b9360643591604435916130cb565b346105735760403660031901126105735760043560243561222581610811565b61222d613a31565b612235613949565b609a549182811161225657808303928311610ce55761104392609a55613af4565b60405162461bcd60e51b815260206004820152602360248201527f5468617420776f756c642065786365656420746865206d61782072657365727660448201526232b21760e91b6064820152608490fd5b34610573576000366003190112610573576122c0613949565b6099805463ffffffff60a01b19169055005b346105735760003660031901126105735760206122ed6139a1565b604051908152f35b3461057357600036600319011261057357602063ffffffff60995460a01c16604051908152f35b3461057357600036600319011261057357602060ff60a25460a81c166040519015158152f35b34610573576000366003190112610573576105e6610b30612604565b3461057357604036600319011261057357602060ff61239760043561238281610811565b6108d66024359161239283610811565b610cea565b54166040519015158152f35b34610573576040366003190112610573576123bc611105565b60243563ffffffff81168103610573576123db61001992611164613949565b6099805463ffffffff60c01b191660c09290921b63ffffffff60c01b16919091179055565b6000527f2569078dfb4b0305704d3008e7403993ae9601b85f7ae5e742de3de8f8011c44602052604060002090565b346105735760203660031901126105735760043560005260a36020526020604060002054604051908152f35b346105735760203660031901126105735760043561247881610811565b612480613949565b6001600160a01b038116156124985761001990613cbe565b60405162461bcd60e51b815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201526564647265737360d01b6064820152608490fd5b34610573576020366003190112610573577f893763ec5f264ab31e47c251fe8d99f8c6c9d84e36fcd0cfe6cae3e925fb13cb602060043561252c81611acd565b612537611575612ca2565b61253f613949565b151560a25460ff60a81b8260a81b169060ff60a81b19161760a255604051908152a1005b34610573576000366003190112610573576020609a54604051908152f35b346105735760203660031901126105735761259a613949565b6125a2613a31565b600435609d5560018055005b3461057357600036600319011261057357602060405160058152f35b90600182811c921680156125fa575b60208310146125e457565b634e487b7160e01b600052602260045260246000fd5b91607f16916125d9565b6040519060008260a65491612618836125ca565b808352926020906001908181169081156126925750600114612643575b505061083092500383611de8565b91509260a660005260008051602061485a833981519152936000925b82841061267a57506108309450505081016020013880612635565b8554888501830152948501948794509281019261265f565b9150506020925061083094915060ff191682840152151560051b8201013880612635565b60a5549068010000000000000000821015611d9257600182018060a5558210156120935760a56000526000805160206147ba83398151915290910180546001600160a01b0319166001600160a01b03909216919091179055565b609a55565b919091612721826139b9565b6001600160a01b03918216939082811685900361286357600084815260008051602061481a83398151915260205260409020805461276e6001600160a01b03881633908114908314171590565b612846575b61283c575b5061278285610d23565b805460001901905561279382610d23565b805460010190556001600160a01b0382164260a01b17600160e11b176127b885612400565b55600160e11b8116156127fb575b501680927fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef600080a4156127f657565b613906565b6001840161280881612400565b5415612815575b506127c6565b6000805160206147da83398151915254811461280f5761283490612400565b55388061280f565b6000905538612778565b612859610e47610f81336108d68b610cea565b15612773576138e5565b6138f6565b602081830312610573578051906001600160401b038211610573570181601f8201121561057357805161289a81611e09565b926128a86040519485611de8565b81845260208284010111610573576106be9160208085019101610665565b6040513d6000823e3d90fd5b604051906128df82611d97565b60008252565b919060018060a01b0360a2541690816129055750505050506106be6128d2565b608460009486604051978896879586946314a0319360e11b86526004860152602485015260606044850152816064850152848401378181018301879052601f01601f191681010301915afa90811561181757600091612962575090565b6106be91503d806000833e6129778183611de8565b810190612868565b634e487b7160e01b600052601160045260246000fd5b81810292918115918404141715610ce557565b8181106129b3575050565b600081556001016129a8565b90601f82116129cc575050565b6108309160a660005260008051602061485a833981519152906020601f840160051c83019310612a04575b601f0160051c01906129a8565b90915081906129f7565b90601f8211612a1b575050565b6108309160008051602061483a8339815191526000527f933ecf8acb7824b680a8d16f3ff3db8864228d986aa4c2ebab1eeb2703b4beb3906020601f840160051c83019310612a0457601f0160051c01906129a8565b90601f8211612a7e575050565b610830916000805160206147fa8339815191526000527f617167b76dcc8247761fd21f427ad8ec3be6b3be203aed34e3aac08b4d31817c906020601f840160051c83019310612a0457601f0160051c01906129a8565b91908201809211610ce557565b90612710918203918211610ce557565b600019810191908211610ce557565b91908203918211610ce557565b91906001600160401b038111611d9257612b3181612b2c60a6546125ca565b6129bf565b6000601f8211600114612bdb578190612b629394600092612bd0575b50508160011b916000199060031b1c19161790565b60a6555b612b6e613bc6565b15610830577f6bd5c950a8d8df17f772f5af37cb3655737899cbf903264b9795592da439661c612b9c6139a1565b612bb7612bb2612baa6139a1565b611a2f613bc6565b612af1565b604080519283526020830191909152819081015b0390a1565b013590503880612b4d565b60a6600052601f1982169360008051602061485a83398151915291805b868110612c335750836001959610612c19575b505050811b0160a655612b66565b0135600019600384901b60f8161c19169055388080612c0b565b90926020600181928686013581550194019101612bf8565b15612c5257565b60405162461bcd60e51b815260206004820152602260248201527f4e6f7420636f6e666f726d7320746f2072656e646572657220696e7465726661604482015261636560f01b6064820152608490fd5b60995463ffffffff808260a01c16918215612cdf5760c01c16908115612cd7574210159081612ccf575090565b905042111590565b905042101590565b505050600090565b60a1546001600160a01b03908116908115612d00575090565b90506065541690565b15612d1057565b60405162461bcd60e51b815260206004820152601960248201527f53616c652073686f756c64206e6f7420626520616374697665000000000000006044820152606490fd5b90816020910312610573575190565b15612d6b57565b60405162461bcd60e51b815260206004820152603e60248201527f596f752063616e6e6f74206d696e74206d6f7265207468616e206d617850657260448201527f57616c6c657420746f6b656e7320666f72206f6e6520616464726573732100006064820152608490fd5b15612ddd57565b60405162461bcd60e51b815260206004820152603d60248201527f596f752063616e6e6f74206d696e74206d6f7265207468616e204d41585f544f60448201527f4b454e535f5045525f4d494e5420746f6b656e73206174206f6e6365210000006064820152608490fd5b15612e4f57565b60405162461bcd60e51b815260206004820152601960248201527f496e636f6e73697374656e7420616d6f756e742073656e7421000000000000006044820152606490fd5b60a5805491906000805b848110612eaf575050505050600090565b8282526000805160206147ba8339815191528101546001600160a01b03858116911614612ede57600101612e9e565b5050505050600190565b60a0546001600160a01b03168015612efd5790565b506106be612ce7565b60a5548015612f5a5760001981019080821015612093577fb29a2b3b6f2ff1b765777a231725941da5072cc4fcc30ac4a2ce09706e8ddefe9060a5600052016001600160601b0360a01b815416905560a555565b634e487b7160e01b600052603160045260246000fd5b929190612f7e828286612715565b803b612f8b575b50505050565b612f9493613f6b565b15612fa25738808080612f85565b6368d2bf6b60e11b60005260046000fd5b60a2546001600160a01b031680613076575b50612fcf81613887565b1561306557612fdc612604565b805190919015613050576040519060a08201604052608082019060008252905b6000190190600a906030828206018353049081612ffc57905061303e926130446106be936080601f199485810192030181526040519586936020850190613f94565b90613f94565b03908101835282611de8565b505060405161305e81611d97565b6000815290565b630a14c4b560e41b60005260046000fd5b60006024916040519283809263c87b56dd60e01b82528660048301525afa908115611817576000916130b0575b50805115612fc557905090565b6130c591503d806000833e6129778183611de8565b386130a3565b9593919492909460008051602061487a833981519152549560ff8760081c1696876000146131b95750303b155b1561314e5761310d9615978861312d576131c2565b61311357565b60008051602061487a833981519152805461ff0019169055565b60008051602061487a833981519152805461ffff19166101011790556131c2565b60405162461bcd60e51b815260206004820152603760248201527f455243373231415f5f496e697469616c697a61626c653a20636f6e747261637460448201527f20697320616c726561647920696e697469616c697a65640000000000000000006064820152608490fd5b60ff16156130f8565b9492909593916000549660ff8860081c1615809881996132e8575b81156132c8575b501561326c5761320a9688613201600160ff196000541617600055565b61325357613660565b61321057565b61322061ff001960005416600055565b604051600181527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb3847402498908060208101612bcb565b61326761010061ff00196000541617600055565b613660565b60405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201526d191e481a5b9a5d1a585b1a5e995960921b6064820152608490fd5b303b159150816132da575b50386131e4565b6001915060ff1614386132d3565b600160ff82161091506131dd565b156132fd57565b60405162461bcd60e51b815260206004820152602c60248201527f4f70656e45646974696f6e20726571756972657320737461727420616e64206560448201526b06e642074696d657374616d760a41b6064820152608490fd5b1561335e57565b60405162461bcd60e51b815260206004820152603260248201527f4f70656e45646974696f6e20726571756972657320737461727454696d6573746044820152710616d70203c20656e6454696d657374616d760741b6064820152608490fd5b156133c557565b60405162461bcd60e51b815260206004820152602660248201527f4f70656e45646974696f6e207265717569726573206d617850657257616c6c6560448201526507420213d20360d41b6064820152608490fd5b9081516001600160401b038111611d925761343981612b2c60a6546125ca565b602080601f831160011461347b5750819061346b93946000926134705750508160011b916000199060031b1c19161790565b60a655565b015190503880612b4d565b90601f1983169461349c60a660005260008051602061485a83398151915290565b926000905b8782106134d95750508360019596106134c0575b505050811b0160a655565b015160001960f88460031b161c191690553880806134b5565b806001859682949686015181550195019301906134a1565b9081516001600160401b038111611d92576000805160206147fa833981519152906135258161352084546125ca565b612a71565b602080601f831160011461355c575081906135589394956000926134705750508160011b916000199060031b1c19161790565b9055565b90601f1983169561359c6000805160206147fa8339815191526000527f617167b76dcc8247761fd21f427ad8ec3be6b3be203aed34e3aac08b4d31817c90565b926000905b8882106135d9575050836001959697106135c0575b505050811b019055565b015160001960f88460031b161c191690553880806135b6565b806001859682949686015181550195019301906135a1565b156135f857565b60405162461bcd60e51b8152602060048201526015602482015274141b185d199bdc9b481b9bdd0819195c1b1bde5959605a1b6044820152606490fd5b919082608091031261057357815161364c81610811565b916020810151916060604083015192015190565b959491936136f161371092956136ec613715968215600014612710576136dd8a60c081016136d56136cc60e06136c063ffffffff94856136a4825163ffffffff1690565b16151580613867575b6136b6906132f6565b5163ffffffff1690565b94015163ffffffff1690565b63ffffffff1690565b911610613357565b61271060408b015115156133be565b609b55565b60a2805460ff60b01b191691151560b01b60ff60b01b16919091179055565b613419565b61371f6032609c55565b61372b333b15156135f1565b60405163776187ab60e01b815290608082600481335afa938415611817576137936137989361380996600090600090600090613829575b61377692935061377190609855565b609755565b60018060a01b03166001600160601b0360a01b6099541617609955565b614014565b6137a0614168565b6137a86141ea565b6137b061420a565b805160208201516040830151606084015160808501519394936001600160a01b0316916137e060a0860151151590565b9361380360e06137f760c089015163ffffffff1690565b97015163ffffffff1690565b96614228565b6002604360981b013b61381857565b613820614329565b6108303361438a565b5050506137766138536137719260803d608011613860575b61384b8183611de8565b810190613635565b5091935083925090613762565b503d613841565b506136b661387e6136cc858a015163ffffffff1690565b151590506136ad565b90600091806138946139a1565b111561389d5750565b6000805160206147da8339815191525481106138b65750565b9091505b6138c381612400565b54806138d957508015610ce557600019016138ba565b600160e01b1615919050565b632ce44b5f60e11b60005260046000fd5b62a1148160e81b60005260046000fd5b633a954ecd60e21b60005260046000fd5b636f96cda160e11b60005260046000fd5b63b562e8dd60e01b60005260046000fd5b622e076360e81b60005260046000fd5b6065546001600160a01b0316330361395d57565b606460405162461bcd60e51b815260206004820152602060248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65726044820152fd5b60a25460b01c60ff16156139b457600190565b600090565b806139c26139a1565b11613917576139d081612400565b549081156139e75750600160e01b81166139175790565b90506000805160206147da83398151915254811015613a2c575b60001901613a0e81612400565b54908115613a255750600160e01b81166139175790565b9050613a01565b613917565b600260015414613a42576002600155565b60405162461bcd60e51b815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c006044820152606490fd5b61083090613aa260018060a01b036099541691609854612995565b906143d3565b15613aaf57565b60405162461bcd60e51b815260206004820152601760248201527f4e6f7420656e6f75676820546f6b656e73206c6566742e0000000000000000006044820152606490fd5b90609b5480613b84575b50613b226000805160206147da833981519152549183613b1c6128d2565b916144ae565b60005b828110613b3157505050565b80613b3e60019284612ad4565b7fa332d417eec9f7658bbe4001b4a5b148d28ae8e74744fd70d1f88175646a6c1b613b7b613b6b836145fe565b6040519081529081906020820190565b0390a201613b25565b6000805160206147da83398151915254613b9c6139a1565b900390838201809211610ce557609a548201809211610ce557613bc0911115613aa8565b38613afe565b6000805160206147da83398151915254613bde6139a1565b900390565b6040519060208083018160006301ffc9a760e01b9586845286602482015260248152613c0e81611dcd565b51617530938685fa933d6000519086613cb3575b5085613ca9575b5084613c46575b50505081613c3c575090565b6106be9150614645565b83945090600091839460405185810192835263ffffffff60e01b602482015260248152613c7281611dcd565b5192fa60005190913d83613c9e575b505081613c94575b501590388080613c30565b9050151538613c89565b101591503880613c81565b1515945038613c29565b841115955038613c22565b606580546001600160a01b039283166001600160a01b0319821681179092559091167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0600080a3565b60405163a9059cbb60e01b60208083019182526001600160a01b039490941660248301526044808301959095529381529192613da092916000908190613d4e606486611de8565b60018060a01b03169260405194613d6486611db2565b8786527f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c656488870152519082855af1613d9a613ea1565b91614724565b8051828115918215613e10575b5050905015613db95750565b6084906040519062461bcd60e51b82526004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e6044820152691bdd081cdd58d8d9595960b21b6064820152fd5b838092935001031261057357810151613e2881611acd565b808238613dad565b9081602091031261057357516106be81610578565b6106be939260809260018060a01b031682526000602083015260408201528160608201520190610688565b6001600160a01b0391821681529116602082015260408101919091526080606082018190526106be92910190610688565b3d15613ecc573d90613eb282611e09565b91613ec06040519384611de8565b82523d6000602084013e565b606090565b613efa60209160009394604051948580948193630a85bd0160e11b998a84523360048501613e45565b03926001600160a01b03165af160009181613f3a575b50613f2c57613f1d613ea1565b805115612fa257805190602001fd5b6001600160e01b0319161490565b613f5d91925060203d602011613f64575b613f558183611de8565b810190613e30565b9038613f10565b503d613f4b565b92602091613efa936000604051809681958294630a85bd0160e11b9a8b85523360048601613e70565b90613fa760209282815194859201610665565b0190565b15613fb257565b60405162461bcd60e51b815260206004820152603460248201527f455243373231415f5f496e697469616c697a61626c653a20636f6e7472616374604482015273206973206e6f7420696e697469616c697a696e6760601b6064820152608490fd5b919061403d60ff60008051602061487a8339815191525460081c1661403881613fab565b613fab565b82516001600160401b038111611d925760008051602061483a833981519152906140708161406b84546125ca565b612a0e565b602080601f83116001146140ca575090806140a6926140ad96976000926134705750508160011b916000199060031b1c19161790565b90556134f1565b6108306140b86139a1565b6000805160206147da83398151915255565b90601f1983169661410a60008051602061483a8339815191526000527f933ecf8acb7824b680a8d16f3ff3db8864228d986aa4c2ebab1eeb2703b4beb390565b926000905b898210614150575050908392916001946140ad989910614137575b505050811b0190556134f1565b015160001960f88460031b161c1916905538808061412a565b8060018596829496860151815501950193019061410f565b61083060ff60008051602061487a8339815191525460081c1661403881613fab565b1561419157565b60405162461bcd60e51b815260206004820152602b60248201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960448201526a6e697469616c697a696e6760a81b6064820152608490fd5b61420460ff60005460081c166141ff8161418a565b61418a565b60018055565b61421f60ff60005460081c166141ff8161418a565b61083033613cbe565b919395969092949663ffffffff90818116614300575b5081166142d7575b50806142ce575b50806142c5575b50806142bc575b50806142b3575b506001600160a01b03811661428e575b5061427957565b60a2805460ff60a01b1916600160a01b179055565b60a180546001600160a01b0319166001600160a01b0390921691909117905538614272565b609f5538614262565b609d553861425b565b609c5538614254565b609e553861424d565b6099805463ffffffff60c01b191660c09290921b63ffffffff60c01b1691909117905538614246565b6099805463ffffffff60a01b191660a09290921b63ffffffff60a01b169190911790553861423e565b6001600160a01b036143396146a2565b16803b1561057357600080916024604051809481936336b91f2b60e01b8352739b1419cd4b86c6c44146276a9a5c34a91872d84160048401525af18015611817576143815750565b61083090611d7f565b6002604360981b0190813b1561057357604051631d70c8d360e31b81526001600160a01b039091166004820152906000908290602490829084905af18015611817576143815750565b814710614469576000918291829182916001600160a01b03165af16143f6613ea1565b50156143fe57565b60405162461bcd60e51b815260206004820152603a60248201527f416464726573733a20756e61626c6520746f2073656e642076616c75652c207260448201527f6563697069656e74206d617920686176652072657665727465640000000000006064820152608490fd5b60405162461bcd60e51b815260206004820152601d60248201527f416464726573733a20696e73756666696369656e742062616c616e63650000006044820152606490fd5b90916000805160206147da8339815191529182549084156145f9576001916001600160a01b0382164260a01b87851460e11b17176144eb82612400565b556144f582610d23565b80546801000000000000000188020190556001600160a01b03821680156145f45786820191908480805b6145a4575b5050505061453e906000805160206147da83398151915255565b803b61454c575b5050505050565b83549485039180805b61456f575b50505050505403610573573880808080614545565b15614597575b6000614588610e47868487019686613ed1565b6145925781614555565b612fa2565b858310614575578061455a565b156145dc575b506000858383837fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef8180a4908161451f565b909101908282146145ed57846145aa565b8481614524565b613939565b613928565b600019430190438211610ce557604051906020820192448452406040830152606082015260608152608081018181106001600160401b03821117611d925760405251902090565b6000602091604051838101906301ffc9a760e01b8252633f2b9d7560e11b60248201526024815261467581611dcd565b5191617530fa6000513d82614696575b508161468f575090565b9050151590565b60201115915038614685565b4662013e31036146c457732536fe9ab3f511540f2f9e2ec2a805005c3dd80090565b46630a0c71fd036146e757732fc95838c71e76ec69ff817983bff17c710f34e090565b60405162461bcd60e51b815260206004820152601560248201527410da185a5b881251081a5cc81b9bdd08109b185cdd605a1b6044820152606490fd5b919290156147865750815115614738575090565b3b156147415790565b60405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000006044820152606490fd5b8251909150156147995750805190602001fd5b60405162461bcd60e51b81529081906147b590600483016106ad565b0390fdfeb29a2b3b6f2ff1b765777a231725941da5072cc4fcc30ac4a2ce09706e8ddeff2569078dfb4b0305704d3008e7403993ae9601b85f7ae5e742de3de8f8011c402569078dfb4b0305704d3008e7403993ae9601b85f7ae5e742de3de8f8011c432569078dfb4b0305704d3008e7403993ae9601b85f7ae5e742de3de8f8011c462569078dfb4b0305704d3008e7403993ae9601b85f7ae5e742de3de8f8011c422da56674729343acc9933752c8c469a244252915242eb6d4c02d11ddd69164a1ee151c8401928dc223602bb187aff91b9a56c7cae5476ef1b3287b085a16c85fa26469706673582212203f43b7596cd5a5c5f365781c320c8eb5373911db34b376a298f17f2e9b353d8664736f6c63430008180033
Deployed Bytecode
0x6080604052600436101561001257600080fd5b6000803560e01c806312e8e2c314610d415780633c0c456614610d185780633ccfd60b14610bd35780633f4ba83a14610b365780635c60da1b14610b0d5780635c975abb14610ae757806367705fc5146105b15780636ea8bc1014610593578063715018a614610539578063776187ab146104f55780637a5caab3146104d75780638456cb59146104b65780638da5cb5b1461048f5780639890220b1461037d578063a51df9da14610359578063b7d86225146102ed578063cc03c34214610256578063db07b68e14610238578063eddd0d9c146101cd5763f2fde38b146100f957600080fd5b346101ca5760203660031901126101ca576004356001600160a01b03818116918290036101c557610128611031565b811561017157600054826bffffffffffffffffffffffff60a01b821617600055167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0600080a380f35b60405162461bcd60e51b815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201526564647265737360d01b6064820152608490fd5b600080fd5b80fd5b50346101ca5760203660031901126101ca576000805160206111538339815191526004356101f9611031565b6002819055600454600354600154604080516001600160a01b039094168452602084019290925290820152606081019190915280608081015b0390a180f35b50346101ca57806003193601126101ca576020600154604051908152f35b50346101ca5760203660031901126101ca576004356001600160a01b0381169082908290036101ca5760008051602061115383398151915291610297611031565b61023260045491806bffffffffffffffffffffffff60a01b841617600455600354600154906002549260405196879616178590949392606092608083019660018060a01b03168352602083015260408201520152565b50346101ca5760203660031901126101ca57600080516020611153833981519152600435610319611031565b6001819055600454600354600254604080516001600160a01b03909416845260208401929092529082019290925260608101919091528060808101610232565b50346101ca57806003193601126101ca57610372611031565b61037a610f0e565b80f35b50346101ca57806003193601126101ca57610396611031565b604051631e0622b360e11b81528190602081600481305afa8015610484578291829161043c575b50818091479082908215610432575b6001600160a01b031690f115610426576103e4611089565b6004805460ff60a01b1916600160a01b1790556040513381527f62e78cea01bee320cd4e420270b5ea74000d11b0c9f74754ebdbfc544b05a25890602090a180f35b604051903d90823e3d90fd5b6108fc91506103cc565b9150506020813d60201161047c575b8161045860209383610e49565b8101031261047957516001600160a01b0381168103610479578190816103bd565b50fd5b3d915061044b565b6040513d84823e3d90fd5b50346101ca57806003193601126101ca57546040516001600160a01b039091168152602090f35b50346101ca57806003193601126101ca576104cf611031565b6103e4611089565b50346101ca57806003193601126101ca576020600254604051908152f35b50346101ca57806003193601126101ca57600454600354600254600154604080516001600160a01b0390951685526020850193909352918301526060820152608090f35b50346101ca57806003193601126101ca57610552611031565b600080546001600160a01b0319811682556001600160a01b03167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e08280a380f35b50346101ca57806003193601126101ca576020600354604051908152f35b506101c03660031901126101ca5767ffffffffffffffff6004358181116109c1576105e0903690600401610e87565b602435828111610a1a576105f8903690600401610e87565b91608435908115158203610ae35760a435818111610ac75761061e903690600401610e87565b91610100918260c319360112610acb5760405192830190811183821017610acf57604090815260c435835260e43560208401526101043590830152610124356060830152610144356001600160a01b0381168103610acb576080830152610164358015158103610acb5760a08301526101843563ffffffff81168103610acb5760c083015263ffffffff6101a435166101a43503610ac7576101a43560e08301526106c7611089565b6001543410610a5c57600554608881901c62ffffff16763d602d80600a3d3981f3363d3d373d3d3d363d7300000017875260781b6effffffffffffffffffffffffffffff19166e5af43d82803e903d91602b57fd5bf3176020526001600160a01b036037600988f016948515610a1e578692863b15610a1a5763ffffffff60e06107b2610789956040519889978897636e9af8fb60e11b89526101c060048a01526107778d6101c48b0190610ece565b8981036003190160248b015290610ece565b9160443560448901526064356064890152151560848801526003198783030160a4880152610ece565b835160c4860152602084015160e48601526040840151610104860152606084015161012486015260808401516001600160a01b031661014486015260a0840151151561016486015260c08401518316610184860152920151166101a4830152038183875af18015610a0f576109fc575b50813b156109c15760405163f2fde38b60e01b81523360048201528390818160248183885af18015610484576109e8575b506002604360981b01803b610937575b50506040516306ea8bc160e41b8152602081600481305afa9384156104265780946108e0575b60208486817ffaa0b290e41b04e5ec48ceb48eb322e2bfdf7e3486580a20198dc1238b2991e1876002546108c860405192606084526060840190610ece565b948783015260408201528033940390a3604051908152f35b9093506020843d60201161092f575b816108fc60209383610e49565b810103126101ca5750915191817ffaa0b290e41b04e5ec48ceb48eb322e2bfdf7e3486580a20198dc1238b2991e1610889565b3d91506108ef565b803b156109d957604051634846428160e11b815260048101859052828160248183865af19081156109dd5783916109c5575b505081546001600160a01b0316813b156109c1578291604483926040519485938492630ca12c4b60e01b845260048401528960248401525af180156104845715610863576109b690610e1f565b6109c1578238610863565b8280fd5b6109ce90610e1f565b6109d9578138610969565b5080fd5b6040513d85823e3d90fd5b6109f190610e1f565b6109c1578238610853565b610a0890939193610e1f565b9138610822565b6040513d86823e3d90fd5b8380fd5b60405162461bcd60e51b8152602060048201526016602482015275115490cc4c4d8dce8818dc99585d194819985a5b195960521b6044820152606490fd5b60405162461bcd60e51b815260206004820152603860248201527f41727467656e65466163746f72793a204e6f7420656e6f75676820657468657260448201527f2073656e7420746f206465706c6f7920636f6e747261637400000000000000006064820152608490fd5b8580fd5b8680fd5b634e487b7160e01b87526041600452602487fd5b8480fd5b50346101ca57806003193601126101ca57602060ff60045460a01c166040519015158152f35b50346101ca57806003193601126101ca576005546040516001600160a01b039091168152602090f35b50346101ca57806003193601126101ca57610b4f611031565b60045460ff8160a01c1615610b975760ff60a01b19166004556040513381527f5db9ee0a495bf2e6ff9c91a7834c1ba4fdd244a5e8aa4e537bd38aeae4b073aa90602090a180f35b60405162461bcd60e51b815260206004820152601460248201527314185d5cd8589b194e881b9bdd081c185d5cd95960621b6044820152606490fd5b50346101ca57806003193601126101ca57610bec611031565b6004546001600160a01b031647478111610cd3578280808084865af13d15610cce573d610c1881610e6b565b90610c266040519283610e49565b81528460203d92013e5b15610c635760207f884edad9ce6fa2440d8a54cc123490eb96d2768479d49ff9c7366125a942436491604051908152a280f35b60405162461bcd60e51b815260206004820152603a60248201527f416464726573733a20756e61626c6520746f2073656e642076616c75652c207260448201527f6563697069656e74206d617920686176652072657665727465640000000000006064820152608490fd5b610c30565b60405162461bcd60e51b815260206004820152601d60248201527f416464726573733a20696e73756666696369656e742062616c616e63650000006044820152606490fd5b50346101ca57806003193601126101ca576004546040516001600160a01b039091168152602090f35b50346101ca5760203660031901126101ca57600435610d5e611031565b6113888111610db4576003819055600454600154600254604080516001600160a01b0390941684526020840194909452928201526060810191909152600080516020611153833981519152908060808101610232565b60405162461bcd60e51b815260206004820152603b60248201527f41727467656e65506c6174666f726d436f6e6669673a20706c6174666f726d2060448201527f6665652063616e6e6f74206265206d6f7265207468616e2031302500000000006064820152608490fd5b67ffffffffffffffff8111610e3357604052565b634e487b7160e01b600052604160045260246000fd5b90601f8019910116810190811067ffffffffffffffff821117610e3357604052565b67ffffffffffffffff8111610e3357601f01601f191660200190565b81601f820112156101c557803590610e9e82610e6b565b92610eac6040519485610e49565b828452602083830101116101c557816000926020809301838601378301015290565b919082519283825260005b848110610efa575050826000602080949584010152601f8019910116010190565b602081830181015184830182015201610ed9565b60006002604360981b01803b1561102d57803b156109d9576040908151634e606c4760e01b8152838160048183865af1801561100d5761101a575b5082546001600160a01b0391908216813b15610ae35784916024839286519485938492631d70c8d360e31b845260048401525af1801561100d57908491610ff9575b5050610f956110d0565b16803b156109c1579082809260248351809581936336b91f2b60e01b8352739b1419cd4b86c6c44146276a9a5c34a91872d84160048401525af1908115610ff05750610fdf575050565b610fe98291610e1f565b6101ca5750565b513d84823e3d90fd5b61100290610e1f565b6109c1578238610f8b565b50505051903d90823e3d90fd5b61102690939193610e1f565b9138610f49565b5050565b6000546001600160a01b0316330361104557565b606460405162461bcd60e51b815260206004820152602060248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65726044820152fd5b60ff60045460a01c1661109857565b60405162461bcd60e51b815260206004820152601060248201526f14185d5cd8589b194e881c185d5cd95960821b6044820152606490fd5b4662013e31036110f257732536fe9ab3f511540f2f9e2ec2a805005c3dd80090565b46630a0c71fd0361111557732fc95838c71e76ec69ff817983bff17c710f34e090565b60405162461bcd60e51b815260206004820152601560248201527410da185a5b881251081a5cc81b9bdd08109b185cdd605a1b6044820152606490fdfe39238a073b5892b28a4255febc1e22eb63283b2fe52a8b98a3181e76c1dfaef7a26469706673582212203e6414a235520c4118b0e6bf1af4b5319dce0431eb7baab2279c0b6b9f65f13764736f6c63430008180033
Net Worth in USD
Net Worth in ETH
Token Allocations
Multichain Portfolio | 35 Chains
| Chain | Token | Portfolio % | Price | Amount | Value |
|---|---|---|---|---|---|
| BLAST | 100.00% | $3,001.56 | 0.05 | $150.08 |
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.