I've been learning the chainlink API and trying to modify the example from the Chainlin's documentation to get a byets32 value from an API. The original code of the example works well, but since the API I was hitting is returning a byets32 foem, the Chainlink job need to be configured to handle this type of return. The node is given here with Kovan testnet. Here is my code
pragma solidity ^0.8.7;
import "#chainlink/contracts/src/v0.8/ChainlinkClient.sol";
/**
* Request testnet LINK and ETH here: https://faucets.chain.link/
* Find information on LINK Token Contracts and get the latest ETH and LINK faucets here: https://docs.chain.link/docs/link-token-contracts/
*/
/**
* THIS IS AN EXAMPLE CONTRACT WHICH USES HARDCODED VALUES FOR CLARITY.
* PLEASE DO NOT USE THIS CODE IN PRODUCTION.
*/
contract APIConsumer is ChainlinkClient {
using Chainlink for Chainlink.Request;
//Result of the api
bytes32 public martket;
address private oracle;
bytes32 private jobId;
uint256 private fee;
/**
* Get -> bytes32
* Network: Kovan
* Oracle: 0xc57B33452b4F7BB189bB5AfaE9cc4aBa1f7a4FD8 (Chainlink Devrel
* Node)
* Job ID: 7401f318127148a894c00c292e486ffd
* Fee: 0.1 LINK
*/
constructor() {
setPublicChainlinkToken();
// Get -> bytes32 node taken from documentation
oracle = 0xc57B33452b4F7BB189bB5AfaE9cc4aBa1f7a4FD8;
jobId = "7401f318127148a894c00c292e486ffd";
fee = 0.1 * 10 ** 18; // (Varies by network and job)
}
/**
* Create a Chainlink request to retrieve API response, find the target
* data, then multiply by 1000000000000000000 (to remove decimal places from data).
*/
function requestVolumeData() 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://min-api.cryptocompare.com/data/pricemultifull?fsyms=ETH&tsyms=USD");
// Set the path to find the desired data in the API response, where the response format is:
// {"RAW":
// {"ETH":
// {"USD":
// {
// "MARKET": "CCCAGG",
// }
// }
// }
// }
//Get the MARKET field of API
request.add("path", "RAW,ETH,USD,MARKET"); // Chainlink nodes 1.0.0 and later support this format
// Sends the request
return sendChainlinkRequestTo(oracle, request, fee);
}
/**
* Receive the response in the form of bytes32
*/
function fulfill(bytes32 _requestId, bytes32 _market) public recordChainlinkFulfillment(_requestId)
{
martket = _market;
}
// function withdrawLink() external {} - Implement a withdraw function to avoid locking your LINK in the contract
}
The value of market should be a byets32 reprsenting "CCCAGG" as shown in the API. But what I got was just 0x0...00 all the time, which means market has not been modified yet. I've checked this various ways and found out that the fulfill function never get rans. Then same thing happens when I changed the jobId and oracle to handle get-> int256, get -> bool (of course I did change the return type of the variable such that it's consistent with the returning form of API). I also noticed that only the job get -> uint256 works well (the example from documentation also used this job). Does anyon know why? Was my code wrong or the problem came from the node/job? Since I was able the get the example right, I don't think the problem cam from my wallet.
Any help would be appreciated!
You can test with a GET>STRING JOB
Go to this link: https://docs.chain.link/docs/any-api-testnet-oracles/
Take the Oracle contract address relevant to your network. For instance: 0xCC79157eb46F5624204f47AB42b3906cAA40eaB7 for Goerli
Use a Get>String job: 7d80a6386ef543a3abb52817f6707e3b
Make sure that your callback function expects to receive a string. (see a full example here: https://docs.chain.link/docs/api-array-response/)
Related
Total beginner here apologies in advance.
I'm learning Solidity and using Hardhat and trying to figure out how to return the value of the Chainlink price feed in this tutorial contract after deployment. I know how to return the function output in remix but having trouble figuring out how to use console.log or another method in Hardhat. I am able to use console.log for built in functions like token address but can't figure out how to apply to other functions. This is using the Goerli Testnet btw.
// SPDX-License-Identifier: MIT
pragma solidity 0.8.0;
import "#chainlink/contracts/src/v0.8/interfaces/AggregatorV3Interface.sol";
contract TestChainlink {
AggregatorV3Interface internal priceFeed;
constructor() {
// ETH / USD
priceFeed = AggregatorV3Interface(0xD4a33860578De61DBAbDc8BFdb98FD742fA7028e);
}
function getLatestPrice() public view returns (int) {
(
uint80 roundID,
int price,
uint startedAt,
uint timeStamp,
uint80 answeredInRound
) = priceFeed.latestRoundData();
// for ETH / USD price is scaled up by 10 ** 8
return price;
}
}
I tried emulating console.log usage that work for built in functions like token address to apply them to the Chainlink getLatestPrice() function.
const Token = await ethers.getContractFactory("TestChainlink");
const token = await Token.deploy();
console.log("Token address:", token.address);
i.e.
I tried a ton of different combinations this was the last one I will spare all the error messages since it probably isn't a complex solve for a non novice.
console.log("ETH Price:", getLatestPrice());
try
let price = await token.getLatestPrice();
console.log(`Eth price is: ${price}`);
I am very new to Solidity, and have recently been working on trying to learn the ropes. For reference, I have been using code from this video (https://www.youtube.com/watch?v=tBMk1iZa85Y) as a primer after having gone through the basic crypto zombies tutorial series.
I have been attempting to adapt the Solidity contract code presented in this video (which I had functioning just fine!) to require a Burn of a specified amount of an ERC-20 token before minting an NFT as an exercise for myself. I thought I had what should be a valid implementation which compiled in Remix, and then deployed to Rinkeby. I call the allowAccess function in Remix after deploying to Rinkeby, and that succeeds. But, when I call the mint function with the two parameters, I get: "gas estimation errored with the following message (see below). The transaction execution will likely fail. Do you want to force sending? execution reverted."
If I still send the transaction, metamask yields "Transaction xx failed! Transaction encountered an error.".
I'm positive it has to do with "require(paymentToken.transfer(burnwallet, amounttopay),"transfer Failed");", though I'm not sure what's wrong. Below is my entire contract code. I'm currently just interacting with the Chainlink contract on Rinkeby as my example, since they have a convenient token faucet.
pragma solidity ^0.8.0;
import "https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/token/ERC721/ERC721.sol";
import "https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/token/ERC20/IERC20.sol";
import "https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/access/Ownable.sol";
import "https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/utils/Counters.sol";
contract myNFTwithBurn is ERC721, Ownable {
address externalTokenAddress = 0x01BE23585060835E02B77ef475b0Cc51aA1e0709; //Token Type to burn on minting
uint256 amounttopay = 5; //number of these tokens to burn
IERC20 paymentToken = IERC20(externalTokenAddress); //my code: create an interface of the external token
address burnwallet = 0x000000000000000000000000000000000000dEaD; //burn wallet
using Counters for Counters.Counter;
Counters.Counter private _tokenIds;
using Strings for uint256;
// Optional mapping for token URIs
mapping (uint256 => string) private _tokenURIs;
// Base URI
string private _baseURIextended;
constructor() ERC721("NFTsWithBurn","NWB") {
}
function setBaseURI(string memory baseURI_) external onlyOwner() {
_baseURIextended = baseURI_;
}
function _setTokenURI(uint256 tokenId, string memory _tokenURI) internal virtual {
require(_exists(tokenId), "ERC721Metadata: URI set of nonexistent token");
_tokenURIs[tokenId] = _tokenURI;
}
function _baseURI() internal view virtual override returns (string memory) {
return _baseURIextended;
}
function tokenURI(uint256 tokenId) public view virtual override returns (string memory) {
require(_exists(tokenId), "ERC721Metadata: URI query for nonexistent token");
string memory _tokenURI = _tokenURIs[tokenId];
string memory base = _baseURI();
// If there is no base URI, return the token URI.
if (bytes(base).length == 0) {
return _tokenURI;
}
// If both are set, concatenate the baseURI and tokenURI (via abi.encodePacked).
if (bytes(_tokenURI).length > 0) {
return string(abi.encodePacked(base, _tokenURI));
}
// If there is a baseURI but no tokenURI, concatenate the tokenID to the baseURI.
return string(abi.encodePacked(base, tokenId.toString()));
}
function allowAccess() public
{
paymentToken.approve(address(this), 5000000); //This is my attempt to allow the contract access to the user's external tokens, in this case Chainlink (paymentToken)
}
function mintItem(address to, string memory tokenURI)
public
onlyOwner
returns (uint256)
{
require(paymentToken.transfer(burnwallet, amounttopay),"transfer Failed"); //Try to transfer 5 chainlink to the burn wallet
_tokenIds.increment();
uint256 id = _tokenIds.current();
_mint(to, id);
_setTokenURI(id, tokenURI);
return id;
}
}
If anybody can at least point me to what I'm doing completely wrong in the code that I've added, please do! TIA!
I'm not sure why are you trying to burn link in order to mint and nft but first check if the link code does not have a require that check if the destination address is the burn address if it has then burn the link is not possible and you should use any other erc20 maybe your own erc20, also your contract probably does not have any link and if you want to transfer the link from the user you should do this in the contract paymentToken.transferFrom(msg.sender,destinationAddress,amount) and if the user previously approve your contract you will able to send the tokens, and i suppose that the purpose of the allowAccess function is to make the user approve the contract to move the tokens that will never work, the approve function let's anyone that call it approve any address to move an amount of tokens, the thing is that to know who is approving to let other to move the tokens the function use msg.sender to explain how this work take a look at this example
let's say that your contract is the contract A and the link contract is the contract B
now a user call allowAccess in the contract A, so here the msg.sender is the user because they call the function
now internally this function call approve on contract B, here the contract A is the msg.sender, because the contract is who call the function
so what allowAccess is really doing is making the contract approving itself to move their own tokens that I assume it doesn't have
I've been trying to integrate Chainlink into my contract, managed to get the random number thingy working, but the API call doesn't work for me. Here's what I got:
contract ValorantCards is Ownable, ERC1155, VRFConsumerBase, ChainlinkClient {
using Chainlink for Chainlink.Request;
address private linkToken;
// Chainlink VRF
bytes32 private keyHash;
uint256 private vrfFee;
uint256 public randomResult;
// Chainlink API calls
address private oracle;
bytes32 private jobId;
uint256 private oracleFee;
uint256 public playerLevel;
constructor(
address _vrfCoordinator,
address _linkToken,
bytes32 _keyHash,
address _oracle,
bytes32 _jobId,
uint256 _oracleFee
) ERC1155("") VRFConsumerBase(_vrfCoordinator, _linkToken) {
setPublicChainlinkToken();
linkToken = _linkToken;
keyHash = _keyHash;
vrfFee = 0.1 * 10**18;
oracle = _oracle;
jobId = _jobId;
oracleFee = _oracleFee;
}
function requestUserLevel() public returns (bytes32 requestId) {
Chainlink.Request memory request = buildChainlinkRequest(
jobId,
address(this),
this.fulfill.selector
);
request.add(
"get",
"https://api.henrikdev.xyz/valorant/v1/account/draven/2023"
);
request.add("path", "data.account_level");
return sendChainlinkRequestTo(oracle, request, oracleFee);
}
function fulfill(bytes32 _requestId, uint256 _level)
public
recordChainlinkFulfillment(_requestId)
{
playerLevel = _level;
}
I'm deploying from hardhat, with the following parameters (ignoring the ones for VRF since that's working):
Oracle: 0x9C0383DE842A3A0f403b0021F6F85756524d5599
JobId: 0x3766623533366265383635623433333662323766633130313437633139336337
OracleFee: 0.1 * 10**18
The function runs fine, the transaction doesn't revert or anything, but when I check "playerLevel", it's always just 0
Looking at the Etherscan activity, it looks like the node you are using may be inactive. Try this node and jobId:
Oracle = 0xc57B33452b4F7BB189bB5AfaE9cc4aBa1f7a4FD8;
JobId = "d5270d1c311941d0b08bead21fea7747";
These were taken from the Chainlink Official Docs.
To check to see if a node may be inactive 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 awhile.
If a node is inactive you will need to find a new one or host one yourself. To find more nodes and jobs, you can check market.link or use the one found in the docs as mentioned earlier.
I have a very simple smart contract which creates and sends a Chainlink request to the Kovan Linkpool node using the get>uint256 job. The contract looks like this (API private key removed).
contract OracleChainlink is ChainlinkClient {
using Chainlink for Chainlink.Request;
uint256 public H_Index;
address private Oracle;
bytes32 private JobId;
uint256 private Fee = .1 * 10 ** 18; //kovan is .1 link per call
constructor() public {
setPublicChainlinkToken();
Oracle = 0x56dd6586DB0D08c6Ce7B2f2805af28616E082455; //Chainlink linkpool node on Kovan
JobId = "b6602d14e4734c49a5e1ce19d45a4632";
}
function getChainlinkToken() public view returns (address) {
return chainlinkTokenAddress();
}
function RequestH_index() public returns (bytes32 Reqid) {
Chainlink.Request memory Req = buildChainlinkRequest(JobId, address(this), this.fulfill.selector);
Req.add("get", "https://serpapi.com/.....");
Req.add("path", "cited_by.table.1.h_index.all");
return sendChainlinkRequestTo(Oracle, Req, Fee);
}
function fulfill(bytes32 Reqid, uint256 _Hindex) public recordChainlinkFulfillment(Reqid) {
H_Index = _Hindex;
}
The Google Scholar Author API https://serpapi.com/google-scholar-author-api returns a pretty large json, seen at the link if you scroll down. The snippet/path I need to follow is shown below (cited_by is at the top level of the json).
"cited_by": {
"table": [
{
"citations": {
"all": 23351,
"since_2016": 13660
}
},
{
"h_index": {
"all": 46,
"since_2016": 37
}
},
{
"i10_index": {
"all": 60,
"since_2016": 53
}
}
],
When ran, I get logs of Chainlink request events, but the public H_Index value remains 0. Am I missing something in terms of adapters? I have tried all sorts of path formats through the JSON with no luck. I have also tried different nodes and jobs. Is there any way to ensure that the API is even being called? What am I missing?
Your JSON Path should look like this:
Req.add("path", "cited_by.table.1.h_index.all");
Looking at the Etherscan activity, it looks like the node you are using may be inactive. Try this node and jobId:
Oracle = 0xc57B33452b4F7BB189bB5AfaE9cc4aBa1f7a4FD8;
JobId = "d5270d1c311941d0b08bead21fea7747";
These were taken from the Chainlink Official Docs.
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.
If a node is inactive you will need to find a new one or host one yourself. To find more nodes and jobs, you can check market.link or use the one found in the docs as mentioned earlier.
I want to use Oraclize in Remix, to test it. I'm too stupid to use their examples.
How can I make this work?
From their Github I took the YouTube-Views code and copied it into Remix
pragma solidity >= 0.5.0 < 0.6.0;
import "github.com/oraclize/ethereum-api/oraclizeAPI.sol";
contract YoutubeViews is usingOraclize {
string public viewsCount;
event LogYoutubeViewCount(string views);
event LogNewOraclizeQuery(string description);
constructor()
public
{
update(); // Update views on contract creation...
}
function __callback(
bytes32 _myid,
string memory _result
)
public
{
require(msg.sender == oraclize_cbAddress());
viewsCount = _result;
emit LogYoutubeViewCount(viewsCount);
// Do something with viewsCount, like tipping the author if viewsCount > X?
}
function update()
public
payable
{
emit LogNewOraclizeQuery("Oraclize query was sent, standing by for the answer...");
oraclize_query("URL", 'html(https://www.youtube.com/watch?v=9bZkp7q19f0).xpath(//*[contains(#class, "watch-view-count")]/text())');
}
}
When I use the viewCount it returns:
0: string:
This happens with all the other examples aswell.
With WolframAlpha eg. I also get the following error:
transact to WolframAlpha.update errored: VM error: revert.
revert The transaction has been reverted to the initial state.
Note: The constructor should be payable if you send value. Debug the transaction to get more information.
Ok you don't see the answer like a normal result in Remix:
You have to go under settings and open the Oraclize plug in.
If you then deploy the contract and or click update, you get the result shown in the plug in.