How to random mint a static number of NFT? - ethereum

I'd like to mint these amount of tokens:
200 super
300 rare
500 common
But the mint process needs to be random, you can get a (super, rare, or common) but at the end of the process, it should be minted the same amount of 200 super, 300 rare, and 500 common.
The following code does the random but the final amount of tokens will be different from the beginning:
function safeMint(address to) public onlyOwner {
require(_tokenIdCounter.current() < totalSupply(), "There's no token to mint.");
require(mintCnt[msg.sender] < maxMintCntPerAddress, "One address can mint 1 tickets.");
if(mintPrice > 0) {
require(mintPrice == msg.value, "Mint price is not correct.");
address payable _to = payable(serviceAddress);
_to.transfer(mintPrice);
}
uint randomNumber = random(expectedTokenSupply - _tokenIdCounter.current());
for (uint256 i = 0; i < _tokenMetadata.length; i++) {
if(_tokenMetadata[i].amount <= randomNumber) {
_safeMint(to, _tokenIdCounter.current());
_setTokenURI(_tokenIdCounter.current(), _tokenMetadata[i].uri);
_tokenIdCounter.increment();
break;
}
}
}
function random(uint maxValue) internal returns (uint) {
return uint(keccak256(abi.encodePacked(block.timestamp, msg.sender, _tokenIdCounter.current()))) % maxValue;
}

First don't use block.timestamp or any block or blockchain data as a source of randomness, because it will cause the "randomness" be predictable or possible to be manipulated by minners, try with chainlink as a source of randomness, they have a good examples in their docs, if you want to have a fixed supply of each type of tokens you can have 3 variables to know how much of each one have been minted, and when you got the random number and all that you need you just need to apply some math, in this case you want the tokens to be 20% of super, 30% of rare and 50% of common, you only have to do the math you need to decide wich one will be minted, and in case of that type has already reach is max supply what will happend?

Related

Gas efficiency of totalSupply() vs. a tokenID counter | ERC-721

I'm creating a solidity contract for an NFT and in my mint function I'm not sure if a call to totalSupply() vs using a token counter and incrementing it is better practice. Does either variation cost more gas? Is one the more standard practice? I've seen examples of both being used.
Variation 1:
contract MyNFT is ERC721Enumerable, PaymentSplitter, Ownable {
using Counters for Counters.Counter;
Counters.Counter private currentTokenId;
...
function mint(uint256 _count)
public payable
{
uint256 tokenId = currentTokenId.current();
require(tokenId < MAX_SUPPLY, "Max supply reached");
for(uint i = 0; i < _count; ++i){
currentTokenId.increment();
uint256 newItemId = currentTokenId.current();
_safeMint(msg.sender, newItemId);
}
}
}
Variation 2:
function mint(uint256 _count)
public payable
{
uint supply = totalSupply();
require( supply + _count <= MAX_SUPPLY, "Exceeds max supply." );
for(uint i = 0; i < _count; ++i){
_safeMint(msg.sender, supply + i);
}
}
Both versions seem to work. I just want to be sure I'm using the most efficient / secure. Thanks for any advice!
First off all, you need to show us the underlying implementations. However, I can speculate that these are unmodified openzeppelin implementations for ERC721Enumerable and Counters.
For your case only, using Counter seems a little bit pointless to me.
It increases your deployment costs(just a little bit) because of redundant code coming from Counter library
You already know the length of your tokens array, why keep it twice? Counters is created for situations where you don't know the number of elements, like a mapping.
I am not guaranteeing correctness of the following analysis
Calling totalSupply (looking from opcode point of view) will:
jump to totalsupply (8 gas)
sload tokens.slot (200) gas
However, while using Counter, you sstore (>= 5000 gas) each time you decrement and sload (200 gas) each time you read.
As long as i am not mistaken about Counter using storage, and therefore sstore and sload opcodes, second variant will use much less gas.

Need help understanding solidity contract function swapback()

