编译器
0.8.17+commit.8df45f5f
文件 1 的 19:Address.sol
pragma solidity ^0.8.1;
library Address {
function isContract(address account) internal view returns (bool) {
return account.code.length > 0;
}
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");
}
function functionCall(address target, bytes memory data) internal returns (bytes memory) {
return functionCallWithValue(target, data, 0, "Address: low-level call failed");
}
function functionCall(
address target,
bytes memory data,
string memory errorMessage
) internal returns (bytes memory) {
return functionCallWithValue(target, data, 0, errorMessage);
}
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");
}
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);
}
function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {
return functionStaticCall(target, data, "Address: low-level static call failed");
}
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);
}
function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {
return functionDelegateCall(target, data, "Address: low-level delegate call failed");
}
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);
}
function verifyCallResultFromTarget(
address target,
bool success,
bytes memory returndata,
string memory errorMessage
) internal view returns (bytes memory) {
if (success) {
if (returndata.length == 0) {
require(isContract(target), "Address: call to non-contract");
}
return returndata;
} else {
_revert(returndata, errorMessage);
}
}
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 {
if (returndata.length > 0) {
assembly {
let returndata_size := mload(returndata)
revert(add(32, returndata), returndata_size)
}
} else {
revert(errorMessage);
}
}
}
文件 2 的 19:Context.sol
pragma solidity ^0.8.0;
abstract contract Context {
function _msgSender() internal view virtual returns (address) {
return msg.sender;
}
function _msgData() internal view virtual returns (bytes calldata) {
return msg.data;
}
}
文件 3 的 19:ERC165.sol
pragma solidity ^0.8.0;
import "./IERC165.sol";
abstract contract ERC165 is IERC165 {
function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {
return interfaceId == type(IERC165).interfaceId;
}
}
文件 4 的 19:ERC2981Base.sol
pragma solidity ^0.8.9;
import "@openzeppelin/contracts/utils/introspection/ERC165.sol";
import "./IERC2981Royalties.sol";
abstract contract ERC2981Base is ERC165, IERC2981Royalties {
struct RoyaltyInfo {
address recipient;
uint24 amount;
}
function supportsInterface(bytes4 interfaceId)
public
view
virtual
override
returns (bool)
{
return
interfaceId == type(IERC2981Royalties).interfaceId ||
super.supportsInterface(interfaceId);
}
}
文件 5 的 19:ERC2981ContractWideRoyalties.sol
pragma solidity ^0.8.9;
import "@openzeppelin/contracts/utils/introspection/ERC165.sol";
import "./ERC2981Base.sol";
abstract contract ERC2981ContractWideRoyalties is ERC2981Base {
RoyaltyInfo private _royalties;
function _setRoyalties(
address _recipient,
uint256 _value
)
internal
{
_royalties = RoyaltyInfo(_recipient, uint24(_value));
}
function royaltyInfo(
uint256,
uint256 _value
)
external
view
override
returns (address receiver, uint256 royaltyAmount)
{
RoyaltyInfo memory royalties = _royalties;
receiver = royalties.recipient;
royaltyAmount = (_value * royalties.amount) / 10000;
}
}
文件 6 的 19:IERC1155.sol
pragma solidity ^0.8.0;
import "../../utils/introspection/IERC165.sol";
interface IERC1155 is IERC165 {
event TransferSingle(address indexed operator, address indexed from, address indexed to, uint256 id, uint256 value);
event TransferBatch(
address indexed operator,
address indexed from,
address indexed to,
uint256[] ids,
uint256[] values
);
event ApprovalForAll(address indexed account, address indexed operator, bool approved);
event URI(string value, uint256 indexed id);
function balanceOf(address account, uint256 id) external view returns (uint256);
function balanceOfBatch(address[] calldata accounts, uint256[] calldata ids)
external
view
returns (uint256[] memory);
function setApprovalForAll(address operator, bool approved) external;
function isApprovedForAll(address account, address operator) external view returns (bool);
function safeTransferFrom(
address from,
address to,
uint256 id,
uint256 amount,
bytes calldata data
) external;
function safeBatchTransferFrom(
address from,
address to,
uint256[] calldata ids,
uint256[] calldata amounts,
bytes calldata data
) external;
}
文件 7 的 19:IERC1155MetadataURI.sol
pragma solidity ^0.8.0;
import "../IERC1155.sol";
interface IERC1155MetadataURI is IERC1155 {
function uri(uint256 id) external view returns (string memory);
}
文件 8 的 19:IERC1155Receiver.sol
pragma solidity ^0.8.0;
import "../../utils/introspection/IERC165.sol";
interface IERC1155Receiver is IERC165 {
function onERC1155Received(
address operator,
address from,
uint256 id,
uint256 value,
bytes calldata data
) external returns (bytes4);
function onERC1155BatchReceived(
address operator,
address from,
uint256[] calldata ids,
uint256[] calldata values,
bytes calldata data
) external returns (bytes4);
}
文件 9 的 19:IERC165.sol
pragma solidity ^0.8.0;
interface IERC165 {
function supportsInterface(bytes4 interfaceId) external view returns (bool);
}
文件 10 的 19:IERC2981Royalties.sol
pragma solidity ^0.8.9;
interface IERC2981Royalties {
function royaltyInfo(uint256 _tokenId, uint256 _value)
external
view
returns (address _receiver, uint256 _royaltyAmount);
}
文件 11 的 19:ISAN.sol
pragma solidity ^0.8.17;
import "./SANSoulbindable.sol";
interface ISAN is SANSoulbindable {
function tokenLevel(uint256 _tokenId)
external
view
returns (SoulboundLevel _level);
function ownerOf(uint256 _tokenId) external view returns (address owner);
}
文件 12 的 19:ISANGA.sol
pragma solidity ^0.8.17;
interface ISANGA {
enum SaleState {
Paused,
Open
}
event SaleStateChanged(
SaleState newSaleState
);
error EpochIsNotMintable(uint256 epoch);
error ExceedsMaxRoyaltiesPercentage();
error SalePhaseNotActive();
error TokenAlreadyUsedThisEpoch(uint256 tokenId);
error TokenIsNotGold(uint256 tokenId);
error TokenIsNotSoulbound(uint256 tokenId);
error TokenIsNotOwned(uint256 tokenId);
}
文件 13 的 19:IStuckTokens.sol
pragma solidity ^0.8.12;
interface IStuckERC20 {
function transfer(
address to,
uint256 amount
) external returns (bool);
}
interface IStuckERC721 {
function safeTransferFrom(
address from,
address to,
uint256 tokenId
) external;
}
文件 14 的 19:Ownable.sol
pragma solidity ^0.8.12;
import "@openzeppelin/contracts/utils/Context.sol";
abstract contract Ownable is Context {
address private _owner;
event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);
constructor() {
_transferOwnership(_msgSender());
}
function owner() public view virtual returns (address) {
return _owner;
}
modifier onlyOwner() {
require(owner() == _msgSender(), "Ownable: caller is not the owner");
_;
}
function transferOwnership(address newOwner) public virtual onlyOwner {
require(newOwner != address(0), "Ownable: new owner is the zero address");
_transferOwnership(newOwner);
}
function _transferOwnership(address newOwner) internal virtual {
address oldOwner = _owner;
_owner = newOwner;
emit OwnershipTransferred(oldOwner, newOwner);
}
}
文件 15 的 19:SAN1155.sol
pragma solidity ^0.8.0;
import "@openzeppelin/contracts/token/ERC1155/IERC1155.sol";
import "@openzeppelin/contracts/token/ERC1155/IERC1155Receiver.sol";
import "@openzeppelin/contracts/token/ERC1155/extensions/IERC1155MetadataURI.sol";
import "@openzeppelin/contracts/utils/Address.sol";
import "@openzeppelin/contracts/utils/Context.sol";
import "@openzeppelin/contracts/utils/introspection/ERC165.sol";
contract SAN1155 is Context, ERC165, IERC1155, IERC1155MetadataURI {
using Address for address;
mapping(uint256 => mapping(address => uint256)) private _balances;
mapping(address => mapping(address => bool)) private _operatorApprovals;
string private _uri;
constructor(string memory uri_) {
_setURI(uri_);
}
function supportsInterface(bytes4 interfaceId) public view virtual override(ERC165, IERC165) returns (bool) {
return
interfaceId == type(IERC1155).interfaceId ||
interfaceId == type(IERC1155MetadataURI).interfaceId ||
super.supportsInterface(interfaceId);
}
function uri(uint256) public view virtual override returns (string memory) {
return _uri;
}
function balanceOf(address account, uint256 id) public view virtual override returns (uint256) {
require(account != address(0), "ERC1155: address zero is not a valid owner");
return _balances[id][account];
}
function balanceOfBatch(address[] memory accounts, uint256[] memory ids)
public
view
virtual
override
returns (uint256[] memory)
{
require(accounts.length == ids.length, "ERC1155: accounts and ids length mismatch");
uint256[] memory batchBalances = new uint256[](accounts.length);
for (uint256 i = 0; i < accounts.length; ++i) {
batchBalances[i] = balanceOf(accounts[i], ids[i]);
}
return batchBalances;
}
function setApprovalForAll(address operator, bool approved) public virtual override {
_setApprovalForAll(_msgSender(), operator, approved);
}
function isApprovedForAll(address account, address operator) public view virtual override returns (bool) {
return _operatorApprovals[account][operator];
}
function safeTransferFrom(
address from,
address to,
uint256 id,
uint256 amount,
bytes memory data
) public virtual override {
require(
from == _msgSender() || isApprovedForAll(from, _msgSender()),
"ERC1155: caller is not token owner or approved"
);
_safeTransferFrom(from, to, id, amount, data);
}
function safeBatchTransferFrom(
address from,
address to,
uint256[] memory ids,
uint256[] memory amounts,
bytes memory data
) public virtual override {
require(
from == _msgSender() || isApprovedForAll(from, _msgSender()),
"ERC1155: caller is not token owner or approved"
);
_safeBatchTransferFrom(from, to, ids, amounts, data);
}
function _safeTransferFrom(
address from,
address to,
uint256 id,
uint256 amount,
bytes memory data
) internal virtual {
require(to != address(0), "ERC1155: transfer to the zero address");
address operator = _msgSender();
uint256[] memory ids = _asSingletonArray(id);
uint256[] memory amounts = _asSingletonArray(amount);
_beforeTokenTransfer(operator, from, to, ids, amounts, data);
uint256 fromBalance = _balances[id][from];
require(fromBalance >= amount, "ERC1155: insufficient balance for transfer");
unchecked {
_balances[id][from] = fromBalance - amount;
}
_balances[id][to] += amount;
emit TransferSingle(operator, from, to, id, amount);
_afterTokenTransfer(operator, from, to, ids, amounts, data);
_doSafeTransferAcceptanceCheck(operator, from, to, id, amount, data);
}
function _safeBatchTransferFrom(
address from,
address to,
uint256[] memory ids,
uint256[] memory amounts,
bytes memory data
) internal virtual {
require(ids.length == amounts.length, "ERC1155: ids and amounts length mismatch");
require(to != address(0), "ERC1155: transfer to the zero address");
address operator = _msgSender();
_beforeTokenTransfer(operator, from, to, ids, amounts, data);
for (uint256 i = 0; i < ids.length; ++i) {
uint256 id = ids[i];
uint256 amount = amounts[i];
uint256 fromBalance = _balances[id][from];
require(fromBalance >= amount, "ERC1155: insufficient balance for transfer");
unchecked {
_balances[id][from] = fromBalance - amount;
}
_balances[id][to] += amount;
}
emit TransferBatch(operator, from, to, ids, amounts);
_afterTokenTransfer(operator, from, to, ids, amounts, data);
_doSafeBatchTransferAcceptanceCheck(operator, from, to, ids, amounts, data);
}
function _setURI(string memory newuri) internal virtual {
_uri = newuri;
}
function _mint(
address to,
uint256 id,
uint256 amount,
bytes memory data
) internal virtual {
require(to != address(0), "ERC1155: mint to the zero address");
address operator = _msgSender();
uint256[] memory ids = _asSingletonArray(id);
uint256[] memory amounts = _asSingletonArray(amount);
_beforeTokenTransfer(operator, address(0), to, ids, amounts, data);
_balances[id][to] += amount;
emit TransferSingle(operator, address(0), to, id, amount);
_afterTokenTransfer(operator, address(0), to, ids, amounts, data);
_doSafeTransferAcceptanceCheck(operator, address(0), to, id, amount, data);
}
function _mintSimple(
uint256 id,
uint256 amount
) internal virtual {
_balances[id][_msgSender()] += amount;
emit TransferSingle(_msgSender(), address(0), _msgSender(), id, amount);
}
function _mintBatch(
address to,
uint256[] memory ids,
uint256[] memory amounts,
bytes memory data
) internal virtual {
require(to != address(0), "ERC1155: mint to the zero address");
require(ids.length == amounts.length, "ERC1155: ids and amounts length mismatch");
address operator = _msgSender();
_beforeTokenTransfer(operator, address(0), to, ids, amounts, data);
for (uint256 i = 0; i < ids.length; i++) {
_balances[ids[i]][to] += amounts[i];
}
emit TransferBatch(operator, address(0), to, ids, amounts);
_afterTokenTransfer(operator, address(0), to, ids, amounts, data);
_doSafeBatchTransferAcceptanceCheck(operator, address(0), to, ids, amounts, data);
}
function _mintBatchSimple(
uint256[] memory ids,
uint256[] memory amounts
) internal virtual {
for (uint256 i = 0; i < ids.length; ++i) {
_balances[ids[i]][_msgSender()] += amounts[i];
}
emit TransferBatch(_msgSender(), address(0), _msgSender(), ids, amounts);
}
function _burn(
address from,
uint256 id,
uint256 amount
) internal virtual {
require(from != address(0), "ERC1155: burn from the zero address");
address operator = _msgSender();
uint256[] memory ids = _asSingletonArray(id);
uint256[] memory amounts = _asSingletonArray(amount);
_beforeTokenTransfer(operator, from, address(0), ids, amounts, "");
uint256 fromBalance = _balances[id][from];
require(fromBalance >= amount, "ERC1155: burn amount exceeds balance");
unchecked {
_balances[id][from] = fromBalance - amount;
}
emit TransferSingle(operator, from, address(0), id, amount);
_afterTokenTransfer(operator, from, address(0), ids, amounts, "");
}
function _burnBatch(
address from,
uint256[] memory ids,
uint256[] memory amounts
) internal virtual {
require(from != address(0), "ERC1155: burn from the zero address");
require(ids.length == amounts.length, "ERC1155: ids and amounts length mismatch");
address operator = _msgSender();
_beforeTokenTransfer(operator, from, address(0), ids, amounts, "");
for (uint256 i = 0; i < ids.length; i++) {
uint256 id = ids[i];
uint256 amount = amounts[i];
uint256 fromBalance = _balances[id][from];
require(fromBalance >= amount, "ERC1155: burn amount exceeds balance");
unchecked {
_balances[id][from] = fromBalance - amount;
}
}
emit TransferBatch(operator, from, address(0), ids, amounts);
_afterTokenTransfer(operator, from, address(0), ids, amounts, "");
}
function _setApprovalForAll(
address owner,
address operator,
bool approved
) internal virtual {
require(owner != operator, "ERC1155: setting approval status for self");
_operatorApprovals[owner][operator] = approved;
emit ApprovalForAll(owner, operator, approved);
}
function _beforeTokenTransfer(
address operator,
address from,
address to,
uint256[] memory ids,
uint256[] memory amounts,
bytes memory data
) internal virtual {}
function _afterTokenTransfer(
address operator,
address from,
address to,
uint256[] memory ids,
uint256[] memory amounts,
bytes memory data
) internal virtual {}
function _doSafeTransferAcceptanceCheck(
address operator,
address from,
address to,
uint256 id,
uint256 amount,
bytes memory data
) private {
if (to.isContract()) {
try IERC1155Receiver(to).onERC1155Received(operator, from, id, amount, data) returns (bytes4 response) {
if (response != IERC1155Receiver.onERC1155Received.selector) {
revert("ERC1155: ERC1155Receiver rejected tokens");
}
} catch Error(string memory reason) {
revert(reason);
} catch {
revert("ERC1155: transfer to non-ERC1155Receiver implementer");
}
}
}
function _doSafeBatchTransferAcceptanceCheck(
address operator,
address from,
address to,
uint256[] memory ids,
uint256[] memory amounts,
bytes memory data
) private {
if (to.isContract()) {
try IERC1155Receiver(to).onERC1155BatchReceived(operator, from, ids, amounts, data) returns (
bytes4 response
) {
if (response != IERC1155Receiver.onERC1155BatchReceived.selector) {
revert("ERC1155: ERC1155Receiver rejected tokens");
}
} catch Error(string memory reason) {
revert(reason);
} catch {
revert("ERC1155: transfer to non-ERC1155Receiver implementer");
}
}
}
function _asSingletonArray(uint256 element) private pure returns (uint256[] memory) {
uint256[] memory array = new uint256[](1);
array[0] = element;
return array;
}
}
文件 16 的 19:SANGA.sol
pragma solidity ^0.8.17;
import "./SAN1155.sol";
import "./token/ERC2981ContractWideRoyalties.sol";
import "./token/TokenRescuer.sol";
import "./ISAN.sol";
import "./SANSoulbindable.sol";
import "./ISANGA.sol";
contract SANGA is
ISANGA,
SAN1155,
ERC2981ContractWideRoyalties,
TokenRescuer,
SANSoulbindable
{
uint256 public constant MAX_ROYALTIES_PCT = 333;
ISAN public immutable SAN;
uint256 immutable public FLOW_ORIGINATION_TIME;
uint256 immutable public FLOW_RATE;
string public name;
string public symbol;
string public contractURI;
SaleState public saleState = SaleState.Open;
mapping(uint256 => bool) private epochSkipped;
mapping(uint256 => uint256[40]) private epochSanUsed;
uint256[40] private sanGoldTokenBitfield = [
36893488147419103232,
11150373928493307355683732040131241033334784,
2305843009213693952,
1606938044258990275541962092341162602522202993782792835301376,
55213970774324510299478046898216203619608871796705905555134260602470400,
21267647932558658688827395834130726912,
205688069665150755269371147819668813122841983204197482918576128,
1725438232202198268064731120538439917384279064465366950225789614817280,
0,
441711766194596180475538996311607334714920236071836368927967390581391360,
28269553036454155550626057352616065595456100367924597067487529538800320512,
452312848583266388373324160190187140051835877600177796092245021597705961472,
784637716923424298460267800393524444885885024004028235776,
11692013098647223345629478661730264157247460343808,
187437584987688299259622580400326207078187935989760,
514220174162876888173427869550470107021738738992833002368795136,
1461501648222607500259002564945408316080753213440,
102844034834071955311312418498074979830122465414226416383295488,
10889077279844899109449015681787216527362,
27606985387162267410077494795375679823640796408330383623876468071727104,
79228162514264337593543950336,
57896044618658097711785492504343953926634992332820282019728792003956564819968,
6277101735386680763835789423207666416102355444466181996545,
40728227292489011044181186969600,
2147549184,
13164036483089576991093975194192356474276505269525381895124156416,
12855504354071922204335696738729300820187068683228081972838912,
21778071482940216404160885548167527923712,
2722258935525964032735525534641233608740,
862718704724959803824391304722084463551968387438819483148461178617856,
3369993333394596315640628243330772752694576644254665679320626757633,
36028938752884736,
0,
2993155353253689176481146537402947624255349864792064,
411376139330488582748320651213029957181100864178446488307761664,
14474011154717180573780651719434947495500583299404132133890181186165372092416,
365380984519025362206706592108638917004359630848,
10385861367669883486462489361645568,
383123885216472214589749016064406509268076358556188672,
0
];
constructor(
string memory _name,
string memory _symbol,
string memory _contractURI,
string memory _baseURI,
address _royaltiesReceiver,
uint256 _royaltiesPercent,
uint256 _flowOriginationTime,
uint256 _flowRate,
address _sanContract
)
SAN1155(_baseURI)
{
name = _name;
symbol = _symbol;
contractURI = _contractURI;
setRoyalties(
_royaltiesReceiver,
_royaltiesPercent
);
FLOW_ORIGINATION_TIME = _flowOriginationTime;
FLOW_RATE = _flowRate;
SAN = ISAN(_sanContract);
}
function mint(
uint256[] calldata _sanIdsForGold,
uint256[] calldata _sanIdsForColor,
uint256[] calldata _sanIdsForMono
)
external
{
if (saleState == SaleState.Paused) revert SalePhaseNotActive();
uint256 epoch = _currentEpoch();
if (epochIsMintable(epoch) == false) revert EpochIsNotMintable(epoch);
unchecked {
for (uint i = 0; i < _sanIdsForGold.length; ++i) {
uint256 tokenId = _sanIdsForGold[i];
if (!sanTokenIsGold(tokenId))
revert TokenIsNotGold(tokenId);
if (tokenWasUsedInEpoch(epoch, tokenId))
revert TokenAlreadyUsedThisEpoch(tokenId);
if (SAN.ownerOf(tokenId) != _msgSender())
revert TokenIsNotOwned(tokenId);
_setTokenUsedThisEpoch(tokenId);
}
for (uint i = 0; i < _sanIdsForColor.length; ++i) {
uint256 tokenId = _sanIdsForColor[i];
if (tokenWasUsedInEpoch(epoch, tokenId))
revert TokenAlreadyUsedThisEpoch(tokenId);
if (SAN.ownerOf(tokenId) != _msgSender())
revert TokenIsNotOwned(tokenId);
if (SAN.tokenLevel(tokenId) == SoulboundLevel.Unbound)
revert TokenIsNotSoulbound(tokenId);
_setTokenUsedThisEpoch(tokenId);
}
for (uint i = 0; i < _sanIdsForMono.length; ++i) {
uint256 tokenId = _sanIdsForMono[i];
if (tokenWasUsedInEpoch(epoch, tokenId))
revert TokenAlreadyUsedThisEpoch(tokenId);
if (SAN.ownerOf(tokenId) != _msgSender())
revert TokenIsNotOwned(tokenId);
_setTokenUsedThisEpoch(tokenId);
}
uint256 idCount;
if (_sanIdsForMono.length > 0) ++idCount;
if (_sanIdsForColor.length > 0) ++idCount;
if (_sanIdsForGold.length > 0) ++idCount;
if (idCount == 1) {
if (_sanIdsForMono.length > 0) {
_mintSimple(currentMonoTokenId(), _sanIdsForMono.length);
}
else if (_sanIdsForColor.length > 0) {
_mintSimple(currentColorTokenId(), _sanIdsForColor.length);
}
else {
_mintSimple(currentGoldTokenId(), _sanIdsForGold.length);
}
}
else {
uint256[] memory ids = new uint256[](idCount);
uint256[] memory amounts = new uint256[](idCount);
uint256 curIndex;
if (_sanIdsForMono.length > 0) {
ids[curIndex] = currentMonoTokenId();
amounts[curIndex] = _sanIdsForMono.length;
++curIndex;
}
if (_sanIdsForColor.length > 0) {
ids[curIndex] = currentColorTokenId();
amounts[curIndex] = _sanIdsForColor.length;
++curIndex;
}
if (_sanIdsForGold.length > 0) {
ids[curIndex] = currentGoldTokenId();
amounts[curIndex] = _sanIdsForGold.length;
}
_mintBatchSimple(ids, amounts);
}
}
}
function setContractURI(
string calldata _newContractURI
)
external
onlyOwner
{
contractURI = _newContractURI;
}
function setEpochSkipped(
uint256 _epoch,
bool _isSkipped
)
external
onlyOwner
{
epochSkipped[_epoch] = _isSkipped;
}
function setSaleState(
SaleState _newSaleState
)
external
onlyOwner
{
saleState = _newSaleState;
emit SaleStateChanged(_newSaleState);
}
function setURI(
string calldata _newURI
)
external
onlyOwner
{
_setURI(_newURI);
}
function currentEpoch()
external
view
returns (uint256 epoch_)
{
epoch_ = _currentEpoch();
}
function tokensUnusedThisEpoch(
uint256[] calldata _sanTokenIds
)
external
view
returns (uint256[] memory unusedTokenIds_)
{
uint256 epoch = _currentEpoch();
unusedTokenIds_ = new uint256[](_sanTokenIds.length);
unchecked {
for(uint i = 0; i < _sanTokenIds.length; ++i) {
uint256 tokenId = _sanTokenIds[i];
if (tokenWasUsedInEpoch(epoch, tokenId) == false) {
unusedTokenIds_[i] = tokenId;
}
}
}
}
function setRoyalties(
address _recipient,
uint256 _value
)
public
onlyOwner
{
if (_value > MAX_ROYALTIES_PCT) revert ExceedsMaxRoyaltiesPercentage();
_setRoyalties(
_recipient,
_value
);
}
function currentGoldTokenId()
public
view
returns (uint256 _tokenId)
{
unchecked {
return 3 + _currentEpoch() * 10;
}
}
function currentColorTokenId()
public
view
returns (uint256 _tokenId)
{
unchecked {
return 2 + _currentEpoch() * 10;
}
}
function currentMonoTokenId()
public
view
returns (uint256 _tokenId)
{
unchecked {
return 1 + _currentEpoch() * 10;
}
}
function currentEpochIsMintable()
public
view
returns (bool isMintable_)
{
uint256 epoch = _currentEpoch();
isMintable_ = epochIsMintable(epoch);
}
function epochIsMintable(
uint256 _epoch
)
public
view
returns (bool isMintable_)
{
isMintable_ = _epoch > 0 && epochSkipped[_epoch] == false;
}
function sanTokenIsGold(
uint256 _sanTokenId
)
public
view
returns (bool isGold_)
{
uint256 bucket = _sanTokenId >> 8;
uint256 mask = 1 << (_sanTokenId & 0xff);
isGold_ = sanGoldTokenBitfield[bucket] & mask > 0;
}
function tokenWasUsedInEpoch(
uint256 _epoch,
uint256 _sanTokenId
)
public
view
returns (bool hasBeenUsed_)
{
uint256 bucket = _sanTokenId >> 8;
uint256 mask = 1 << (_sanTokenId & 0xff);
hasBeenUsed_ = epochSanUsed[_epoch][bucket] & mask > 0;
}
function supportsInterface(
bytes4 _interfaceId
)
public
view
override (SAN1155, ERC2981Base)
returns (bool)
{
return super.supportsInterface(_interfaceId);
}
function _setTokenUsedThisEpoch(
uint256 _sanTokenId
)
private
{
uint256 bucket = _sanTokenId >> 8;
uint256 mask = 1 << (_sanTokenId & 0xff);
epochSanUsed[_currentEpoch()][bucket] |= mask;
}
function _currentEpoch()
private
view
returns (uint256 epoch_)
{
if (block.timestamp < FLOW_ORIGINATION_TIME) {
epoch_ = 0;
}
else {
unchecked {
epoch_ = 1 + (block.timestamp - FLOW_ORIGINATION_TIME) / FLOW_RATE;
}
}
}
function ___ART_MUST_FLOW___()
external
pure
returns (string memory haiku_)
{
haiku_ =
"cromagnus the name ||| "
"mystery in his brush strokes ||| "
"art must always flow";
}
}
文件 17 的 19:SANSoulbindable.sol
pragma solidity ^0.8.17;
interface SANSoulbindable {
enum SoulboundLevel { Unbound, One, Two, Three, Four }
}
文件 18 的 19:SafeERC20.sol
pragma solidity ^0.8.0;
import "./IStuckTokens.sol";
import "@openzeppelin/contracts/utils/Address.sol";
library SafeERC20 {
using Address for address;
function safeTransfer(
IStuckERC20 token,
address to,
uint256 value
) internal {
_callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value));
}
function _callOptionalReturn(IStuckERC20 token, bytes memory data) private {
bytes memory returndata = address(token).functionCall(data, "SafeERC20: low-level call failed");
if (returndata.length > 0) {
require(abi.decode(returndata, (bool)), "SafeERC20: ERC20 operation did not succeed");
}
}
}
文件 19 的 19:TokenRescuer.sol
pragma solidity ^0.8.12;
import "./IStuckTokens.sol";
import "./SafeERC20.sol";
import "../utils/Ownable.sol";
error ArrayLengthMismatch();
contract TokenRescuer is Ownable {
using SafeERC20 for IStuckERC20;
function rescueBatchERC20(
address _token,
address[] calldata _receivers,
uint256[] calldata _amounts
)
external
onlyOwner
{
if (_receivers.length != _amounts.length) revert ArrayLengthMismatch();
unchecked {
for (uint i; i < _receivers.length; i += 1) {
_rescueERC20(_token, _receivers[i], _amounts[i]);
}
}
}
function rescueERC20(
address _token,
address _receiver,
uint256 _amount
)
external
onlyOwner
{
_rescueERC20(_token, _receiver, _amount);
}
function rescueBatchERC721(
address _token,
address[] calldata _receivers,
uint256[][] calldata _tokenIDs
)
external
onlyOwner
{
if (_receivers.length != _tokenIDs.length) revert ArrayLengthMismatch();
unchecked {
for (uint i; i < _receivers.length; i += 1) {
uint256[] memory tokenIDs = _tokenIDs[i];
for (uint j; j < tokenIDs.length; j += 1) {
_rescueERC721(_token, _receivers[i], tokenIDs[j]);
}
}
}
}
function rescueERC721(
address _token,
address _receiver,
uint256 _tokenID
)
external
onlyOwner
{
_rescueERC721(_token, _receiver, _tokenID);
}
function _rescueERC20(
address _token,
address _receiver,
uint256 _amount
)
private
{
IStuckERC20(_token).safeTransfer(_receiver, _amount);
}
function _rescueERC721(
address _token,
address _receiver,
uint256 _tokenID
)
private
{
IStuckERC721(_token).safeTransferFrom(
address(this),
_receiver,
_tokenID
);
}
}
{
"compilationTarget": {
"contracts/SANGA.sol": "SANGA"
},
"evmVersion": "london",
"libraries": {},
"metadata": {
"bytecodeHash": "ipfs"
},
"optimizer": {
"enabled": true,
"runs": 33333
},
"remappings": []
}
[{"inputs":[{"internalType":"string","name":"_name","type":"string"},{"internalType":"string","name":"_symbol","type":"string"},{"internalType":"string","name":"_contractURI","type":"string"},{"internalType":"string","name":"_baseURI","type":"string"},{"internalType":"address","name":"_royaltiesReceiver","type":"address"},{"internalType":"uint256","name":"_royaltiesPercent","type":"uint256"},{"internalType":"uint256","name":"_flowOriginationTime","type":"uint256"},{"internalType":"uint256","name":"_flowRate","type":"uint256"},{"internalType":"address","name":"_sanContract","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"ArrayLengthMismatch","type":"error"},{"inputs":[{"internalType":"uint256","name":"epoch","type":"uint256"}],"name":"EpochIsNotMintable","type":"error"},{"inputs":[],"name":"ExceedsMaxRoyaltiesPercentage","type":"error"},{"inputs":[],"name":"SalePhaseNotActive","type":"error"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"TokenAlreadyUsedThisEpoch","type":"error"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"TokenIsNotGold","type":"error"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"TokenIsNotOwned","type":"error"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"TokenIsNotSoulbound","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":true,"internalType":"address","name":"operator","type":"address"},{"indexed":false,"internalType":"bool","name":"approved","type":"bool"}],"name":"ApprovalForAll","type":"event"},{"anonymous":false,"inputs":[{"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":"enum ISANGA.SaleState","name":"newSaleState","type":"uint8"}],"name":"SaleStateChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"operator","type":"address"},{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"uint256[]","name":"ids","type":"uint256[]"},{"indexed":false,"internalType":"uint256[]","name":"values","type":"uint256[]"}],"name":"TransferBatch","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"operator","type":"address"},{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"uint256","name":"id","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"value","type":"uint256"}],"name":"TransferSingle","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"string","name":"value","type":"string"},{"indexed":true,"internalType":"uint256","name":"id","type":"uint256"}],"name":"URI","type":"event"},{"inputs":[],"name":"FLOW_ORIGINATION_TIME","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"FLOW_RATE","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"MAX_ROYALTIES_PCT","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"SAN","outputs":[{"internalType":"contract ISAN","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"___ART_MUST_FLOW___","outputs":[{"internalType":"string","name":"haiku_","type":"string"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"},{"internalType":"uint256","name":"id","type":"uint256"}],"name":"balanceOf","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address[]","name":"accounts","type":"address[]"},{"internalType":"uint256[]","name":"ids","type":"uint256[]"}],"name":"balanceOfBatch","outputs":[{"internalType":"uint256[]","name":"","type":"uint256[]"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"contractURI","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"currentColorTokenId","outputs":[{"internalType":"uint256","name":"_tokenId","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"currentEpoch","outputs":[{"internalType":"uint256","name":"epoch_","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"currentEpochIsMintable","outputs":[{"internalType":"bool","name":"isMintable_","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"currentGoldTokenId","outputs":[{"internalType":"uint256","name":"_tokenId","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"currentMonoTokenId","outputs":[{"internalType":"uint256","name":"_tokenId","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_epoch","type":"uint256"}],"name":"epochIsMintable","outputs":[{"internalType":"bool","name":"isMintable_","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"},{"internalType":"address","name":"operator","type":"address"}],"name":"isApprovedForAll","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256[]","name":"_sanIdsForGold","type":"uint256[]"},{"internalType":"uint256[]","name":"_sanIdsForColor","type":"uint256[]"},{"internalType":"uint256[]","name":"_sanIdsForMono","type":"uint256[]"}],"name":"mint","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"name","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_token","type":"address"},{"internalType":"address[]","name":"_receivers","type":"address[]"},{"internalType":"uint256[]","name":"_amounts","type":"uint256[]"}],"name":"rescueBatchERC20","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_token","type":"address"},{"internalType":"address[]","name":"_receivers","type":"address[]"},{"internalType":"uint256[][]","name":"_tokenIDs","type":"uint256[][]"}],"name":"rescueBatchERC721","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_token","type":"address"},{"internalType":"address","name":"_receiver","type":"address"},{"internalType":"uint256","name":"_amount","type":"uint256"}],"name":"rescueERC20","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_token","type":"address"},{"internalType":"address","name":"_receiver","type":"address"},{"internalType":"uint256","name":"_tokenID","type":"uint256"}],"name":"rescueERC721","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"uint256","name":"_value","type":"uint256"}],"name":"royaltyInfo","outputs":[{"internalType":"address","name":"receiver","type":"address"},{"internalType":"uint256","name":"royaltyAmount","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256[]","name":"ids","type":"uint256[]"},{"internalType":"uint256[]","name":"amounts","type":"uint256[]"},{"internalType":"bytes","name":"data","type":"bytes"}],"name":"safeBatchTransferFrom","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"id","type":"uint256"},{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"bytes","name":"data","type":"bytes"}],"name":"safeTransferFrom","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"saleState","outputs":[{"internalType":"enum ISANGA.SaleState","name":"","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_sanTokenId","type":"uint256"}],"name":"sanTokenIsGold","outputs":[{"internalType":"bool","name":"isGold_","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"operator","type":"address"},{"internalType":"bool","name":"approved","type":"bool"}],"name":"setApprovalForAll","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"string","name":"_newContractURI","type":"string"}],"name":"setContractURI","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_epoch","type":"uint256"},{"internalType":"bool","name":"_isSkipped","type":"bool"}],"name":"setEpochSkipped","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_recipient","type":"address"},{"internalType":"uint256","name":"_value","type":"uint256"}],"name":"setRoyalties","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"enum ISANGA.SaleState","name":"_newSaleState","type":"uint8"}],"name":"setSaleState","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"string","name":"_newURI","type":"string"}],"name":"setURI","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes4","name":"_interfaceId","type":"bytes4"}],"name":"supportsInterface","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"symbol","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_epoch","type":"uint256"},{"internalType":"uint256","name":"_sanTokenId","type":"uint256"}],"name":"tokenWasUsedInEpoch","outputs":[{"internalType":"bool","name":"hasBeenUsed_","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256[]","name":"_sanTokenIds","type":"uint256[]"}],"name":"tokensUnusedThisEpoch","outputs":[{"internalType":"uint256[]","name":"unusedTokenIds_","type":"uint256[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"uri","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"}]