SmartContract/Solidity: The transaction has been reverted to the initial state - solidity

I have the code below inside a contract, whenever I run the function getTimeUntilRewrdClaimable it works until the time is under zero.. If the time is under zero it throws this error...
VM error: revert.
revert
The transaction has been reverted to the initial state.
Note: The called function should be payable if you send value and the value you
send should be less than your current balance.
Debug the transaction to get more information.
My Code inside my contract:
mapping( uint256 => ObjectDetails) private attributes;
// Object Structure...
struct ObjectDetails {
uint dailyClaim;
uint lastClaimDate;
}
function getTimeUntilRewrdClaimable(uint256 tokenId) public view returns (int) {
return int(attributes[tokenId].lastClaimDate + 60 - block.timestamp);
}
Thanks to any and all feedback!

attributes[tokenId].lastClaimDate is a uint, so attributes[tokenId].lastClaimDate + 60 - block.timestamp is as well. This causes an issue when attributes[tokenId].lastClaimDate + 60 is less than block.timestamp. To fix, cast both parts to int before doing the subtraction:
return int(attributes[tokenId].lastClaimDate + 60) - int(block.timestamp);

Related

Reverse Lotto Search has CRAZY fees (new to solidity): Gas estimation errored with the following message

I am new to solidity and for this project I am trying to do a reverse lottery drawing, where the losers are drawn and appended until only the winner remains.
I keep getting a gas estimation error:
Gas estimation errored with the following message (see below). The transaction execution will likely fail. Do you want to force sending?
gas required exceeds allowance (29970705)
I have tried upping my gas when I deploy on remix and all that does is up my cost when I run - it currently estimates 75000ethererum for running: drawLoser()
I use fulfullRandomWords which calls Chainlink VRF - which gives me a verified random seed, I then use this seed in drawLoser(). current_supply is hardcoded at 10000 for testing. I then use my random seed to make a random number and check if that number exists in my losers array, if it does not exist, I increment and generate a new number from the same seed and repeat until I find a new number. I am trying to do all of this without storing anything except my uint16 entry in my loser array, but I am guessing I am doing something stupid and storing more than I realize on the blockchain since the gas fee is absurd.
Thank you for any help!
function fulfillRandomWords(
uint256, /* requestId */
uint256[] memory randomWords
) internal override {
s_randomWords = randomWords;
}
function exists1(uint16 num) public view returns (bool) {
for (uint i = 0; i < losers.length; i++) {
if (losers[i] == num) {
return true;
}
}
return false;
}
//Right now I need to fulfill randomwords and then drawLoser - draw loser does not generate a new seed
function drawLoser() public {
//fulfillRandomWords;
uint16 drawing;
uint i = 0;
uint j = 1;
//generate 10% of total entrys as losers
while(i < 10*(current_supply-getCountLosers())/100) { //current_supply is entrys in lotto
drawing = uint16(uint256(keccak256(abi.encode(s_randomWords[0], j)))%(current_supply-losers.length)+1);
if (exists1(drawing) == true){
j++;
}
if (exists1(drawing) == false){
losers.push(drawing);
i++;
}
}
}
error: Gas estimation errored with the following message (see below). The transaction execution will likely fail. Do you want to force sending? gas required exceeds allowance (29970705)
This means that your transaction is going to fail to tripped require() or revert.

How can i set 2 max supply's in a ERC721