I have recently been delving into the code of a few contracts and have been commenting them myself to try and understand how they work as the entire field seems ironically black-box from a development perspective with most code copy and pasted from other contracts with 0 comments explaining what functions do.
As such I have seen a recurring function across multiple projects which I am struggling to get my head around. Namely shouldswapback() and swapback().
shouldSwapBack():
function shouldSwapBack() internal view returns (bool) {
return msg.sender != pair
&& !inSwap
&& swapEnabled
&& _balances[address(this)] >= swapThreshold;
}
My understanding of above is to return true only when the caller of the function is not the LP address, swapping is allowed and we are not in a swap currently and the balance of the contract is >= the predefined swap threshold.
2 questions regarding this:
1. In what context/circumstance is the msg.sender the LP contract?
2. Why is it important to only swap if the contract balance is greater than a certain percentage? What would be the effect if this was 0?
The actual swap function is longer:
function swapBack() internal swapping {
uint256 contractTokenBalance = balanceOf(address(this));
/* (contract balance * 3)/15/2 */
uint256 amountToLiquify = contractTokenBalance.mul(liquidityFee).div(totalFee).div(2);
uint256 amountToSwap = contractTokenBalance.sub(amountToLiquify);
/* set the address path for the BNB and Token addresses */
address[] memory path = new address[](2);
path[0] = address(this);
path[1] = WBNB;
/* note before balance of contract */
uint256 balanceBefore = address(this).balance;
/*swap tokens using PCS */
router.swapExactTokensForETHSupportingFeeOnTransferTokens(
amountToSwap, /*The amount of input tokens to send. */
0, /*The minimum amount of output tokens that must be received for the transaction not to revert. */
path, /*An array of token addresses. path.length must be >= 2. Pools for each consecutive pair of addresses must exist and have liquidity. */
address(this), /*Recipient of the BNB. */
block.timestamp /*Unix timestamp after which the transaction will revert. (Think set to one block?)*/
);
uint256 amountBNB = address(this).balance.sub(balanceBefore); /* get amount swapped by checking new contract balance vs beforeswap */
uint256 totalBNBFee = totalFee.sub(liquidityFee.div(2));
uint256 amountBNBLiquidity = amountBNB.mul(liquidityFee).div(totalBNBFee).div(2);
uint256 amountBNBMarketing = amountBNB.mul(marketingFee).div(totalBNBFee);
/* send marketing fee to marketing wallet */
(bool MarketingSuccess, /* bytes memory data */) = payable(marketingFeeReceiver).call{value: amountBNBMarketing, gas: 30000}("");
require(MarketingSuccess, "receiver rejected ETH transfer");
/* if we meet the liquidity threshold add to marketwallet */
if(amountToLiquify > 0){
router.addLiquidityETH{value: amountBNBLiquidity}(
address(this),
amountToLiquify,
0,
0,
marketingFeeReceiver,
block.timestamp
);
emit AutoLiquify(amountBNBLiquidity, amountToLiquify);
}
}
My understanding for this is that the contract tokens are swapped to BNB and then the fees are calculated and sent to the appropriate wallet. However with this I don't understand:
1.Why are the tokens going the contract and not the LP?
2.If all the tokens are swapped to ETH do none get swapped back?
3.What is the significance of adding to the LP, why would this be necessary? (if this wasn't done what would the affect be on the token? I have seen projects fail in the past because they didn't buyback liquidity but I'm struggling to understand what it would do apart from ease volatility?)
I understand that this a lengthy question and my issue seems to be less from a code perspective and more from a key concept one but if anyone could help me it would be great. I have looked online for courses but none seem to really delve into dex interactions, a lot just seem very basic token/NFT creation I haven't been able to find one tutorial on making a contract that has a working tax implementation so instead I've just been cross referencing a bunch of different contracts.
If anyone can point me in the right direction for a course or even better a tutor that would be great.
Thanks.

How to Avoid making time-based decisions in contract business logic?

I wrote a Money-saving smart contract where users deposit ETH and define the amount of time they want to keep that ETH in the contract, EX: USER X deposits 2ETH for one year, they can only withdraw their ETH after that period.
But solidity linter keeps telling me that I should not rely on block.timestamp to make decisions.
This is the Saving struct I'm using to map every address to a balance and endTime:
struct Saving {
uint256 balance;
uint256 endTime;
}
Here is my function modifier where I require the withdrawal time to be greater than the endTime I stored at the deposit moment:
modifier onlyValidTimeWithdraw() {
require(
block.timestamp > balances[msg.sender].endTime,
"You cannot withdraw yet"
);
_;
}
This is the message I get through the linter.
After doing some research I found that I should not have time-dependent conditions in my contract since miners can manipulate timestamps, but I did not find any alternative to this.
Miners can manipulate block timestamp to an extent of approx. few seconds, which is enough to affect business logic depending on a second-level precision.
function betLottery() external {
// the block.timestamp can be affected by a miner
// and they can submit their own winning transaction
if (block.timestamp % 2 == 0) {
win();
}
}
But since your logic depends on much longer period, I'd simply ignore or suppress the warning.
Or if it fits your usecase, you can validate against the block number, which most linters allow.
struct Saving {
uint256 balance;
uint256 endBlock;
}
require(
block.number > balances[msg.sender].endBlock,
"You cannot withdraw yet"
);

ERC20 Token: What is address(0)? And best practices for initial token distribution?

I have a pretty boilerplate test token that I'm going to use to support a DApp project. Key functions I have questions regarding are as follows:
constructor() {
name = "Test Token";
symbol = "TTKN";
decimals = 18;
_totalSupply = 1000000000000000000000000000000;
//WITHOUT DECIMALS = 1,000,000,000,000; should be 1 trillion
balances[msg.sender] = _totalSupply;
emit Transfer(address(0), msg.sender, _totalSupply);
}
function totalSupply() public override view returns (uint256) {
return _totalSupply - balances[address(0)];
}
First, a quick question about decimals and supply: did I set this up correctly to create 1 trillion of the TTKN token? And do I really need so many decimal places?
Second, what exactly is address(0)? My understanding of the constructor is that address(0) first transfers all the tokens to msg.sender, which is me, the person who deploys this contract.
And finally, what are the best practices for initially distributing the tokens? What I want is basically as follows:
a) Myself and a few other devs each get 1% of the initial supply
b) Our DApp, a separate smart contract, will get 50% of the initial supply, and will use this to reward users for interacting with our website/project
c) To accomplish a) and b), me, the contract deployer, should manually transfer these tokens as planned?
d) The rest of the coins... available to go on an exchange somehow (maybe out of scope of question)
So now that I've deployed this test token on remix and am getting a feel for how to transfer around the tokens, I want to understand the above points in relation to our project. Is my plan generally acceptable and feasible, and is it the case that as the initial owner I'm just making a bunch of transfer calls on the ETH mainnet eventually when I deploy?
did I set this up correctly to create 1 trillion of the TTKN token?
This is one of the correct ways. More readable would be also:
_totalSupply = 1000000000000 * 1e18;
or
// 10 to the power of
_totalSupply = 1000000000000 * (10 ** decimals);
^^ mind that this snippet performs a storage read (of the decimals variable) so it's more expensive gas-wise
a well as
_totalSupply = 1000000000000 ether;
^^ using the ether unit, an alias for * 1e18
what exactly is address(0)
If it's in the first param of the Transfer event, it means the tokens are minted. If it's in the second param, it means a burn of the tokens.
A token contract which creates new tokens SHOULD trigger a Transfer event with the _from address set to 0x0 when tokens are created.
Source: https://github.com/ethereum/EIPs/blob/master/EIPS/eip-20.md#transfer-1
initially distributing the tokens
You can perform the distribution in the constructor. For the sake of simplicity, my example shows the "exchange" as a regular address managed by your team that will send the tokens to the exchange manually. But it's possible to list a token on a DEX automatically as well.
_totalSupply = 1000000000000 * 1e18;
address[3] memory devs = [address(0x123), address(0x456), address(0x789)];
address dapp = address(0xabc);
address exchange = address(0xdef);
// helper variable to calculate the remaining balance for the exchange
uint256 totalSupplyRemaining = _totalSupply;
// 1% for each of the devs
uint256 devBalance = _totalSupply / 100;
for (uint i = 0; i < 3; i++) {
balances[devs[i]] = devBalance;
emit Transfer(address(0x0), devs[i], devBalance);
totalSupplyRemaining -= devBalance;
}
// 50% for the DApp
uint256 dappBalance = _totalSupply / 2;
balances[dapp] = dappBalance;
emit Transfer(address(0x0), dapp, dappBalance);
totalSupplyRemaining -= dappBalance;
// the rest for the exchange
balances[exchange] = totalSupplyRemaining;
emit Transfer(address(0x0), exchange, totalSupplyRemaining);

