I am having issues verifying my smart contract on Rinkeby Testnet using #chainlink. My contract is deploying to Rinkeby fine but runs into issues when I have publish_source on. The contract verifies fine when using v0.6 and Solidity 0.6.6, I seem to only have issues with v0.8. Anyone know why this might be happening?
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
import "#chainlink/contracts/src/v0.8/ChainlinkClient.sol";
import "#openzeppelin/contracts/token/ERC721/ERC721.sol";
/**
* #title MyContract is an example contract which requests data from
* the Chainlink network
* #dev This contract is designed to work on multiple networks, including
* local test networks
*/
contract MyContract is ChainlinkClient, ERC721 {
using Chainlink for Chainlink.Request;
address constant RINKEBY_ORACLE =
0x3A56aE4a2831C3d3514b5D7Af5578E45eBDb7a40;
bytes32 constant RINKEBY_JOB_ID =
bytes32("187bb80e5ee74a139734cac7475f3c6e");
uint256 constant FEE = 0.1 * 10**18;
uint256 public tokenCounter;
bytes32 public data;
string public image_url;
struct Clip {
string name;
string url;
}
Clip[] public clips;
mapping(bytes32 => string) public requestIdToClipName;
mapping(bytes32 => address) public requestIdToSender;
mapping(bytes32 => string) public requestIdToTokenURI;
event requestedCollectible(bytes32 indexed requestId);
mapping(bytes32 => uint256) public requestToTokenId;
mapping(uint256 => string) public tokenIdToName;
mapping(uint256 => string) public tokenIdToImgUrl;
constructor(address _link) public ERC721("Tests", "TST") {
if (_link == address(0)) {
setPublicChainlinkToken();
} else {
setChainlinkToken(_link);
}
setChainlinkOracle(0x3A56aE4a2831C3d3514b5D7Af5578E45eBDb7a40);
tokenCounter = 0;
}
function getChainlinkToken() public view returns (address) {
return chainlinkTokenAddress();
}
function createRequestTo(
string memory _url,
string memory _path,
string memory clipName
) public returns (bytes32 requestId) {
Chainlink.Request memory req = buildChainlinkRequest(
RINKEBY_JOB_ID,
address(this),
this.fulfill.selector
);
req.add("get", _url);
req.add("path", _path);
requestId = sendChainlinkRequestTo(RINKEBY_ORACLE, req, FEE);
requestIdToClipName[requestId] = clipName;
requestIdToSender[requestId] = msg.sender;
emit requestedCollectible(requestId);
return requestId;
}
function fulfill(bytes32 _requestId, bytes32 _data)
public
recordChainlinkFulfillment(_requestId)
{
address nftOwner = requestIdToSender[_requestId];
string memory name = requestIdToClipName[_requestId];
uint256 newItemId = clips.length;
data = _data;
image_url = bytes32ToString(data);
clips.push(Clip(name, image_url));
_safeMint(nftOwner, newItemId);
tokenIdToName[newItemId] = name;
tokenIdToImgUrl[newItemId] = image_url;
}
function getNumberOfClips() public view returns (uint256) {
return clips.length;
}
/**
* #notice Allows the owner to withdraw any LINK balance on the contract
*/
function withdrawLink() public {
LinkTokenInterface link = LinkTokenInterface(chainlinkTokenAddress());
require(
link.transfer(msg.sender, link.balanceOf(address(this))),
"Unable to transfer"
);
}
/**
* #notice Call this method if no response is received within 5 minutes
* #param _requestId The ID that was generated for the request to cancel
* #param _payment The payment specified for the request to cancel
* #param _callbackFunctionId The bytes4 callback function ID specified for
* the request to cancel
* #param _expiration The expiration generated for the request to cancel
*/
function cancelRequest(
bytes32 _requestId,
uint256 _payment,
bytes4 _callbackFunctionId,
uint256 _expiration
) public {
cancelChainlinkRequest(
_requestId,
_payment,
_callbackFunctionId,
_expiration
);
}
}
Here is the script I am using to deploy:
from brownie import MyContract, accounts, network, config
from scripts.helpful_scripts import fund_contract
def main():
dev = accounts.add(config['wallets']['from_key'])
print(network.show_active())
publish_source = True
my_contract = MyContract.deploy(
config['networks'][network.show_active()]['link_token'],
{"from": dev},
publish_source=publish_source
)
fund_contract(my_contract)
return my_contract
This is the error:
Transaction sent: 0x01ef409a5b0c2f6de60194f14f1d2e8ffac9a6ce6397aaa38392d949e2656909
Gas price: 1.000000008 gwei Gas limit: 2793499 Nonce: 359
MyContract.constructor confirmed Block: 9332417 Gas used: 2539545 (90.91%)
MyContract deployed at: 0x42fBa06808C3cB11e5D7AcC6BB02B1A612e040d1
File "brownie/_cli/run.py", line 49, in main
return_value, frame = run(
File "brownie/project/scripts.py", line 103, in run
return_value = f_locals[method_name](*args, **kwargs)
File "./scripts/deploy_api.py", line 11, in main
my_contract = MyContract.deploy(
File "brownie/network/contract.py", line 600, in __call__
return tx["from"].deploy(
File "brownie/network/account.py", line 555, in deploy
contract.publish_source(deployed_contract, silent=silent)
File "brownie/network/contract.py", line 410, in publish_source
contract_info = self.get_verification_info()
File "brownie/network/contract.py", line 292, in get_verification_info
if symbol_alias["local"] is not None:
KeyError: 'local'
Two points going on here:
Brownie Etherscan verification doesn't work well with Solidity v0.8. Work is being done to fix this issue.
Looks like you are deploying to a local network instead of Rinkeby. Either remove publish_source when deploying locally or add --network rinkeby to the end of your deploy script to deploy to Rinkeby.
Related
I'm trying to deploy my contract to the goerli testnet however hardhat keeps throwing this error:
Error: cannot estimate gas; transaction may fail or may require manual gas limit [ See: https://links.ethers.org/v5-errors-UNPREDICTABLE_GAS_LIMIT ] (reason="execution reverted", method="estimateGas", transaction={"from":"0xb5E8683Aa524069C5714Fc2D8c3e64F78f2862fb","data":"0x6103e86009556... (I shortened it down)","accessList":null}, error={"name":"ProviderError","_stack":"ProviderError: HttpProviderError\n at HttpProvider.request (C:\\Programming\\Personal Projects\\NFT Minting Dapp\\smart-contract\\node_modules\\hardhat\\src\\internal\\core\\providers\\http.ts:78:19)\n at LocalAccountsProvider.request (C:\\Programming\\Personal Projects\\NFT Minting Dapp\\smart-contract\\node_modules\\hardhat\\src\\internal\\core\\providers\\accounts.ts:187:34)\n at processTicksAndRejections (node:internal/process/task_queues:95:5)\n at async EthersProviderWrapper.send (C:\\Programming\\Personal Projects\\NFT Minting Dapp\\smart-contract\\node_modules\\#nomiclabs\\hardhat-ethers\\src\\internal\\ethers-provider-wrapper.ts:13:20)","code":3,"_isProviderError":true,"data":"0xbfc6c337000000000000000000000000fd7bfa171b5b81b79c245456e986db2f32fbfadb"}, code=UNPREDICTABLE_GAS_LIMIT, version=providers/5.7.2)
at Logger.makeError (C:\Programming\Personal Projects\NFT Minting Dapp\smart-contract\node_modules\#ethersproject\logger\src.ts\index.ts:269:28)
at Logger.throwError (C:\Programming\Personal Projects\NFT Minting Dapp\smart-contract\node_modules\#ethersproject\logger\src.ts\index.ts:281:20)
at checkError (C:\Programming\Personal Projects\NFT Minting Dapp\smart-contract\node_modules\#ethersproject\providers\src.ts\json-rpc-provider.ts:78:20)
at EthersProviderWrapper.<anonymous> (C:\Programming\Personal Projects\NFT Minting Dapp\smart-contract\node_modules\#ethersproject\providers\src.ts\json-rpc-provider.ts:642:20)
at step (C:\Programming\Personal Projects\NFT Minting Dapp\smart-contract\node_modules\#ethersproject\providers\lib\json-rpc-provider.js:48:23)
at Object.throw (C:\Programming\Personal Projects\NFT Minting Dapp\smart-contract\node_modules\#ethersproject\providers\lib\json-rpc-provider.js:29:53)
at rejected (C:\Programming\Personal Projects\NFT Minting Dapp\smart-contract\node_modules\#ethersproject\providers\lib\json-rpc-provider.js:21:65)
at processTicksAndRejections (node:internal/process/task_queues:95:5) {
reason: 'execution reverted',
code: 'UNPREDICTABLE_GAS_LIMIT',
method: 'estimateGas',
transaction: {
from: '0xb5E8683Aa524069C5714Fc2D8c3e64F78f2862fb',
data: '0x6103e86009556... (I shortened it down)',
accessList: null
}
Here is my contract:
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.15;
/// #title John's ERC721A Contract
/// #author John Pioc (www.johnpioc.com)
/// #notice This contract can be used to mint ERC721A standard NFTs with industry standard functionality - whitelisted addresses, reveals, NFT metadata, etc.
import "erc721a/contracts/ERC721A.sol";
import "#openzeppelin/contracts/access/Ownable.sol";
import "#openzeppelin/contracts/utils/Strings.sol";
import "#openzeppelin/contracts/utils/cryptography/MerkleProof.sol";
import {DefaultOperatorFilterer} from "./DefaultOperatorFilterer.sol";
error CallerIsNotUser();
error InvalidWhitelistAllocation();
error MintingTooMany();
error InsufficientFunds();
error MintingOverCollectionSize();
error SaleIsClosed();
error MintingOverWhitelistAllocation();
error InvalidProof();
error URIQueryForNonexistentToken();
contract NFT is ERC721A, Ownable, DefaultOperatorFilterer {
using Strings for uint256;
enum SaleState {
CLOSED,
WHITELIST,
PUBLIC
}
uint256 public collectionSize = 1000;
uint256 public publicMintPrice = 0.1 ether;
uint256 public publicMaxMintAmount = 3;
uint256 public whitelistAllocation = 500;
uint256 public whitelistMintPrice = 0.05 ether;
uint256 public whitelistMaxMintAmount = 1;
bytes32 public whitelistMerkleRoot;
string public unrevealedUri = "https://exampleUnrevealedUri.com";
string public baseUri = "https://exampleUri.com/";
bool public isRevealed;
SaleState public saleState;
/// #notice Modifier to verify that caller doesn't come from a contract
modifier callerIsUser() {
if (tx.origin != msg.sender) revert CallerIsNotUser();
_;
}
constructor() ERC721A ("NFT", "NFT") {
isRevealed = false;
saleState = SaleState.CLOSED;
}
/// #notice Function to mint NFTs during the public sale
/// #param _mintAmount Number of NFTs to mint
function publicMint(uint64 _mintAmount) public payable callerIsUser {
if (_numberMinted(msg.sender) - _getAux(msg.sender) + _mintAmount > publicMaxMintAmount) revert MintingTooMany();
if (totalSupply() + _mintAmount > collectionSize) revert MintingOverCollectionSize();
if (saleState != SaleState.PUBLIC) revert SaleIsClosed();
if (msg.value < _mintAmount * publicMintPrice) revert InsufficientFunds();
_safeMint(msg.sender, _mintAmount);
}
/// #notice Function to mint NFTs during the whitelist sale
/// #param _merkleProof Merkle Proof for caller's address
/// #param _mintAmount Number of NFTs to mint
function whitelistMint(bytes32[] calldata _merkleProof, uint64 _mintAmount) public payable callerIsUser {
if (_getAux(msg.sender) + _mintAmount > whitelistMaxMintAmount) revert MintingTooMany();
if (totalSupply() + _mintAmount > whitelistAllocation) revert MintingOverWhitelistAllocation();
if (saleState != SaleState.WHITELIST) revert SaleIsClosed();
if (msg.value < _mintAmount * whitelistMintPrice) revert InsufficientFunds();
bytes32 leaf = keccak256(abi.encodePacked(msg.sender));
if(!(MerkleProof.verify(_merkleProof, whitelistMerkleRoot, leaf))) revert InvalidProof();
_setAux(msg.sender, _getAux(msg.sender) + _mintAmount);
_safeMint(msg.sender, _mintAmount);
}
/// #notice Sets a new collection size
/// #dev Only owner can call this function
/// #param _collectionSize New Collection Size
function setCollectionSize(uint256 _collectionSize) public onlyOwner {
collectionSize = _collectionSize;
}
/// #notice Sets a new public mint price
/// #dev Only owner can call this function
/// #param _publicMintPrice New public mint price
function setPublicMintPrice(uint256 _publicMintPrice) public onlyOwner {
publicMintPrice = _publicMintPrice;
}
/// #notice Sets a new public max mint amount
/// #dev Only owner can call this function
/// #param _publicMaxMintAmount New public max mint amount
function setPublicMaxMintAmount(uint256 _publicMaxMintAmount) public onlyOwner {
publicMaxMintAmount = _publicMaxMintAmount;
}
/// #notice Sets a new whitelist allocation
/// #dev Only owner can call this function. New whitelist allocation cannot be greater than collection size
/// #param _whitelistAllocation New whitelist allocation
function setWhitelistAllocation(uint256 _whitelistAllocation) public onlyOwner {
if (_whitelistAllocation > collectionSize) revert InvalidWhitelistAllocation();
whitelistAllocation = _whitelistAllocation;
}
/// #notice Sets a new whitelist mint price
/// #dev Only owner can call this function
/// #param _whitelistMintPrice New whitelist mint price
function setWhitelistMintPrice(uint256 _whitelistMintPrice) public onlyOwner {
whitelistMintPrice = _whitelistMintPrice;
}
/// #notice Sets a new whitelist max mint amount
/// #dev Only owner can call this function
/// #param _whitelistMaxMintAmount New whitelist max mint amount
function setWhitelistMaxMintAmount(uint256 _whitelistMaxMintAmount) public onlyOwner {
whitelistMaxMintAmount = _whitelistMaxMintAmount;
}
/// #notice Sets a new whitelist merkle root
/// #dev Only owner can call this function
/// #param _whitelistMerkleRoot New whitelist merkle root
function setWhitelistMerkleRoot(bytes32 _whitelistMerkleRoot) public onlyOwner {
whitelistMerkleRoot = _whitelistMerkleRoot;
}
/// #notice Sets a new unrevealed URI
/// #dev Only owner can call this function
/// #param _unrevealedUri New unrevealed URI
function setUnrevealedUri(string memory _unrevealedUri) public onlyOwner {
unrevealedUri = _unrevealedUri;
}
/// #notice Sets a new base URI
/// #dev Only owner can call this function
/// #param _baseUri New base URI
function setBaseUri(string memory _baseUri) public onlyOwner {
baseUri = _baseUri;
}
/// #notice Toggles reveal from false to true, vice versa
/// #dev Only owner can call this function. Starts at false
function toggleRevealed() public onlyOwner {
isRevealed = !isRevealed;
}
/// #notice Sets a new sale state
/// #dev Only owner can call this function. 0 = CLOSED, 1 = WHITELIST, 2 = PUBLIC
/// #param _saleState new sale state
function setSaleState(uint256 _saleState) public onlyOwner {
saleState = SaleState(_saleState);
}
/// #notice Generates and returns the token URI for a given token ID
/// #param _tokenId An NFT's token ID
function tokenURI(uint256 _tokenId) public view override returns (string memory) {
if (!_exists(_tokenId)) revert URIQueryForNonexistentToken();
if (!isRevealed) return unrevealedUri;
return string(abi.encodePacked(baseUri, _tokenId.toString(), ".json"));
}
/// #notice Withdraws all ETH from contract to owner's address
/// #dev Only owner can call this function
function withdraw() public payable onlyOwner {
(bool os,) = payable(owner()).call{value: address(this).balance}("");
require(os);
}
/// #notice All functions below are mandatory add-ons as per the Default Operator Filterer protocol
function transferFrom(address from, address to, uint256 tokenId) public payable override onlyAllowedOperator(from) {
super.transferFrom(from, to, tokenId);
}
function safeTransferFrom(address from, address to, uint256 tokenId) public payable override onlyAllowedOperator(from) {
super.safeTransferFrom(from, to, tokenId);
}
function safeTransferFrom(address from, address to, uint256 tokenId, bytes memory data)
public
payable
override
onlyAllowedOperator(from)
{
super.safeTransferFrom(from, to, tokenId, data);
}
}
Here is my config file:
import { HardhatUserConfig } from "hardhat/config";
import "#nomicfoundation/hardhat-toolbox";
import "#nomiclabs/hardhat-waffle";
import "dotenv/config";
import "#typechain/hardhat";
const GOERLI_RPC_URL = process.env.GOERLI_RPC_URL;
const PRIVATE_KEY = process.env.PRIVATE_KEY;
const ETHERSCAN_API_KEY = process.env.ETHERSCAN_API_KEY;
const config: HardhatUserConfig = {
solidity: {
version: "0.8.17",
settings: {
optimizer: {
enabled: true,
runs: 200
}
}
},
networks: {
goerli: {
url: GOERLI_RPC_URL,
accounts: [PRIVATE_KEY!],
chainId: 5,
allowUnlimitedContractSize: true,
}
},
etherscan: {
apiKey: {
goerli: ETHERSCAN_API_KEY!
}
}
};
export default config;
and here is my deploy script:
// imports
import { ethers, run, network } from 'hardhat';
// async main
async function main() {
const contractFactory = await ethers.getContractFactory("NFT");
const contract = await contractFactory.deploy();
console.log(`Contract deployed to ${contract.address}`);
if (network.config.chainId === 5 && process.env.ETHERSCAN_API_KEY) {
console.log("Waiting for block confirmations...")
await contract.deployTransaction.wait(6)
await verify(contract.address, [])
}
}
// async function verify(contractAddress, args) {
const verify = async (contractAddress: string, args: any[]) => {
console.log("Verifying contract...")
try {
await run("verify:verify", {
address: contractAddress,
constructorArguments: args,
})
} catch (e: any) {
if (e.message.toLowerCase().includes("already verified")) {
console.log("Already Verified!")
} else {
console.log(e)
}
}
}
// main
main()
.then(() => process.exit(0))
.catch((error) => {
console.error(error)
process.exit(1)
})
I ran the command:
npx hardhat run scripts/deploy.ts --network goerli
And by running that command, it throws the error. I double checked that the it's grabbing the environment variables and everything. I actually forked all this code from one of my repos where the deploy script worked back then, however now it's not
I've had some similar issues when using hardhat to deploy for both goerli and mainnet. What seemed to solve it for me is manually adding in a gas limit and gas price, here is what your goerli config object should look like, just be aware you'll want to adjust the limit and price to account for current gas prices.
goerli: {
url: GOERLI_RPC_URL,
accounts: [PRIVATE_KEY!],
chainId: 5,
allowUnlimitedContractSize: true,
gas: 5000000, //units of gas you are willing to pay, aka gas limit
gasPrice: 50000000000, //gas is typically in units of gwei, but you must enter it as wei here
}
Reading the hardhat config docs is also worth a look here
Check the eth gas tracker to see up to date gas price estimates
I am practising this tutorial in Remix IDE - https://www.youtube.com/watch?v=_aXumgdpnPU
I saw in the Chainlink documentation that their Randomness VRF code has been changed since the development of the video.
I started replacing the parts and trying to deploy the class via Remix but it gives an error which I am not sure how to fix.
Would you be able to check what I have as code and I'll send a screenshot of the error?
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.11;
import "#chainlink/contracts/src/v0.8/ConfirmedOwner.sol";
import "#chainlink/contracts/src/v0.8/VRFV2WrapperConsumerBase.sol";
contract Lottery is
VRFV2WrapperConsumerBase,
ConfirmedOwner
{
address public owner;
address payable[] public players;
uint public lotteryId;
mapping (uint => address payable) public lotteryHistory;
event RequestSent(uint256 requestId, uint32 numWords);
event RequestFulfilled(
uint256 requestId,
uint256[] randomWords,
uint256 payment
);
struct RequestStatus {
uint256 paid; // amount paid in link
bool fulfilled; // whether the request has been successfully fulfilled
uint256[] randomWords;
}
mapping(uint256 => RequestStatus)
public s_requests; /* requestId --> requestStatus */
// past requests Id.
uint256[] public requestIds;
uint256 public lastRequestId;
// Depends on the number of requested values that you want sent to the
// fulfillRandomWords() function. Test and adjust
// this limit based on the network that you select, the size of the request,
// and the processing of the callback request in the fulfillRandomWords()
// function.
uint32 callbackGasLimit = 100000;
// The default is 3, but you can set this higher.
uint16 requestConfirmations = 3;
// For this example, retrieve 2 random values in one request.
// Cannot exceed VRFV2Wrapper.getConfig().maxNumWords.
uint32 numWords = 2;
// Address LINK - hardcoded for Goerli
address linkAddress = 0x326C977E6efc84E512bB9C30f76E30c160eD06FB;
// address WRAPPER - hardcoded for Goerli
address wrapperAddress = 0x708701a1DfF4f478de54383E49a627eD4852C816;
constructor()
ConfirmedOwner(msg.sender)
VRFV2WrapperConsumerBase(linkAddress, wrapperAddress)
{
owner = msg.sender;
lotteryId = 1;
}
function requestRandomWords()
external
onlyOwner
returns (uint256 requestId)
{
requestId = requestRandomness(
callbackGasLimit,
requestConfirmations,
numWords
);
s_requests[requestId] = RequestStatus({
paid: VRF_V2_WRAPPER.calculateRequestPrice(callbackGasLimit),
randomWords: new uint256[](0),
fulfilled: false
});
requestIds.push(requestId);
lastRequestId = requestId;
emit RequestSent(requestId, numWords);
return requestId;
}
function fulfillRandomWords(
uint256 _requestId,
uint256[] memory _randomWords
) internal override {
require(s_requests[_requestId].paid > 0, "request not found");
s_requests[_requestId].fulfilled = true;
s_requests[_requestId].randomWords = _randomWords;
emit RequestFulfilled(
_requestId,
_randomWords,
s_requests[_requestId].paid
);
payWinner();
}
function getRequestStatus(
uint256 _requestId
)
external
view
returns (uint256 paid, bool fulfilled, uint256[] memory randomWords)
{
require(s_requests[_requestId].paid > 0, "request not found");
RequestStatus memory request = s_requests[_requestId];
return (request.paid, request.fulfilled, request.randomWords);
}
/**
* Allow withdraw of Link tokens from the contract
*/
function withdrawLink() public onlyOwner {
LinkTokenInterface link = LinkTokenInterface(linkAddress);
require(
link.transfer(msg.sender, link.balanceOf(address(this))),
"Unable to transfer"
);
}
function getWinnerByLottery(uint lottery) public view returns (address payable) {
return lotteryHistory[lottery];
}
function getBalance() public view returns (uint) {
return address(this).balance;
}
function getPlayers() public view returns (address payable[] memory) {
return players;
}
function enter() public payable {
require(msg.value > .01 ether);
// address of player entering lottery
players.push(payable(msg.sender));
}
//function getRandomNumber() public view returns (uint) {
//return uint(keccak256(abi.encodePacked(owner, block.timestamp)));
//}
function pickWinner() public onlyowner {
requestRandomWords;
}
function payWinner() public {
uint index = lastRequestId % players.length;
players[index].transfer(address(this).balance);
lotteryHistory[lotteryId] = players[index];
lotteryId++;
// reset the state of the contract
players = new address payable[](0);
}
modifier onlyowner() {
require(msg.sender == owner);
_;
}
}
enter image description here
I'm new to smart contract and Solidity programming and I've been trying to deploy an NFT contract on goerli testnet. The contract deploys without any problem but when I try to call the "createCollectible" function, I get the following error:
Gas estimation errored with the following message (see below). The transaction execution will likely fail. Do you want to force sending?
execution reverted
{
"originalError": {
"code": 3,
"data": "0xf0019fe60000000000000000000000000000000000000000000000000000000000000c6a000000000000000000000000b54644506388a04187d943dbbbd3edbb3ee53094",
"message": "execution reverted"
}
}
Here is my contract:
// SPDX-License-Identifier: MIT
pragma solidity >=0.6.0 <0.9.0;
import "#openzeppelin/contracts/token/ERC721/ERC721.sol";
import "#chainlink/contracts/src/v0.8/VRFConsumerBaseV2.sol";
import "#chainlink/contracts/src/v0.8/interfaces/LinkTokenInterface.sol";
import "#chainlink/contracts/src/v0.8/interfaces/VRFCoordinatorV2Interface.sol";
/**
* #title The AdvandedCollectible contract
* #notice A contract that mints an NFT
*/
contract AdvancedCollectible is ERC721, VRFConsumerBaseV2 {
VRFCoordinatorV2Interface immutable COORDINATOR;
LinkTokenInterface immutable LINKTOKEN;
uint256 public tokenCounter;
uint64 immutable s_subscriptionId;
// The gas lane to use, which specifies the maximum gas price to bump to.
// For a list of available gas lanes on each network,
// see https://docs.chain.link/docs/vrf-contracts/#configurations
bytes32 immutable s_keyhash;
uint32 immutable s_numWords = 1;
uint16 immutable s_requestConfirmations = 3;
// Depends on the number of requested values that you want sent to the
// fulfillRandomWords() function. Storing each word costs about 20,000 gas,
// so 100,000 is a safe default for this example contract. Test and adjust
// this limit based on the network that you select, the size of the request,
// and the processing of the callback request in the fulfillRandomWords()
// function.
uint32 immutable s_callbackGasLimit = 100000;
uint256 public s_requestId;
uint256 public s_randomWords;
address s_owner;
enum Breed {
PUG,
SHIBA_INU,
ST_BERNARD
}
mapping(uint256 => Breed) public tokenIdToBreed;
mapping(uint256 => address) public requestIdToSender;
event requestCollectible(uint256 indexed requestId, address requester);
event breedAssigned(uint256 tokenId, Breed breed);
constructor(
address vrfCoordinator,
address link,
bytes32 keyhash,
uint64 subscriptionId
) VRFConsumerBaseV2(vrfCoordinator) ERC721("Dogie", "DOG") {
tokenCounter = 0;
COORDINATOR = VRFCoordinatorV2Interface(vrfCoordinator);
LINKTOKEN = LinkTokenInterface(link);
s_keyhash = keyhash;
s_owner = msg.sender;
s_subscriptionId = subscriptionId;
}
modifier onlyOwner() {
require(msg.sender == s_owner, "You are not the owner");
_;
}
function createCollectible() public returns (uint256) {
s_requestId = COORDINATOR.requestRandomWords(
s_keyhash,
s_subscriptionId,
s_requestConfirmations,
s_callbackGasLimit,
s_numWords
);
requestIdToSender[s_requestId] = msg.sender;
emit requestCollectible(s_requestId, msg.sender);
}
function fulfillRandomWords(uint256 requestId, uint256[] memory randomWords)
internal
override
{
s_randomWords = randomWords[0];
Breed breed = Breed(s_randomWords % 3);
uint256 newTokenId = tokenCounter;
tokenIdToBreed[newTokenId] = breed;
emit breedAssigned(newTokenId, breed);
address owner = requestIdToSender[requestId];
_safeMint(owner, newTokenId);
tokenCounter++;
}
function setTokenURI(uint256 tokenId, string memory _tokenURI) public {
require(
_isApprovedOrOwner(_msgSender(), tokenId),
"ERC721: Caller is not owner nor approved."
);
setTokenURI(tokenId, _tokenURI);
}
}
Does anybody have an idea what I'm doing wrong here?
So I realized that I'm missing one small yet important step, and that is adding a consumer to my subscription.
Using the Chainlink VRF V2, you need to create a subscription, add funds to that subscription and add the address where your contract is deployed at as a consumer to the subscription. I wasn't doing that last step and that's why my transaction's execution kept reverting.
I've altered the chainlink APIconsumer example to read a JSON file which contains data that I wish to bring into and store in the smart contract
pragma solidity ^0.6.0;
import "https://raw.githubusercontent.com/smartcontractkit/chainlink/develop/evm-contracts/src/v0.6/ChainlinkClient.sol";
contract APIConsumer is ChainlinkClient {
string public Name;
address private oracle;
bytes32 private jobId;
uint256 private fee;
/**
* Network: Kovan
* Oracle: Chainlink - 0x2f90A6D021db21e1B2A077c5a37B3C7E75D15b7e
* Job ID: Chainlink - 50fc4215f89443d185b061e5d7af9490
* Fee: 0.1 LINK
*/
constructor() public {
setPublicChainlinkToken();
oracle = 0x2f90A6D021db21e1B2A077c5a37B3C7E75D15b7e;
jobId = "50fc4215f89443d185b061e5d7af9490";
fee = 0.1 * 10 ** 18; // 0.1 LINK
}
/**
* Create a Chainlink request to retrieve API response, find the target price
* data, then multiply by 100 (to remove decimal places from price).
*/
function requestAthleteData() 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://1e68b62e-578e-4390-bf43-6b70a92a23b6.mock.pstmn.io/get");
// Set the path to find the desired data in the API response, where the response format is:
// {"USD":243.33}
request.add("path", "Name");
// Multiply the result by 100 to remove decimals
// request.addInt("times", 100);
// Sends the request
return sendChainlinkRequestTo(oracle, request, fee);
}
/**
* Receive the response in the form of uint256
*/
function fulfill(bytes32 _requestId, string memory _name) public recordChainlinkFulfillment(_requestId)
{
Name = _name;
}
}
This is the data its trying to read:
https://1e68b62e-578e-4390-bf43-6b70a92a23b6.mock.pstmn.io/get
[ { "Name": "Tom", "Birthday": "2021-07-01", "Nationality": "SA", "Address": "123 st st" } ]
It has no problems deploying but then when I call the function 'requesttAthletedata' it processes it but doesn't return anything. Am I missing a step somewhere? Or is it a problem with the code?
First, change the _name argument in fulfill() to bytes32.
Second, change your request path to this:
request.add("path", "0.Name");
Chainlink cannot currently write strings to a smart contract, only bytes32 which can then be converted into a string. Also, your JSON object was within an array (at the first index) which is why we need to specify "0.Name" as the JSON path.
Third, if you want to convert the bytes32 to a string within the smart contract, you will need to do it within the fulfill() method.
Your final code should look like this:
pragma solidity ^0.6.0;
import "#chainlink/contracts/src/v0.6/ChainlinkClient.sol";
contract test is ChainlinkClient {
string public Name;
address private oracle;
bytes32 private jobId;
uint256 private fee;
/**
* Network: Kovan
* Oracle: Chainlink - 0x2f90A6D021db21e1B2A077c5a37B3C7E75D15b7e
* Job ID: Chainlink - 50fc4215f89443d185b061e5d7af9490
* Fee: 0.1 LINK
*/
constructor() public {
setPublicChainlinkToken();
oracle = 0x2f90A6D021db21e1B2A077c5a37B3C7E75D15b7e;
jobId = "50fc4215f89443d185b061e5d7af9490";
fee = 0.1 * 10 ** 18; // 0.1 LINK
}
/**
* Create a Chainlink request to retrieve API response, find the target price
* data, then multiply by 100 (to remove decimal places from price).
*/
function requestAthleteData() 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://1e68b62e-578e-4390-bf43-6b70a92a23b6.mock.pstmn.io/get");
// Set the path to find the desired data in the API response, where the response format is:
// {"USD":243.33}
request.add("path", "0.Name");
// Multiply the result by 100 to remove decimals
// request.addInt("times", 100);
// Sends the request
return sendChainlinkRequestTo(oracle, request, fee);
}
/**
* Receive the response in the form of uint256
*/
function bytes32ToString(bytes32 _bytes32) public pure returns (string memory) {
uint8 i = 0;
while(i < 32 && _bytes32[i] != 0) {
i++;
}
bytes memory bytesArray = new bytes(i);
for (i = 0; i < 32 && _bytes32[i] != 0; i++) {
bytesArray[i] = _bytes32[i];
}
return string(bytesArray);
}
function fulfill(bytes32 _requestId, bytes32 _name) public recordChainlinkFulfillment(_requestId)
{
string memory stringName = bytes32ToString(_name);
Name = stringName;
}
}
I'm trying to implement PatrickAlpha NFT implementation Github. When I followed readme instructions, collectibles are minted correctly. But If I tried to change anything in the code , it gives me error like this.
Compiling contracts...
Solc version: 0.6.6
Optimizer: Enabled Runs: 200
EVM Version: Istanbul
CompilerError: solc returned the following errors:
/Users/batuhansesli/.brownie/packages/smartcontractkit/chainlink-brownie-contracts#1.0.2/contracts/src/v0.6/VRFConsumerBase.sol:2:1: ParserError: Source file requires different compiler version (current compiler is 0.6.6+commit.6c089d02.Darwin.appleclang - note that nightly builds are considered to be strictly less than the released version
pragma solidity 0.6.0;
^--------------------^
For debug, I tried to change only ERC721 constructor parameters, but error occured again.
Original Code:
pragma solidity 0.6.6;
import "#openzeppelin/contracts/token/ERC721/ERC721.sol";
import "#chainlink/contracts/src/v0.6/VRFConsumerBase.sol";
contract AdvancedCollectible is ERC721, VRFConsumerBase {
uint256 public tokenCounter;
enum Breed{PUG, SHIBA_INU, ST_BERNARD}
// add other things
mapping(bytes32 => address) public requestIdToSender;
mapping(bytes32 => string) public requestIdToTokenURI;
mapping(uint256 => Breed) public tokenIdToBreed;
mapping(bytes32 => uint256) public requestIdToTokenId;
event requestedCollectible(bytes32 indexed requestId);
bytes32 internal keyHash;
uint256 internal fee;
constructor(address _VRFCoordinator, address _LinkToken, bytes32 _keyhash)
public
VRFConsumerBase(_VRFCoordinator, _LinkToken)
ERC721("Dogie", "DOG")
{
tokenCounter = 0;
keyHash = _keyhash;
fee = 0.1 * 10 ** 18;
}
function createCollectible(string memory tokenURI, uint256 userProvidedSeed)
public returns (bytes32){
bytes32 requestId = requestRandomness(keyHash, fee, userProvidedSeed);
requestIdToSender[requestId] = msg.sender;
requestIdToTokenURI[requestId] = tokenURI;
emit requestedCollectible(requestId);
}
function fulfillRandomness(bytes32 requestId, uint256 randomNumber) internal override {
address dogOwner = requestIdToSender[requestId];
string memory tokenURI = requestIdToTokenURI[requestId];
uint256 newItemId = tokenCounter;
_safeMint(dogOwner, newItemId);
_setTokenURI(newItemId, tokenURI);
Breed breed = Breed(randomNumber % 3);
tokenIdToBreed[newItemId] = breed;
requestIdToTokenId[requestId] = newItemId;
tokenCounter = tokenCounter + 1;
}
function setTokenURI(uint256 tokenId, string memory _tokenURI) public {
require(
_isApprovedOrOwner(_msgSender(), tokenId),
"ERC721: transfer caller is not owner nor approved"
);
_setTokenURI(tokenId, _tokenURI);
}
}
My Code :
pragma solidity 0.6.6;
import "#openzeppelin/contracts/token/ERC721/ERC721.sol";
import "#chainlink/contracts/src/v0.6/VRFConsumerBase.sol";
contract FootballerCollectible is ERC721, VRFConsumerBase {
bytes32 internal keyHash;
uint256 public fee;
uint256 public tokenCounter;
enum Player{MBAPPE, NEYMAR, MESSI, RONALDO}
mapping (bytes32 => address) public requestIdToSender;
mapping (bytes32 => string) public requestIdToTokenURI;
mapping (uint256 => Player) public tokenIdToPlayer;
event requestedCollectible(bytes32 indexed requestId);
constructor(address _VRFCoordinator, address _LinkToken, bytes32 _keyhash) public
VRFConsumer(_VRFCoordinator, _LinkToken)
ERC721("Footballer", "FTC")
{
keyHash = _keyhash;
fee = 0.1 * 10 ** 18;
tokenCounter = 0;
}
function createCollectible(uint256 userProvidedSeed, string memory tokenURI)
public returns (bytes32) {
bytes32 requestId = requestRandomness(keyHash, fee, userProvidedSeed);
requestIdToSender[requestId] = msg.sender;
requestIdToTokenURI[requestId] = tokenURI;
emit requestedCollectible(requestId);
}
function fulfillRandomness(bytes32 requestId, uint256 randomNumber) internal override{
address cardOwner = requestIdToSender[requestId];
string memory tokenURI = requestIdToTokenURI[requestId];
uint256 newItemId = tokenCounter;
_safeMint(cardOwner, newItemId);
_setTokenURI(newItemId, tokenURI);
Player player = Player(randomNumber % 4);
tokenIdToPlayer[newItemId] = player;
requestIdToTokenId[requestId] = newItemId;
tokenCounter = tokenCounter + 1;
}
function setTokenURI(uint256 tokenId, string memory _tokenURI) public {
require(
_isApprovedOrOwner(_msgSender(), tokenId),
"ERC721: transfer caller is not owner nor approved"
);
_setTokenURI(tokenId, _tokenURI);
}
}
Hi :) In the Error message that you received
Blockquote ParserError: Source file requires different compiler version (current compiler is 0.6.6+commit.6c089d02.Darwin.appleclang - note that nightly builds are considered to be strictly less than the released version
pragma solidity 0.6.0;
it says that you are trying to compile your contract with a different version of pragma solidity. The smart contract in question is:
[https://github.com/smartcontractkit/chainlink-brownie-contracts/blob/main/contracts/src/v0.6/VRFConsumerBase.sol]
which is using
pragma solidity ^0.6.0;
You are specifying to use version 0.6.6 in your contract which is later than the selected compiler. To get around this, you can either drop down to ^0.6.0 or you can change your pragma to
pragma solidity ^0.6.0;
For more information, you can read this ticket