I have a problem. The problem is that i want a max mint supply for the whitelist sale and public sale. So for example;
In total i have 10.000 NFT's. There will be an whitelist sale and a public sale. For the whitelist sale i have 2.000 wallet addresses, but i only want them to be able to mint 1.500 NFT's. and in the public sale i want the remaining 8.500 NFT's to be sold.
I already tried somethings with the normal maxsupply but can't figure it out. I want a max mint per wallet like 10 and cant seem to limit the supply to 1500 for only the whitelist
Does anyone can explain this to me or have a code example?
I don't recommend limiting your whitelist per-wallet minting amount (you want to mint out, don't you?!), but I understand the reasons why you might. I'll provide both options. All code is abbreviated for brevity sake:
*Note 1: We will be using OpenZeppelin Utilities - Counters for tracking minted progress. You can also consider using totalSupply(), however, if burned tokens are a concern totalSupply() will decrement and throw off your count, whereas Counters will not.
Note 2: This assumes you're whitelist occurs before public and that you're not also juggling a reserve count as well - additional checks and counters would be required for that.
Note 3: This covers ONLY the check for limiting whitelist; you will obviously also need additional checks for valid whitelist account, sufficient payment, etc.
Limit Whitelist Total Supply
...
import "#openzeppelin/contracts/utils/Counters.sol";
...
error ExceededWhitelistSupply();
...
using Counters for Counters.Counter;
uint256 public maxSupply = 10000;
uint256 public maxWhitelistSupply = 1500;
Counters.Counter private totalWhitelistSupply;
...
function mintWhitelist(uint256 _qty) external payable {
if ( totalWhitelistSupply.current() + _qty > maxWhitelistSupply ) revert ExceededWhitelistSupply();
for (uint256 i = 0; i < _qty; i++) {
totalWhitelistSupply.increment();
}
_mint(msg.sender, _qty, '', true);
}
Limit Wallet && Limit Whitelist Total Supply
...
import "#openzeppelin/contracts/utils/Counters.sol";
...
error ExceededWhitelistSupply();
error ExceededMaxPerWallet();
...
using Counters for Counters.Counter;
uint256 public maxSupply = 10000;
uint256 public maxWhitelistSupply = 1500;
uint256 public maxWhitelistPerWallet = 10;
Counters.Counter private totalWhitelistSupply;
mapping(address => uint256) public whitelistMintedAmount;
...
function mintWhitelist(uint256 _qty) external payable {
if ( whitelistMintedAmount[msg.sender] + _qty > maxWhitelistPerWallet ) revert ExceededMaxPerWallet();
if ( totalWhitelistSupply.current() + _qty > maxWhitelistSupply ) revert ExceededWhitelistSupply();
for (uint256 i = 0; i < _qty; i++) {
totalWhitelistSupply.increment();
}
whitelistMintedAmount[msg.sender] += _qty;
_mint(msg.sender, _qty, '', true);
}
Here, we've used mapping - good tutorial here - to track the number of NFTs that have been minted to this wallet (preferred method, as this won't be fooled by the account transferring NFTs out of the wallet and then minting more). If you want to go WAY down the rabbit hole, you can also look at trash-canning this whole approach and learn up on this approach for handling your whitelist.
Keep in mind that there are more checks and balances that you'll need to add (e.g., visualizing this in the front end of your dApp to avoid minting when they shouldn't be able to, additional validation layers in your mint functions, etc.), but this should provide you with the core pieces needed for limiting by a max wallet and max supply. I apologize for any code errors - this is my first StackOverflow answer and the short-handing and readability of the code is a bit difficult to error check.
Have a whitelistMaxSupply
Have a getMaxSupply function
Have a finishWhitelist function
Have a maxSupply
Unless whitelist finished, getMaxSupply will return whitelistMaxSupply, after finished, it will return maxSupply
Profit
There are many ways to solve your problem, this is just the first one that came to my mind
function getMaxSupply() view public returns(uint256){
if(whitelistFinished){
return maxSupply;
}
return whitelistMaxSupply;
}
function finishWhitelist() public{
whitelistFinished = true;
}

Getting TransferHelper: TRANSFER_FROM_FAILED from TransferHelper.sol. Why?

