Transaction Hash:
Block:
13702876 at Nov-28-2021 02:21:18 PM +UTC
Transaction Fee:
0.005353515721158792 ETH
$13.54
Gas Used:
46,596 Gas / 114.892173602 Gwei
Emitted Events:
216 |
WhalesGame.ApprovalForAll( owner=[Sender] 0x1287b8f028f50b79faaf23e67e9c0cc646d83b6b, operator=0xdC1deCd8...e28CB7154, approved=True )
|
Account State Difference:
Address | Before | After | State Difference | ||
---|---|---|---|---|---|
0x1287B8f0...646D83B6B |
0.83985794344069757 Eth
Nonce: 476
|
0.834504427719538778 Eth
Nonce: 477
| 0.005353515721158792 | ||
0x1Ebb2184...f183318cE | |||||
0xEA674fdD...16B898ec8
Miner
| (Ethermine) | 1,462.13491411581162343 Eth | 1,462.134992516737384126 Eth | 0.000078400925760696 |
Execution Trace
WhalesGame.setApprovalForAll( _operator=0xdC1deCd8Eb1A78612859Db022be0536e28CB7154, _approved=True )
setApprovalForAll[WhalesGame (ln:575)]
ApprovalForAll[WhalesGame (ln:577)]
// SPDX-License-Identifier: MIT pragma solidity ^0.8.10; /* . ":" ___:____ |"\/"| ,' `. \ / | O \___/ | ~^~^~^~^~^~^~^~^~^~^~^~^~ Whales Game | Generative Yield NFTs Mint tokens and earn KRILL with this new blockchain based game! Battle it out to see who can generate the most yield. Website: https://whales.game/ */ interface MetadataInterface { function name() external view returns (string memory); function symbol() external view returns (string memory); function tokenURI(uint256 _tokenId) external view returns (string memory); function deploySetWhalesGame(WhalesGame _wg) external; } interface Callable { function tokenCallback(address _from, uint256 _tokens, bytes calldata _data) external returns (bool); } interface Receiver { function onERC721Received(address _operator, address _from, uint256 _tokenId, bytes calldata _data) external returns (bytes4); } interface Router { function WETH() external pure returns (address); function factory() external pure returns (address); } interface Factory { function getPair(address, address) external view returns (address); function createPair(address, address) external returns (address); } interface Pair { function token0() external view returns (address); function totalSupply() external view returns (uint256); function balanceOf(address) external view returns (uint256); function allowance(address, address) external view returns (uint256); function getReserves() external view returns (uint112 reserve0, uint112 reserve1, uint32 blockTimestampLast); function transfer(address, uint256) external returns (bool); function transferFrom(address, address, uint256) external returns (bool); } contract KRILL { uint256 constant private UINT_MAX = type(uint256).max; uint256 constant private TRANSFER_FEE = 1; // 1% per transfer string constant public name = "Krill Token"; string constant public symbol = "KRILL"; uint8 constant public decimals = 18; struct User { uint256 balance; mapping(address => uint256) allowance; } struct Info { uint256 totalSupply; mapping(address => User) users; mapping(address => bool) toWhitelist; mapping(address => bool) fromWhitelist; address owner; Router router; Pair pair; bool weth0; WhalesGame wg; StakingRewards stakingRewards; } Info private info; event Transfer(address indexed from, address indexed to, uint256 tokens); event Approval(address indexed owner, address indexed spender, uint256 tokens); event WhitelistUpdated(address indexed user, bool fromWhitelisted, bool toWhitelisted); modifier _onlyOwner() { require(msg.sender == owner()); _; } constructor() { info.router = Router(0x7a250d5630B4cF539739dF2C5dAcb4c659F2488D); info.pair = Pair(Factory(info.router.factory()).createPair(info.router.WETH(), address(this))); info.weth0 = info.pair.token0() == info.router.WETH(); info.owner = msg.sender; } function setOwner(address _owner) external _onlyOwner { info.owner = _owner; } function setWhitelisted(address _address, bool _fromWhitelisted, bool _toWhitelisted) external _onlyOwner { info.fromWhitelist[_address] = _fromWhitelisted; info.toWhitelist[_address] = _toWhitelisted; emit WhitelistUpdated(_address, _fromWhitelisted, _toWhitelisted); } function deploySetWhalesGame(WhalesGame _wg) external { require(tx.origin == owner() && stakingRewardsAddress() == address(0x0)); info.wg = _wg; info.stakingRewards = new StakingRewards(info.wg, info.pair); _approve(address(this), stakingRewardsAddress(), UINT_MAX); } function mint(address _receiver, uint256 _tokens) external { require(msg.sender == address(info.wg)); info.totalSupply += _tokens; info.users[_receiver].balance += _tokens; emit Transfer(address(0x0), _receiver, _tokens); } function burn(uint256 _tokens) external { require(balanceOf(msg.sender) >= _tokens); info.totalSupply -= _tokens; info.users[msg.sender].balance -= _tokens; emit Transfer(msg.sender, address(0x0), _tokens); } function transfer(address _to, uint256 _tokens) external returns (bool) { return _transfer(msg.sender, _to, _tokens); } function approve(address _spender, uint256 _tokens) external returns (bool) { return _approve(msg.sender, _spender, _tokens); } function transferFrom(address _from, address _to, uint256 _tokens) external returns (bool) { uint256 _allowance = allowance(_from, msg.sender); require(_allowance >= _tokens); if (_allowance != UINT_MAX) { info.users[_from].allowance[msg.sender] -= _tokens; } return _transfer(_from, _to, _tokens); } function transferAndCall(address _to, uint256 _tokens, bytes calldata _data) external returns (bool) { uint256 _balanceBefore = balanceOf(_to); _transfer(msg.sender, _to, _tokens); uint256 _tokensReceived = balanceOf(_to) - _balanceBefore; uint32 _size; assembly { _size := extcodesize(_to) } if (_size > 0) { require(Callable(_to).tokenCallback(msg.sender, _tokensReceived, _data)); } return true; } function whalesGameAddress() public view returns (address) { return address(info.wg); } function pairAddress() external view returns (address) { return address(info.pair); } function stakingRewardsAddress() public view returns (address) { return address(info.stakingRewards); } function owner() public view returns (address) { return info.owner; } function isFromWhitelisted(address _address) public view returns (bool) { return info.fromWhitelist[_address]; } function isToWhitelisted(address _address) public view returns (bool) { return info.toWhitelist[_address]; } function totalSupply() public view returns (uint256) { return info.totalSupply; } function balanceOf(address _user) public view returns (uint256) { return info.users[_user].balance; } function allowance(address _user, address _spender) public view returns (uint256) { return info.users[_user].allowance[_spender]; } function allInfoFor(address _user) external view returns (uint256 totalTokens, uint256 totalLPTokens, uint256 wethReserve, uint256 krillReserve, uint256 userAllowance, uint256 userBalance, uint256 userLPBalance) { totalTokens = totalSupply(); totalLPTokens = info.pair.totalSupply(); (uint256 _res0, uint256 _res1, ) = info.pair.getReserves(); wethReserve = info.weth0 ? _res0 : _res1; krillReserve = info.weth0 ? _res1 : _res0; userAllowance = allowance(_user, whalesGameAddress()); userBalance = balanceOf(_user); userLPBalance = info.pair.balanceOf(_user); } function _approve(address _owner, address _spender, uint256 _tokens) internal returns (bool) { info.users[_owner].allowance[_spender] = _tokens; emit Approval(_owner, _spender, _tokens); return true; } function _transfer(address _from, address _to, uint256 _tokens) internal returns (bool) { require(balanceOf(_from) >= _tokens); info.users[_from].balance -= _tokens; uint256 _fee = 0; if (!(_from == stakingRewardsAddress() || _to == stakingRewardsAddress() || _to == whalesGameAddress() || isFromWhitelisted(_from) || isToWhitelisted(_to))) { _fee = _tokens * TRANSFER_FEE / 100; address _this = address(this); info.users[_this].balance += _fee; emit Transfer(_from, _this, _fee); info.stakingRewards.disburse(balanceOf(_this)); } info.users[_to].balance += _tokens - _fee; emit Transfer(_from, _to, _tokens - _fee); return true; } } contract StakingRewards { uint256 constant private FLOAT_SCALAR = 2**64; struct User { uint256 deposited; int256 scaledPayout; } struct Info { uint256 totalDeposited; uint256 scaledRewardsPerToken; uint256 pendingRewards; mapping(address => User) users; WhalesGame wg; KRILL krill; Pair pair; } Info private info; event Deposit(address indexed user, uint256 amount); event Withdraw(address indexed user, uint256 amount); event Claim(address indexed user, uint256 amount); event Reward(uint256 amount); constructor(WhalesGame _wg, Pair _pair) { info.wg = _wg; info.krill = KRILL(msg.sender); info.pair = _pair; } function disburse(uint256 _amount) external { if (_amount > 0) { info.krill.transferFrom(msg.sender, address(this), _amount); _disburse(_amount); } } function deposit(uint256 _amount) external { depositFor(_amount, msg.sender); } function depositFor(uint256 _amount, address _user) public { require(_amount > 0); _update(); info.pair.transferFrom(msg.sender, address(this), _amount); info.totalDeposited += _amount; info.users[_user].deposited += _amount; info.users[_user].scaledPayout += int256(_amount * info.scaledRewardsPerToken); emit Deposit(_user, _amount); } function withdrawAll() external { uint256 _deposited = depositedOf(msg.sender); if (_deposited > 0) { withdraw(_deposited); } } function withdraw(uint256 _amount) public { require(_amount > 0 && _amount <= depositedOf(msg.sender)); _update(); info.totalDeposited -= _amount; info.users[msg.sender].deposited -= _amount; info.users[msg.sender].scaledPayout -= int256(_amount * info.scaledRewardsPerToken); info.pair.transfer(msg.sender, _amount); emit Withdraw(msg.sender, _amount); } function claim() external { _update(); uint256 _rewards = rewardsOf(msg.sender); if (_rewards > 0) { info.users[msg.sender].scaledPayout += int256(_rewards * FLOAT_SCALAR); info.krill.transfer(msg.sender, _rewards); emit Claim(msg.sender, _rewards); } } function totalDeposited() public view returns (uint256) { return info.totalDeposited; } function depositedOf(address _user) public view returns (uint256) { return info.users[_user].deposited; } function rewardsOf(address _user) public view returns (uint256) { return uint256(int256(info.scaledRewardsPerToken * depositedOf(_user)) - info.users[_user].scaledPayout) / FLOAT_SCALAR; } function allInfoFor(address _user) external view returns (uint256 totalLPDeposited, uint256 totalLPTokens, uint256 wethReserve, uint256 krillReserve, uint256 userBalance, uint256 userAllowance, uint256 userDeposited, uint256 userRewards) { totalLPDeposited = totalDeposited(); ( , totalLPTokens, wethReserve, krillReserve, , , ) = info.krill.allInfoFor(address(this)); userBalance = info.pair.balanceOf(_user); userAllowance = info.pair.allowance(_user, address(this)); userDeposited = depositedOf(_user); userRewards = rewardsOf(_user); } function _update() internal { address _this = address(this); uint256 _balanceBefore = info.krill.balanceOf(_this); info.wg.claim(); _disburse(info.krill.balanceOf(_this) - _balanceBefore); } function _disburse(uint256 _amount) internal { if (_amount > 0) { if (totalDeposited() == 0) { info.pendingRewards += _amount; } else { info.scaledRewardsPerToken += (_amount + info.pendingRewards) * FLOAT_SCALAR / totalDeposited(); info.pendingRewards = 0; } emit Reward(_amount); } } } contract WhalesGame { uint256 constant public ETH_MINTABLE_SUPPLY = 2000; uint256 constant public WHITELIST_ETH_MINTABLE_SUPPLY = 8000; uint256 constant public KRILL_MINTABLE_SUPPLY = 40000; uint256 constant public MAX_SUPPLY = ETH_MINTABLE_SUPPLY + WHITELIST_ETH_MINTABLE_SUPPLY + KRILL_MINTABLE_SUPPLY; uint256 constant public INITIAL_MINT_COST_ETH = 0.05 ether; uint256 constant public KRILL_PER_DAY_PER_FISHERMAN = 1e22; // 10,000 uint256 constant private KRILL_COST_ADD = 1e4; uint256 constant private KRILL_COST_EXPONENT = 3; uint256 constant private KRILL_COST_SCALER = 2e10; // KRILL minted tokens = 0, minting cost = 20,000 // KRILL minted tokens = 40k, minting cost = 2,500,000 uint256 constant private FLOAT_SCALAR = 2**64; uint256 constant private WHALE_MODULUS = 10; // 1 in 10 uint256 constant private WHALES_CUT = 20; // 20% of all yield uint256 constant private STAKING_CUT = 25; // 25% of minting costs uint256 constant private DEV_TOKENS = 50; uint256 constant private OPENING_DELAY = 2 hours; uint256 constant private WHITELIST_DURATION = 8 hours; struct User { uint256 balance; mapping(uint256 => uint256) list; mapping(address => bool) approved; mapping(uint256 => uint256) indexOf; uint256 rewards; uint256 lastUpdated; uint256 krillPerDay; uint256 whales; int256 scaledPayout; } struct Token { address owner; address approved; bytes32 seed; bool isWhale; } struct Info { uint256 totalSupply; uint256 totalWhales; uint256 ethMintedTokens; uint256 krillMintedTokens; uint256 scaledRewardsPerWhale; uint256 openingTime; uint256 whitelistExpiry; mapping(uint256 => Token) list; mapping(address => User) users; mapping(uint256 => uint256) claimedBitMap; bytes32 merkleRoot; MetadataInterface metadata; address owner; KRILL krill; StakingRewards stakingRewards; } Info private info; mapping(bytes4 => bool) public supportsInterface; event Transfer(address indexed from, address indexed to, uint256 indexed tokenId); event Approval(address indexed owner, address indexed approved, uint256 indexed tokenId); event ApprovalForAll(address indexed owner, address indexed operator, bool approved); event Mint(address indexed owner, uint256 indexed tokenId, bytes32 seed, bool isWhale); event ClaimFishermenRewards(address indexed user, uint256 amount); event ClaimWhaleRewards(address indexed user, uint256 amount); event Reward(address indexed user, uint256 amount); event WhalesReward(uint256 amount); event StakingReward(uint256 amount); modifier _onlyOwner() { require(msg.sender == owner()); _; } constructor(MetadataInterface _metadata, KRILL _krill, bytes32 _merkleRoot) { info.metadata = _metadata; info.metadata.deploySetWhalesGame(this); info.krill = _krill; info.krill.deploySetWhalesGame(this); info.stakingRewards = StakingRewards(info.krill.stakingRewardsAddress()); info.krill.approve(stakingRewardsAddress(), type(uint256).max); info.merkleRoot = _merkleRoot; info.owner = 0x99A768bd14Ea62FaADA61F2c7f123303CDAa69fC; info.openingTime = block.timestamp + OPENING_DELAY; info.whitelistExpiry = block.timestamp + OPENING_DELAY + WHITELIST_DURATION; supportsInterface[0x01ffc9a7] = true; // ERC-165 supportsInterface[0x80ac58cd] = true; // ERC-721 supportsInterface[0x5b5e139f] = true; // Metadata supportsInterface[0x780e9d63] = true; // Enumerable for (uint256 i = 0; i < DEV_TOKENS; i++) { _mint(0xa1450E7D547b4748fc94C8C98C9dB667eaD31cF8); } } function setOwner(address _owner) external _onlyOwner { info.owner = _owner; } function setMetadata(MetadataInterface _metadata) external _onlyOwner { info.metadata = _metadata; } function withdraw() external { address _this = address(this); require(_this.balance > 0); payable(0xFaDED72464D6e76e37300B467673b36ECc4d2ccF).transfer(_this.balance / 2); // 50% total payable(0x1cC79d49ce5b9519C912D810E39025DD27d1F033).transfer(_this.balance / 10); // 5% total payable(0xa1450E7D547b4748fc94C8C98C9dB667eaD31cF8).transfer(_this.balance); // 45% total } receive() external payable { mintManyWithETH(msg.value / INITIAL_MINT_COST_ETH); } function mintWithETH() external payable { mintManyWithETH(1); } function mintManyWithETH(uint256 _tokens) public payable { require(isOpen()); require(_tokens > 0); if (whitelistExpired()) { require(totalSupply() - krillMintedTokens() + _tokens <= ETH_MINTABLE_SUPPLY + WHITELIST_ETH_MINTABLE_SUPPLY); } else { require(ethMintedTokens() + _tokens <= ETH_MINTABLE_SUPPLY); } uint256 _cost = _tokens * INITIAL_MINT_COST_ETH; require(msg.value >= _cost); info.ethMintedTokens += _tokens; for (uint256 i = 0; i < _tokens; i++) { _mint(msg.sender); } if (msg.value > _cost) { payable(msg.sender).transfer(msg.value - _cost); } } function mintWithProof(uint256 _index, address _account, bytes32[] calldata _merkleProof) external payable { require(isOpen()); require(!whitelistExpired() && whitelistMintedTokens() < WHITELIST_ETH_MINTABLE_SUPPLY); require(msg.value >= INITIAL_MINT_COST_ETH); require(!proofClaimed(_index)); bytes32 _node = keccak256(abi.encodePacked(_index, _account)); require(_verify(_merkleProof, _node)); uint256 _claimedWordIndex = _index / 256; uint256 _claimedBitIndex = _index % 256; info.claimedBitMap[_claimedWordIndex] = info.claimedBitMap[_claimedWordIndex] | (1 << _claimedBitIndex); _mint(_account); if (msg.value > INITIAL_MINT_COST_ETH) { payable(msg.sender).transfer(msg.value - INITIAL_MINT_COST_ETH); } } function mint() external { mintMany(1); } function mintMany(uint256 _tokens) public { require(isOpen()); require(_tokens > 0 && krillMintedTokens() + _tokens <= KRILL_MINTABLE_SUPPLY); uint256 _cost = calculateKrillMintCost(_tokens); info.krill.transferFrom(msg.sender, address(this), _cost); uint256 _stakingReward = _cost * STAKING_CUT / 100; info.stakingRewards.disburse(_stakingReward); emit StakingReward(_stakingReward); info.krill.burn(info.krill.balanceOf(address(this))); info.krillMintedTokens += _tokens; for (uint256 i = 0; i < _tokens; i++) { _mint(msg.sender); } } function claim() external { claimFishermenRewards(); claimWhaleRewards(); } function claimFishermenRewards() public { _update(msg.sender); uint256 _rewards = info.users[msg.sender].rewards; if (_rewards > 0) { info.users[msg.sender].rewards = 0; info.krill.mint(msg.sender, _rewards); emit ClaimFishermenRewards(msg.sender, _rewards); } } function claimWhaleRewards() public { uint256 _rewards = whaleRewardsOf(msg.sender); if (_rewards > 0) { info.users[msg.sender].scaledPayout += int256(_rewards * FLOAT_SCALAR); info.krill.mint(msg.sender, _rewards); emit ClaimWhaleRewards(msg.sender, _rewards); } } function approve(address _approved, uint256 _tokenId) external { require(msg.sender == ownerOf(_tokenId)); info.list[_tokenId].approved = _approved; emit Approval(msg.sender, _approved, _tokenId); } function setApprovalForAll(address _operator, bool _approved) external { info.users[msg.sender].approved[_operator] = _approved; emit ApprovalForAll(msg.sender, _operator, _approved); } function transferFrom(address _from, address _to, uint256 _tokenId) external { _transfer(_from, _to, _tokenId); } function safeTransferFrom(address _from, address _to, uint256 _tokenId) external { safeTransferFrom(_from, _to, _tokenId, ""); } function safeTransferFrom(address _from, address _to, uint256 _tokenId, bytes memory _data) public { _transfer(_from, _to, _tokenId); uint32 _size; assembly { _size := extcodesize(_to) } if (_size > 0) { require(Receiver(_to).onERC721Received(msg.sender, _from, _tokenId, _data) == 0x150b7a02); } } function name() external view returns (string memory) { return info.metadata.name(); } function symbol() external view returns (string memory) { return info.metadata.symbol(); } function tokenURI(uint256 _tokenId) external view returns (string memory) { return info.metadata.tokenURI(_tokenId); } function krillAddress() external view returns (address) { return address(info.krill); } function pairAddress() external view returns (address) { return info.krill.pairAddress(); } function stakingRewardsAddress() public view returns (address) { return address(info.stakingRewards); } function merkleRoot() public view returns (bytes32) { return info.merkleRoot; } function openingTime() public view returns (uint256) { return info.openingTime; } function isOpen() public view returns (bool) { return block.timestamp > openingTime(); } function whitelistExpiry() public view returns (uint256) { return info.whitelistExpiry; } function whitelistExpired() public view returns (bool) { return block.timestamp > whitelistExpiry(); } function owner() public view returns (address) { return info.owner; } function totalSupply() public view returns (uint256) { return info.totalSupply; } function ethMintedTokens() public view returns (uint256) { return info.ethMintedTokens; } function krillMintedTokens() public view returns (uint256) { return info.krillMintedTokens; } function whitelistMintedTokens() public view returns (uint256) { return totalSupply() - ethMintedTokens() - krillMintedTokens(); } function totalWhales() public view returns (uint256) { return info.totalWhales; } function totalFishermen() public view returns (uint256) { return totalSupply() - totalWhales(); } function totalKrillPerDay() external view returns (uint256) { return totalFishermen() * KRILL_PER_DAY_PER_FISHERMAN; } function currentKrillMintCost() public view returns (uint256) { return krillMintCost(krillMintedTokens()); } function krillMintCost(uint256 _krillMintedTokens) public pure returns (uint256) { return (_krillMintedTokens + KRILL_COST_ADD)**KRILL_COST_EXPONENT * KRILL_COST_SCALER; } function calculateKrillMintCost(uint256 _tokens) public view returns (uint256 cost) { cost = 0; for (uint256 i = 0; i < _tokens; i++) { cost += krillMintCost(krillMintedTokens() + i); } } function fishermenRewardsOf(address _owner) public view returns (uint256) { uint256 _pending = 0; uint256 _last = info.users[_owner].lastUpdated; if (_last < block.timestamp) { uint256 _diff = block.timestamp - _last; _pending += ownerKrillPerDay(_owner) * _diff * (100 - WHALES_CUT) / 8640000; } return info.users[_owner].rewards + _pending; } function whaleRewardsOf(address _owner) public view returns (uint256) { return uint256(int256(info.scaledRewardsPerWhale * whalesOf(_owner)) - info.users[_owner].scaledPayout) / FLOAT_SCALAR; } function balanceOf(address _owner) public view returns (uint256) { return info.users[_owner].balance; } function whalesOf(address _owner) public view returns (uint256) { return info.users[_owner].whales; } function fishermenOf(address _owner) public view returns (uint256) { return balanceOf(_owner) - whalesOf(_owner); } function ownerOf(uint256 _tokenId) public view returns (address) { require(_tokenId < totalSupply()); return info.list[_tokenId].owner; } function getApproved(uint256 _tokenId) public view returns (address) { require(_tokenId < totalSupply()); return info.list[_tokenId].approved; } function isApprovedForAll(address _owner, address _operator) public view returns (bool) { return info.users[_owner].approved[_operator]; } function getSeed(uint256 _tokenId) public view returns (bytes32) { require(_tokenId < totalSupply()); return info.list[_tokenId].seed; } function getIsWhale(uint256 _tokenId) public view returns (bool) { require(_tokenId < totalSupply()); return info.list[_tokenId].isWhale; } function tokenByIndex(uint256 _index) public view returns (uint256) { require(_index < totalSupply()); return _index; } function tokenOfOwnerByIndex(address _owner, uint256 _index) public view returns (uint256) { require(_index < balanceOf(_owner)); return info.users[_owner].list[_index]; } function ownerKrillPerDay(address _owner) public view returns (uint256 amount) { return info.users[_owner].krillPerDay; } function proofClaimed(uint256 _index) public view returns (bool) { uint256 _claimedWordIndex = _index / 256; uint256 _claimedBitIndex = _index % 256; uint256 _claimedWord = info.claimedBitMap[_claimedWordIndex]; uint256 _mask = (1 << _claimedBitIndex); return _claimedWord & _mask == _mask; } function getToken(uint256 _tokenId) public view returns (address tokenOwner, address approved, bytes32 seed, bool isWhale) { return (ownerOf(_tokenId), getApproved(_tokenId), getSeed(_tokenId), getIsWhale(_tokenId)); } function getTokens(uint256[] memory _tokenIds) public view returns (address[] memory owners, address[] memory approveds, bytes32[] memory seeds, bool[] memory isWhales) { uint256 _length = _tokenIds.length; owners = new address[](_length); approveds = new address[](_length); seeds = new bytes32[](_length); isWhales = new bool[](_length); for (uint256 i = 0; i < _length; i++) { (owners[i], approveds[i], seeds[i], isWhales[i]) = getToken(_tokenIds[i]); } } function getTokensTable(uint256 _limit, uint256 _page, bool _isAsc) external view returns (uint256[] memory tokenIds, address[] memory owners, address[] memory approveds, bytes32[] memory seeds, bool[] memory isWhales, uint256 totalTokens, uint256 totalPages) { require(_limit > 0); totalTokens = totalSupply(); if (totalTokens > 0) { totalPages = (totalTokens / _limit) + (totalTokens % _limit == 0 ? 0 : 1); require(_page < totalPages); uint256 _offset = _limit * _page; if (_page == totalPages - 1 && totalTokens % _limit != 0) { _limit = totalTokens % _limit; } tokenIds = new uint256[](_limit); for (uint256 i = 0; i < _limit; i++) { tokenIds[i] = tokenByIndex(_isAsc ? _offset + i : totalTokens - _offset - i - 1); } } else { totalPages = 0; tokenIds = new uint256[](0); } (owners, approveds, seeds, isWhales) = getTokens(tokenIds); } function getOwnerTokensTable(address _owner, uint256 _limit, uint256 _page, bool _isAsc) external view returns (uint256[] memory tokenIds, address[] memory approveds, bytes32[] memory seeds, bool[] memory isWhales, uint256 totalTokens, uint256 totalPages) { require(_limit > 0); totalTokens = balanceOf(_owner); if (totalTokens > 0) { totalPages = (totalTokens / _limit) + (totalTokens % _limit == 0 ? 0 : 1); require(_page < totalPages); uint256 _offset = _limit * _page; if (_page == totalPages - 1 && totalTokens % _limit != 0) { _limit = totalTokens % _limit; } tokenIds = new uint256[](_limit); for (uint256 i = 0; i < _limit; i++) { tokenIds[i] = tokenOfOwnerByIndex(_owner, _isAsc ? _offset + i : totalTokens - _offset - i - 1); } } else { totalPages = 0; tokenIds = new uint256[](0); } ( , approveds, seeds, isWhales) = getTokens(tokenIds); } function allMintingInfo() external view returns (uint256 ethMinted, uint256 whitelistMinted, uint256 krillMinted, uint256 currentKrillCost, uint256 whitelistExpiryTime, bool hasWhitelistExpired, uint256 openTime, bool open) { return (ethMintedTokens(), whitelistMintedTokens(), krillMintedTokens(), currentKrillMintCost(), whitelistExpiry(), whitelistExpired(), openingTime(), isOpen()); } function allInfoFor(address _owner) external view returns (uint256 supply, uint256 whales, uint256 ownerBalance, uint256 ownerWhales, uint256 ownerFishermenRewards, uint256 ownerWhaleRewards, uint256 ownerDailyKrill) { return (totalSupply(), totalWhales(), balanceOf(_owner), whalesOf(_owner), fishermenRewardsOf(_owner), whaleRewardsOf(_owner), ownerKrillPerDay(_owner)); } function _mint(address _receiver) internal { require(msg.sender == tx.origin); require(totalSupply() < MAX_SUPPLY); uint256 _tokenId = info.totalSupply++; Token storage _newToken = info.list[_tokenId]; _newToken.owner = _receiver; bytes32 _seed = keccak256(abi.encodePacked(_tokenId, _receiver, blockhash(block.number - 1), gasleft())); _newToken.seed = _seed; _newToken.isWhale = _tokenId < DEV_TOKENS || _tokenId % WHALE_MODULUS == 0; if (_newToken.isWhale) { info.totalWhales++; info.users[_receiver].whales++; info.users[_receiver].scaledPayout += int256(info.scaledRewardsPerWhale); } else { _update(_receiver); info.users[_receiver].krillPerDay += KRILL_PER_DAY_PER_FISHERMAN; } uint256 _index = info.users[_receiver].balance++; info.users[_receiver].indexOf[_tokenId] = _index + 1; info.users[_receiver].list[_index] = _tokenId; emit Transfer(address(0x0), _receiver, _tokenId); emit Mint(_receiver, _tokenId, _seed, _newToken.isWhale); } function _transfer(address _from, address _to, uint256 _tokenId) internal { address _owner = ownerOf(_tokenId); address _approved = getApproved(_tokenId); require(_from == _owner); require(msg.sender == _owner || msg.sender == _approved || isApprovedForAll(_owner, msg.sender)); info.list[_tokenId].owner = _to; if (_approved != address(0x0)) { info.list[_tokenId].approved = address(0x0); emit Approval(address(0x0), address(0x0), _tokenId); } if (getIsWhale(_tokenId)) { info.users[_from].whales--; info.users[_from].scaledPayout -= int256(info.scaledRewardsPerWhale); info.users[_to].whales++; info.users[_to].scaledPayout += int256(info.scaledRewardsPerWhale); } else { _update(_from); info.users[_from].krillPerDay -= KRILL_PER_DAY_PER_FISHERMAN; _update(_to); info.users[_to].krillPerDay += KRILL_PER_DAY_PER_FISHERMAN; } uint256 _index = info.users[_from].indexOf[_tokenId] - 1; uint256 _moved = info.users[_from].list[info.users[_from].balance - 1]; info.users[_from].list[_index] = _moved; info.users[_from].indexOf[_moved] = _index + 1; info.users[_from].balance--; delete info.users[_from].indexOf[_tokenId]; uint256 _newIndex = info.users[_to].balance++; info.users[_to].indexOf[_tokenId] = _newIndex + 1; info.users[_to].list[_newIndex] = _tokenId; emit Transfer(_from, _to, _tokenId); } function _update(address _owner) internal { uint256 _last = info.users[_owner].lastUpdated; if (_last < block.timestamp) { uint256 _diff = block.timestamp - _last; uint256 _rewards = ownerKrillPerDay(_owner) * _diff / 86400; uint256 _whalesCut = _rewards * WHALES_CUT / 100; info.scaledRewardsPerWhale += _whalesCut * FLOAT_SCALAR / totalWhales(); emit WhalesReward(_whalesCut); info.users[_owner].lastUpdated = block.timestamp; info.users[_owner].rewards += _rewards - _whalesCut; emit Reward(_owner, _rewards - _whalesCut); } } function _verify(bytes32[] memory _proof, bytes32 _leaf) internal view returns (bool) { require(_leaf != merkleRoot()); bytes32 _computedHash = _leaf; for (uint256 i = 0; i < _proof.length; i++) { bytes32 _proofElement = _proof[i]; if (_computedHash <= _proofElement) { _computedHash = keccak256(abi.encodePacked(_computedHash, _proofElement)); } else { _computedHash = keccak256(abi.encodePacked(_proofElement, _computedHash)); } } return _computedHash == merkleRoot(); } }