I have a contract with the following payable function
Contract Constructor
constructor( address payable _NFT_CONTRACT, address payable _TOKEN_CONTRACT) payable {
NFT_CONTRACT = IERC721(_NFT_CONTRACT);
TOKEN_CONTRACT = IERC20(_TOKEN_CONTRACT);
}
Function Stake:
function stake(uint256[] calldata tokenIds, uint256[] calldata powers) external payable {
for (uint i = 0; i <= tokenIds.length; i++) {
uint256 tokenId = tokenIds[i];
uint256 power = powers[i];
require(NFT_CONTRACT.ownerOf(tokenId) == msg.sender, "You can only stake your own token");
require(vault[tokenId].tokenId == 0, "You can only stake once");
NFT_CONTRACT.safeTransferFrom(msg.sender, address(this), tokenId);
vault[tokenId] = Stake({
tokenId: tokenId,
timestamp: block.timestamp,
owner: msg.sender,
power: power
});
userStacks[msg.sender].push(tokenId);
hasPaid[tokenId] = 0;
}
}
vault, userStacks, and hasPaid are all structs.
struct Stake {
address owner;
uint256 tokenId;
uint256 timestamp;
uint256 power;
}
mapping(uint256 => Stake) public vault;
mapping(address => uint256[]) public userStacks;
mapping(uint256 => uint256) public hasPaid;
The problem:
Function stake works perfectly fine if I remove the for loop, but, throws this error if I have the loop:
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.
I am using solidity ^0.8.0;
I test with arrays such as [1,2], [4,5], for both params.
Thanks.
Related
How do I add in the arguments and set the baseURI?
It is mainly having issues identifying totalsupply and baseuri.
input the below
name (string): Test MB
symbol (string): TEST
maxNftSupply (uint256): 10000
saleStart (uint256): 1619060439?
Where would I put this, there is also an encoded view after verification on etherscan, is that something I need to add?
contract TestMB is ERC721, Ownable {
using SafeMath for uint256;
string public TEST_PROVENANCE = "";
uint256 public startingIndexBlock;
uint256 public startingIndex;
uint256 public constant testPrice = 80000000000000000; //0.08 ETH
uint public constant maxTestPurchase = 20;
uint256 public MAX_TEST;
bool public saleIsActive = false;
uint256 public REVEAL_TIMESTAMP;
constructor(string memory name, string memory symbol, uint256 maxNftSupply, uint256 saleStart) ERC721(name, symbol) {
MAX_TEST = maxNftSupply;
REVEAL_TIMESTAMP = saleStart + (9900 * 9);
}
function withdraw() public onlyOwner {
uint balance = address(this).balance;
msg.sender.transfer(balance);
}
function reserveTest() public onlyOwner {
uint supply = totalSupply();
uint i;
for (i = 0; i < 100; i++) {
_safeMint(msg.sender, supply + i);
}
}
function setRevealTimestamp(uint256 revealTimeStamp) public onlyOwner {
REVEAL_TIMESTAMP = revealTimeStamp;
}
function setProvenanceHash(string memory provenanceHash) public onlyOwner {
TEST_PROVENANCE = provenanceHash;
}
function setBaseURI(string memory baseURI) public onlyOwner {
_setBaseURI(baseURI);
}
function flipSaleState() public onlyOwner {
saleIsActive = !saleIsActive;
}
function mintTest(uint numberOfTokens) public payable {
require(saleIsActive, "Sale must be active to mint Test");
require(numberOfTokens <= maxTestPurchase, "Can only mint 20 tokens at a time");
require(totalSupply().add(numberOfTokens) <= MAX_TEST, "Purchase would exceed max supply of Test");
require(testPrice.mul(numberOfTokens) <= msg.value, "Ether value sent is not correct");
for(uint i = 0; i < numberOfTokens; i++) {
uint mintIndex = totalSupply();
if (totalSupply() < MAX_TEST) {
_safeMint(msg.sender, mintIndex);
}
}
if (startingIndexBlock == 0 && (totalSupply() == MAX_TEST || block.timestamp >= REVEAL_TIMESTAMP)) {
startingIndexBlock = block.number;
}
}
function setStartingIndex() public {
require(startingIndex == 0, "Starting index is already set");
require(startingIndexBlock != 0, "Starting index block must be set");
startingIndex = uint(blockhash(startingIndexBlock)) % MAX_TEST;
// Just a sanity case in the worst case if this function is called late (EVM only stores last 256 block hashes)
if (block.number.sub(startingIndexBlock) > 255) {
startingIndex = uint(blockhash(block.number - 1)) % MAX_TEST;
}
// Prevent default sequence
if (startingIndex == 0) {
startingIndex = startingIndex.add(1);
}
}
function emergencySetStartingIndexBlock() public onlyOwner {
require(startingIndex == 0, "Starting index is already set");
startingIndexBlock = block.number;
}
}
If you are the deployer of the contract so you will be the contract owner. Then you will be able to call onlyOwner functions.
To set baseURI, you have to call setBaseURI function with parameter of your base url.
You have to verify your contract source code on etherscan to call functions.
If you don't know how to verify your contract code, then you can deploy your contract through Remix and then you will be able to call contract functions.
I hope i got the problem and this is the answer.
I would like to know if it is possible to generate a unique number for each address, I tried mapping but it does not work
contract RandomNumberConsumer is VRFConsumerBase {
bytes32 internal keyHash;
uint256 internal fee;
uint256 public randomResult;
mapping(address => uint) public random;
constructor()
VRFConsumerBase(
0x8C7382F9D8f56b33781fE506E897a4F1e2d17255, // VRF Coordinator
0x326C977E6efc84E512bB9C30f76E30c160eD06FB // LINK Token
)
{
keyHash = 0x6e75b569a01ef56d18cab6a8e71e6600d6ce853834d4a5748b720d06f878b3a4;
fee = 0.0001 * 10 ** 18; // 0.0001 LINK (Varies by network)
}
function getRandomNumber() public returns (bytes32 requestId) {
require(LINK.balanceOf(address(this)) >= fee, "Not enough LINK - fill contract with faucet");
return requestRandomness(keyHash, fee);
}
function fulfillRandomness(bytes32 requestId, uint256 randomness) internal override {
randomResult = randomness;
random[msg.sender] = randomness;
}
}
here is the mapping
mapping(address => uint) public random;
random[msg.sender] = randomness;
Thanks!
You are close with what you have so far. I've updated the contract a bit and included notes below. The main change was a new mapping to store the request id -> address. This lets the fulfillRandomness function update the correct address -> randomNumber mapping.
pragma solidity ^0.8.0;
import "#chainlink/contracts/src/v0.8/VRFConsumerBase.sol";
contract RandomNumberConsumer is VRFConsumerBase {
bytes32 internal keyHash;
uint256 internal fee;
uint256 public randomResult;
// ** New mapping to store requests
mapping(bytes32 => address) public requestIdToAddress;
mapping(address => uint) public random;
constructor()
VRFConsumerBase(
0x8C7382F9D8f56b33781fE506E897a4F1e2d17255, // VRF Coordinator
0x326C977E6efc84E512bB9C30f76E30c160eD06FB // LINK Token
)
{
keyHash = 0x6e75b569a01ef56d18cab6a8e71e6600d6ce853834d4a5748b720d06f878b3a4;
fee = 0.0001 * 10 ** 18; // 0.0001 LINK (Varies by network)
}
function getRandomNumber() public {
require(LINK.balanceOf(address(this)) >= fee, "Not enough LINK - fill contract with faucet");
// ** Store the random request in requestID
bytes32 requestId = requestRandomness(keyHash, fee);
// ** Map requestId to the sender's address
requestIdToAddress[requestId] = msg.sender;
}
function fulfillRandomness(bytes32 requestId, uint256 randomness) internal override {
// ** Find the sender address based on the request
address _sender = requestIdToAddress[requestId];
// ** Update sender's mapping for randomness
random[_sender] = randomness;
}
}
This is the documentation of my used API.
The price is still showing 0 as you can see in this image reference.
Here is my code:
pragma solidity ^0.6.0;
import "#chainlink/contracts/src/v0.6/ChainlinkClient.sol";
contract APIConsumer is ChainlinkClient {
event below20(uint _price);
event below30(uint _price);
event below40(uint _price);
event below50(uint _price);
uint256 public Price;
address private oracle;
bytes32 private jobId;
uint256 private fee;
constructor() public {
setChainlinkToken(0x326C977E6efc84E512bB9C30f76E30c160eD06FB);
oracle = 0xb33D8A4e62236eA91F3a8fD7ab15A95B9B7eEc7D;
jobId = "da20aae0e4c843f6949e5cb3f7cfe8c";
fee = 10 ** 16; // 0.01 LINK
}
function requestBTCCNYPrice() public returns (bytes32 requestId)
{
Chainlink.Request memory request = buildChainlinkRequest(jobId, address(this), this.fulfill.selector);
// Set the URL to perform the GET request on
request.add("get", "https://www.alphavantage.co/query?function=CURRENCY_EXCHANGE_RATE&from_currency=BTC&to_currency=CNY&apikey=demo");
string[] memory path = new string[](2);
path[0] = "Realtime Currency Exchange Rate";
path[1] = "5. Exchange Rate";
request.addStringArray("path", path);
request.addInt("times", 10000000000);
// Sends the request
return sendChainlinkRequestTo(oracle, request, fee);
}
/**
* Receive the response in the form of uint256
*/
function fulfill(bytes32 _requestId, uint256 _price) public recordChainlinkFulfillment(_requestId)
{
Price = _price;
}
That node is down. Use the following node and JobID in this code:
pragma solidity ^0.6.0;
import "#chainlink/contracts/src/v0.6/ChainlinkClient.sol";
contract APIConsumer is ChainlinkClient {
event below20(uint _price);
event below30(uint _price);
event below40(uint _price);
event below50(uint _price);
uint256 public Price;
address private oracle;
bytes32 private jobId;
uint256 private fee;
constructor() public {
setChainlinkToken(0x326C977E6efc84E512bB9C30f76E30c160eD06FB);
oracle = 0xc8D925525CA8759812d0c299B90247917d4d4b7C;
jobId = "bbf0badad29d49dc887504bacfbb905b";
fee = 10 ** 16; // 0.01 LINK
}
function requestBTCCNYPrice() public returns (bytes32 requestId)
{
Chainlink.Request memory request = buildChainlinkRequest(jobId, address(this), this.fulfill.selector);
// Set the URL to perform the GET request on
request.add("get", "https://www.alphavantage.co/query?function=CURRENCY_EXCHANGE_RATE&from_currency=BTC&to_currency=CNY&apikey=demo");
string[] memory path = new string[](2);
path[0] = "Realtime Currency Exchange Rate";
path[1] = "5. Exchange Rate";
request.addStringArray("path", path);
request.addInt("times", 10000000000);
// Sends the request
return sendChainlinkRequestTo(oracle, request, fee);
}
/**
* Receive the response in the form of uint256
*/
function fulfill(bytes32 _requestId, uint256 _price) public recordChainlinkFulfillment(_requestId)
{
Price = _price;
}
}
To check to see if a node is running or not, check out the oracle address in a block explorer. You can see here that the original node you tried to use hasn't posted a transaction in quite a long time.
To find nodes and jobs that are currently working, you should check market.link.
I am working on smart contract to generate random cards with some specific rules, I was trying to use Chainlink VRF to generate random number and implemented such contract.
//SPDX-License-Identifier: Unlicense
pragma solidity >=0.7.4;
import "#chainlink/contracts/src/v0.8/VRFConsumerBase.sol";
import "../utils/Context.sol";
import "../utils/ReentrancyGuard.sol";
import "../utils/Address.sol";
import "../NFT/CardNFTAccessControls.sol";
import "../NFT/CardNFT.sol";
/**
* #notice Factory contract for NFT handling payments on mint
*/
contract NFTFactory is Context, ReentrancyGuard, VRFConsumerBase {
// using SafeMath for uint256;
using Address for address payable;
struct CardInfo {
uint256 num;
uint256 kind;
uint256 value;
uint256 qty;
}
struct NFTInfo {
uint256 edition;
uint256 cardInfoId;
}
struct RequestNFTConfig {
uint256 limit;
bool kind;
uint256 id;
}
event NFTCreated(
uint256 id,
uint256 num,
uint256 kind,
uint256 edition
);
event RandomReturned(
bytes32 requestId,
uint256 randomness
);
/// #notice chainlink rng request value mapping
mapping(bytes32 => RequestNFTConfig) private requestIds;
/// #notice edition number id
uint256 private editionId;
/// #notice for switching off factory functionality
bool public isPaused;
/// #notice responsible for enforcing mint and admin role
CardNFTAccessControls accessControls;
/// #notice NFT contract
CardNFT cardNFT;
/// #notice platform fee recipient address which will accept all fees and mint price
address payable platformFeeRecipient;
/// #notice keyhash for chainlink rng generator
bytes32 internal keyHash;
/// #notice fee for chainlink rng generator
uint256 internal rngFee;
/// #notice rng generator result
uint256 public randomResult;
/// #notice deck card information for calculation
mapping(uint256 => CardInfo) deckInfo;
/// #notice nft array
mapping(uint256 => NFTInfo) nfts;
modifier whenNotPaused() {
require(!isPaused, "Function is currently paused");
_;
}
constructor(
CardNFTAccessControls _accessControls,
CardNFT _cardNFT,
address payable _platformFeeRecipient
) VRFConsumerBase(
0xa555fC018435bef5A13C6c6870a9d4C11DEC329C,
0x84b9B910527Ad5C03A9Ca831909E21e236EA7b06
) {
require(address(_accessControls) != address(0), "NFTFactory: Invalid Access Controls");
require(address(_cardNFT) != address(0), "NFTFactory: Invalid NFT");
require(_platformFeeRecipient != address(0), "NFTFactory: Invalid platform Fee recipient");
accessControls = _accessControls;
cardNFT = _cardNFT;
platformFeeRecipient = _platformFeeRecipient;
keyHash = 0xcaf3c3727e033261d383b315559476f48034c13b18f8cafed4d871abe5049186;
rngFee = 0.1 * 10 ** 18; // 0.1 LINK
}
/**
#notice create one NFT
#param _limit min or maximum number of card
#param _kind limit kind with lower or higher
#param _price price of NFT mint
#param _amount amount of NFTs to mint
#param _data additional data to leave
*/
function create(uint256 _limit, bool _kind, uint256 _price, uint256 _amount, bytes memory _data) external payable nonReentrant whenNotPaused {
require(_msgSender().isContract() == false, "Factory.create: No contracts are permitted");
require(_msgSender() != address(0), "Factory.create: sender address is ZERO");
uint256 buyPrice = msg.value;
require(buyPrice >= _price, "Factory.create: payment should be same to original price");
// (bool platformTransferSuccess,) = platformFeeRecipient.call{value : buyPrice}("");
// require(platformTransferSuccess, "Factory.mintPayment: Failed to send platform fee");
address creator = _msgSender();
if(_amount > 1) {
uint256[] memory _ids = cardNFT.batchMint(creator, _amount, _data);
require(_amount == _ids.length, "Factory.create: should batch mint same amount of nfts");
for(uint256 i=0; i<_ids.length; i++) {
getRandomNumber(_ids[i], _limit, _kind);
}
} else {
uint256 id = cardNFT.mint(creator, _data);
getRandomNumber(id, _limit, _kind);
}
}
/**
#notice generate actual NFT info
#param _requestId request id for chainlink rng
#param _randomness random number which return from chainlink org
*/
function generateNFTInfo(bytes32 _requestId, uint256 _randomness) private {
RequestNFTConfig storage config = requestIds[_requestId];
uint256 total = getTotalQtyToNumber(config.limit);
bool _kind = config.kind;
uint256 rngResult = 0;
if(_kind) {
rngResult = _randomness * (200000 - total) + total;
} else {
rngResult = _randomness * total;
}
uint256 cardInfoId = getNearestQtyCard(rngResult);
NFTInfo storage nft = nfts[config.id];
uint256 edition = _getNextEditionID();
_incrementEditionId();
nft.edition = edition;
nft.cardInfoId = cardInfoId;
CardInfo storage cardInfo = deckInfo[cardInfoId];
emit NFTCreated(config.id, cardInfo.num, cardInfo.kind, edition);
}
/**
* Requests randomness
*/
function getRandomNumber(uint256 _id, uint256 _limit, bool _kind) private {
require(LINK.balanceOf(address(this)) >= rngFee, "Not enough LINK - fill contract with faucet");
bytes32 requestId = requestRandomness(keyHash, rngFee);
RequestNFTConfig storage config = requestIds[requestId];
config.id = _id;
config.kind = _kind;
config.limit = _limit;
}
/**
* Callback function used by VRF Coordinator
*/
function fulfillRandomness(bytes32 requestId, uint256 randomness) internal override {
emit RandomReturned(requestId, randomness);
generateNFTInfo(requestId, randomness);
}
......
}
I tried this one on BSC testnet but no RandomReturned event log and also no updates with generateNFTInfo function.
Also I am not sure how to test unit test on my local without installing chainlink-node on my local.
Can anybody help me on this one?
I thought I ran into the same issue, however, I found that it can take over 2 minutes to generate a random number depending on network congestion. I am testing in the Rinkeby network.
I am creating nft smart contract and using chainlinkClient.sol for updation of URI.
chainlinkClient Version: v0.6
Error: TypeError: Member "add" not found or not visible after argument-dependent lookup in struct Chainlink.Request memory.
Any Idea Why am I getting this error?
Code:
// SPDX-License-Identifier: MIT
pragma solidity >=0.6.0 <0.9.0;
import "chainlink/evm-contracts/src/v0.6/ChainlinkClient.sol";
contract phoneNumber is ChainlinkClient{
uint256 public phone_no;
address private oracle;
bytes32 private jobId;
uint256 private fee;
constructor(uint256 _initial_phone_no){
setPublicChainlinkToken();
oracle = 0x7AFe1118Ea78C1eae84ca8feE5C65Bc76CcF879e;
jobId = "6d1bfe27e7034b1d87b5270556b17277";
fee = 0.1 * 10 ** 18; // 0.1 LINK
phone_no = _initial_phone_no;
}
function requestVolumeData() public returns (bytes32 requestId)
{
Chainlink.Request memory request = buildChainlinkRequest(jobId, address(this), this.update_phone_no.selector);
// Set the URL to perform the GET request on
request.add("get", "http://localhost:3000/images/phone.json");
request.add("path", "phone.new");
// Multiply the result by 1000000000000000000 to remove decimals
int timesAmount = 10**18;
request.addInt("times", timesAmount);
// Sends the request
return sendChainlinkRequestTo(oracle, request, fee);
}
function update_phone_no(bytes32 _requestId, uint256 new_phone_no) public recordChainlinkFulfillment(_requestId)
{
phone_no = new_phone_no;
}
function withdrawLink() external {
LinkTokenInterface linkToken = LinkTokenInterface(chainlinkTokenAddress());
require(linkToken.transfer(msg.sender, linkToken.balanceOf(address(this))), "Unable to transfer");
}
}
Your import statement is missing an "#" symbol. Add it to the beginning like this:
import "#chainlink/contracts/src/v0.6/ChainlinkClient.sol";
Note: Also don't forget to explicitly state your constructor visibility specifier to public or internal as well.