I'm new to solidity. I'm currently getting the following error TransferHelper: TRANSFER_FROM_FAILED from the safeTransferFrom function. Can someone tell me why?
What is this line doing?
(bool success, bytes memory data) = token.call(
abi.encodeWithSelector(0x23b872dd, from, to, value)
);
Here's the entire contract:
// SPDX-License-Identifier: MIT
pragma solidity 0.8.7;
/**
* #dev A helper methods for interacting with ERC20 tokens and
sending ETH that do not consistently return true/false.
*/
library TransferHelper {
function safeApprove(
address token,
address to,
uint256 value
) internal {
// bytes4(keccak256(bytes('approve(address,uint256)')));
(bool success, bytes memory data) = token.call(
abi.encodeWithSelector(0x095ea7b3, to, value)
);
require(
success && (data.length == 0 || abi.decode(data, (bool))),
"TransferHelper: APPROVE_FAILED"
);
}
function safeTransfer(
address token,
address to,
uint256 value
) internal {
// bytes4(keccak256(bytes('transfer(address,uint256)')));
(bool success, bytes memory data) = token.call(
abi.encodeWithSelector(0xa9059cbb, to, value)
);
require(
success && (data.length == 0 || abi.decode(data, (bool))),
"TransferHelper: TRANSFER_FAILED"
);
}
function safeTransferFrom(
address token,
address from,
address to,
uint256 value
) internal {
// bytes4(keccak256(bytes('transferFrom(address,address,uint256)')));
(bool success, bytes memory data) = token.call(
abi.encodeWithSelector(0x23b872dd, from, to, value)
);
require(
success && (data.length == 0 || abi.decode(data, (bool))),
"TransferHelper: TRANSFER_FROM_FAILED"
);
}
function safeTransferETH(address to, uint256 value) internal {
(bool success, ) = to.call{value: value}(new bytes(0));
require(success, "TransferHelper: ETH_TRANSFER_FAILED");
}
}
Just a note, TransferHelper is the prewritten library, and we shouldn't touch into it. What you should do is see the message like: Transfer From Failed or approved fail and check our ERC20 token code as well as the data submit whether it's valid or not.
1st question:
This problem usually happens when your ERC20 token can't be transfer.
There're several reason for this: un-approval, not enough balance...
2nd question:
abi.encodeWithSelector(0x23b872dd, from, to, value)
This function returns a selector (think of is as a function ref) to the transfer(...) of your ERC20 token. And this is called by token.call( a kind of reflection.
This error is for the following reasons:
if the token has fees on transfer remember to be correctly calling the exchange function that supports transfer fees: https://docs.uniswap.org/protocol/V2/reference/smart-contracts/router-02
note that the token submissions permission is sufficient in the token contract. The same happens with the manipulation of WETH it is necessary to give the necessary permissions in the contract.

gas estimation errored with message: "execution reverted: Below agreed payment"

I am having issues when trying to use the Chainlink random number generator and deploying to Rinkeby. Relevant code pieces are the following:
Constructor from the importing contract (should be working fine).
// RandomNumberConsumer parameters for RINKEBY testnet
address _vrfCoordinator = 0xb3dCcb4Cf7a26f6cf6B120Cf5A73875B7BBc655B;
address _link = 0x01BE23585060835E02B77ef475b0Cc51aA1e0709;
bytes32 _keyHash = 0x2ed0feb3e7fd2022120aa84fab1945545a9f2ffc9076fd6156fa96eaff4c1311;
uint256 _fee = 0.1 * 10 ** 18; // 0.1 LINK
constructor() RandomNumberConsumer(_vrfCoordinator, _link, _keyHash, _fee) {}
RandomNumberConsumer.sol. As specified in the chainlink docs, with a few tweaks needed for my approach.
pragma solidity ^0.8.7;
import "#chainlink/contracts/src/v0.8/VRFConsumerBase.sol";
import "#openzeppelin/contracts/access/Ownable.sol";
import "hardhat/console.sol";
contract RandomNumberConsumer is VRFConsumerBase, Ownable{
// Variables
bytes32 internal s_keyHash;
uint256 internal s_fee;
uint256 private constant ROLL_IN_PROGRESS = 150;
mapping(bytes32 => address) private s_rollers;
mapping(address => uint256) private s_results;
//address vrfCoordinator = 0x3d2341ADb2D31f1c5530cDC622016af293177AE0;
//address link = 0xb0897686c545045aFc77CF20eC7A532E3120E0F1;
// Events
event DiceRolled(bytes32 indexed requestId, address indexed roller);
event DiceLanded(bytes32 indexed requestId, uint256 indexed result);
/**
* Constructor inherits VRFConsumerBase
*
* Network: Rinkeby
* Chainlink VRF Coordinator address: 0xb3dCcb4Cf7a26f6cf6B120Cf5A73875B7BBc655B
* LINK token address: 0x01BE23585060835E02B77ef475b0Cc51aA1e0709
* Key Hash: 0x2ed0feb3e7fd2022120aa84fab1945545a9f2ffc9076fd6156fa96eaff4c1311
*/
constructor(address vrfCoordinator, address link, bytes32 keyHash, uint256 fee)
VRFConsumerBase(vrfCoordinator, link){
s_keyHash = keyHash;
s_fee = fee;
}
// Functions
function rollDice(address roller) public onlyOwner returns (bytes32 requestId){
console.log("RNG Contract address",address(this));
// Checking LINK balance
require(LINK.balanceOf(address(this)) >= s_fee, "Not enough LINK in contract.");
// Checking if roller has already rolled dice since each roller can only ever be assigned to a single house. TODO: this can be changed
require(s_results[roller] == 0, "Already rolled");
// Requesting randomness
requestId = requestRandomness(s_keyHash, s_fee); // Error is happening here!
// Storing requestId and roller address
s_rollers[requestId] = roller;
// Emitting event to signal rolling of dice
s_results[roller] = ROLL_IN_PROGRESS;
emit DiceRolled(requestId, roller);
}
// fulfillRandomness is a special function defined within the VRFConsumerBase contract that our contract extends from.
// The coordinator sends the result of our generated randomness back to fulfillRandomness.
function fulfillRandomness(bytes32 requestId, uint256 randomness) override internal {
// Transform the result to a number between 0 and 100, both included. Using % as modulo
require(randomness!=0, "Modulo zero!");
uint256 d100Value = (randomness % 100) + 1; // +1 so s_results[player] can be 0 if no dice has been rolled
// Assign the transformed value to the address in the s_results mapping variable.
s_results[s_rollers[requestId]] = d100Value;
// Emit a DiceLanded event.
emit DiceLanded(requestId, d100Value);
}
// playerWins determines whether the player wins or lose the battle, based on a fixed chance (0-100)
function playerWins (address player, uint8 chance) internal view returns (bool wins){
require(s_results[player] != 0, "Player has not engaged in battle!");
require(s_results[player] != ROLL_IN_PROGRESS, "Battle in progress!");
return s_results[player] <= (chance + 1); //+1 because dice is 1-101
}
}
RNG call from the importing contract(simplified to relevant part only. _player address is working correctly).
address _player = ownerOf(_monId);
rollDice(_player);
I have the certainty that the error occurs inside the rollDice function, more specifically in the call to requestRandomness. Apart from that, I cannot seem to find why the error is hapenning, nor any references to the error message (Below agreed payment) inside any of the dependency contracts. Cannot find any references online either.
Any help is appreciated, thanks.
Below agreed payment error message comes from the sufficientLINK modifier of the VRFCoordinator.sol contract. You can see it here and here.
Double-check the constructor parameters, especially the fee value.
Also, make sure to fund your smart contract with Rinkeby LINK tokens which you can claim from the faucet.

How to set msg.value in Remix IDE

This is probably an easy error I'm missing, but I cannot for the life of me figure out how to set the msg.value variable in this contract. I've read online that this value is the amount of wei associated with the transaction, but how do I, as a caller of the contract, specifically set that value. Here's the contract I'm struggling with.
pragma solidity 0.8.7;
contract VendingMachine {
// Declare state variables of the contract
address public owner;
mapping (address => uint) public cupcakeBalances;
// When 'VendingMachine' contract is deployed:
// 1. set the deploying address as the owner of the contract
// 2. set the deployed smart contract's cupcake balance to 100
constructor() {
owner = msg.sender;
cupcakeBalances[address(this)] = 100;
}
// Allow the owner to increase the smart contract's cupcake balance
function refill(uint amount) public {
require(msg.sender == owner, "Only the owner can refill.");
cupcakeBalances[address(this)] += amount;
}
// Allow anyone to purchase cupcakes
function purchase(uint amount) public payable {
require(msg.value >= amount * 1 ether, "You must pay at least 1 ETH per cupcake");
require(cupcakeBalances[address(this)] >= amount, "Not enough cupcakes in stock to complete this purchase");
cupcakeBalances[address(this)] -= amount;
cupcakeBalances[msg.sender] += amount;
}
}
Every time I enter an amount, I'm getting thrown the error that says "You must pay at least 1 ETH per cupcake"
There's nowhere for me to specifically enter in a value for how much I'm going to pay for this, any help would be great
here's what I'm able to input when I deploy the contract on Remix
Top of the Deploy Button you can see the Value Field :
when you want to call the purchase , first fill the value field and select Ether after that calls your function.
I try this way with your code and it works fine.