can anyone explain me this assert condition?

i would like to understand this assert condition in function send token.....i think the first assert for before adding tokenbalance is always gather then the up coming token but I don't sure about it....?
pragma solidity ^0.5.11;
contract EventExample {
mapping(address => uint) public tokenBalance;
event TokensSent(address _from, address _to, uint _amount);
constructor() public {
tokenBalance[msg.sender] = 100;
}
function sendToken(address _to, uint _amount) public returns(bool) {
require(tokenBalance[msg.sender] >= _amount, "Not enough tokens");
assert(tokenBalance[_to] + _amount >= tokenBalance[_to]);
assert(tokenBalance[msg.sender] - _amount <= tokenBalance[msg.sender])
;
tokenBalance[msg.sender] -= _amount;
tokenBalance[_to] += _amount;
emit TokensSent(msg.sender, _to, _amount);
return true;
}
}
These two assert conditions provide a way to prevent integer overflow and underflow.
The max value of uint256 is 2^256-1, which is approx. 10^77. If you want to add two numbers that would result in a value larger that the max value, it would overflow the integer.
Example with smaller values so it's easier to imagine:
Largest value of uint8 is 255. So if you have a value 250 and you want to add 10, it overflows the max value, and becomes 4 (because 255 + 1 equals 0 in case of uint8).
The same goes the other way around. You have a value 5 and want to subtract 10. Since it's an unsigned integer, there's no negative numbers, and it underflows and becomes 251 (because 5 - 5 is 0, and then the remaining 5 is subtracted from the "max value + 1").
You can find more info about the integer overflow/underflow vulnerability in the SWC registry: https://swcregistry.io/docs/SWC-101