Diff
checker
文本
文本
图像
文档
Excel
文件夹
Legal
Enterprise
桌面版
定价
登录
下载 Diffchecker 桌面版
比较文本
查找两个文本文件之间的差异
工具
历史
实时编辑器
折叠未更改行
关闭换行
视图
拆分
统一
比对精度
智能
单词
字符
语法高亮
选择语法
忽略
文本转换
转到第一个差异
编辑输入
Diffchecker Desktop
运行Diffchecker最安全的方式。获取Diffchecker桌面应用:您的差异永远不会离开您的电脑!
获取桌面版
CryptoPunks v1 vs CryptoPhunks
创建于
4年前
差异永不过期
清除
导出
分享
解释
124 删除
行
总计
删除
字符
总计
删除
要继续使用此功能,请升级到
Diff
checker
Pro
查看价格
140 行
全部复制
298 添加
行
总计
添加
字符
总计
添加
要继续使用此功能,请升级到
Diff
checker
Pro
查看价格
314 行
全部复制
复制
已复制
复制
已复制
/**
// SPDX-License-Identifier: UNLICENSE
*Submitted for verification at Etherscan.io on 2017-06-17
pragma solidity ^0.8.0;
*/
复制
已复制
复制
已复制
pragma solidity ^0.4.8;
import "@openzeppelin/contracts/access/Ownable.sol";
contract CryptoPunks {
import "@openzeppelin/contracts/security/ReentrancyGuard.sol";
import "@openzeppelin/contracts/token/ERC721/ERC721.sol";
import "@openzeppelin/contracts/token/ERC721/extensions/ERC721Enumerable.sol";
import "@openzeppelin/contracts/utils/Counters.sol";
import "@openzeppelin/contracts/utils/Strings.sol";
复制
已复制
复制
已复制
// You can use this hash to verify the image file containing all the punks
contract CryptoPhunksV2 is Ownable, ERC721Enumerable, ReentrancyGuard {
string public imageHash = "ac39af4793119ee46bbff351d8cb6b5f23da60222126add4268e261199a2921b";
using Counters for Counters.Counter;
using Strings for uint256;
复制
已复制
复制
已复制
address owner;
// You can use this hash to verify the image file containing all the phunks
string public constant imageHash =
"122dab9670c21ad538dafdbb87191c4d7114c389af616c42c54556aa2211b899";
复制
已复制
复制
已复制
string public standard = 'CryptoPunks';
constructor() ERC721("CryptoPhunksV2", "PHUNK") {}
string public name;
string public symbol;
uint8 public decimals;
uint256 public totalSupply;
复制
已复制
复制
已复制
uint
public
nextPunkIndexToAssign
=
0
;
bool
public
isSaleOn
=
false
;
复制
已复制
复制
已复制
//
bool public
allPunksAssigned
= false;
bool public
saleHasBeenStarted
= false;
uint public punksRemainingToAssign = 0;
uint public numberOfPunksToReserve;
uint public numberOfPunksReserved = 0;
复制
已复制
复制
已复制
//mapping (address =>
uint
)
public
addressToPunkIndex;
uint
256
public
constant MAX_MINTABLE_AT_ONCE = 50;
mapping (uint => address) public punkIndexToAddress;
复制
已复制
复制
已复制
/* This creates an array with all balances */
uint256[10000] private _availableTokens;
mapping (address =>
uint256
) public balanceOf
;
uint256 private _numAvailableTokens = 10000;
uint256
private _numFreeRollsGiven = 0
;
复制
已复制
复制
已复制
struct Offer {
mapping(
address
=>
uint
256) public freeRollPhunks;
bool isForSale;
uint punkIndex;
address
seller;
uint
minValue; // in ether
address onlySellTo; // specify to sell only to a specific person
}
复制
已复制
复制
已复制
// A record of punks that are offered for sale at a specific minimum value, and perhaps to a specific person
uint256 private _lastTokenIdMintedInInitialSet = 10000;
mapping (uint => Offer) public punksOfferedForSale;
复制
已复制
复制
已复制
mapping (address => uint
) public
pendingWithdrawals;
function numTotalPhunks(
) public
view virtual returns (uint256) {
return 10000;
}
复制
已复制
复制
已复制
event Assign(address indexed to, uint256 punkIndex);
function freeRollMint() public nonReentrant() {
event Transfer(address indexed from, address indexed to, uint256 value);
uint256 toMint = freeRollPhunks[msg.sender];
event PunkTransfer(address indexed from, address indexed to, uint256 punkIndex);
freeRollPhunks[msg.sender] = 0;
event PunkOffered(uint indexed punkIndex, uint minValue, address indexed toAddress);
uint256 remaining = numTotalPhunks() - totalSupply();
event PunkBought(uint indexed punkIndex, uint value, address indexed fromAddress, address indexed toAddress);
if (toMint > remaining) {
event PunkNoLongerForSale(u
int
indexed punkIndex);
toMint = remaining;
}
_m
int
(toMint);
}
复制
已复制
复制
已复制
/* Initializes contract with initial supply tokens to the creator of the contract */
function getNumFreeRollPhunks(address owner) public view returns (uint256) {
function CryptoPunks() payable {
return freeRollPhunks[owner];
// balanceOf[msg.sender] = initialSupply; // Give the creator all initial tokens
}
owner = msg.sender;
totalSupply = 10000; // Update total supply
function mint(uint256 _numToMint) public payable nonReentrant() {
punksRemainingToAssign = totalSupply;
require(isSaleOn, "Sale hasn't started.");
numberOfPunksToReserve = 1000;
uint256 totalSupply = totalSupply();
name = "CRYPTOPUNKS"; // Set the name for display purposes
require(
symbol
=
"Ͼ";
// Set the symbol for display purposes
totalSupply + _numToMint <= numTotalPhunks(),
decimals = 0;
// Amount of decimals for display purposes
"There aren't this many phunks left."
);
uint256 costForMintingPhunks
=
getCostForMintingPhunks(_numToMint);
require(
msg.value >= costForMintingPhunks,
"Too little sent, please send more eth."
);
if (msg.value > costForMintingPhunks) {
payable(msg.sender).transfer(msg.value - costForMintingPhunks);
}
}
复制
已复制
复制
已复制
function reservePunksForOwner(uint maxForThisRun) {
_mint(_numToMint);
if (msg.sender != owner) throw;
}
if (numberOfPunksReserved >= numberOfPunksToReserve) throw;
uint numberPunksReservedThisRun = 0;
// internal minting function
while (numberOfPunksReserved < numberOfPunksToReserve && numberPunksReservedThisRun < maxForThisRun) {
function _mint(uint256 _numToMint) internal {
punkIndexToAddress[nextPunkIndexToAssign]
=
msg.sender
;
require(_numToMint <= MAX_MINTABLE_AT_ONCE, "Minting too many at once.");
Assign
(msg.sender,
nextPunkIndexToAssign
);
numberPunksReservedThisRun++;
uint256 updatedNumAvailableTokens = _numAvailableTokens;
nextPunkIndexToAssign++;
for (uint256 i = 0; i < _numToMint; i++) {
}
uint256 newTokenId
=
useRandomAvailableToken(_numToMint, i)
;
punksRemainingToAssign -= numberPunksReservedThisRun;
_safeMint
(msg.sender,
newTokenId
);
numberOfPunksReserved += numberPunksReservedThisRun;
updatedNumAvailableTokens--;
balanceOf[msg.sender] += numberPunksReservedThisRun;
}
}
复制
已复制
复制
已复制
_numAvailableTokens = updatedNumAvailableTokens;
}
复制
已复制
复制
已复制
function getPunk(uint punkIndex) {
function useRandomAvailableToken(uint256 _numToFetch, uint256 _i)
if (punksRemainingToAssign == 0) throw;
internal
if (punkIndexToAddress[punkIndex] != 0x0) throw;
returns (uint256)
punkIndexToAddress[punkIndex] = msg.sender;
{
balanceOf[msg.sender]++;
uint256 randomNum =
punksRemainingToAssign--;
uint256(
Assign(msg.sender, punkIndex);
keccak256(
abi.encode(
msg.sender,
tx.gasprice,
block.number,
block.timestamp,
blockhash(block.number - 1),
_numToFetch,
_i
)
)
);
uint256 randomIndex = randomNum % _numAvailableTokens;
return useAvailableTokenAtIndex(randomIndex);
}
function useAvailableTokenAtIndex(uint256 indexToUse)
internal
returns (uint256)
{
uint256 valAtIndex = _availableTokens[indexToUse];
uint256 result;
if (valAtIndex == 0) {
// This means the index itself is still an available token
result = indexToUse;
} else {
// This means the index itself is not an available token, but the val at that index is.
result = valAtIndex;
}
}
复制
已复制
复制
已复制
// Transfer ownership of a punk to another user without requiring payment
uint256 lastIndex = _numAvailableTokens - 1;
function transferPunk(address to, uint punkIndex
) {
if (indexToUse != lastIndex
) {
if (punkIndexToAddress[punkIndex] != msg.sender) throw;
// Replace the value at indexToUse, now that it's been used.
punkIndexToAddress[punkIndex] = to;
// Replace it with the data from the last index in the array, since we are going to decrease the array size afterwards.
balanceOf[msg.sender]--;
uint256 lastValInArray = _availableTokens[lastIndex];
balanceOf[to]++;
if (lastValInArray == 0) {
Transfer(msg.sender, to, 1);
// This means the index itself is still an available token
PunkTransfer(msg.sender, to, punkIndex);
_availableTokens[indexToUse] = lastIndex;
} else {
// This means the index itself is not an available token, but the val at that index is.
_availableTokens[indexToUse] = lastValInArray;
}
}
}
复制
已复制
复制
已复制
function punkNoLongerForSale(uint punkIndex) {
_numAvailableTokens--;
if (punkIndexToAddress[punkIndex] != msg.sender) throw;
return result;
punksOfferedForSale[punkIndex] = Offer(false, punkIndex, msg.sender, 0, 0x0);
}
PunkNoLongerForSale(punkIndex);
function getCostForMintingPhunks(uint256 _numToMint)
public
view
returns (uint256)
{
require(
totalSupply() + _numToMint <= numTotalPhunks(),
"There aren't this many phunks left."
);
if (_numToMint == 1) {
return 0.02 ether;
} else if (_numToMint == 3) {
return 0.05 ether;
} else if (_numToMint == 5) {
return 0.07 ether;
} else if (_numToMint == 10) {
return 0.10 ether;
} else {
revert("Unsupported mint amount");
}
}
复制
已复制
复制
已复制
}
复制
已复制
复制
已复制
function offerPunkForSale(uint punkIndex, uint minSalePriceInWei) {
function getPhunksBelongingToOwner(address _owner)
if (punkIndexToAddress[punkIndex] != msg.sender) throw;
external
punksOfferedForSale[punkIndex] = Offer(true, punkIndex, msg.sender, minSalePriceInWei, 0x0);
view
PunkOffered(punkIndex, minSalePriceInWei, 0x0)
;
returns (uint256[] memory)
{
uint256 numPhunks = balanceOf(_owner);
if (numPhunks == 0) {
return new uint256[](0);
} else {
uint256[] memory result = new uint256[](numPhunks);
for (uint256 i = 0; i < numPhunks; i++) {
result[i] = tokenOfOwnerByIndex(_owner, i);
}
return result
;
}
}
复制
已复制
复制
已复制
}
复制
已复制
复制
已复制
function offerPunkForSaleToAddress(uint punkIndex, uint minSalePriceInWei, address toAddress) {
/*
if (punkIndexToAddress[punkIndex] != msg.sender) throw;
* Dev stuff.
punksOfferedForSale[punkIndex] = Offer(true, punkIndex, msg.sender, minSalePriceInWei, toAddress);
*/
PunkOffered(punkIndex, minSalePriceInWei, toAddress);
// metadata URI
string private _baseTokenURI;
function _baseURI() internal view virtual override returns (string memory) {
return _baseTokenURI;
}
function tokenURI(uint256 _tokenId)
public
view
override
returns (string memory)
{
string memory base = _baseURI();
string memory _tokenURI = Strings.toString(_tokenId);
// If there is no base URI, return the token URI.
if (bytes(base).length == 0) {
return _tokenURI;
}
}
复制
已复制
复制
已复制
function buyPunk(uint punkIndex) payable {
return string(abi.encodePacked(base, _tokenURI));
Offer offer = punksOfferedForSale[punkIndex];
}
if (!offer.isForSale) throw; // punk not actually for sale
if (offer.onlySellTo != 0x0 && offer.onlySellTo != msg.sender) throw; // punk not supposed to be sold to this user
if (msg.value < offer.minValue) throw; // Didn't send enough ETH
if (offer.seller != punkIndexToAddress[punkIndex]) throw; // Seller no longer owner of punk
复制
已复制
复制
已复制
punkIndexToAddress[punkIndex] = msg.sender;
// contract metadata URI for opensea
balanceOf[offer.seller]--;
string public contractURI;
balanceOf[msg.sender]++;
Transfer(offer.seller, msg.sender, 1);
复制
已复制
复制
已复制
punkNoLongerForSale(punkIndex);
/*
pendingWithdrawals[offer.seller] += msg.value;
* Owner stuff
PunkBought(punkIndex, msg.value, offer.seller, msg.sender);
*/
function startSale() public onlyOwner {
isSaleOn = true;
saleHasBeenStarted = true;
}
function endSale() public onlyOwner {
isSaleOn = false;
}
function giveFreeRoll(address receiver) public onlyOwner {
// max number of free mints we can give to the community for promotions/marketing
require(_numFreeRollsGiven < 200, "already given max number of free rolls");
uint256 freeRolls = freeRollPhunks[receiver];
freeRollPhunks[receiver] = freeRolls + 1;
_numFreeRollsGiven = _numFreeRollsGiven + 1;
}
// for handing out free rolls to v1 phunk owners
// details on seeding info here: https://gist.github.com/cryptophunks/7f542feaee510e12464da3bb2a922713
function seedFreeRolls(
address[] memory tokenOwners,
uint256[] memory numOfFreeRolls
) public onlyOwner {
require(
!saleHasBeenStarted,
"cannot seed free rolls after sale has started"
);
require(
tokenOwners.length == numOfFreeRolls.length,
"tokenOwners does not match numOfFreeRolls length"
);
// light check to make sure the proper values are being passed
require(numOfFreeRolls[0] <= 3, "cannot give more than 3 free rolls");
for (uint256 i = 0; i < tokenOwners.length; i++) {
freeRollPhunks[tokenOwners[i]] = numOfFreeRolls[i];
}
}
复制
已复制
复制
已复制
}
复制
已复制
复制
已复制
function withdraw() {
// for seeding the v2 contract with v1 state
uint amount = pendingWithdrawals[msg.sender];
// details on seeding info here: https://gist.github.com/cryptophunks/7f542feaee510e12464da3bb2a922713
// Remember to zero the pending refund before
function seedInitialContractState(
// sending to prevent re-entrancy attacks
address[] memory tokenOwners,
pendingWithdrawals[msg.sender] = 0;
uint256[] memory tokens
msg.sender.transfer(amount);
) public onlyOwner {
require(
!saleHasBeenStarted,
"cannot initial phunk mint if sale has started"
);
require(
tokenOwners.length == tokens.length,
"tokenOwners does not match tokens length"
);
uint256 lastTokenIdMintedInInitialSetCopy = _lastTokenIdMintedInInitialSet;
for (uint256 i = 0; i < tokenOwners.length; i++) {
uint256 token = tokens[i];
require(
lastTokenIdMintedInInitialSetCopy > token,
"initial phunk mints must be in decreasing order for our availableToken index to work"
);
lastTokenIdMintedInInitialSetCopy = token;
useAvailableTokenAtIndex(token);
_safeMint(tokenOwners[i], token);
}
}
复制
已复制
复制
已复制
_lastTokenIdMintedInInitialSet = lastTokenIdMintedInInitialSetCopy;
}
// URIs
function setBaseURI(string memory baseURI) external onlyOwner {
_baseTokenURI = baseURI;
}
function setContractURI(string memory _contractURI) external onlyOwner {
contractURI = _contractURI;
}
function withdrawMoney() public payable onlyOwner {
(bool success, ) = msg.sender.call{value: address(this).balance}("");
require(success, "Transfer failed.");
}
function _beforeTokenTransfer(
address from,
address to,
uint256 tokenId
) internal virtual override(ERC721Enumerable) {
super._beforeTokenTransfer(from, to, tokenId);
}
function supportsInterface(bytes4 interfaceId)
public
view
virtual
override(ERC721Enumerable)
returns (bool)
{
return super.supportsInterface(interfaceId);
}
}
}
已保存差异
原始文本
打开文件
/** *Submitted for verification at Etherscan.io on 2017-06-17 */ pragma solidity ^0.4.8; contract CryptoPunks { // You can use this hash to verify the image file containing all the punks string public imageHash = "ac39af4793119ee46bbff351d8cb6b5f23da60222126add4268e261199a2921b"; address owner; string public standard = 'CryptoPunks'; string public name; string public symbol; uint8 public decimals; uint256 public totalSupply; uint public nextPunkIndexToAssign = 0; //bool public allPunksAssigned = false; uint public punksRemainingToAssign = 0; uint public numberOfPunksToReserve; uint public numberOfPunksReserved = 0; //mapping (address => uint) public addressToPunkIndex; mapping (uint => address) public punkIndexToAddress; /* This creates an array with all balances */ mapping (address => uint256) public balanceOf; struct Offer { bool isForSale; uint punkIndex; address seller; uint minValue; // in ether address onlySellTo; // specify to sell only to a specific person } // A record of punks that are offered for sale at a specific minimum value, and perhaps to a specific person mapping (uint => Offer) public punksOfferedForSale; mapping (address => uint) public pendingWithdrawals; event Assign(address indexed to, uint256 punkIndex); event Transfer(address indexed from, address indexed to, uint256 value); event PunkTransfer(address indexed from, address indexed to, uint256 punkIndex); event PunkOffered(uint indexed punkIndex, uint minValue, address indexed toAddress); event PunkBought(uint indexed punkIndex, uint value, address indexed fromAddress, address indexed toAddress); event PunkNoLongerForSale(uint indexed punkIndex); /* Initializes contract with initial supply tokens to the creator of the contract */ function CryptoPunks() payable { // balanceOf[msg.sender] = initialSupply; // Give the creator all initial tokens owner = msg.sender; totalSupply = 10000; // Update total supply punksRemainingToAssign = totalSupply; numberOfPunksToReserve = 1000; name = "CRYPTOPUNKS"; // Set the name for display purposes symbol = "Ͼ"; // Set the symbol for display purposes decimals = 0; // Amount of decimals for display purposes } function reservePunksForOwner(uint maxForThisRun) { if (msg.sender != owner) throw; if (numberOfPunksReserved >= numberOfPunksToReserve) throw; uint numberPunksReservedThisRun = 0; while (numberOfPunksReserved < numberOfPunksToReserve && numberPunksReservedThisRun < maxForThisRun) { punkIndexToAddress[nextPunkIndexToAssign] = msg.sender; Assign(msg.sender, nextPunkIndexToAssign); numberPunksReservedThisRun++; nextPunkIndexToAssign++; } punksRemainingToAssign -= numberPunksReservedThisRun; numberOfPunksReserved += numberPunksReservedThisRun; balanceOf[msg.sender] += numberPunksReservedThisRun; } function getPunk(uint punkIndex) { if (punksRemainingToAssign == 0) throw; if (punkIndexToAddress[punkIndex] != 0x0) throw; punkIndexToAddress[punkIndex] = msg.sender; balanceOf[msg.sender]++; punksRemainingToAssign--; Assign(msg.sender, punkIndex); } // Transfer ownership of a punk to another user without requiring payment function transferPunk(address to, uint punkIndex) { if (punkIndexToAddress[punkIndex] != msg.sender) throw; punkIndexToAddress[punkIndex] = to; balanceOf[msg.sender]--; balanceOf[to]++; Transfer(msg.sender, to, 1); PunkTransfer(msg.sender, to, punkIndex); } function punkNoLongerForSale(uint punkIndex) { if (punkIndexToAddress[punkIndex] != msg.sender) throw; punksOfferedForSale[punkIndex] = Offer(false, punkIndex, msg.sender, 0, 0x0); PunkNoLongerForSale(punkIndex); } function offerPunkForSale(uint punkIndex, uint minSalePriceInWei) { if (punkIndexToAddress[punkIndex] != msg.sender) throw; punksOfferedForSale[punkIndex] = Offer(true, punkIndex, msg.sender, minSalePriceInWei, 0x0); PunkOffered(punkIndex, minSalePriceInWei, 0x0); } function offerPunkForSaleToAddress(uint punkIndex, uint minSalePriceInWei, address toAddress) { if (punkIndexToAddress[punkIndex] != msg.sender) throw; punksOfferedForSale[punkIndex] = Offer(true, punkIndex, msg.sender, minSalePriceInWei, toAddress); PunkOffered(punkIndex, minSalePriceInWei, toAddress); } function buyPunk(uint punkIndex) payable { Offer offer = punksOfferedForSale[punkIndex]; if (!offer.isForSale) throw; // punk not actually for sale if (offer.onlySellTo != 0x0 && offer.onlySellTo != msg.sender) throw; // punk not supposed to be sold to this user if (msg.value < offer.minValue) throw; // Didn't send enough ETH if (offer.seller != punkIndexToAddress[punkIndex]) throw; // Seller no longer owner of punk punkIndexToAddress[punkIndex] = msg.sender; balanceOf[offer.seller]--; balanceOf[msg.sender]++; Transfer(offer.seller, msg.sender, 1); punkNoLongerForSale(punkIndex); pendingWithdrawals[offer.seller] += msg.value; PunkBought(punkIndex, msg.value, offer.seller, msg.sender); } function withdraw() { uint amount = pendingWithdrawals[msg.sender]; // Remember to zero the pending refund before // sending to prevent re-entrancy attacks pendingWithdrawals[msg.sender] = 0; msg.sender.transfer(amount); } }
更改后文本
打开文件
// SPDX-License-Identifier: UNLICENSE pragma solidity ^0.8.0; import "@openzeppelin/contracts/access/Ownable.sol"; import "@openzeppelin/contracts/security/ReentrancyGuard.sol"; import "@openzeppelin/contracts/token/ERC721/ERC721.sol"; import "@openzeppelin/contracts/token/ERC721/extensions/ERC721Enumerable.sol"; import "@openzeppelin/contracts/utils/Counters.sol"; import "@openzeppelin/contracts/utils/Strings.sol"; contract CryptoPhunksV2 is Ownable, ERC721Enumerable, ReentrancyGuard { using Counters for Counters.Counter; using Strings for uint256; // You can use this hash to verify the image file containing all the phunks string public constant imageHash = "122dab9670c21ad538dafdbb87191c4d7114c389af616c42c54556aa2211b899"; constructor() ERC721("CryptoPhunksV2", "PHUNK") {} bool public isSaleOn = false; bool public saleHasBeenStarted = false; uint256 public constant MAX_MINTABLE_AT_ONCE = 50; uint256[10000] private _availableTokens; uint256 private _numAvailableTokens = 10000; uint256 private _numFreeRollsGiven = 0; mapping(address => uint256) public freeRollPhunks; uint256 private _lastTokenIdMintedInInitialSet = 10000; function numTotalPhunks() public view virtual returns (uint256) { return 10000; } function freeRollMint() public nonReentrant() { uint256 toMint = freeRollPhunks[msg.sender]; freeRollPhunks[msg.sender] = 0; uint256 remaining = numTotalPhunks() - totalSupply(); if (toMint > remaining) { toMint = remaining; } _mint(toMint); } function getNumFreeRollPhunks(address owner) public view returns (uint256) { return freeRollPhunks[owner]; } function mint(uint256 _numToMint) public payable nonReentrant() { require(isSaleOn, "Sale hasn't started."); uint256 totalSupply = totalSupply(); require( totalSupply + _numToMint <= numTotalPhunks(), "There aren't this many phunks left." ); uint256 costForMintingPhunks = getCostForMintingPhunks(_numToMint); require( msg.value >= costForMintingPhunks, "Too little sent, please send more eth." ); if (msg.value > costForMintingPhunks) { payable(msg.sender).transfer(msg.value - costForMintingPhunks); } _mint(_numToMint); } // internal minting function function _mint(uint256 _numToMint) internal { require(_numToMint <= MAX_MINTABLE_AT_ONCE, "Minting too many at once."); uint256 updatedNumAvailableTokens = _numAvailableTokens; for (uint256 i = 0; i < _numToMint; i++) { uint256 newTokenId = useRandomAvailableToken(_numToMint, i); _safeMint(msg.sender, newTokenId); updatedNumAvailableTokens--; } _numAvailableTokens = updatedNumAvailableTokens; } function useRandomAvailableToken(uint256 _numToFetch, uint256 _i) internal returns (uint256) { uint256 randomNum = uint256( keccak256( abi.encode( msg.sender, tx.gasprice, block.number, block.timestamp, blockhash(block.number - 1), _numToFetch, _i ) ) ); uint256 randomIndex = randomNum % _numAvailableTokens; return useAvailableTokenAtIndex(randomIndex); } function useAvailableTokenAtIndex(uint256 indexToUse) internal returns (uint256) { uint256 valAtIndex = _availableTokens[indexToUse]; uint256 result; if (valAtIndex == 0) { // This means the index itself is still an available token result = indexToUse; } else { // This means the index itself is not an available token, but the val at that index is. result = valAtIndex; } uint256 lastIndex = _numAvailableTokens - 1; if (indexToUse != lastIndex) { // Replace the value at indexToUse, now that it's been used. // Replace it with the data from the last index in the array, since we are going to decrease the array size afterwards. uint256 lastValInArray = _availableTokens[lastIndex]; if (lastValInArray == 0) { // This means the index itself is still an available token _availableTokens[indexToUse] = lastIndex; } else { // This means the index itself is not an available token, but the val at that index is. _availableTokens[indexToUse] = lastValInArray; } } _numAvailableTokens--; return result; } function getCostForMintingPhunks(uint256 _numToMint) public view returns (uint256) { require( totalSupply() + _numToMint <= numTotalPhunks(), "There aren't this many phunks left." ); if (_numToMint == 1) { return 0.02 ether; } else if (_numToMint == 3) { return 0.05 ether; } else if (_numToMint == 5) { return 0.07 ether; } else if (_numToMint == 10) { return 0.10 ether; } else { revert("Unsupported mint amount"); } } function getPhunksBelongingToOwner(address _owner) external view returns (uint256[] memory) { uint256 numPhunks = balanceOf(_owner); if (numPhunks == 0) { return new uint256[](0); } else { uint256[] memory result = new uint256[](numPhunks); for (uint256 i = 0; i < numPhunks; i++) { result[i] = tokenOfOwnerByIndex(_owner, i); } return result; } } /* * Dev stuff. */ // metadata URI string private _baseTokenURI; function _baseURI() internal view virtual override returns (string memory) { return _baseTokenURI; } function tokenURI(uint256 _tokenId) public view override returns (string memory) { string memory base = _baseURI(); string memory _tokenURI = Strings.toString(_tokenId); // If there is no base URI, return the token URI. if (bytes(base).length == 0) { return _tokenURI; } return string(abi.encodePacked(base, _tokenURI)); } // contract metadata URI for opensea string public contractURI; /* * Owner stuff */ function startSale() public onlyOwner { isSaleOn = true; saleHasBeenStarted = true; } function endSale() public onlyOwner { isSaleOn = false; } function giveFreeRoll(address receiver) public onlyOwner { // max number of free mints we can give to the community for promotions/marketing require(_numFreeRollsGiven < 200, "already given max number of free rolls"); uint256 freeRolls = freeRollPhunks[receiver]; freeRollPhunks[receiver] = freeRolls + 1; _numFreeRollsGiven = _numFreeRollsGiven + 1; } // for handing out free rolls to v1 phunk owners // details on seeding info here: https://gist.github.com/cryptophunks/7f542feaee510e12464da3bb2a922713 function seedFreeRolls( address[] memory tokenOwners, uint256[] memory numOfFreeRolls ) public onlyOwner { require( !saleHasBeenStarted, "cannot seed free rolls after sale has started" ); require( tokenOwners.length == numOfFreeRolls.length, "tokenOwners does not match numOfFreeRolls length" ); // light check to make sure the proper values are being passed require(numOfFreeRolls[0] <= 3, "cannot give more than 3 free rolls"); for (uint256 i = 0; i < tokenOwners.length; i++) { freeRollPhunks[tokenOwners[i]] = numOfFreeRolls[i]; } } // for seeding the v2 contract with v1 state // details on seeding info here: https://gist.github.com/cryptophunks/7f542feaee510e12464da3bb2a922713 function seedInitialContractState( address[] memory tokenOwners, uint256[] memory tokens ) public onlyOwner { require( !saleHasBeenStarted, "cannot initial phunk mint if sale has started" ); require( tokenOwners.length == tokens.length, "tokenOwners does not match tokens length" ); uint256 lastTokenIdMintedInInitialSetCopy = _lastTokenIdMintedInInitialSet; for (uint256 i = 0; i < tokenOwners.length; i++) { uint256 token = tokens[i]; require( lastTokenIdMintedInInitialSetCopy > token, "initial phunk mints must be in decreasing order for our availableToken index to work" ); lastTokenIdMintedInInitialSetCopy = token; useAvailableTokenAtIndex(token); _safeMint(tokenOwners[i], token); } _lastTokenIdMintedInInitialSet = lastTokenIdMintedInInitialSetCopy; } // URIs function setBaseURI(string memory baseURI) external onlyOwner { _baseTokenURI = baseURI; } function setContractURI(string memory _contractURI) external onlyOwner { contractURI = _contractURI; } function withdrawMoney() public payable onlyOwner { (bool success, ) = msg.sender.call{value: address(this).balance}(""); require(success, "Transfer failed."); } function _beforeTokenTransfer( address from, address to, uint256 tokenId ) internal virtual override(ERC721Enumerable) { super._beforeTokenTransfer(from, to, tokenId); } function supportsInterface(bytes4 interfaceId) public view virtual override(ERC721Enumerable) returns (bool) { return super.supportsInterface(interfaceId); } }
查找差异