Address Contract Verified
Address
0x3CAE07354674657f3D99F5d16a0e7B676CaBA8aA
Balance
0 ETH
Nonce
1
Code Size
3898 bytes
Creator
0xB7759A43...8532 at tx 0x5070b8ce...a072b6
Indexed Transactions
0
Contract Bytecode
3898 bytes
0x608060405234801561001057600080fd5b50600436106100f55760003560e01c80638da5cb5b11610097578063dc0023a411610066578063dc0023a41461019c578063e047cd02146101af578063e2c7ea49146101c2578063f2fde38b146101ca576100f5565b80638da5cb5b1461016f5780639175442b14610184578063929e26ce1461018c578063b915d51414610194576100f5565b806358f6ec17116100d357806358f6ec1714610128578063715018a61461013057806381b89c011461013a5780638da413101461015c576100f5565b8063038d97fc146100fa5780632b38d96714610118578063345e958d14610120575b600080fd5b6101026101dd565b60405161010f9190610e67565b60405180910390f35b6101026101e3565b6101026101e9565b6101026101ee565b6101386101f5565b005b61014d610148366004610c4b565b610249565b60405161010f93929190610e70565b61013861016a366004610bb2565b610273565b610177610474565b60405161010f9190610c7b565b610177610483565b610177610492565b6101776104a1565b6101386101aa366004610bf2565b6104c5565b6101386101bd366004610b73565b61059a565b6101026105fb565b6101386101d8366004610b73565b610601565b60065481565b60055481565b601481565b6207e90081565b6101fd610672565b6001600160a01b031661020e610474565b6001600160a01b03161461023d5760405162461bcd60e51b815260040161023490610dfb565b60405180910390fd5b6102476000610676565b565b6003602052600090815260409020805460018201546002909201549091906001600160a01b031683565b60005b8181101561046f57610286610672565b6001600160a01b03167f0000000000000000000000006eb96c788abe0ee611d0610d4cc3b0463f411f806001600160a01b0316636352211e8585858181106102de57634e487b7160e01b600052603260045260246000fd5b905060200201356040518263ffffffff1660e01b81526004016103019190610e67565b60206040518083038186803b15801561031957600080fd5b505afa15801561032d573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906103519190610b96565b6001600160a01b0316146103775760405162461bcd60e51b815260040161023490610e30565b7f0000000000000000000000006eb96c788abe0ee611d0610d4cc3b0463f411f806001600160a01b03166323b872dd6103ae610672565b308686868181106103cf57634e487b7160e01b600052603260045260246000fd5b905060200201356040518463ffffffff1660e01b81526004016103f493929190610c8f565b600060405180830381600087803b15801561040e57600080fd5b505af1158015610422573d6000803e3d6000fd5b5050505061045d610431610672565b84848481811061045157634e487b7160e01b600052603260045260246000fd5b905060200201356106c6565b8061046781610ebe565b915050610276565b505050565b6000546001600160a01b031690565b6002546001600160a01b031681565b6001546001600160a01b031681565b7f0000000000000000000000006eb96c788abe0ee611d0610d4cc3b0463f411f8081565b6000805b8381101561051f576105018585838181106104f457634e487b7160e01b600052603260045260246000fd5b905060200201358461080c565b61050b9083610e8f565b91508061051781610ebe565b9150506104c9565b508061052b575061046f565b6001546001600160a01b03166340c10f19610544610672565b836040518363ffffffff1660e01b8152600401610562929190610ce6565b600060405180830381600087803b15801561057c57600080fd5b505af1158015610590573d6000803e3d6000fd5b5050505050505050565b6105a2610672565b6001600160a01b03166105b3610474565b6001600160a01b0316146105d95760405162461bcd60e51b815260040161023490610dfb565b600280546001600160a01b0319166001600160a01b0392909216919091179055565b60045481565b610609610672565b6001600160a01b031661061a610474565b6001600160a01b0316146106405760405162461bcd60e51b815260040161023490610dfb565b6001600160a01b0381166106665760405162461bcd60e51b815260040161023490610d25565b61066f81610676565b50565b3390565b600080546001600160a01b038381166001600160a01b0319831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b600260009054906101000a90046001600160a01b03166001600160a01b0316632b38d9676040518163ffffffff1660e01b815260040160206040518083038186803b15801561071457600080fd5b505afa158015610728573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061074c9190610c63565b6005819055604080516060810182529182524260208084019182526001600160a01b03868116858501908152600087815260039093529382209451855591516001808601919091559251600290940180546001600160a01b0319169490921693909317905560048054919290916107c4908490610e8f565b90915550506005546040517f5b51df9e1d0bef50785d50d1e458a299efb92d839dbcdbd071c53d0e7598747c9161080091859185914290610cff565b60405180910390a15050565b6000828152600360209081526040808320815160608101835281548152600182015493810193909352600201546001600160a01b03169082015261084e610672565b6001600160a01b031681604001516001600160a01b0316146108825760405162461bcd60e51b815260040161023490610d6b565b60008160200151426108949190610ea7565b90506207e90081116108b85760405162461bcd60e51b815260040161023490610db6565b600260009054906101000a90046001600160a01b03166001600160a01b0316632b38d9676040518163ffffffff1660e01b815260040160206040518083038186803b15801561090657600080fd5b505afa15801561091a573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061093e9190610c63565b600581905582516000916109529190610ea7565b90506c097761759c34d7b26fb0000000816006546109709190610e8f565b111561099357600654610990906c097761759c34d7b26fb0000000610ea7565b90505b8415610ab1577f0000000000000000000000006eb96c788abe0ee611d0610d4cc3b0463f411f806001600160a01b031663b88d4fde306109d1610672565b896040518463ffffffff1660e01b81526004016109f093929190610cb3565b600060405180830381600087803b158015610a0a57600080fd5b505af1158015610a1e573d6000803e3d6000fd5b50505060008781526003602052604081208181556001808201839055600290910180546001600160a01b0319169055600480549193509190610a61908490610ea7565b909155507fe975c186f5b9a7363e112820b924ffa6c8705779c23cf5b322e9654d9477b80e9050610a90610672565b600554604051610aa492918a914290610cff565b60405180910390a1610b09565b6005546000878152600360205260409020557f20b2c0fa80a2767a2208e117551c7db22093ea54b8f557d5ec465fc516119cf6610aec610672565b600554604051610b0092918a914290610cff565b60405180910390a15b8060066000828254610b1b9190610e8f565b90915550909695505050505050565b60008083601f840112610b3b578182fd5b50813567ffffffffffffffff811115610b52578182fd5b6020830191508360208083028501011115610b6c57600080fd5b9250929050565b600060208284031215610b84578081fd5b8135610b8f81610eef565b9392505050565b600060208284031215610ba7578081fd5b8151610b8f81610eef565b60008060208385031215610bc4578081fd5b823567ffffffffffffffff811115610bda578182fd5b610be685828601610b2a565b90969095509350505050565b600080600060408486031215610c06578081fd5b833567ffffffffffffffff811115610c1c578182fd5b610c2886828701610b2a565b90945092505060208401358015158114610c40578182fd5b809150509250925092565b600060208284031215610c5c578081fd5b5035919050565b600060208284031215610c74578081fd5b5051919050565b6001600160a01b0391909116815260200190565b6001600160a01b039384168152919092166020820152604081019190915260600190565b6001600160a01b039384168152919092166020820152604081019190915260806060820181905260009082015260a00190565b6001600160a01b03929092168252602082015260400190565b6001600160a01b0394909416845260208401929092526040830152606082015260800190565b60208082526026908201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160408201526564647265737360d01b606082015260800190565b6020808252602b908201527f54686973207765616c746879207768616c65206973206f776e6564206279207360408201526a6f6d656f6e6520656c736560a81b606082015260800190565b60208082526025908201527f4d7573742068617665207374616b656420666f72206174206c65617374203620604082015264646179732160d81b606082015260800190565b6020808252818101527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e6572604082015260600190565b60208082526017908201527f54686973206973206e6f7420796f757220746f6b656e21000000000000000000604082015260600190565b90815260200190565b92835260208301919091526001600160a01b0316604082015260600190565b60008219821115610ea257610ea2610ed9565b500190565b600082821015610eb957610eb9610ed9565b500390565b6000600019821415610ed257610ed2610ed9565b5060010190565b634e487b7160e01b600052601160045260246000fd5b6001600160a01b038116811461066f57600080fdfea26469706673582212208f5f1daaf0c29af2c472f32ed78366f6ffc9dfad54e3469d6a0547e905205c0264736f6c63430008000033
Verified Source Code Full Match
Compiler: v0.8.0+commit.c7dfd78e
EVM: istanbul
Optimization: Yes (200 runs)
IERC721Metadata.sol 26 lines
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
import "../IERC721.sol";
/**
* @title ERC-721 Non-Fungible Token Standard, optional metadata extension
* @dev See https://eips.ethereum.org/EIPS/eip-721
*/
interface IERC721Metadata is IERC721 {
/**
* @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);
}
Whales.sol 98 lines
// SPDX-License-Identifier: MIT
/*
«∩ⁿ─╖
⌐ ╦╠Σ▌╓┴ .⌐─≈-,
≤╠╠╠╫╕╬╦╜ ┌"░░░░░░░░░░≈╖φ░╔╦╬░░Σ╜^
¼,╠.:╬╬╦╖╔≡p "╙φ░ ╠╩╚` ░╩░╟╓╜
Γ╠▀╬═┘` Θ Å░▄
,,,,, ┌# ] ▌░░╕
,-─S╜" ,⌐"",`░░φ░░░░S>╫▐ ╩ ░░░░¼
╙ⁿ═s, <░φ╬░░φù ░░░░░░░░╬╠░░"Zw, ,─╓φ░Å░░╩╧w¼
∩²≥┴╝δ»╬░╝░░╩░╓║╙░░░░░░Åφ▄φ░░╦≥░⌠░≥╖, ,≈"╓φ░░░╬╬░░╕ {⌐\
} ▐ ½,#░░░░░╦╚░░╬╜Σ░p╠░░╬╘░░░░╩ ^"¥7"""░"¬╖╠░░░#▒░░░╩ φ╩ ∩
Γ ╬░⌐"╢╙φ░░▒╬╓╓░░░░▄▄╬▄░╬░░Å░░░░╠░╦,φ╠░░░░░░-"╠░╩╩ ê░Γ╠
╘░,, ╠╬ '░╗Σ╢░░░░░░▀╢▓▒▒╬╬░╦#####≥╨░░░╝╜╙` ,φ╬░░░. é░░╔⌐
▐░ `^Σ░▒╗, ▐░░░░░ ▒░"╙Σ░╨▀╜╬░▓▓▓▓▓▓▀▀░»φ░N ╔╬▒░░░"`,╬≥░░╢
\ ╠░░░░░░╬#╩╣▄░Γ, ▐░,φ╬▄Å` ░ ```"╚░░░░,╓▄▄▄╬▀▀░╠╙░╔╬░░░ ½"
└ '░░░░░░╦╠ ╟▒M╗▄▄,▄▄▄╗#▒╬▒╠"╙╙╙╙╙╙╢▒▒▓▀▀░░░░░╠╦#░░░░╚,╩
¼░░░░░░░⌂╦ ▀░░░╚╙░╚▓▒▀░░░½░░╠╜ ╘▀░░░╩╩╩,▄╣╬░░░░░╙╔╩
╢^╙╨╠░░▄æ,Σ ",╓╥m╬░░░░░░░Θ░φ░φ▄ ╬╬░,▄#▒▀░░░░░≥░░#`
*╓,╙φ░░░░░#░░░░░░░#╬╠╩ ╠╩╚╠╟▓▄╣▒▓╬▓▀░░░░░╩░╓═^
`"╜╧Σ░░░Σ░░░░░░╬▓µ ─"░░░░░░░░░░╜░╬▄≈"
`"╙╜╜╜╝╩ÅΣM≡,`╙╚░╙╙░╜| ╙╙╙┴7≥╗
`"┴╙¬¬¬┴┴╙╙╙╙""
*/
pragma solidity ^0.8.0;
import "@openzeppelin/contracts/token/ERC721/ERC721.sol";
import "@openzeppelin/contracts/access/Ownable.sol";
import "@openzeppelin/contracts/token/ERC721/extensions/ERC721Enumerable.sol";
contract Whales is ERC721, ERC721Enumerable, Ownable {
string public PROVENANCE;
uint256 public constant tokenPrice = 50000000000000000; // 0.05 ETH
uint public constant maxTokenPurchase = 10;
uint256 public MAX_TOKENS = 10000;
bool public saleIsActive = false;
string private _baseURIextended;
constructor() ERC721("Secret Society of Whales", "SSOW") {
}
function _beforeTokenTransfer(address from, address to, uint256 tokenId) internal override(ERC721, ERC721Enumerable) {
super._beforeTokenTransfer(from, to, tokenId);
}
function supportsInterface(bytes4 interfaceId) public view virtual override(ERC721, ERC721Enumerable) returns (bool) {
return super.supportsInterface(interfaceId);
}
function setBaseURI(string memory baseURI_) external onlyOwner() {
_baseURIextended = baseURI_;
}
function _baseURI() internal view virtual override returns (string memory) {
return _baseURIextended;
}
function setProvenance(string memory provenance) public onlyOwner {
PROVENANCE = provenance;
}
function reserveTokens() public onlyOwner {
uint supply = totalSupply();
require(supply < 200, "More than 200 tokens have already been reserved or minted.");
uint i;
for (i = 0; i < 100; i++) {
_safeMint(msg.sender, supply + i);
}
}
function flipSaleState() public onlyOwner {
saleIsActive = !saleIsActive;
}
function mintToken(uint numberOfTokens) public payable {
require(saleIsActive, "Sale must be active to mint Tokens");
require(numberOfTokens <= maxTokenPurchase, "Exceeded max token purchase");
require(totalSupply() + numberOfTokens <= MAX_TOKENS, "Purchase would exceed max supply of tokens");
require(tokenPrice * numberOfTokens <= msg.value, "Ether value sent is not correct");
for(uint i = 0; i < numberOfTokens; i++) {
uint mintIndex = totalSupply();
if (totalSupply() < MAX_TOKENS) {
_safeMint(msg.sender, mintIndex);
}
}
}
function withdraw() public onlyOwner {
uint balance = address(this).balance;
payable(msg.sender).transfer(balance);
}
}
SecurityOrcas.sol 118 lines
// SPDX-License-Identifier: MIT
/*
«∩ⁿ─╖
⌐ ╦╠Σ▌╓┴ .⌐─≈-,
≤╠╠╠╫╕╬╦╜ ┌"░░░░░░░░░░≈╖φ░╔╦╬░░Σ╜^
¼,╠.:╬╬╦╖╔≡p "╙φ░ ╠╩╚` ░╩░╟╓╜
Γ╠▀╬═┘` Θ Å░▄
,,,,, ┌# ] ▌░░╕
,-─S╜" ,⌐"",`░░φ░░░░S>╫▐ ╩ ░░░░¼
╙ⁿ═s, <░φ╬░░φù ░░░░░░░░╬╠░░"Zw, ,─╓φ░Å░░╩╧w¼
∩²≥┴╝δ»╬░╝░░╩░╓║╙░░░░░░Åφ▄φ░░╦≥░⌠░≥╖, ,≈"╓φ░░░╬╬░░╕ {⌐\
} ▐ ½,#░░░░░╦╚░░╬╜Σ░p╠░░╬╘░░░░╩ ^"¥7"""░"¬╖╠░░░#▒░░░╩ φ╩ ∩
Γ ╬░⌐"╢╙φ░░▒╬╓╓░░░░▄▄╬▄░╬░░Å░░░░╠░╦,φ╠░░░░░░-"╠░╩╩ ê░Γ╠
╘░,, ╠╬ '░╗Σ╢░░░░░░▀╢▓▒▒╬╬░╦#####≥╨░░░╝╜╙` ,φ╬░░░. é░░╔⌐
▐░ `^Σ░▒╗, ▐░░░░░ ▒░"╙Σ░╨▀╜╬░▓▓▓▓▓▓▀▀░»φ░N ╔╬▒░░░"`,╬≥░░╢
\ ╠░░░░░░╬#╩╣▄░Γ, ▐░,φ╬▄Å` ░ ```"╚░░░░,╓▄▄▄╬▀▀░╠╙░╔╬░░░ ½"
└ '░░░░░░╦╠ ╟▒M╗▄▄,▄▄▄╗#▒╬▒╠"╙╙╙╙╙╙╢▒▒▓▀▀░░░░░╠╦#░░░░╚,╩
¼░░░░░░░⌂╦ ▀░░░╚╙░╚▓▒▀░░░½░░╠╜ ╘▀░░░╩╩╩,▄╣╬░░░░░╙╔╩
╢^╙╨╠░░▄æ,Σ ",╓╥m╬░░░░░░░Θ░φ░φ▄ ╬╬░,▄#▒▀░░░░░≥░░#`
*╓,╙φ░░░░░#░░░░░░░#╬╠╩ ╠╩╚╠╟▓▄╣▒▓╬▓▀░░░░░╩░╓═^
`"╜╧Σ░░░Σ░░░░░░╬▓µ ─"░░░░░░░░░░╜░╬▄≈"
`"╙╜╜╜╝╩ÅΣM≡,`╙╚░╙╙░╜| ╙╙╙┴7≥╗
`"┴╙¬¬¬┴┴╙╙╙╙""
*/
pragma solidity ^0.8.0;
import "@openzeppelin/contracts/token/ERC721/ERC721.sol";
import "@openzeppelin/contracts/access/Ownable.sol";
import "@openzeppelin/contracts/token/ERC721/extensions/ERC721Enumerable.sol";
abstract contract WHALES {
function ownerOf(uint256 tokenId) public view virtual returns (address);
function balanceOf(address owner) public view virtual returns (uint256);
function tokenOfOwnerByIndex(address owner, uint256 index) public view virtual returns (uint256);
}
contract SecurityOrcas is ERC721, ERC721Enumerable, Ownable {
// Removed tokenPrice
WHALES private whales;
string public PROVENANCE;
bool public saleIsActive = false;
uint256 public MAX_TOKENS = 10000;
uint256 public MAX_MINT = 50;
string private _baseURIextended;
event PermanentURI(string _value, uint256 indexed _id);
constructor(address whalesContract) ERC721("SSoW Security Orcas", "SO") {
whales = WHALES(whalesContract);
}
function _beforeTokenTransfer(address from, address to, uint256 tokenId) internal override(ERC721, ERC721Enumerable) {
super._beforeTokenTransfer(from, to, tokenId);
}
function supportsInterface(bytes4 interfaceId) public view virtual override(ERC721, ERC721Enumerable) returns (bool) {
return super.supportsInterface(interfaceId);
}
function setBaseURI(string memory baseURI_) external onlyOwner() {
_baseURIextended = baseURI_;
}
function _baseURI() internal view virtual override returns (string memory) {
return _baseURIextended;
}
function setProvenance(string memory provenance) public onlyOwner {
PROVENANCE = provenance;
}
// Removed reserveTokens
function flipSaleState() public onlyOwner {
saleIsActive = !saleIsActive;
}
// TODO: see which costs more gas: mintToken() or mintMultipleTokens(0, 1);
function mintToken(uint256 tokenId) public {
require(saleIsActive, "Sale must be active to mint Security Orcas");
require(totalSupply() < MAX_TOKENS, "Purchase would exceed max supply of tokens");
require(tokenId < MAX_TOKENS, "TokenId does not exist");
require(!_exists(tokenId), "TokenId has already been minted");
require(whales.ownerOf(tokenId) == msg.sender, "Sender does not own the correct Whale token");
_safeMint(msg.sender, tokenId);
}
function mintMultipleTokens(uint256 startingIndex, uint256 numberOfTokens) public {
require(saleIsActive, "Sale must be active to mint Security Orcas");
require(numberOfTokens > 0, "Need to mint at least one token");
require(numberOfTokens <= MAX_MINT, "Cannot adopt more than 50 Orcas in one tx");
require(whales.balanceOf(msg.sender) >= numberOfTokens + startingIndex, "Sender does not own the correct number of Whale tokens");
for(uint i = 0; i < numberOfTokens; i++) {
require(totalSupply() < MAX_TOKENS, "Cannot exceed max supply of tokens");
uint tokenId = whales.tokenOfOwnerByIndex(msg.sender, i + startingIndex);
if(!_exists(tokenId)) {
_safeMint(msg.sender, tokenId);
}
}
}
function withdraw() public onlyOwner {
uint balance = address(this).balance;
payable(msg.sender).transfer(balance);
}
function markPermanentURI(string memory value, uint256 id) public onlyOwner {
emit PermanentURI(value, id);
}
}
WealthyWhales.sol 163 lines
// SPDX-License-Identifier: MIT
/*
«∩ⁿ─╖
⌐ ╦╠Σ▌╓┴ .⌐─≈-,
≤╠╠╠╫╕╬╦╜ ┌"░░░░░░░░░░≈╖φ░╔╦╬░░Σ╜^
¼,╠.:╬╬╦╖╔≡p "╙φ░ ╠╩╚` ░╩░╟╓╜
Γ╠▀╬═┘` Θ Å░▄
,,,,, ┌# ] ▌░░╕
,-─S╜" ,⌐"",`░░φ░░░░S>╫▐ ╩ ░░░░¼
╙ⁿ═s, <░φ╬░░φù ░░░░░░░░╬╠░░"Zw, ,─╓φ░Å░░╩╧w¼
∩²≥┴╝δ»╬░╝░░╩░╓║╙░░░░░░Åφ▄φ░░╦≥░⌠░≥╖, ,≈"╓φ░░░╬╬░░╕ {⌐\
} ▐ ½,#░░░░░╦╚░░╬╜Σ░p╠░░╬╘░░░░╩ ^"¥7"""░"¬╖╠░░░#▒░░░╩ φ╩ ∩
Γ ╬░⌐"╢╙φ░░▒╬╓╓░░░░▄▄╬▄░╬░░Å░░░░╠░╦,φ╠░░░░░░-"╠░╩╩ ê░Γ╠
╘░,, ╠╬ '░╗Σ╢░░░░░░▀╢▓▒▒╬╬░╦#####≥╨░░░╝╜╙` ,φ╬░░░. é░░╔⌐
▐░ `^Σ░▒╗, ▐░░░░░ ▒░"╙Σ░╨▀╜╬░▓▓▓▓▓▓▀▀░»φ░N ╔╬▒░░░"`,╬≥░░╢
\ ╠░░░░░░╬#╩╣▄░Γ, ▐░,φ╬▄Å` ░ ```"╚░░░░,╓▄▄▄╬▀▀░╠╙░╔╬░░░ ½"
└ '░░░░░░╦╠ ╟▒M╗▄▄,▄▄▄╗#▒╬▒╠"╙╙╙╙╙╙╢▒▒▓▀▀░░░░░╠╦#░░░░╚,╩
¼░░░░░░░⌂╦ ▀░░░╚╙░╚▓▒▀░░░½░░╠╜ ╘▀░░░╩╩╩,▄╣╬░░░░░╙╔╩
╢^╙╨╠░░▄æ,Σ ",╓╥m╬░░░░░░░Θ░φ░φ▄ ╬╬░,▄#▒▀░░░░░≥░░#`
*╓,╙φ░░░░░#░░░░░░░#╬╠╩ ╠╩╚╠╟▓▄╣▒▓╬▓▀░░░░░╩░╓═^
`"╜╧Σ░░░Σ░░░░░░╬▓µ ─"░░░░░░░░░░╜░╬▄≈"
`"╙╜╜╜╝╩ÅΣM≡,`╙╚░╙╙░╜| ╙╙╙┴7≥╗
`"┴╙¬¬¬┴┴╙╙╙╙""
*/
pragma solidity ^0.8.0;
import "@openzeppelin/contracts/token/ERC721/ERC721.sol";
import "@openzeppelin/contracts/access/Ownable.sol";
import "@openzeppelin/contracts/token/ERC721/extensions/ERC721Enumerable.sol";
import "@openzeppelin/contracts/utils/Context.sol";
import "./staking/CigarClub.sol";
import "./staking/TreasureChest.sol";
import "./experimental/SimpleToken.sol";
contract WealthyWhales is Context, ERC721, ERC721Enumerable, Ownable {
string public PROVENANCE;
bool public saleIsActive = false;
CigarClub public cigarClub;
TreasureChest public treasureChest;
uint256 public constant MAX_TOKENS = 1000;
string private _baseURIextended;
event PermanentURI(string _value, uint256 indexed _id);
constructor(address _treasureChest) ERC721("Wealthy Whales", "WW") {
treasureChest = TreasureChest(_treasureChest);
}
function _beforeTokenTransfer(address from, address to, uint256 tokenId) internal override(ERC721, ERC721Enumerable) {
super._beforeTokenTransfer(from, to, tokenId);
}
function supportsInterface(bytes4 interfaceId) public view virtual override(ERC721, ERC721Enumerable) returns (bool) {
return super.supportsInterface(interfaceId);
}
function setBaseURI(string memory baseURI_) external onlyOwner() {
_baseURIextended = baseURI_;
}
function _baseURI() internal view virtual override returns (string memory) {
return _baseURIextended;
}
function setProvenance(string memory provenance) public onlyOwner {
PROVENANCE = provenance;
}
function flipSaleState() public onlyOwner {
require(address(cigarClub) != address(0), "The CigarClub has not been initialized");
saleIsActive = !saleIsActive;
}
function mintWithGems(uint numberOfWealthyWhales) external {
require(numberOfWealthyWhales > 0, "Must mint at least 1 wealthy whale");
require(saleIsActive, "Sale must be active to mint Tokens");
uint256 totalSupply = totalSupply();
require(totalSupply + numberOfWealthyWhales <= MAX_TOKENS, "Purchase would exceed max supply of tokens");
uint256 numSapphires = treasureChest.userToTokenTypes(_msgSender(), 1);
uint256 numEmeralds = treasureChest.userToTokenTypes(_msgSender(), 2);
uint256 numRubies = treasureChest.userToTokenTypes(_msgSender(), 3);
require(numSapphires >= numberOfWealthyWhales, "Must have enough sapphires");
require(numEmeralds >= numberOfWealthyWhales, "Must have enough emeralds");
require(numRubies >= numberOfWealthyWhales, "Must have enough rubies");
for(uint i = 0; i < numberOfWealthyWhales; i++) {
_safeMint(_msgSender(), totalSupply);
totalSupply++;
}
uint256[5] memory tokensToSpend = [0, numberOfWealthyWhales, numberOfWealthyWhales, numberOfWealthyWhales, 0];
treasureChest.burn(_msgSender(), tokensToSpend);
}
function mintWithDiamonds(uint numberOfWealthyWhales) external {
require(numberOfWealthyWhales > 0, "Must mint at least 1 wealthy whale");
require(saleIsActive, "Sale must be active to mint Tokens");
uint256 totalSupply = totalSupply();
require(totalSupply + numberOfWealthyWhales <= MAX_TOKENS, "Purchase would exceed max supply of tokens");
uint256 numDiamonds = treasureChest.userToTokenTypes(_msgSender(), 4);
require(numDiamonds >= numberOfWealthyWhales, "Must have enough diamonds");
for(uint i = 0; i < numberOfWealthyWhales; i++) {
_safeMint(_msgSender(), totalSupply);
totalSupply++;
}
uint256[5] memory tokensToSpend = [0, 0, 0, 0, numberOfWealthyWhales];
treasureChest.burn(_msgSender(), tokensToSpend);
}
function mintWithSanddollars(uint numberOfWealthyWhales) external {
require(numberOfWealthyWhales > 0, "Must mint at least 1 wealthy whale");
require(saleIsActive, "Sale must be active to mint Tokens");
uint256 totalSupply = totalSupply();
require(totalSupply + numberOfWealthyWhales <= MAX_TOKENS, "Purchase would exceed max supply of tokens");
uint256 numSanddollars = treasureChest.userToTokenTypes(_msgSender(), 0);
require(numSanddollars >= numberOfWealthyWhales * 100, "Must have enough sand dollars");
for(uint i = 0; i < numberOfWealthyWhales; i++) {
_safeMint(_msgSender(), totalSupply);
totalSupply++;
}
uint256[5] memory tokensToSpend = [numberOfWealthyWhales * 100, 0, 0, 0, 0];
treasureChest.burn(_msgSender(), tokensToSpend);
}
function transferFrom(
address from,
address to,
uint256 tokenId
) public virtual override {
if (_msgSender() != address(cigarClub)) {
require(_isApprovedOrOwner(_msgSender(), tokenId), "");
}
_transfer(from, to, tokenId);
}
function setCigarClub(address _cigarClub) external onlyOwner {
require(address(cigarClub) == address(0), "CigarClub has already been initialized.");
cigarClub = CigarClub(_cigarClub);
}
function withdraw() public onlyOwner {
uint balance = address(this).balance;
payable(msg.sender).transfer(balance);
}
function markPermanentURI(string memory value, uint256 id) public onlyOwner {
emit PermanentURI(value, id);
}
}
CIGAR.sol 140 lines
// SPDX-License-Identifier: MIT
/*
«∩ⁿ─╖
⌐ ╦╠Σ▌╓┴ .⌐─≈-,
≤╠╠╠╫╕╬╦╜ ┌"░░░░░░░░░░≈╖φ░╔╦╬░░Σ╜^
¼,╠.:╬╬╦╖╔≡p "╙φ░ ╠╩╚` ░╩░╟╓╜
Γ╠▀╬═┘` Θ Å░▄
,,,,, ┌# ] ▌░░╕
,-─S╜" ,⌐"",`░░φ░░░░S>╫▐ ╩ ░░░░¼
╙ⁿ═s, <░φ╬░░φù ░░░░░░░░╬╠░░"Zw, ,─╓φ░Å░░╩╧w¼
∩²≥┴╝δ»╬░╝░░╩░╓║╙░░░░░░Åφ▄φ░░╦≥░⌠░≥╖, ,≈"╓φ░░░╬╬░░╕ {⌐\
} ▐ ½,#░░░░░╦╚░░╬╜Σ░p╠░░╬╘░░░░╩ ^"¥7"""░"¬╖╠░░░#▒░░░╩ φ╩ ∩
Γ ╬░⌐"╢╙φ░░▒╬╓╓░░░░▄▄╬▄░╬░░Å░░░░╠░╦,φ╠░░░░░░-"╠░╩╩ ê░Γ╠
╘░,, ╠╬ '░╗Σ╢░░░░░░▀╢▓▒▒╬╬░╦#####≥╨░░░╝╜╙` ,φ╬░░░. é░░╔⌐
▐░ `^Σ░▒╗, ▐░░░░░ ▒░"╙Σ░╨▀╜╬░▓▓▓▓▓▓▀▀░»φ░N ╔╬▒░░░"`,╬≥░░╢
\ ╠░░░░░░╬#╩╣▄░Γ, ▐░,φ╬▄Å` ░ ```"╚░░░░,╓▄▄▄╬▀▀░╠╙░╔╬░░░ ½"
└ '░░░░░░╦╠ ╟▒M╗▄▄,▄▄▄╗#▒╬▒╠"╙╙╙╙╙╙╢▒▒▓▀▀░░░░░╠╦#░░░░╚,╩
¼░░░░░░░⌂╦ ▀░░░╚╙░╚▓▒▀░░░½░░╠╜ ╘▀░░░╩╩╩,▄╣╬░░░░░╙╔╩
╢^╙╨╠░░▄æ,Σ ",╓╥m╬░░░░░░░Θ░φ░φ▄ ╬╬░,▄#▒▀░░░░░≥░░#`
*╓,╙φ░░░░░#░░░░░░░#╬╠╩ ╠╩╚╠╟▓▄╣▒▓╬▓▀░░░░░╩░╓═^
`"╜╧Σ░░░Σ░░░░░░╬▓µ ─"░░░░░░░░░░╜░╬▄≈"
`"╙╜╜╜╝╩ÅΣM≡,`╙╚░╙╙░╜| ╙╙╙┴7≥╗
`"┴╙¬¬¬┴┴╙╙╙╙""
*/
pragma solidity ^0.8.0;
import "@openzeppelin/contracts/token/ERC20/ERC20.sol";
import "@openzeppelin/contracts/access/Ownable.sol";
import "../interfaces/ICIGAR.sol";
contract CIGAR is ICIGAR, ERC20, Ownable {
uint256 public constant DAO_AMOUNT = 600000000000 ether;
uint256 public constant LIQUIDITY_AMOUNT = 150000000000 ether;
uint256 public constant TEAM_AMOUNT = 450000000000 ether;
uint256 public constant PUBLIC_SALE_AMOUNT = 300000000000 ether;
uint256 public constant STAKING_AMOUNT = 1500000000000 ether;
uint256 public constant TOTAL_AMOUNT = 3000000000000 ether;
// price per 1 ether tokens
uint256 public mintPrice = .00001 ether;
// max number of tokens to mint in one tx in ether
uint256 public maxMint = 10000;
uint256 public immutable timeStarted;
uint256 public teamValueMinted;
uint256 public publicSaleMinted;
uint256 public totalMinted;
bool public saleIsActive;
bool public areControllersLocked;
// a mapping from an address to whether or not it can mint / burn
mapping(address => bool) public controllers;
constructor() ERC20("CIGAR", "CIGAR") {
timeStarted = block.timestamp;
}
function publicSaleMint(address to, uint256 amountInEther) external override payable {
require(saleIsActive, "Sale is not active");
uint256 amountInWei = amountInEther * 1 ether;
require(publicSaleMinted + amountInWei <= PUBLIC_SALE_AMOUNT, "The public sale cap has been reached");
require(amountInEther <= maxMint, "Amount requested is greater than max mint");
require(amountInEther * mintPrice == msg.value, "Given ether does not match price required");
_mint(to, amountInWei);
publicSaleMinted += amountInWei;
totalMinted += amountInWei;
}
function mint(address to, uint256 amount) external override {
require(controllers[msg.sender], "Only controllers are allowed to mint");
totalMinted += amount;
require(totalMinted <= TOTAL_AMOUNT, "Max CIGAR reached");
_mint(to, amount);
}
function reserveToDAO(address dao) external override onlyOwner {
totalMinted += DAO_AMOUNT;
_mint(dao, DAO_AMOUNT);
}
function reserveToLiquidity(address liquidityHandler) external override onlyOwner {
totalMinted += LIQUIDITY_AMOUNT;
_mint(liquidityHandler, LIQUIDITY_AMOUNT);
}
function reserveToTeam(address team) external override onlyOwner {
require(teamValueMinted < TEAM_AMOUNT, "Team amount has been fully vested");
uint256 quarter = 13 * (1 weeks);
uint256 quarterNum = (block.timestamp - timeStarted) / quarter;
require(quarterNum > 0, "A quarter has not passed");
uint256 quarterAmount = TEAM_AMOUNT / 4;
require(quarterNum * quarterAmount > teamValueMinted, "Quarter value already minted");
uint256 amountToMint = (quarterNum * quarterAmount) - teamValueMinted;
totalMinted += amountToMint;
teamValueMinted += amountToMint;
_mint(team, amountToMint);
}
function burn(address from, uint256 amount) external override {
require(controllers[msg.sender], "Only controllers are allowed to burn");
_burn(from, amount);
}
function addController(address controller) external override onlyOwner {
require(!areControllersLocked, 'Controllers have been locked! No more controllers allowed.');
controllers[controller] = true;
}
function removeController(address controller) external override onlyOwner {
require(!areControllersLocked, 'Controllers have been locked! No more changes allowed.');
controllers[controller] = false;
}
function flipSaleState() external override onlyOwner {
saleIsActive = !saleIsActive;
}
function setMintPrice(uint256 _mintPrice) external override onlyOwner {
mintPrice = _mintPrice;
}
function setMaxMint(uint256 _maxMint) external override onlyOwner {
maxMint = _maxMint;
}
function lockControllers() external override onlyOwner {
areControllersLocked = true;
}
function withdrawPublicSale() external override onlyOwner {
uint balance = address(this).balance;
payable(msg.sender).transfer(balance);
}
}
WealthyWhales2.sol 156 lines
// SPDX-License-Identifier: MIT
/*
«∩ⁿ─╖
⌐ ╦╠Σ▌╓┴ .⌐─≈-,
≤╠╠╠╫╕╬╦╜ ┌"░░░░░░░░░░≈╖φ░╔╦╬░░Σ╜^
¼,╠.:╬╬╦╖╔≡p "╙φ░ ╠╩╚` ░╩░╟╓╜
Γ╠▀╬═┘` Θ Å░▄
,,,,, ┌# ] ▌░░╕
,-─S╜" ,⌐"",`░░φ░░░░S>╫▐ ╩ ░░░░¼
╙ⁿ═s, <░φ╬░░φù ░░░░░░░░╬╠░░"Zw, ,─╓φ░Å░░╩╧w¼
∩²≥┴╝δ»╬░╝░░╩░╓║╙░░░░░░Åφ▄φ░░╦≥░⌠░≥╖, ,≈"╓φ░░░╬╬░░╕ {⌐\
} ▐ ½,#░░░░░╦╚░░╬╜Σ░p╠░░╬╘░░░░╩ ^"¥7"""░"¬╖╠░░░#▒░░░╩ φ╩ ∩
Γ ╬░⌐"╢╙φ░░▒╬╓╓░░░░▄▄╬▄░╬░░Å░░░░╠░╦,φ╠░░░░░░-"╠░╩╩ ê░Γ╠
╘░,, ╠╬ '░╗Σ╢░░░░░░▀╢▓▒▒╬╬░╦#####≥╨░░░╝╜╙` ,φ╬░░░. é░░╔⌐
▐░ `^Σ░▒╗, ▐░░░░░ ▒░"╙Σ░╨▀╜╬░▓▓▓▓▓▓▀▀░»φ░N ╔╬▒░░░"`,╬≥░░╢
\ ╠░░░░░░╬#╩╣▄░Γ, ▐░,φ╬▄Å` ░ ```"╚░░░░,╓▄▄▄╬▀▀░╠╙░╔╬░░░ ½"
└ '░░░░░░╦╠ ╟▒M╗▄▄,▄▄▄╗#▒╬▒╠"╙╙╙╙╙╙╢▒▒▓▀▀░░░░░╠╦#░░░░╚,╩
¼░░░░░░░⌂╦ ▀░░░╚╙░╚▓▒▀░░░½░░╠╜ ╘▀░░░╩╩╩,▄╣╬░░░░░╙╔╩
╢^╙╨╠░░▄æ,Σ ",╓╥m╬░░░░░░░Θ░φ░φ▄ ╬╬░,▄#▒▀░░░░░≥░░#`
*╓,╙φ░░░░░#░░░░░░░#╬╠╩ ╠╩╚╠╟▓▄╣▒▓╬▓▀░░░░░╩░╓═^
`"╜╧Σ░░░Σ░░░░░░╬▓µ ─"░░░░░░░░░░╜░╬▄≈"
`"╙╜╜╜╝╩ÅΣM≡,`╙╚░╙╙░╜| ╙╙╙┴7≥╗
`"┴╙¬¬¬┴┴╙╙╙╙""
*/
pragma solidity ^0.8.0;
import "@openzeppelin/contracts/token/ERC721/ERC721.sol";
import "@openzeppelin/contracts/interfaces/IERC20.sol";
import "@openzeppelin/contracts/access/Ownable.sol";
import "@openzeppelin/contracts/token/ERC721/extensions/ERC721Enumerable.sol";
import "@openzeppelin/contracts/utils/Context.sol";
import "./staking/CigarClub2.sol";
contract WealthyWhales2 is Context, ERC721, ERC721Enumerable, Ownable {
uint256 public constant MAX_TOKENS = 2000;
uint public maxTokenPurchase = 10;
uint256 public priceInWrld = 100 ether;
uint256 public priceInEth = 0.08 ether;
IERC20 public wrldToken;
CigarClub2 public cigarClub;
string public PROVENANCE;
bool public saleIsActive = false;
bool public wrldSaleIsActive = false;
string private _baseURIextended;
event PermanentURI(string _value, uint256 indexed _id);
constructor(address _wrldToken, address _cigarClub) ERC721("Wealthy Whales Gen2", "WW") {
wrldToken = IERC20(_wrldToken);
cigarClub = CigarClub2(_cigarClub);
}
function _beforeTokenTransfer(address from, address to, uint256 tokenId) internal override(ERC721, ERC721Enumerable) {
super._beforeTokenTransfer(from, to, tokenId);
}
function supportsInterface(bytes4 interfaceId) public view virtual override(ERC721, ERC721Enumerable) returns (bool) {
return super.supportsInterface(interfaceId);
}
function setBaseURI(string memory baseURI_) external onlyOwner() {
_baseURIextended = baseURI_;
}
function _baseURI() internal view virtual override returns (string memory) {
return _baseURIextended;
}
function setProvenance(string memory provenance) public onlyOwner {
PROVENANCE = provenance;
}
function mintTokenWithEth(uint numberOfTokens) public payable {
require(saleIsActive, "Sale must be active to mint Tokens");
require(numberOfTokens <= maxTokenPurchase, "Exceeded max token purchase");
require(totalSupply() + numberOfTokens <= MAX_TOKENS, "Purchase would exceed max supply of tokens");
require(priceInEth * numberOfTokens == msg.value, "Ether value sent is not correct");
for(uint i = 0; i < numberOfTokens; i++) {
uint mintIndex = totalSupply();
if (totalSupply() < MAX_TOKENS) {
_safeMint(msg.sender, mintIndex);
}
}
}
function mintTokenWithWrld(uint numberOfTokens) public {
require(wrldSaleIsActive, "Sale must be active to mint Tokens");
require(numberOfTokens <= maxTokenPurchase, "Exceeded max token purchase");
require(totalSupply() + numberOfTokens <= MAX_TOKENS, "Purchase would exceed max supply of tokens");
require(priceInWrld * numberOfTokens <= wrldToken.balanceOf(msg.sender), "WRLD balance is not enough");
require(wrldToken.transferFrom(msg.sender, address(this), priceInWrld * numberOfTokens), "WRLD transfer failed");
for(uint i = 0; i < numberOfTokens; i++) {
uint mintIndex = totalSupply();
if (totalSupply() < MAX_TOKENS) {
_safeMint(msg.sender, mintIndex);
}
}
}
function setPriceInEth(uint256 price) external onlyOwner {
priceInEth = price;
}
function setPriceInWrld(uint256 price) external onlyOwner {
priceInWrld = price;
}
function setWrldAddress(address token) external onlyOwner {
wrldToken = IERC20(token);
}
function setMaxTokenPurchase(uint256 max) external onlyOwner {
maxTokenPurchase = max;
}
function flipSaleState() external onlyOwner {
saleIsActive = !saleIsActive;
}
function flipWrldSaleState() external onlyOwner {
wrldSaleIsActive = !wrldSaleIsActive;
}
function transferFrom(
address from,
address to,
uint256 tokenId
) public virtual override {
if (_msgSender() != address(cigarClub)) {
require(_isApprovedOrOwner(_msgSender(), tokenId), "");
}
_transfer(from, to, tokenId);
}
function setCigarClub(address _cigarClub) external onlyOwner {
cigarClub = CigarClub2(_cigarClub);
}
function withdraw() public onlyOwner {
uint balance = address(this).balance;
payable(msg.sender).transfer(balance);
}
function markPermanentURI(string memory value, uint256 id) public onlyOwner {
emit PermanentURI(value, id);
}
}
ICIGAR.sol 31 lines
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
interface ICIGAR {
function publicSaleMint(address to, uint256 amountInEther) external payable;
function mint(address to, uint256 amount) external;
function reserveToDAO(address dao) external;
function reserveToLiquidity(address liquidityHandler) external;
function reserveToTeam(address team) external;
function burn(address from, uint256 amount) external;
function addController(address controller) external;
function removeController(address controller) external;
function flipSaleState() external;
function setMintPrice(uint256 _mintPrice) external;
function setMaxMint(uint256 _maxMint) external;
function lockControllers() external;
function withdrawPublicSale() external;
}
CigarClub.sol 453 lines
// SPDX-License-Identifier: MIT
/*
«∩ⁿ─╖
⌐ ╦╠Σ▌╓┴ .⌐─≈-,
≤╠╠╠╫╕╬╦╜ ┌"░░░░░░░░░░≈╖φ░╔╦╬░░Σ╜^
¼,╠.:╬╬╦╖╔≡p "╙φ░ ╠╩╚` ░╩░╟╓╜
Γ╠▀╬═┘` Θ Å░▄
,,,,, ┌# ] ▌░░╕
,-─S╜" ,⌐"",`░░φ░░░░S>╫▐ ╩ ░░░░¼
╙ⁿ═s, <░φ╬░░φù ░░░░░░░░╬╠░░"Zw, ,─╓φ░Å░░╩╧w¼
∩²≥┴╝δ»╬░╝░░╩░╓║╙░░░░░░Åφ▄φ░░╦≥░⌠░≥╖, ,≈"╓φ░░░╬╬░░╕ {⌐\
} ▐ ½,#░░░░░╦╚░░╬╜Σ░p╠░░╬╘░░░░╩ ^"¥7"""░"¬╖╠░░░#▒░░░╩ φ╩ ∩
Γ ╬░⌐"╢╙φ░░▒╬╓╓░░░░▄▄╬▄░╬░░Å░░░░╠░╦,φ╠░░░░░░-"╠░╩╩ ê░Γ╠
╘░,, ╠╬ '░╗Σ╢░░░░░░▀╢▓▒▒╬╬░╦#####≥╨░░░╝╜╙` ,φ╬░░░. é░░╔⌐
▐░ `^Σ░▒╗, ▐░░░░░ ▒░"╙Σ░╨▀╜╬░▓▓▓▓▓▓▀▀░»φ░N ╔╬▒░░░"`,╬≥░░╢
\ ╠░░░░░░╬#╩╣▄░Γ, ▐░,φ╬▄Å` ░ ```"╚░░░░,╓▄▄▄╬▀▀░╠╙░╔╬░░░ ½"
└ '░░░░░░╦╠ ╟▒M╗▄▄,▄▄▄╗#▒╬▒╠"╙╙╙╙╙╙╢▒▒▓▀▀░░░░░╠╦#░░░░╚,╩
¼░░░░░░░⌂╦ ▀░░░╚╙░╚▓▒▀░░░½░░╠╜ ╘▀░░░╩╩╩,▄╣╬░░░░░╙╔╩
╢^╙╨╠░░▄æ,Σ ",╓╥m╬░░░░░░░Θ░φ░φ▄ ╬╬░,▄#▒▀░░░░░≥░░#`
*╓,╙φ░░░░░#░░░░░░░#╬╠╩ ╠╩╚╠╟▓▄╣▒▓╬▓▀░░░░░╩░╓═^
`"╜╧Σ░░░Σ░░░░░░╬▓µ ─"░░░░░░░░░░╜░╬▄≈"
`"╙╜╜╜╝╩ÅΣM≡,`╙╚░╙╙░╜| ╙╙╙┴7≥╗
`"┴╙¬¬¬┴┴╙╙╙╙""
*/
pragma solidity ^0.8.0;
import "@openzeppelin/contracts/access/Ownable.sol";
import "@openzeppelin/contracts/token/ERC721/IERC721Receiver.sol";
import "./CIGAR.sol";
import "./TreasureChest.sol";
import "../Whales.sol";
import "../SecurityOrcas.sol";
import "../WealthyWhales.sol";
contract CigarClub is Ownable, IERC721Receiver {
struct WhaleOrcaStakeInfo {
uint16 orcaTokenId;
address owner;
uint256 stakeTimestamp;
}
struct WhaleWhaleStakeInfo {
uint16 whaleToken2Id;
address owner;
uint256 stakeTimestamp;
}
struct WealthyWhaleStakeInfo {
uint256 previousCigarVaultAmount;
uint256 stakeTimestamp;
address owner;
}
// base rate
uint256 public constant DAILY_WHALE_RATE = 10000 ether;
// 1.25 rate
uint256 public constant DAILY_WHALE_ORCA_RATE = DAILY_WHALE_RATE + (DAILY_WHALE_RATE / 4);
// 2.5 rate
uint256 public constant DAILY_GOLD_WHALE_RATE = (2 * DAILY_WHALE_RATE) + (DAILY_WHALE_RATE / 2);
// 3 rate
uint256 public constant DAILY_WHALE_YACHT_RATE = (3 * DAILY_WHALE_RATE);
// 3.125 rate
uint256 public constant DAILY_GOLD_WHALE_ORCA_RATE = (3 * DAILY_WHALE_RATE) + (DAILY_WHALE_RATE / 8);
// 5x rate
uint256 public constant DAILY_DOUBLE_GOLD_WHALE_RATE = 5 * DAILY_WHALE_RATE;
// 7.5 rate
uint256 public constant DAILY_GOLD_WHALE_YACHT_RATE = (7 * DAILY_WHALE_RATE) + (DAILY_WHALE_RATE / 2);
uint256 public constant MIN_STAKING_TIME_WHALES = 2 days;
uint256 public constant MIN_STAKING_TIME_WEALTHY_WHALES = 6 days;
uint256 public constant WEALTHY_WHALE_TAX = 20;
uint256 public constant ZERO_WHALE = 10000;
CIGAR public cigar;
Whales public immutable whales;
SecurityOrcas public immutable securityOrcas;
WealthyWhales public immutable wealthyWhales;
// Whale Orca pairing info
mapping(uint256 => WhaleOrcaStakeInfo) public whaleOrcaClub;
// Whale whale pairing info
mapping(uint256 => WhaleWhaleStakeInfo) public whaleWhaleClub;
// Wealthy whale info
mapping(uint256 => WealthyWhaleStakeInfo) public wealthyWhaleClub;
// staking info for nfts sent using safeTransferFrom
// map from user address to whale id sent
mapping(address => uint256) public whaleStaked;
// Total tokens staked
uint256 public totalWhaleOrcasStaked;
uint256 public totalWhaleWhalesStaked;
uint256 public totalWealthyWhalesStaked;
// Wealthy whale vault
uint256 public unclaimedWealthyWhaleVault;
uint256 public wealthyWhaleVault;
// Cigar limits
uint256 public immutable cigarStakingCap;
uint256 public cigarAwarded;
// gold whales and yachts
mapping(uint256 => bool) public isGoldWhale;
mapping(uint256 => bool) public isYacht;
mapping(uint256 => uint256) public whaleIdToRate;
mapping(uint256 => uint256) public orcaIdToRate;
event WhaleOrcaStaked(address owner, uint256 whaleId, uint256 orcaId, uint256 timestamp);
event WhaleWhaleStaked(address owner, uint256 whaleId, uint256 whale2Id, uint256 timestamp);
event WealthyWhaleStaked(address owner, uint256 tokenId, uint256 wealthyWhaleVault, uint256 timestamp);
event RewardsClaimedWhaleOrca(address owner, uint256 whaleId, uint256 orcaId, uint256 timestamp);
event RewardsClaimedWhaleWhale(address owner, uint256 whaleId, uint256 whale2Id, uint256 timestamp);
event RewardsClaimedWealthyWhale(address owner, uint256 tokenId, uint256 wealthyWhaleVault, uint256 timestamp);
event WhaleOrcaUnstaked(address owner, uint256 whaleId, uint256 orcaId, uint256 timestamp);
event WhaleWhaleUnstaked(address owner, uint256 whaleId, uint256 whale2Id, uint256 timestamp);
event WealthyWhaleUnstaked(address owner, uint256 tokenId, uint256 wealthyWhaleVault, uint256 timestamp);
constructor(address _whales, address _securityOrcas, address _cigar, address _wealthyWhales) {
whales = Whales(_whales);
securityOrcas = SecurityOrcas(_securityOrcas);
cigar = CIGAR(_cigar);
wealthyWhales = WealthyWhales(_wealthyWhales);
cigarStakingCap = cigar.STAKING_AMOUNT();
}
function stakeWhalesAndOrcasInCigarClub(uint256[] calldata whaleIds, uint256[] calldata orcaIds) external {
require(whaleIds.length == orcaIds.length, "Must stake an equal number of whales and orcas!");
for (uint i = 0; i < whaleIds.length; i++) {
require(whales.ownerOf(whaleIds[i]) == _msgSender(), "This is not your whale!");
require(securityOrcas.ownerOf(orcaIds[i]) == _msgSender(), "This is not your orca!");
whales.transferFrom(_msgSender(), address(this), whaleIds[i]);
securityOrcas.transferFrom(_msgSender(), address(this), orcaIds[i]);
_addWhaleAndOrcaToCigarClub(_msgSender(), whaleIds[i], orcaIds[i]);
}
totalWhaleOrcasStaked += whaleIds.length;
}
function stakeWhalesInCigarClub(uint256[] calldata whaleIds) external {
require(whaleIds.length > 1, "Must provide at least 2 whaleIds");
require(whaleIds.length % 2 == 0, "Must be even number of whales");
for (uint i = 0; i < whaleIds.length; i += 2) {
require(whales.ownerOf(whaleIds[i]) == _msgSender(), "This is not your whale!");
require(whales.ownerOf(whaleIds[i + 1]) == _msgSender(), "This is not your whale!");
whales.transferFrom(_msgSender(), address(this), whaleIds[i]);
whales.transferFrom(_msgSender(), address(this), whaleIds[i + 1]);
_addWhalesToCigarClub(_msgSender(), whaleIds[i], whaleIds[i + 1]);
}
totalWhaleWhalesStaked += whaleIds.length / 2;
}
function stakeWealthyWhalesInCigarClub(uint256[] calldata tokenIds) external {
for (uint i = 0; i < tokenIds.length; i++) {
require(wealthyWhales.ownerOf(tokenIds[i]) == _msgSender(), "This is not your token!");
wealthyWhales.transferFrom(_msgSender(), address(this), tokenIds[i]);
_addWealthyWhaleToCigarClub(_msgSender(), tokenIds[i]);
}
}
function claimWhalesAndOrcas(uint256[] calldata whaleIds, bool unstake) external {
uint256 reward;
for (uint i = 0; i < whaleIds.length; i++) {
reward += _claimWhaleOrcaAndGetReward(whaleIds[i], unstake);
}
if (reward == 0) return;
cigar.mint(_msgSender(), reward);
}
// must only use the primary whale ids being staked
function claimWhales(uint256[] calldata whaleIds, bool unstake) external {
require(whaleIds.length > 0, "Must claim at least 1 whale");
uint256 reward;
for (uint i = 0; i < whaleIds.length; i++) {
reward += _claimWhalesAndGetReward(whaleIds[i], unstake);
}
if (reward == 0) return;
cigar.mint(_msgSender(), reward);
}
function claimWealthyWhales(uint256[] calldata tokenIds, bool unstake) external {
uint256 reward;
for (uint i = 0; i < tokenIds.length; i++) {
reward += _claimWealthyWhaleAndGetReward(tokenIds[i], unstake);
}
if (reward == 0) return;
cigar.mint(_msgSender(), reward);
}
function onERC721Received(address, address from, uint256 tokenId, bytes calldata)
external override returns (bytes4) {
require(msg.sender == address(securityOrcas) || msg.sender == address(whales),
"Only accepts whale and security orca tokens");
uint256 currentWhale = whaleStaked[from];
if (msg.sender == address(whales)) {
require(currentWhale == 0, "Must not have sent other unstaked whales");
if (tokenId == 0) {
whaleStaked[from] = ZERO_WHALE;
} else {
whaleStaked[from] = tokenId;
}
} else if (msg.sender == address(securityOrcas)) {
require(currentWhale != 0, "This address must have deposited a whale first!");
if (currentWhale == ZERO_WHALE) {
currentWhale = 0;
}
_addWhaleAndOrcaToCigarClub(from, currentWhale, tokenId);
whaleStaked[from] = 0;
totalWhaleOrcasStaked++;
}
return IERC721Receiver.onERC721Received.selector;
}
function retrieveLoneWhale() external {
uint256 whaleId = whaleStaked[_msgSender()];
require(whaleId != 0, "User must have sent an unstaked whale");
whaleStaked[_msgSender()] = 0;
whales.safeTransferFrom(address(this), _msgSender(), whaleId, "");
}
function setGoldWhales(uint256[] calldata goldWhaleIds) external onlyOwner {
for(uint256 i = 0; i < goldWhaleIds.length; i++) {
isGoldWhale[goldWhaleIds[i]] = true;
}
}
function setYachts(uint256[] calldata yachtIds) external onlyOwner {
for(uint256 i = 0; i < yachtIds.length; i++) {
isYacht[yachtIds[i]] = true;
}
}
function setWhaleRates(uint256[] calldata whaleIds, uint256 rate) external onlyOwner {
for (uint i = 0; i < whaleIds.length; i++) {
whaleIdToRate[whaleIds[i]] = rate;
}
}
function setOrcaRates(uint256[] calldata orcaIds, uint256 rate) external onlyOwner {
for (uint i = 0; i < orcaIds.length; i++) {
orcaIdToRate[orcaIds[i]] = rate;
}
}
function getDailyRateWhaleOrca(uint256 whaleId, uint256 orcaId) public view returns (uint256) {
uint256 bonusWhaleRate = whaleIdToRate[whaleId];
uint256 bonusOrcaRate = orcaIdToRate[orcaId];
if (bonusWhaleRate == 0) {
bonusWhaleRate = 1;
}
if (bonusOrcaRate == 0) {
bonusOrcaRate = 1;
}
if (bonusWhaleRate != 1 || bonusOrcaRate != 1) {
return DAILY_WHALE_ORCA_RATE * bonusWhaleRate * bonusOrcaRate;
}
bool goldWhale = isGoldWhale[whaleId];
bool yacht = isYacht[orcaId];
if (goldWhale && yacht) {
return DAILY_GOLD_WHALE_YACHT_RATE;
} else if (goldWhale) {
return DAILY_GOLD_WHALE_ORCA_RATE;
} else if (yacht) {
return DAILY_WHALE_YACHT_RATE;
} else {
return DAILY_WHALE_ORCA_RATE;
}
}
function getDailyRateWhaleWhale(uint256 whaleId, uint256 whale2Id) public view returns (uint256) {
uint256 bonusWhaleRate1 = whaleIdToRate[whaleId];
uint256 bonusWhaleRate2 = whaleIdToRate[whale2Id];
if (bonusWhaleRate1 == 0) {
bonusWhaleRate1 = 1;
}
if (bonusWhaleRate2 == 0) {
bonusWhaleRate2 = 1;
}
if (bonusWhaleRate1 != 1 || bonusWhaleRate2 != 1) {
return DAILY_WHALE_RATE * bonusWhaleRate1 * bonusWhaleRate2;
}
bool isWhale1Gold = isGoldWhale[whaleId];
bool isWhale2Gold = isGoldWhale[whale2Id];
if (isWhale1Gold && isWhale2Gold) {
return DAILY_DOUBLE_GOLD_WHALE_RATE;
} else if (isWhale1Gold || isWhale2Gold) {
return DAILY_GOLD_WHALE_RATE;
} else {
return DAILY_WHALE_RATE;
}
}
// INTERNAL FUNCTIONS
function _addWhaleAndOrcaToCigarClub(address account, uint256 whaleId, uint256 orcaId) internal {
whaleOrcaClub[whaleId] = WhaleOrcaStakeInfo({
owner: account,
orcaTokenId: uint16(orcaId),
stakeTimestamp: block.timestamp
});
emit WhaleOrcaStaked(account, whaleId, orcaId, block.timestamp);
}
function _addWhalesToCigarClub(address account, uint256 whaleId, uint256 whale2Id) internal {
whaleWhaleClub[whaleId] = WhaleWhaleStakeInfo({
owner: account,
whaleToken2Id: uint16(whale2Id),
stakeTimestamp: block.timestamp
});
emit WhaleWhaleStaked(account, whaleId, whale2Id, block.timestamp);
}
function _addWealthyWhaleToCigarClub(address account, uint256 tokenId) internal {
wealthyWhaleClub[tokenId] = WealthyWhaleStakeInfo({
owner: account,
stakeTimestamp: block.timestamp,
previousCigarVaultAmount: wealthyWhaleVault
});
totalWealthyWhalesStaked += 1;
emit WealthyWhaleStaked(account, tokenId, wealthyWhaleVault, block.timestamp);
}
function _claimWhaleOrcaAndGetReward(uint256 whaleId, bool unstake) internal returns (uint256) {
WhaleOrcaStakeInfo memory stakeInfo = whaleOrcaClub[whaleId];
require(stakeInfo.owner == _msgSender(), "This whale is owned by someone else.");
uint256 timeStaked = block.timestamp - stakeInfo.stakeTimestamp;
require(timeStaked > MIN_STAKING_TIME_WHALES, "Must have staked for at least 2 days!");
uint256 rewardRate = getDailyRateWhaleOrca(whaleId, stakeInfo.orcaTokenId);
uint256 reward = timeStaked * rewardRate / 1 days;
reward = _loadWealthyWhaleVault(reward);
if (cigarAwarded + reward > cigarStakingCap) {
reward = cigarStakingCap - cigarAwarded;
}
if (unstake) {
uint256 securityOrcaId = stakeInfo.orcaTokenId;
whales.safeTransferFrom(address(this), _msgSender(), whaleId, "");
securityOrcas.safeTransferFrom(address(this), _msgSender(), securityOrcaId, "");
delete whaleOrcaClub[whaleId];
totalWhaleOrcasStaked -= 1;
emit WhaleOrcaUnstaked(_msgSender(), whaleId, securityOrcaId, block.timestamp);
} else {
whaleOrcaClub[whaleId].stakeTimestamp = block.timestamp;
emit RewardsClaimedWhaleOrca(_msgSender(), whaleId, stakeInfo.orcaTokenId, block.timestamp);
}
cigarAwarded += reward;
return reward;
}
function _claimWhalesAndGetReward(uint256 whaleId, bool unstake) internal returns (uint256) {
WhaleWhaleStakeInfo memory stakeInfo = whaleWhaleClub[whaleId];
require(stakeInfo.owner == _msgSender(), "This whale is owned by someone else.");
uint256 timeStaked = block.timestamp - stakeInfo.stakeTimestamp;
require(timeStaked > MIN_STAKING_TIME_WHALES, "Must have staked for at least 2 days!");
uint256 rewardRate = getDailyRateWhaleWhale(whaleId, stakeInfo.whaleToken2Id);
uint256 reward = timeStaked * rewardRate / 1 days;
reward = _loadWealthyWhaleVault(reward);
if (cigarAwarded + reward > cigarStakingCap) {
reward = cigarStakingCap - cigarAwarded;
}
if (unstake) {
whales.safeTransferFrom(address(this), _msgSender(), whaleId, "");
whales.safeTransferFrom(address(this), _msgSender(), stakeInfo.whaleToken2Id, "");
delete whaleWhaleClub[whaleId];
totalWhaleWhalesStaked -= 1;
emit WhaleWhaleUnstaked(_msgSender(), whaleId, stakeInfo.whaleToken2Id, block.timestamp);
} else {
whaleWhaleClub[whaleId].stakeTimestamp = block.timestamp;
emit RewardsClaimedWhaleWhale(_msgSender(), whaleId, stakeInfo.whaleToken2Id, block.timestamp);
}
cigarAwarded += reward;
return reward;
}
function _claimWealthyWhaleAndGetReward(uint256 tokenId, bool unstake) internal returns (uint256) {
WealthyWhaleStakeInfo memory stakeInfo = wealthyWhaleClub[tokenId];
require(stakeInfo.owner == _msgSender(), "This wealthy whale is owned by someone else");
uint256 timeStaked = block.timestamp - stakeInfo.stakeTimestamp;
require(timeStaked > MIN_STAKING_TIME_WEALTHY_WHALES, "Must have staked for at least 6 days!");
uint256 reward = wealthyWhaleVault - stakeInfo.previousCigarVaultAmount;
if (cigarAwarded + reward > cigarStakingCap) {
reward = cigarStakingCap - cigarAwarded;
}
if (unstake) {
wealthyWhales.safeTransferFrom(address(this), _msgSender(), tokenId, "");
delete wealthyWhaleClub[tokenId];
totalWealthyWhalesStaked -= 1;
emit WealthyWhaleUnstaked(_msgSender(), tokenId, wealthyWhaleVault, block.timestamp);
} else {
wealthyWhaleClub[tokenId].previousCigarVaultAmount = wealthyWhaleVault;
emit RewardsClaimedWealthyWhale(_msgSender(), tokenId, wealthyWhaleVault, block.timestamp);
}
cigarAwarded += reward;
return reward;
}
function _loadWealthyWhaleVault(uint256 whaleReward) internal returns (uint256) {
uint256 wealthyWhaleTribute = whaleReward * WEALTHY_WHALE_TAX / 100;
if (totalWealthyWhalesStaked == 0) {
unclaimedWealthyWhaleVault += wealthyWhaleTribute;
} else {
wealthyWhaleVault += (wealthyWhaleTribute + unclaimedWealthyWhaleVault)
/ totalWealthyWhalesStaked;
unclaimedWealthyWhaleVault = 0;
}
return whaleReward - wealthyWhaleTribute;
}
}
CigarClub2.sol 134 lines
// SPDX-License-Identifier: MIT
/*
«∩ⁿ─╖
⌐ ╦╠Σ▌╓┴ .⌐─≈-,
≤╠╠╠╫╕╬╦╜ ┌"░░░░░░░░░░≈╖φ░╔╦╬░░Σ╜^
¼,╠.:╬╬╦╖╔≡p "╙φ░ ╠╩╚` ░╩░╟╓╜
Γ╠▀╬═┘` Θ Å░▄
,,,,, ┌# ] ▌░░╕
,-─S╜" ,⌐"",`░░φ░░░░S>╫▐ ╩ ░░░░¼
╙ⁿ═s, <░φ╬░░φù ░░░░░░░░╬╠░░"Zw, ,─╓φ░Å░░╩╧w¼
∩²≥┴╝δ»╬░╝░░╩░╓║╙░░░░░░Åφ▄φ░░╦≥░⌠░≥╖, ,≈"╓φ░░░╬╬░░╕ {⌐\
} ▐ ½,#░░░░░╦╚░░╬╜Σ░p╠░░╬╘░░░░╩ ^"¥7"""░"¬╖╠░░░#▒░░░╩ φ╩ ∩
Γ ╬░⌐"╢╙φ░░▒╬╓╓░░░░▄▄╬▄░╬░░Å░░░░╠░╦,φ╠░░░░░░-"╠░╩╩ ê░Γ╠
╘░,, ╠╬ '░╗Σ╢░░░░░░▀╢▓▒▒╬╬░╦#####≥╨░░░╝╜╙` ,φ╬░░░. é░░╔⌐
▐░ `^Σ░▒╗, ▐░░░░░ ▒░"╙Σ░╨▀╜╬░▓▓▓▓▓▓▀▀░»φ░N ╔╬▒░░░"`,╬≥░░╢
\ ╠░░░░░░╬#╩╣▄░Γ, ▐░,φ╬▄Å` ░ ```"╚░░░░,╓▄▄▄╬▀▀░╠╙░╔╬░░░ ½"
└ '░░░░░░╦╠ ╟▒M╗▄▄,▄▄▄╗#▒╬▒╠"╙╙╙╙╙╙╢▒▒▓▀▀░░░░░╠╦#░░░░╚,╩
¼░░░░░░░⌂╦ ▀░░░╚╙░╚▓▒▀░░░½░░╠╜ ╘▀░░░╩╩╩,▄╣╬░░░░░╙╔╩
╢^╙╨╠░░▄æ,Σ ",╓╥m╬░░░░░░░Θ░φ░φ▄ ╬╬░,▄#▒▀░░░░░≥░░#`
*╓,╙φ░░░░░#░░░░░░░#╬╠╩ ╠╩╚╠╟▓▄╣▒▓╬▓▀░░░░░╩░╓═^
`"╜╧Σ░░░Σ░░░░░░╬▓µ ─"░░░░░░░░░░╜░╬▄≈"
`"╙╜╜╜╝╩ÅΣM≡,`╙╚░╙╙░╜| ╙╙╙┴7≥╗
`"┴╙¬¬¬┴┴╙╙╙╙""
*/
pragma solidity ^0.8.0;
import "@openzeppelin/contracts/access/Ownable.sol";
import "@openzeppelin/contracts/token/ERC721/IERC721Receiver.sol";
import "./CIGAR.sol";
import "./CigarClub.sol";
import "../WealthyWhales.sol";
import "../WealthyWhales2.sol";
contract CigarClub2 is Ownable {
struct WealthyWhaleStakeInfo {
uint256 previousCigarVaultAmount;
uint256 stakeTimestamp;
address owner;
}
uint256 public constant WEALTHY_WHALE_TAX = 20;
uint256 public constant MIN_STAKING_TIME_WEALTHY_WHALES = 6 days;
CIGAR public cigar;
CigarClub public cigarClub;
WealthyWhales2 public immutable wealthyWhales2;
// Wealthy whale info
mapping(uint256 => WealthyWhaleStakeInfo) public wealthyWhaleClub;
uint256 public totalWealthyWhalesStaked;
uint256 public wealthyWhaleVault;
// Cigar limits
uint256 constant CAP = 750000000000 ether;
uint256 public cigarAwarded;
event WealthyWhaleStaked(address owner, uint256 tokenId, uint256 wealthyWhaleVault, uint256 timestamp);
event RewardsClaimedWealthyWhale(address owner, uint256 tokenId, uint256 wealthyWhaleVault, uint256 timestamp);
event WealthyWhaleUnstaked(address owner, uint256 tokenId, uint256 wealthyWhaleVault, uint256 timestamp);
constructor(address _cigar, address _wealthyWhales2) {
cigar = CIGAR(_cigar);
wealthyWhales2 = WealthyWhales2(_wealthyWhales2);
}
function stakeWealthyWhalesInCigarClub(uint256[] calldata tokenIds) external {
for (uint i = 0; i < tokenIds.length; i++) {
require(wealthyWhales2.ownerOf(tokenIds[i]) == _msgSender(), "This is not your token!");
wealthyWhales2.transferFrom(_msgSender(), address(this), tokenIds[i]);
_addWealthyWhaleToCigarClub(_msgSender(), tokenIds[i]);
}
}
function claimWealthyWhales(uint256[] calldata tokenIds, bool unstake) external {
uint256 reward;
for (uint i = 0; i < tokenIds.length; i++) {
reward += _claimWealthyWhaleAndGetReward(tokenIds[i], unstake);
}
if (reward == 0) return;
cigar.mint(_msgSender(), reward);
}
function setCigarClub(address _cigarClub) external onlyOwner {
cigarClub = CigarClub(_cigarClub);
}
// INTERNAL FUNCTIONS
function _addWealthyWhaleToCigarClub(address account, uint256 tokenId) internal {
wealthyWhaleVault = cigarClub.wealthyWhaleVault();
wealthyWhaleClub[tokenId] = WealthyWhaleStakeInfo({
owner: account,
stakeTimestamp: block.timestamp,
previousCigarVaultAmount: wealthyWhaleVault
});
totalWealthyWhalesStaked += 1;
emit WealthyWhaleStaked(account, tokenId, wealthyWhaleVault, block.timestamp);
}
function _claimWealthyWhaleAndGetReward(uint256 tokenId, bool unstake) internal returns (uint256) {
WealthyWhaleStakeInfo memory stakeInfo = wealthyWhaleClub[tokenId];
require(stakeInfo.owner == _msgSender(), "This wealthy whale is owned by someone else");
uint256 timeStaked = block.timestamp - stakeInfo.stakeTimestamp;
require(timeStaked > MIN_STAKING_TIME_WEALTHY_WHALES, "Must have staked for at least 6 days!");
wealthyWhaleVault = cigarClub.wealthyWhaleVault();
uint256 reward = wealthyWhaleVault - stakeInfo.previousCigarVaultAmount;
if (cigarAwarded + reward > CAP) {
reward = CAP - cigarAwarded;
}
if (unstake) {
wealthyWhales2.safeTransferFrom(address(this), _msgSender(), tokenId, "");
delete wealthyWhaleClub[tokenId];
totalWealthyWhalesStaked -= 1;
emit WealthyWhaleUnstaked(_msgSender(), tokenId, wealthyWhaleVault, block.timestamp);
} else {
wealthyWhaleClub[tokenId].previousCigarVaultAmount = wealthyWhaleVault;
emit RewardsClaimedWealthyWhale(_msgSender(), tokenId, wealthyWhaleVault, block.timestamp);
}
cigarAwarded += reward;
return reward;
}
}
TreasureChest.sol 232 lines
// SPDX-License-Identifier: MIT
/*
«∩ⁿ─╖
⌐ ╦╠Σ▌╓┴ .⌐─≈-,
≤╠╠╠╫╕╬╦╜ ┌"░░░░░░░░░░≈╖φ░╔╦╬░░Σ╜^
¼,╠.:╬╬╦╖╔≡p "╙φ░ ╠╩╚` ░╩░╟╓╜
Γ╠▀╬═┘` Θ Å░▄
,,,,, ┌# ] ▌░░╕
,-─S╜" ,⌐"",`░░φ░░░░S>╫▐ ╩ ░░░░¼
╙ⁿ═s, <░φ╬░░φù ░░░░░░░░╬╠░░"Zw, ,─╓φ░Å░░╩╧w¼
∩²≥┴╝δ»╬░╝░░╩░╓║╙░░░░░░Åφ▄φ░░╦≥░⌠░≥╖, ,≈"╓φ░░░╬╬░░╕ {⌐\
} ▐ ½,#░░░░░╦╚░░╬╜Σ░p╠░░╬╘░░░░╩ ^"¥7"""░"¬╖╠░░░#▒░░░╩ φ╩ ∩
Γ ╬░⌐"╢╙φ░░▒╬╓╓░░░░▄▄╬▄░╬░░Å░░░░╠░╦,φ╠░░░░░░-"╠░╩╩ ê░Γ╠
╘░,, ╠╬ '░╗Σ╢░░░░░░▀╢▓▒▒╬╬░╦#####≥╨░░░╝╜╙` ,φ╬░░░. é░░╔⌐
▐░ `^Σ░▒╗, ▐░░░░░ ▒░"╙Σ░╨▀╜╬░▓▓▓▓▓▓▀▀░»φ░N ╔╬▒░░░"`,╬≥░░╢
\ ╠░░░░░░╬#╩╣▄░Γ, ▐░,φ╬▄Å` ░ ```"╚░░░░,╓▄▄▄╬▀▀░╠╙░╔╬░░░ ½"
└ '░░░░░░╦╠ ╟▒M╗▄▄,▄▄▄╗#▒╬▒╠"╙╙╙╙╙╙╢▒▒▓▀▀░░░░░╠╦#░░░░╚,╩
¼░░░░░░░⌂╦ ▀░░░╚╙░╚▓▒▀░░░½░░╠╜ ╘▀░░░╩╩╩,▄╣╬░░░░░╙╔╩
╢^╙╨╠░░▄æ,Σ ",╓╥m╬░░░░░░░Θ░φ░φ▄ ╬╬░,▄#▒▀░░░░░≥░░#`
*╓,╙φ░░░░░#░░░░░░░#╬╠╩ ╠╩╚╠╟▓▄╣▒▓╬▓▀░░░░░╩░╓═^
`"╜╧Σ░░░Σ░░░░░░╬▓µ ─"░░░░░░░░░░╜░╬▄≈"
`"╙╜╜╜╝╩ÅΣM≡,`╙╚░╙╙░╜| ╙╙╙┴7≥╗
`"┴╙¬¬¬┴┴╙╙╙╙""
*/
pragma solidity ^0.8.0;
import "@openzeppelin/contracts/token/ERC721/ERC721.sol";
import "@openzeppelin/contracts/access/Ownable.sol";
import "@openzeppelin/contracts/token/ERC721/extensions/ERC721Enumerable.sol";
import "@openzeppelin/contracts/utils/Context.sol";
import "../interfaces/ICIGAR.sol";
contract TreasureChest is Context, ERC721, ERC721Enumerable, Ownable {
/*
Initial Token Types:
0 - Sand Dollar
1 - Sapphire
2 - Emerald
3 - Ruby
4 - Diamond
*/
uint256 public constant NUM_TYPES = 5;
// mint price in Cigar
uint256 public mintPrice = 20000 ether;
string private _baseURIextended;
// maps user address => map of (token type => num tokens)
mapping(address => uint256[5]) public userToTokenTypes;
mapping(address => bool) public controllers;
ICIGAR public cigar;
bool public chestIsOpen;
uint256 public nftChance;
uint256 public currentNftCount;
uint256 public nftMaxCount;
event PermanentURI(string _value, uint256 indexed _id);
constructor() ERC721("Treasure Chest", "TC") {
chestIsOpen = true;
}
function _beforeTokenTransfer(address from, address to, uint256 tokenId) internal override(ERC721, ERC721Enumerable) {
super._beforeTokenTransfer(from, to, tokenId);
}
function supportsInterface(bytes4 interfaceId) public view virtual override(ERC721, ERC721Enumerable) returns (bool) {
return super.supportsInterface(interfaceId);
}
function setBaseURI(string memory baseURI_) external onlyOwner() {
_baseURIextended = baseURI_;
}
function _baseURI() internal view virtual override returns (string memory) {
return _baseURIextended;
}
function mint(uint256 amount) public {
require(chestIsOpen, "Chest must be open!");
uint256 totalCost = 0;
for(uint i = 0; i < amount; i++) {
uint256 rand = random(i);
uint256 itemType = getType(rand % 100);
userToTokenTypes[_msgSender()][itemType]++;
totalCost += mintPrice;
}
cigar.burn(_msgSender(), totalCost);
}
function mintGem(uint256 amount, uint256 gemType) external {
require(chestIsOpen, "Chest must be open!");
require(gemType == 1 || gemType == 2 || gemType == 3, "GemType must be 1, 2, or 3");
uint256 totalCost = 0;
for(uint i = 0; i < amount; i++) {
uint256 rand = random(i);
uint256 rand2 = rand % 10;
if (rand2 < 4) {
userToTokenTypes[_msgSender()][gemType]++;
} else {
userToTokenTypes[_msgSender()][0]++;
}
totalCost += mintPrice;
}
cigar.burn(_msgSender(), totalCost);
}
function mintDiamond(uint256 amount) external {
require(chestIsOpen, "Chest must be open!");
uint256 totalCost = 0;
for(uint i = 0; i < amount; i++) {
uint256 rand = random(i);
uint256 rand2 = rand % 7;
if (rand2 == 0) {
userToTokenTypes[_msgSender()][4]++;
} else {
userToTokenTypes[_msgSender()][0]++;
}
totalCost += mintPrice;
}
cigar.burn(_msgSender(), totalCost);
}
function superMint(uint256 amount) external {
require(chestIsOpen, "Chest must be open!");
uint256 supply = totalSupply();
uint256 numMinted = 0;
uint256 nftsMinted = 0;
uint256 totalCost = 0;
for(uint i = 0; i < amount; i++) {
if (currentNftCount < nftMaxCount) {
uint256 rand = random(i);
uint256 rand2 = rand % 10000;
if (rand2 < nftChance) {
_safeMint(_msgSender(), supply + nftsMinted);
nftsMinted++;
currentNftCount++;
totalCost += mintPrice;
} else {
mint(1);
}
numMinted++;
} else {
break;
}
}
cigar.burn(_msgSender(), totalCost);
mint(amount - numMinted);
}
function reserveTokens(uint256 numTokens) external onlyOwner {
uint supply = totalSupply();
uint i;
for (i = 0; i < numTokens; i++) {
_safeMint(msg.sender, supply + i);
}
}
function burn(address user, uint256[5] calldata amounts) external {
require(controllers[_msgSender()], "Must be called by a valid controller address");
for(uint256 i = 0; i < 5; i++) {
userToTokenTypes[user][i] -= amounts[i];
}
}
function setNftMintInfo(uint256 chance, uint256 maxCount) external onlyOwner {
require(chance <= 10000, "Chance must be less than 10000");
nftChance = chance;
nftMaxCount = maxCount;
currentNftCount = 0;
}
function adjustTreasureChestPrice(uint256 newPrice) external onlyOwner {
mintPrice = newPrice;
}
function setCigarToken(address cigarToken) external onlyOwner {
require(address(cigar) == address(0), "Cigar Token already set.");
cigar = ICIGAR(cigarToken);
}
// adds or removes a controller
function setController(address controller) external onlyOwner {
controllers[controller] = !controllers[controller];
}
function withdraw() public onlyOwner {
uint balance = address(this).balance;
payable(msg.sender).transfer(balance);
}
function closeOrOpenChest(bool open) external onlyOwner {
chestIsOpen = open;
}
function markPermanentURI(string memory value, uint256 id) public onlyOwner {
emit PermanentURI(value, id);
}
function getTokensForUser(address user) external view returns (uint256[5] memory) {
return userToTokenTypes[user];
}
// Internal functions
function random(uint256 seed) internal view returns (uint256) {
return uint256(keccak256(abi.encodePacked(
tx.origin,
blockhash(block.number - 1),
block.timestamp,
seed
)));
}
function getType(uint256 rand) internal pure returns (uint256) {
if (rand < 35) {
return 0;
} else if (rand < 40) {
return 4;
} else if (rand < 60) {
return 1;
} else if (rand < 80) {
return 2;
} else {
return 3;
}
}
}
SimpleToken.sol 111 lines
// SPDX-License-Identifier: MIT
/*
«∩ⁿ─╖
⌐ ╦╠Σ▌╓┴ .⌐─≈-,
≤╠╠╠╫╕╬╦╜ ┌"░░░░░░░░░░≈╖φ░╔╦╬░░Σ╜^
¼,╠.:╬╬╦╖╔≡p "╙φ░ ╠╩╚` ░╩░╟╓╜
Γ╠▀╬═┘` Θ Å░▄
,,,,, ┌# ] ▌░░╕
,-─S╜" ,⌐"",`░░φ░░░░S>╫▐ ╩ ░░░░¼
╙ⁿ═s, <░φ╬░░φù ░░░░░░░░╬╠░░"Zw, ,─╓φ░Å░░╩╧w¼
∩²≥┴╝δ»╬░╝░░╩░╓║╙░░░░░░Åφ▄φ░░╦≥░⌠░≥╖, ,≈"╓φ░░░╬╬░░╕ {⌐\
} ▐ ½,#░░░░░╦╚░░╬╜Σ░p╠░░╬╘░░░░╩ ^"¥7"""░"¬╖╠░░░#▒░░░╩ φ╩ ∩
Γ ╬░⌐"╢╙φ░░▒╬╓╓░░░░▄▄╬▄░╬░░Å░░░░╠░╦,φ╠░░░░░░-"╠░╩╩ ê░Γ╠
╘░,, ╠╬ '░╗Σ╢░░░░░░▀╢▓▒▒╬╬░╦#####≥╨░░░╝╜╙` ,φ╬░░░. é░░╔⌐
▐░ `^Σ░▒╗, ▐░░░░░ ▒░"╙Σ░╨▀╜╬░▓▓▓▓▓▓▀▀░»φ░N ╔╬▒░░░"`,╬≥░░╢
\ ╠░░░░░░╬#╩╣▄░Γ, ▐░,φ╬▄Å` ░ ```"╚░░░░,╓▄▄▄╬▀▀░╠╙░╔╬░░░ ½"
└ '░░░░░░╦╠ ╟▒M╗▄▄,▄▄▄╗#▒╬▒╠"╙╙╙╙╙╙╢▒▒▓▀▀░░░░░╠╦#░░░░╚,╩
¼░░░░░░░⌂╦ ▀░░░╚╙░╚▓▒▀░░░½░░╠╜ ╘▀░░░╩╩╩,▄╣╬░░░░░╙╔╩
╢^╙╨╠░░▄æ,Σ ",╓╥m╬░░░░░░░Θ░φ░φ▄ ╬╬░,▄#▒▀░░░░░≥░░#`
*╓,╙φ░░░░░#░░░░░░░#╬╠╩ ╠╩╚╠╟▓▄╣▒▓╬▓▀░░░░░╩░╓═^
`"╜╧Σ░░░Σ░░░░░░╬▓µ ─"░░░░░░░░░░╜░╬▄≈"
`"╙╜╜╜╝╩ÅΣM≡,`╙╚░╙╙░╜| ╙╙╙┴7≥╗
`"┴╙¬¬¬┴┴╙╙╙╙""
*/
pragma solidity ^0.8.0;
import "@openzeppelin/contracts/token/ERC721/ERC721.sol";
import "@openzeppelin/contracts/access/Ownable.sol";
import "@openzeppelin/contracts/token/ERC721/extensions/ERC721Enumerable.sol";
import "@openzeppelin/contracts/utils/Context.sol";
import "../staking/CIGAR.sol";
import "../WealthyWhales.sol";
contract SimpleToken is Context, Ownable, ERC721, ERC721Enumerable {
uint public constant MINT_PRICE = 100 ether;
CIGAR public cigar;
address public wealthyWhales;
mapping(address => mapping(uint256 => uint256)) public userToTokenTypes;
/*
Token Types:
0 - Sand Dollar
1 - Sapphire
2 - Emerald
3 - Ruby
4 - Diamond
Can always add more types to adjust probabilities through addTypes()
*/
uint256 public numTypes;
/*
repalce wealthyWhales variable with setBurner function. Similar to addController
*/
constructor() ERC721("TreasureChest", "TC"){
numTypes = 5;
}
function _beforeTokenTransfer(address from, address to, uint256 tokenId) internal override(ERC721, ERC721Enumerable) {
super._beforeTokenTransfer(from, to, tokenId);
}
function supportsInterface(bytes4 interfaceId) public view virtual override(ERC721, ERC721Enumerable) returns (bool) {
return super.supportsInterface(interfaceId);
}
function mint(uint256 amount) external {
uint256 totalCost = 0;
for(uint i = 0; i < amount; i++) {
uint256 rand = random(i);
uint256 itemType = rand % numTypes;
userToTokenTypes[_msgSender()][itemType]++;
totalCost += MINT_PRICE;
}
cigar.burn(_msgSender(), totalCost);
}
// if burn gems, burn one of each of 3 gems. Otherwise burn diamond.
function burn(address user, bool burnGems) external {
require(_msgSender() == wealthyWhales, "Must be called by WealthyWhales");
if (burnGems) {
userToTokenTypes[user][1]--;
userToTokenTypes[user][2]--;
userToTokenTypes[user][3]--;
} else {
userToTokenTypes[user][4]--;
}
}
function setExternalContracts(address wealthyWhalesAddress, address cigarToken) public onlyOwner {
require(wealthyWhales == address(0) && address(cigar) == address(0), "External contracts already initialized");
wealthyWhales = wealthyWhalesAddress;
cigar = CIGAR(cigarToken);
}
function random(uint256 seed) internal view returns (uint256) {
return uint256(keccak256(abi.encodePacked(
tx.origin,
blockhash(block.number - 1),
block.timestamp,
seed
)));
}
}
Address.sol 216 lines
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
/**
* @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
* ====
*/
function isContract(address account) internal view returns (bool) {
// This method relies on extcodesize, which returns 0 for contracts in
// construction, since the code is only stored at the end of the
// constructor execution.
uint256 size;
assembly {
size := extcodesize(account)
}
return size > 0;
}
/**
* @dev Replacement for Solidity's `transfer`: sends `amount` wei to
* `recipient`, forwarding all available gas and reverting on errors.
*
* https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost
* of certain opcodes, possibly making contracts go over the 2300 gas limit
* imposed by `transfer`, making them unable to receive funds via
* `transfer`. {sendValue} removes this limitation.
*
* https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more].
*
* IMPORTANT: because control is transferred to `recipient`, care must be
* taken to not create reentrancy vulnerabilities. Consider using
* {ReentrancyGuard} or the
* https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].
*/
function sendValue(address payable recipient, uint256 amount) internal {
require(address(this).balance >= amount, "Address: insufficient balance");
(bool success, ) = recipient.call{value: amount}("");
require(success, "Address: unable to send value, recipient may have reverted");
}
/**
* @dev Performs a Solidity function call using a low level `call`. A
* plain `call` is an unsafe replacement for a function call: use this
* function instead.
*
* If `target` reverts with a revert reason, it is bubbled up by this
* function (like regular Solidity function calls).
*
* Returns the raw returned data. To convert to the expected return value,
* use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].
*
* Requirements:
*
* - `target` must be a contract.
* - calling `target` with `data` must not revert.
*
* _Available since v3.1._
*/
function functionCall(address target, bytes memory data) internal returns (bytes memory) {
return functionCall(target, data, "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");
require(isContract(target), "Address: call to non-contract");
(bool success, bytes memory returndata) = target.call{value: value}(data);
return verifyCallResult(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) {
require(isContract(target), "Address: static call to non-contract");
(bool success, bytes memory returndata) = target.staticcall(data);
return verifyCallResult(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) {
require(isContract(target), "Address: delegate call to non-contract");
(bool success, bytes memory returndata) = target.delegatecall(data);
return verifyCallResult(success, returndata, errorMessage);
}
/**
* @dev Tool to verifies that a low level call was successful, and revert if it wasn't, either by bubbling the
* revert reason 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 {
// 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
assembly {
let returndata_size := mload(returndata)
revert(add(32, returndata), returndata_size)
}
} else {
revert(errorMessage);
}
}
}
}
Context.sol 23 lines
// SPDX-License-Identifier: MIT
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;
}
}
Strings.sol 66 lines
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
/**
* @dev String operations.
*/
library Strings {
bytes16 private constant _HEX_SYMBOLS = "0123456789abcdef";
/**
* @dev Converts a `uint256` to its ASCII `string` decimal representation.
*/
function toString(uint256 value) internal pure returns (string memory) {
// Inspired by OraclizeAPI's implementation - MIT licence
// https://github.com/oraclize/ethereum-api/blob/b42146b063c7d6ee1358846c198246239e9360e8/oraclizeAPI_0.4.25.sol
if (value == 0) {
return "0";
}
uint256 temp = value;
uint256 digits;
while (temp != 0) {
digits++;
temp /= 10;
}
bytes memory buffer = new bytes(digits);
while (value != 0) {
digits -= 1;
buffer[digits] = bytes1(uint8(48 + uint256(value % 10)));
value /= 10;
}
return string(buffer);
}
/**
* @dev Converts a `uint256` to its ASCII `string` hexadecimal representation.
*/
function toHexString(uint256 value) internal pure returns (string memory) {
if (value == 0) {
return "0x00";
}
uint256 temp = value;
uint256 length = 0;
while (temp != 0) {
length++;
temp >>= 8;
}
return toHexString(value, length);
}
/**
* @dev Converts a `uint256` to its ASCII `string` hexadecimal representation with fixed length.
*/
function toHexString(uint256 value, uint256 length) internal pure returns (string memory) {
bytes memory buffer = new bytes(2 * length + 2);
buffer[0] = "0";
buffer[1] = "x";
for (uint256 i = 2 * length + 1; i > 1; --i) {
buffer[i] = _HEX_SYMBOLS[value & 0xf];
value >>= 4;
}
require(value == 0, "Strings: hex length insufficient");
return string(buffer);
}
}
Ownable.sol 71 lines
// SPDX-License-Identifier: MIT
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() {
_setOwner(_msgSender());
}
/**
* @dev Returns the address of the current owner.
*/
function owner() public view virtual returns (address) {
return _owner;
}
/**
* @dev Throws if called by any account other than the owner.
*/
modifier onlyOwner() {
require(owner() == _msgSender(), "Ownable: caller is not the owner");
_;
}
/**
* @dev Leaves the contract without owner. It will not be possible to call
* `onlyOwner` functions anymore. Can only be called by the current owner.
*
* NOTE: Renouncing ownership will leave the contract without an owner,
* thereby removing any functionality that is only available to the owner.
*/
function renounceOwnership() public virtual onlyOwner {
_setOwner(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");
_setOwner(newOwner);
}
function _setOwner(address newOwner) private {
address oldOwner = _owner;
_owner = newOwner;
emit OwnershipTransferred(oldOwner, newOwner);
}
}
IERC20.sol 5 lines
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; import "../token/ERC20/IERC20.sol";
ERC20.sol 355 lines
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
import "./IERC20.sol";
import "./extensions/IERC20Metadata.sol";
import "../../utils/Context.sol";
/**
* @dev Implementation of the {IERC20} interface.
*
* This implementation is agnostic to the way tokens are created. This means
* that a supply mechanism has to be added in a derived contract using {_mint}.
* For a generic mechanism see {ERC20PresetMinterPauser}.
*
* TIP: For a detailed writeup see our guide
* https://forum.zeppelin.solutions/t/how-to-implement-erc20-supply-mechanisms/226[How
* to implement supply mechanisms].
*
* We have followed general OpenZeppelin Contracts guidelines: functions revert
* instead returning `false` on failure. This behavior is nonetheless
* conventional and does not conflict with the expectations of ERC20
* applications.
*
* Additionally, an {Approval} event is emitted on calls to {transferFrom}.
* This allows applications to reconstruct the allowance for all accounts just
* by listening to said events. Other implementations of the EIP may not emit
* these events, as it isn't required by the specification.
*
* Finally, the non-standard {decreaseAllowance} and {increaseAllowance}
* functions have been added to mitigate the well-known issues around setting
* allowances. See {IERC20-approve}.
*/
contract ERC20 is Context, IERC20, IERC20Metadata {
mapping(address => uint256) private _balances;
mapping(address => mapping(address => uint256)) private _allowances;
uint256 private _totalSupply;
string private _name;
string private _symbol;
/**
* @dev Sets the values for {name} and {symbol}.
*
* The default value of {decimals} is 18. To select a different value for
* {decimals} you should overload it.
*
* All two of these values are immutable: they can only be set once during
* construction.
*/
constructor(string memory name_, string memory symbol_) {
_name = name_;
_symbol = symbol_;
}
/**
* @dev Returns the name of the token.
*/
function name() public view virtual override returns (string memory) {
return _name;
}
/**
* @dev Returns the symbol of the token, usually a shorter version of the
* name.
*/
function symbol() public view virtual override returns (string memory) {
return _symbol;
}
/**
* @dev Returns the number of decimals used to get its user representation.
* For example, if `decimals` equals `2`, a balance of `505` tokens should
* be displayed to a user as `5.05` (`505 / 10 ** 2`).
*
* Tokens usually opt for a value of 18, imitating the relationship between
* Ether and Wei. This is the value {ERC20} uses, unless this function is
* overridden;
*
* NOTE: This information is only used for _display_ purposes: it in
* no way affects any of the arithmetic of the contract, including
* {IERC20-balanceOf} and {IERC20-transfer}.
*/
function decimals() public view virtual override returns (uint8) {
return 18;
}
/**
* @dev See {IERC20-totalSupply}.
*/
function totalSupply() public view virtual override returns (uint256) {
return _totalSupply;
}
/**
* @dev See {IERC20-balanceOf}.
*/
function balanceOf(address account) public view virtual override returns (uint256) {
return _balances[account];
}
/**
* @dev See {IERC20-transfer}.
*
* Requirements:
*
* - `recipient` cannot be the zero address.
* - the caller must have a balance of at least `amount`.
*/
function transfer(address recipient, uint256 amount) public virtual override returns (bool) {
_transfer(_msgSender(), recipient, amount);
return true;
}
/**
* @dev See {IERC20-allowance}.
*/
function allowance(address owner, address spender) public view virtual override returns (uint256) {
return _allowances[owner][spender];
}
/**
* @dev See {IERC20-approve}.
*
* Requirements:
*
* - `spender` cannot be the zero address.
*/
function approve(address spender, uint256 amount) public virtual override returns (bool) {
_approve(_msgSender(), spender, amount);
return true;
}
/**
* @dev See {IERC20-transferFrom}.
*
* Emits an {Approval} event indicating the updated allowance. This is not
* required by the EIP. See the note at the beginning of {ERC20}.
*
* Requirements:
*
* - `sender` and `recipient` cannot be the zero address.
* - `sender` must have a balance of at least `amount`.
* - the caller must have allowance for ``sender``'s tokens of at least
* `amount`.
*/
function transferFrom(
address sender,
address recipient,
uint256 amount
) public virtual override returns (bool) {
_transfer(sender, recipient, amount);
uint256 currentAllowance = _allowances[sender][_msgSender()];
require(currentAllowance >= amount, "ERC20: transfer amount exceeds allowance");
unchecked {
_approve(sender, _msgSender(), currentAllowance - amount);
}
return true;
}
/**
* @dev Atomically increases the allowance granted to `spender` by the caller.
*
* This is an alternative to {approve} that can be used as a mitigation for
* problems described in {IERC20-approve}.
*
* Emits an {Approval} event indicating the updated allowance.
*
* Requirements:
*
* - `spender` cannot be the zero address.
*/
function increaseAllowance(address spender, uint256 addedValue) public virtual returns (bool) {
_approve(_msgSender(), spender, _allowances[_msgSender()][spender] + addedValue);
return true;
}
/**
* @dev Atomically decreases the allowance granted to `spender` by the caller.
*
* This is an alternative to {approve} that can be used as a mitigation for
* problems described in {IERC20-approve}.
*
* Emits an {Approval} event indicating the updated allowance.
*
* Requirements:
*
* - `spender` cannot be the zero address.
* - `spender` must have allowance for the caller of at least
* `subtractedValue`.
*/
function decreaseAllowance(address spender, uint256 subtractedValue) public virtual returns (bool) {
uint256 currentAllowance = _allowances[_msgSender()][spender];
require(currentAllowance >= subtractedValue, "ERC20: decreased allowance below zero");
unchecked {
_approve(_msgSender(), spender, currentAllowance - subtractedValue);
}
return true;
}
/**
* @dev Moves `amount` of tokens from `sender` to `recipient`.
*
* This internal function is equivalent to {transfer}, and can be used to
* e.g. implement automatic token fees, slashing mechanisms, etc.
*
* Emits a {Transfer} event.
*
* Requirements:
*
* - `sender` cannot be the zero address.
* - `recipient` cannot be the zero address.
* - `sender` must have a balance of at least `amount`.
*/
function _transfer(
address sender,
address recipient,
uint256 amount
) internal virtual {
require(sender != address(0), "ERC20: transfer from the zero address");
require(recipient != address(0), "ERC20: transfer to the zero address");
_beforeTokenTransfer(sender, recipient, amount);
uint256 senderBalance = _balances[sender];
require(senderBalance >= amount, "ERC20: transfer amount exceeds balance");
unchecked {
_balances[sender] = senderBalance - amount;
}
_balances[recipient] += amount;
emit Transfer(sender, recipient, amount);
_afterTokenTransfer(sender, recipient, amount);
}
/** @dev Creates `amount` tokens and assigns them to `account`, increasing
* the total supply.
*
* Emits a {Transfer} event with `from` set to the zero address.
*
* Requirements:
*
* - `account` cannot be the zero address.
*/
function _mint(address account, uint256 amount) internal virtual {
require(account != address(0), "ERC20: mint to the zero address");
_beforeTokenTransfer(address(0), account, amount);
_totalSupply += amount;
_balances[account] += amount;
emit Transfer(address(0), account, amount);
_afterTokenTransfer(address(0), account, amount);
}
/**
* @dev Destroys `amount` tokens from `account`, reducing the
* total supply.
*
* Emits a {Transfer} event with `to` set to the zero address.
*
* Requirements:
*
* - `account` cannot be the zero address.
* - `account` must have at least `amount` tokens.
*/
function _burn(address account, uint256 amount) internal virtual {
require(account != address(0), "ERC20: burn from the zero address");
_beforeTokenTransfer(account, address(0), amount);
uint256 accountBalance = _balances[account];
require(accountBalance >= amount, "ERC20: burn amount exceeds balance");
unchecked {
_balances[account] = accountBalance - amount;
}
_totalSupply -= amount;
emit Transfer(account, address(0), amount);
_afterTokenTransfer(account, address(0), amount);
}
/**
* @dev Sets `amount` as the allowance of `spender` over the `owner` s tokens.
*
* This internal function is equivalent to `approve`, and can be used to
* e.g. set automatic allowances for certain subsystems, etc.
*
* Emits an {Approval} event.
*
* Requirements:
*
* - `owner` cannot be the zero address.
* - `spender` cannot be the zero address.
*/
function _approve(
address owner,
address spender,
uint256 amount
) internal virtual {
require(owner != address(0), "ERC20: approve from the zero address");
require(spender != address(0), "ERC20: approve to the zero address");
_allowances[owner][spender] = amount;
emit Approval(owner, spender, amount);
}
/**
* @dev Hook that is called before any transfer of tokens. This includes
* minting and burning.
*
* Calling conditions:
*
* - when `from` and `to` are both non-zero, `amount` of ``from``'s tokens
* will be transferred to `to`.
* - when `from` is zero, `amount` tokens will be minted for `to`.
* - when `to` is zero, `amount` of ``from``'s tokens will be burned.
* - `from` and `to` are never both zero.
*
* To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks].
*/
function _beforeTokenTransfer(
address from,
address to,
uint256 amount
) internal virtual {}
/**
* @dev Hook that is called after any transfer of tokens. This includes
* minting and burning.
*
* Calling conditions:
*
* - when `from` and `to` are both non-zero, `amount` of ``from``'s tokens
* has been transferred to `to`.
* - when `from` is zero, `amount` tokens have been minted for `to`.
* - when `to` is zero, `amount` of ``from``'s tokens have been burned.
* - `from` and `to` are never both zero.
*
* To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks].
*/
function _afterTokenTransfer(
address from,
address to,
uint256 amount
) internal virtual {}
}
IERC20.sol 81 lines
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
/**
* @dev Interface of the ERC20 standard as defined in the EIP.
*/
interface IERC20 {
/**
* @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 `recipient`.
*
* Returns a boolean value indicating whether the operation succeeded.
*
* Emits a {Transfer} event.
*/
function transfer(address recipient, 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 `sender` to `recipient` 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 sender,
address recipient,
uint256 amount
) external returns (bool);
/**
* @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);
}
ERC721.sol 411 lines
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
import "./IERC721.sol";
import "./IERC721Receiver.sol";
import "./extensions/IERC721Metadata.sol";
import "../../utils/Address.sol";
import "../../utils/Context.sol";
import "../../utils/Strings.sol";
import "../../utils/introspection/ERC165.sol";
/**
* @dev Implementation of https://eips.ethereum.org/EIPS/eip-721[ERC721] Non-Fungible Token Standard, including
* the Metadata extension, but not including the Enumerable extension, which is available separately as
* {ERC721Enumerable}.
*/
contract ERC721 is Context, ERC165, IERC721, IERC721Metadata {
using Address for address;
using Strings for uint256;
// Token name
string private _name;
// Token symbol
string private _symbol;
// Mapping from token ID to owner address
mapping(uint256 => address) private _owners;
// Mapping owner address to token count
mapping(address => uint256) private _balances;
// Mapping from token ID to approved address
mapping(uint256 => address) private _tokenApprovals;
// Mapping from owner to operator approvals
mapping(address => mapping(address => bool)) private _operatorApprovals;
/**
* @dev Initializes the contract by setting a `name` and a `symbol` to the token collection.
*/
constructor(string memory name_, string memory symbol_) {
_name = name_;
_symbol = symbol_;
}
/**
* @dev See {IERC165-supportsInterface}.
*/
function supportsInterface(bytes4 interfaceId) public view virtual override(ERC165, IERC165) returns (bool) {
return
interfaceId == type(IERC721).interfaceId ||
interfaceId == type(IERC721Metadata).interfaceId ||
super.supportsInterface(interfaceId);
}
/**
* @dev See {IERC721-balanceOf}.
*/
function balanceOf(address owner) public view virtual override returns (uint256) {
require(owner != address(0), "ERC721: balance query for the zero address");
return _balances[owner];
}
/**
* @dev See {IERC721-ownerOf}.
*/
function ownerOf(uint256 tokenId) public view virtual override returns (address) {
address owner = _owners[tokenId];
require(owner != address(0), "ERC721: owner query for nonexistent token");
return owner;
}
/**
* @dev See {IERC721Metadata-name}.
*/
function name() public view virtual override returns (string memory) {
return _name;
}
/**
* @dev See {IERC721Metadata-symbol}.
*/
function symbol() public view virtual override returns (string memory) {
return _symbol;
}
/**
* @dev See {IERC721Metadata-tokenURI}.
*/
function tokenURI(uint256 tokenId) public view virtual override returns (string memory) {
require(_exists(tokenId), "ERC721Metadata: URI query for nonexistent token");
string memory baseURI = _baseURI();
return bytes(baseURI).length > 0 ? string(abi.encodePacked(baseURI, tokenId.toString())) : "";
}
/**
* @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, can be overriden in child contracts.
*/
function _baseURI() internal view virtual returns (string memory) {
return "";
}
/**
* @dev See {IERC721-approve}.
*/
function approve(address to, uint256 tokenId) public virtual override {
address owner = ERC721.ownerOf(tokenId);
require(to != owner, "ERC721: approval to current owner");
require(
_msgSender() == owner || isApprovedForAll(owner, _msgSender()),
"ERC721: approve caller is not owner nor approved for all"
);
_approve(to, tokenId);
}
/**
* @dev See {IERC721-getApproved}.
*/
function getApproved(uint256 tokenId) public view virtual override returns (address) {
require(_exists(tokenId), "ERC721: approved query for nonexistent token");
return _tokenApprovals[tokenId];
}
/**
* @dev See {IERC721-setApprovalForAll}.
*/
function setApprovalForAll(address operator, bool approved) public virtual override {
require(operator != _msgSender(), "ERC721: approve to caller");
_operatorApprovals[_msgSender()][operator] = approved;
emit ApprovalForAll(_msgSender(), operator, approved);
}
/**
* @dev See {IERC721-isApprovedForAll}.
*/
function isApprovedForAll(address owner, address operator) public view virtual override returns (bool) {
return _operatorApprovals[owner][operator];
}
/**
* @dev See {IERC721-transferFrom}.
*/
function transferFrom(
address from,
address to,
uint256 tokenId
) public virtual override {
//solhint-disable-next-line max-line-length
require(_isApprovedOrOwner(_msgSender(), tokenId), "ERC721: transfer caller is not owner nor approved");
_transfer(from, to, tokenId);
}
/**
* @dev See {IERC721-safeTransferFrom}.
*/
function safeTransferFrom(
address from,
address to,
uint256 tokenId
) public virtual override {
safeTransferFrom(from, to, tokenId, "");
}
/**
* @dev See {IERC721-safeTransferFrom}.
*/
function safeTransferFrom(
address from,
address to,
uint256 tokenId,
bytes memory _data
) public virtual override {
require(_isApprovedOrOwner(_msgSender(), tokenId), "ERC721: transfer caller is not owner nor approved");
_safeTransfer(from, to, tokenId, _data);
}
/**
* @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.
*
* `_data` is additional data, it has no specified format and it is sent in call to `to`.
*
* This internal function is equivalent to {safeTransferFrom}, and can be used to e.g.
* implement alternative mechanisms to perform token transfer, such as signature-based.
*
* Requirements:
*
* - `from` cannot be the zero address.
* - `to` cannot be the zero address.
* - `tokenId` token must exist and be owned by `from`.
* - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon a safe transfer.
*
* Emits a {Transfer} event.
*/
function _safeTransfer(
address from,
address to,
uint256 tokenId,
bytes memory _data
) internal virtual {
_transfer(from, to, tokenId);
require(_checkOnERC721Received(from, to, tokenId, _data), "ERC721: transfer to non ERC721Receiver implementer");
}
/**
* @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 (`_mint`),
* and stop existing when they are burned (`_burn`).
*/
function _exists(uint256 tokenId) internal view virtual returns (bool) {
return _owners[tokenId] != address(0);
}
/**
* @dev Returns whether `spender` is allowed to manage `tokenId`.
*
* Requirements:
*
* - `tokenId` must exist.
*/
function _isApprovedOrOwner(address spender, uint256 tokenId) internal view virtual returns (bool) {
require(_exists(tokenId), "ERC721: operator query for nonexistent token");
address owner = ERC721.ownerOf(tokenId);
return (spender == owner || getApproved(tokenId) == spender || isApprovedForAll(owner, spender));
}
/**
* @dev Safely mints `tokenId` and transfers it to `to`.
*
* Requirements:
*
* - `tokenId` must not exist.
* - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon a safe transfer.
*
* Emits a {Transfer} event.
*/
function _safeMint(address to, uint256 tokenId) internal virtual {
_safeMint(to, tokenId, "");
}
/**
* @dev Same as {xref-ERC721-_safeMint-address-uint256-}[`_safeMint`], with an additional `data` parameter which is
* forwarded in {IERC721Receiver-onERC721Received} to contract recipients.
*/
function _safeMint(
address to,
uint256 tokenId,
bytes memory _data
) internal virtual {
_mint(to, tokenId);
require(
_checkOnERC721Received(address(0), to, tokenId, _data),
"ERC721: transfer to non ERC721Receiver implementer"
);
}
/**
* @dev Mints `tokenId` and transfers it to `to`.
*
* WARNING: Usage of this method is discouraged, use {_safeMint} whenever possible
*
* Requirements:
*
* - `tokenId` must not exist.
* - `to` cannot be the zero address.
*
* Emits a {Transfer} event.
*/
function _mint(address to, uint256 tokenId) internal virtual {
require(to != address(0), "ERC721: mint to the zero address");
require(!_exists(tokenId), "ERC721: token already minted");
_beforeTokenTransfer(address(0), to, tokenId);
_balances[to] += 1;
_owners[tokenId] = to;
emit Transfer(address(0), to, tokenId);
}
/**
* @dev Destroys `tokenId`.
* The approval is cleared when the token is burned.
*
* Requirements:
*
* - `tokenId` must exist.
*
* Emits a {Transfer} event.
*/
function _burn(uint256 tokenId) internal virtual {
address owner = ERC721.ownerOf(tokenId);
_beforeTokenTransfer(owner, address(0), tokenId);
// Clear approvals
_approve(address(0), tokenId);
_balances[owner] -= 1;
delete _owners[tokenId];
emit Transfer(owner, address(0), tokenId);
}
/**
* @dev Transfers `tokenId` from `from` to `to`.
* As opposed to {transferFrom}, this imposes no restrictions on msg.sender.
*
* Requirements:
*
* - `to` cannot be the zero address.
* - `tokenId` token must be owned by `from`.
*
* Emits a {Transfer} event.
*/
function _transfer(
address from,
address to,
uint256 tokenId
) internal virtual {
require(ERC721.ownerOf(tokenId) == from, "ERC721: transfer of token that is not own");
require(to != address(0), "ERC721: transfer to the zero address");
_beforeTokenTransfer(from, to, tokenId);
// Clear approvals from the previous owner
_approve(address(0), tokenId);
_balances[from] -= 1;
_balances[to] += 1;
_owners[tokenId] = to;
emit Transfer(from, to, tokenId);
}
/**
* @dev Approve `to` to operate on `tokenId`
*
* Emits a {Approval} event.
*/
function _approve(address to, uint256 tokenId) internal virtual {
_tokenApprovals[tokenId] = to;
emit Approval(ERC721.ownerOf(tokenId), to, tokenId);
}
/**
* @dev Internal function to invoke {IERC721Receiver-onERC721Received} on a target address.
* The call is not executed if the target address is not a contract.
*
* @param from address representing the previous owner of the given token ID
* @param to target address that will receive the tokens
* @param tokenId uint256 ID of the token to be transferred
* @param _data bytes optional data to send along with the call
* @return bool whether the call correctly returned the expected magic value
*/
function _checkOnERC721Received(
address from,
address to,
uint256 tokenId,
bytes memory _data
) private returns (bool) {
if (to.isContract()) {
try IERC721Receiver(to).onERC721Received(_msgSender(), from, tokenId, _data) returns (bytes4 retval) {
return retval == IERC721Receiver.onERC721Received.selector;
} catch (bytes memory reason) {
if (reason.length == 0) {
revert("ERC721: transfer to non ERC721Receiver implementer");
} else {
assembly {
revert(add(32, reason), mload(reason))
}
}
}
} else {
return true;
}
}
/**
* @dev Hook that is called before any token transfer. This includes minting
* and burning.
*
* 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, ``from``'s `tokenId` will be burned.
* - `from` and `to` are never both zero.
*
* To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks].
*/
function _beforeTokenTransfer(
address from,
address to,
uint256 tokenId
) internal virtual {}
}
IERC721.sol 142 lines
// SPDX-License-Identifier: MIT
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`, 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
) external;
/**
* @dev Transfers `tokenId` token 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;
/**
* @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 Returns the account approved for `tokenId` token.
*
* Requirements:
*
* - `tokenId` must exist.
*/
function getApproved(uint256 tokenId) external view returns (address operator);
/**
* @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 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);
/**
* @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;
}
ERC165.sol 28 lines
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
import "./IERC165.sol";
/**
* @dev Implementation of the {IERC165} interface.
*
* Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check
* for the additional interface id that will be supported. For example:
*
* ```solidity
* function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {
* return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId);
* }
* ```
*
* Alternatively, {ERC165Storage} provides an easier to use but more expensive implementation.
*/
abstract contract ERC165 is IERC165 {
/**
* @dev See {IERC165-supportsInterface}.
*/
function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {
return interfaceId == type(IERC165).interfaceId;
}
}
IERC165.sol 24 lines
// SPDX-License-Identifier: MIT
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);
}
IERC721Receiver.sol 26 lines
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
/**
* @title ERC721 token receiver interface
* @dev Interface for any contract that wants to support safeTransfers
* from ERC721 asset contracts.
*/
interface IERC721Receiver {
/**
* @dev Whenever an {IERC721} `tokenId` token is transferred to this contract via {IERC721-safeTransferFrom}
* by `operator` from `from`, this function is called.
*
* It must return its Solidity selector to confirm the token transfer.
* If any other value is returned or the interface is not implemented by the recipient, the transfer will be reverted.
*
* The selector can be obtained in Solidity with `IERC721.onERC721Received.selector`.
*/
function onERC721Received(
address operator,
address from,
uint256 tokenId,
bytes calldata data
) external returns (bytes4);
}
IERC20Metadata.sol 27 lines
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
import "../IERC20.sol";
/**
* @dev Interface for the optional metadata functions from the ERC20 standard.
*
* _Available since v4.1._
*/
interface IERC20Metadata is IERC20 {
/**
* @dev Returns the name of the token.
*/
function name() external view returns (string memory);
/**
* @dev Returns the symbol of the token.
*/
function symbol() external view returns (string memory);
/**
* @dev Returns the decimals places of the token.
*/
function decimals() external view returns (uint8);
}
ERC721Enumerable.sol 162 lines
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
import "../ERC721.sol";
import "./IERC721Enumerable.sol";
/**
* @dev This implements an optional extension of {ERC721} defined in the EIP that adds
* enumerability of all the token ids in the contract as well as all token ids owned by each
* account.
*/
abstract contract ERC721Enumerable is ERC721, IERC721Enumerable {
// Mapping from owner to list of owned token IDs
mapping(address => mapping(uint256 => uint256)) private _ownedTokens;
// Mapping from token ID to index of the owner tokens list
mapping(uint256 => uint256) private _ownedTokensIndex;
// Array with all token ids, used for enumeration
uint256[] private _allTokens;
// Mapping from token id to position in the allTokens array
mapping(uint256 => uint256) private _allTokensIndex;
/**
* @dev See {IERC165-supportsInterface}.
*/
function supportsInterface(bytes4 interfaceId) public view virtual override(IERC165, ERC721) returns (bool) {
return interfaceId == type(IERC721Enumerable).interfaceId || super.supportsInterface(interfaceId);
}
/**
* @dev See {IERC721Enumerable-tokenOfOwnerByIndex}.
*/
function tokenOfOwnerByIndex(address owner, uint256 index) public view virtual override returns (uint256) {
require(index < ERC721.balanceOf(owner), "ERC721Enumerable: owner index out of bounds");
return _ownedTokens[owner][index];
}
/**
* @dev See {IERC721Enumerable-totalSupply}.
*/
function totalSupply() public view virtual override returns (uint256) {
return _allTokens.length;
}
/**
* @dev See {IERC721Enumerable-tokenByIndex}.
*/
function tokenByIndex(uint256 index) public view virtual override returns (uint256) {
require(index < ERC721Enumerable.totalSupply(), "ERC721Enumerable: global index out of bounds");
return _allTokens[index];
}
/**
* @dev Hook that is called before any token transfer. This includes minting
* and burning.
*
* 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, ``from``'s `tokenId` will be burned.
* - `from` cannot be the zero address.
* - `to` cannot be the zero address.
*
* To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks].
*/
function _beforeTokenTransfer(
address from,
address to,
uint256 tokenId
) internal virtual override {
super._beforeTokenTransfer(from, to, tokenId);
if (from == address(0)) {
_addTokenToAllTokensEnumeration(tokenId);
} else if (from != to) {
_removeTokenFromOwnerEnumeration(from, tokenId);
}
if (to == address(0)) {
_removeTokenFromAllTokensEnumeration(tokenId);
} else if (to != from) {
_addTokenToOwnerEnumeration(to, tokenId);
}
}
/**
* @dev Private function to add a token to this extension's ownership-tracking data structures.
* @param to address representing the new owner of the given token ID
* @param tokenId uint256 ID of the token to be added to the tokens list of the given address
*/
function _addTokenToOwnerEnumeration(address to, uint256 tokenId) private {
uint256 length = ERC721.balanceOf(to);
_ownedTokens[to][length] = tokenId;
_ownedTokensIndex[tokenId] = length;
}
/**
* @dev Private function to add a token to this extension's token tracking data structures.
* @param tokenId uint256 ID of the token to be added to the tokens list
*/
function _addTokenToAllTokensEnumeration(uint256 tokenId) private {
_allTokensIndex[tokenId] = _allTokens.length;
_allTokens.push(tokenId);
}
/**
* @dev Private function to remove a token from this extension's ownership-tracking data structures. Note that
* while the token is not assigned a new owner, the `_ownedTokensIndex` mapping is _not_ updated: this allows for
* gas optimizations e.g. when performing a transfer operation (avoiding double writes).
* This has O(1) time complexity, but alters the order of the _ownedTokens array.
* @param from address representing the previous owner of the given token ID
* @param tokenId uint256 ID of the token to be removed from the tokens list of the given address
*/
function _removeTokenFromOwnerEnumeration(address from, uint256 tokenId) private {
// To prevent a gap in from's tokens array, we store the last token in the index of the token to delete, and
// then delete the last slot (swap and pop).
uint256 lastTokenIndex = ERC721.balanceOf(from) - 1;
uint256 tokenIndex = _ownedTokensIndex[tokenId];
// When the token to delete is the last token, the swap operation is unnecessary
if (tokenIndex != lastTokenIndex) {
uint256 lastTokenId = _ownedTokens[from][lastTokenIndex];
_ownedTokens[from][tokenIndex] = lastTokenId; // Move the last token to the slot of the to-delete token
_ownedTokensIndex[lastTokenId] = tokenIndex; // Update the moved token's index
}
// This also deletes the contents at the last position of the array
delete _ownedTokensIndex[tokenId];
delete _ownedTokens[from][lastTokenIndex];
}
/**
* @dev Private function to remove a token from this extension's token tracking data structures.
* This has O(1) time complexity, but alters the order of the _allTokens array.
* @param tokenId uint256 ID of the token to be removed from the tokens list
*/
function _removeTokenFromAllTokensEnumeration(uint256 tokenId) private {
// To prevent a gap in the tokens array, we store the last token in the index of the token to delete, and
// then delete the last slot (swap and pop).
uint256 lastTokenIndex = _allTokens.length - 1;
uint256 tokenIndex = _allTokensIndex[tokenId];
// When the token to delete is the last token, the swap operation is unnecessary. However, since this occurs so
// rarely (when the last minted token is burnt) that we still do the swap here to avoid the gas cost of adding
// an 'if' statement (like in _removeTokenFromOwnerEnumeration)
uint256 lastTokenId = _allTokens[lastTokenIndex];
_allTokens[tokenIndex] = lastTokenId; // Move the last token to the slot of the to-delete token
_allTokensIndex[lastTokenId] = tokenIndex; // Update the moved token's index
// This also deletes the contents at the last position of the array
delete _allTokensIndex[tokenId];
_allTokens.pop();
}
}
IERC721Enumerable.sol 28 lines
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
import "../IERC721.sol";
/**
* @title ERC-721 Non-Fungible Token Standard, optional enumeration extension
* @dev See https://eips.ethereum.org/EIPS/eip-721
*/
interface IERC721Enumerable is IERC721 {
/**
* @dev Returns the total amount of tokens stored by the contract.
*/
function totalSupply() external view returns (uint256);
/**
* @dev Returns a token ID owned by `owner` at a given `index` of its token list.
* Use along with {balanceOf} to enumerate all of ``owner``'s tokens.
*/
function tokenOfOwnerByIndex(address owner, uint256 index) external view returns (uint256 tokenId);
/**
* @dev Returns a token ID at a given `index` of all the tokens stored by the contract.
* Use along with {totalSupply} to enumerate all tokens.
*/
function tokenByIndex(uint256 index) external view returns (uint256);
}
Read Contract
MIN_STAKING_TIME_WEALTHY_WHALES 0x58f6ec17 → uint256
WEALTHY_WHALE_TAX 0x345e958d → uint256
cigar 0x929e26ce → address
cigarAwarded 0x038d97fc → uint256
cigarClub 0x9175442b → address
owner 0x8da5cb5b → address
totalWealthyWhalesStaked 0xe2c7ea49 → uint256
wealthyWhaleClub 0x81b89c01 → uint256, uint256, address
wealthyWhaleVault 0x2b38d967 → uint256
wealthyWhales2 0xb915d514 → address
Write Contract 5 functions
These functions modify contract state and require a wallet transaction to execute.
claimWealthyWhales 0xdc0023a4
uint256[] tokenIds
bool unstake
renounceOwnership 0x715018a6
No parameters
setCigarClub 0xe047cd02
address _cigarClub
stakeWealthyWhalesInCigarClub 0x8da41310
uint256[] tokenIds
transferOwnership 0xf2fde38b
address newOwner
Recent Transactions
No transactions found for this address