Transaction Hash:
Block:
12078072 at Mar-20-2021 09:14:33 PM +UTC
Transaction Fee:
0.00287121369 ETH
$8.00
Gas Used:
23,731 Gas / 120.99 Gwei
Account State Difference:
Address | Before | After | State Difference | ||
---|---|---|---|---|---|
0x2CedDb80...38850AC16 |
0.123156501 Eth
Nonce: 1
|
0.12028528731 Eth
Nonce: 2
| 0.00287121369 | ||
0x829BD824...93333A830
Miner
| (F2Pool Old) | 5,480.34332682743669238 Eth | 5,480.34619804112669238 Eth | 0.00287121369 |
Execution Trace
MoonCatRescue.rescueCat( seed=410E03BB5BD1827039D2F366177682C8C6E7B9AEF301203510CB8CEA6B4486A8 )
rescueCat[MoonCatRescue (ln:68)]
CatRescued[MoonCatRescue (ln:82)]
pragma solidity ^0.4.13; contract MoonCatRescue { enum Modes { Inactive, Disabled, Test, Live } Modes public mode = Modes.Inactive; address owner; bytes16 public imageGenerationCodeMD5 = 0xdbad5c08ec98bec48490e3c196eec683; // use this to verify mooncatparser.js the cat image data generation javascript file. string public name = "MoonCats"; string public symbol = "?"; // unicode cat symbol uint8 public decimals = 0; uint256 public totalSupply = 25600; uint16 public remainingCats = 25600 - 256; // there will only ever be 25,000 cats uint16 public remainingGenesisCats = 256; // there can only be a maximum of 256 genesis cats uint16 public rescueIndex = 0; bytes5[25600] public rescueOrder; bytes32 public searchSeed = 0x0; // gets set with the immediately preceding blockhash when the contract is activated to prevent "premining" struct AdoptionOffer { bool exists; bytes5 catId; address seller; uint price; address onlyOfferTo; } struct AdoptionRequest{ bool exists; bytes5 catId; address requester; uint price; } mapping (bytes5 => AdoptionOffer) public adoptionOffers; mapping (bytes5 => AdoptionRequest) public adoptionRequests; mapping (bytes5 => bytes32) public catNames; mapping (bytes5 => address) public catOwners; mapping (address => uint256) public balanceOf; //number of cats owned by a given address mapping (address => uint) public pendingWithdrawals; /* events */ event CatRescued(address indexed to, bytes5 indexed catId); event CatNamed(bytes5 indexed catId, bytes32 catName); event Transfer(address indexed from, address indexed to, uint256 value); event CatAdopted(bytes5 indexed catId, uint price, address indexed from, address indexed to); event AdoptionOffered(bytes5 indexed catId, uint price, address indexed toAddress); event AdoptionOfferCancelled(bytes5 indexed catId); event AdoptionRequested(bytes5 indexed catId, uint price, address indexed from); event AdoptionRequestCancelled(bytes5 indexed catId); event GenesisCatsAdded(bytes5[16] catIds); function MoonCatRescue() payable { owner = msg.sender; assert((remainingCats + remainingGenesisCats) == totalSupply); assert(rescueOrder.length == totalSupply); assert(rescueIndex == 0); } /* registers and validates cats that are found */ function rescueCat(bytes32 seed) activeMode returns (bytes5) { require(remainingCats > 0); // cannot register any cats once supply limit is reached bytes32 catIdHash = keccak256(seed, searchSeed); // generate the prospective catIdHash require(catIdHash[0] | catIdHash[1] | catIdHash[2] == 0x0); // ensures the validity of the catIdHash bytes5 catId = bytes5((catIdHash & 0xffffffff) << 216); // one byte to indicate genesis, and the last 4 bytes of the catIdHash require(catOwners[catId] == 0x0); // if the cat is already registered, throw an error. All cats are unique. rescueOrder[rescueIndex] = catId; rescueIndex++; catOwners[catId] = msg.sender; balanceOf[msg.sender]++; remainingCats--; CatRescued(msg.sender, catId); return catId; } /* assigns a name to a cat, once a name is assigned it cannot be changed */ function nameCat(bytes5 catId, bytes32 catName) onlyCatOwner(catId) { require(catNames[catId] == 0x0); // ensure the current name is empty; cats can only be named once require(!adoptionOffers[catId].exists); // cats cannot be named while they are up for adoption catNames[catId] = catName; CatNamed(catId, catName); } /* puts a cat up for anyone to adopt */ function makeAdoptionOffer(bytes5 catId, uint price) onlyCatOwner(catId) { require(price > 0); adoptionOffers[catId] = AdoptionOffer(true, catId, msg.sender, price, 0x0); AdoptionOffered(catId, price, 0x0); } /* puts a cat up for a specific address to adopt */ function makeAdoptionOfferToAddress(bytes5 catId, uint price, address to) onlyCatOwner(catId) isNotSender(to){ adoptionOffers[catId] = AdoptionOffer(true, catId, msg.sender, price, to); AdoptionOffered(catId, price, to); } /* cancel an adoption offer */ function cancelAdoptionOffer(bytes5 catId) onlyCatOwner(catId) { adoptionOffers[catId] = AdoptionOffer(false, catId, 0x0, 0, 0x0); AdoptionOfferCancelled(catId); } /* accepts an adoption offer */ function acceptAdoptionOffer(bytes5 catId) payable { AdoptionOffer storage offer = adoptionOffers[catId]; require(offer.exists); require(offer.onlyOfferTo == 0x0 || offer.onlyOfferTo == msg.sender); require(msg.value >= offer.price); if(msg.value > offer.price) { pendingWithdrawals[msg.sender] += (msg.value - offer.price); // if the submitted amount exceeds the price allow the buyer to withdraw the difference } transferCat(catId, catOwners[catId], msg.sender, offer.price); } /* transfer a cat directly without payment */ function giveCat(bytes5 catId, address to) onlyCatOwner(catId) { transferCat(catId, msg.sender, to, 0); } /* requests adoption of a cat with an ETH offer */ function makeAdoptionRequest(bytes5 catId) payable isNotSender(catOwners[catId]) { require(catOwners[catId] != 0x0); // the cat must be owned AdoptionRequest storage existingRequest = adoptionRequests[catId]; require(msg.value > 0); require(msg.value > existingRequest.price); if(existingRequest.price > 0) { pendingWithdrawals[existingRequest.requester] += existingRequest.price; } adoptionRequests[catId] = AdoptionRequest(true, catId, msg.sender, msg.value); AdoptionRequested(catId, msg.value, msg.sender); } /* allows the owner of the cat to accept an adoption request */ function acceptAdoptionRequest(bytes5 catId) onlyCatOwner(catId) { AdoptionRequest storage existingRequest = adoptionRequests[catId]; require(existingRequest.exists); address existingRequester = existingRequest.requester; uint existingPrice = existingRequest.price; adoptionRequests[catId] = AdoptionRequest(false, catId, 0x0, 0); // the adoption request must be cancelled before calling transferCat to prevent refunding the requester. transferCat(catId, msg.sender, existingRequester, existingPrice); } /* allows the requester to cancel their adoption request */ function cancelAdoptionRequest(bytes5 catId) { AdoptionRequest storage existingRequest = adoptionRequests[catId]; require(existingRequest.exists); require(existingRequest.requester == msg.sender); uint price = existingRequest.price; adoptionRequests[catId] = AdoptionRequest(false, catId, 0x0, 0); msg.sender.transfer(price); AdoptionRequestCancelled(catId); } function withdraw() { uint amount = pendingWithdrawals[msg.sender]; pendingWithdrawals[msg.sender] = 0; msg.sender.transfer(amount); } /* owner only functions */ /* disable contract before activation. A safeguard if a bug is found before the contract is activated */ function disableBeforeActivation() onlyOwner inactiveMode { mode = Modes.Disabled; // once the contract is disabled it's mode cannot be changed } /* activates the contract in *Live* mode which sets the searchSeed and enables rescuing */ function activate() onlyOwner inactiveMode { searchSeed = block.blockhash(block.number - 1); // once the searchSeed is set it cannot be changed; mode = Modes.Live; // once the contract is activated it's mode cannot be changed } /* activates the contract in *Test* mode which sets the searchSeed and enables rescuing */ function activateInTestMode() onlyOwner inactiveMode { // searchSeed = 0x5713bdf5d1c3398a8f12f881f0f03b5025b6f9c17a97441a694d5752beb92a3d; // once the searchSeed is set it cannot be changed; mode = Modes.Test; // once the contract is activated it's mode cannot be changed } /* add genesis cats in groups of 16 */ function addGenesisCatGroup() onlyOwner activeMode { require(remainingGenesisCats > 0); bytes5[16] memory newCatIds; uint256 price = (17 - (remainingGenesisCats / 16)) * 300000000000000000; for(uint8 i = 0; i < 16; i++) { uint16 genesisCatIndex = 256 - remainingGenesisCats; bytes5 genesisCatId = (bytes5(genesisCatIndex) << 24) | 0xff00000ca7; newCatIds[i] = genesisCatId; rescueOrder[rescueIndex] = genesisCatId; rescueIndex++; balanceOf[0x0]++; remainingGenesisCats--; adoptionOffers[genesisCatId] = AdoptionOffer(true, genesisCatId, owner, price, 0x0); } GenesisCatsAdded(newCatIds); } /* aggregate getters */ function getCatIds() constant returns (bytes5[]) { bytes5[] memory catIds = new bytes5[](rescueIndex); for (uint i = 0; i < rescueIndex; i++) { catIds[i] = rescueOrder[i]; } return catIds; } function getCatNames() constant returns (bytes32[]) { bytes32[] memory names = new bytes32[](rescueIndex); for (uint i = 0; i < rescueIndex; i++) { names[i] = catNames[rescueOrder[i]]; } return names; } function getCatOwners() constant returns (address[]) { address[] memory owners = new address[](rescueIndex); for (uint i = 0; i < rescueIndex; i++) { owners[i] = catOwners[rescueOrder[i]]; } return owners; } function getCatOfferPrices() constant returns (uint[]) { uint[] memory catOffers = new uint[](rescueIndex); for (uint i = 0; i < rescueIndex; i++) { bytes5 catId = rescueOrder[i]; if(adoptionOffers[catId].exists && adoptionOffers[catId].onlyOfferTo == 0x0) { catOffers[i] = adoptionOffers[catId].price; } } return catOffers; } function getCatRequestPrices() constant returns (uint[]) { uint[] memory catRequests = new uint[](rescueIndex); for (uint i = 0; i < rescueIndex; i++) { bytes5 catId = rescueOrder[i]; catRequests[i] = adoptionRequests[catId].price; } return catRequests; } function getCatDetails(bytes5 catId) constant returns (bytes5 id, address owner, bytes32 name, address onlyOfferTo, uint offerPrice, address requester, uint requestPrice) { return (catId, catOwners[catId], catNames[catId], adoptionOffers[catId].onlyOfferTo, adoptionOffers[catId].price, adoptionRequests[catId].requester, adoptionRequests[catId].price); } /* modifiers */ modifier onlyOwner() { require(msg.sender == owner); _; } modifier inactiveMode() { require(mode == Modes.Inactive); _; } modifier activeMode() { require(mode == Modes.Live || mode == Modes.Test); _; } modifier onlyCatOwner(bytes5 catId) { require(catOwners[catId] == msg.sender); _; } modifier isNotSender(address a) { require(msg.sender != a); _; } /* transfer helper */ function transferCat(bytes5 catId, address from, address to, uint price) private { catOwners[catId] = to; balanceOf[from]--; balanceOf[to]++; adoptionOffers[catId] = AdoptionOffer(false, catId, 0x0, 0, 0x0); // cancel any existing adoption offer when cat is transferred AdoptionRequest storage request = adoptionRequests[catId]; //if the recipient has a pending adoption request, cancel it if(request.requester == to) { pendingWithdrawals[to] += request.price; adoptionRequests[catId] = AdoptionRequest(false, catId, 0x0, 0); } pendingWithdrawals[from] += price; Transfer(from, to, 1); CatAdopted(catId, price, from, to); } }