我正在尝试使用 chainlink 请求进行 api 调用,然后使用 api 调用的结果更新卷变量。
API 调用应检索一个字符串。在部署智能合约并为其提供资金后,我似乎能够成功进行 api 调用(尽管我对此不确定)。问题是体积变量没有更新。
我改编了chainlink教程中的代码。原始教程代码有效,在我看来,我所做的更改也应该有效。有人可以帮忙吗?
// SPDX-License-Identifier: MIT
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;
string public volume;
address private oracle;
bytes32 private jobId;
uint256 private fee;
/**
* Network: Kovan
* Oracle: 0xc57B33452b4F7BB189bB5AfaE9cc4aBa1f7a4FD8 (Chainlink Devrel
* Node)
* Job ID: d5270d1c311941d0b08bead21fea7747
* Fee: 0.1 LINK
*/
constructor() {
setPublicChainlinkToken();
oracle = 0xF405B99ACa8578B9eb989ee2b69D518aaDb90c1F;
jobId = "c51694e71fa94217b0f4a71b2a6b565a";
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":
// {
// "VOLUME24HOUR": xxx.xxx,
// }
// }
// }
// }
request.add("path", "RAW.ETH.USD.MARKET");
// // Multiply the result by 1000000000000000000 to remove decimals
// int timesAmount = 10**18;
// request.addInt("times", timesAmount);
// Sends the request
return sendChainlinkRequestTo(oracle, request, fee);
}
/**
* Receive the response in the form of uint256
*/
function fulfill(bytes32 _requestId, bytes32 _volume) public recordChainlinkFulfillment(_requestId)
{
volume = bytes32ToString(_volume);
}
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 withdrawLink() external {} - Implement a withdraw function to avoid locking your LINK in the contract
}
要返回一个字符串,实际上必须返回一个
bytes32
并将其转换为链上的字符串。
您可以使用类似的方法,将 bytes32 转换为字符串:
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);
}
这是 AviationStack 的一个工作示例。将 API URL 中的
<access_key>
替换为您的 access_key。
//SPDX-License-Identifier: MIT
pragma solidity ^0.8.7;
import '@chainlink/contracts/src/v0.8/ChainlinkClient.sol';
import '@chainlink/contracts/src/v0.8/ConfirmedOwner.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 THAT USES HARDCODED VALUES FOR CLARITY.
* THIS IS AN EXAMPLE CONTRACT THAT USES UN-AUDITED CODE.
* DO NOT USE THIS CODE IN PRODUCTION.
*/
contract AviationGenericLargeResponse is ChainlinkClient, ConfirmedOwner {
using Chainlink for Chainlink.Request;
// variable bytes(arbitrary-length raw byte data) returned in a single oracle response
bytes public data;
string public flightStatus;
bytes32 private jobId;
uint256 private fee;
event RequestFulfilled(bytes32 indexed requestId, bytes indexed data);
/**
* @notice Initialize the link token and target oracle
* @dev The oracle address must be an Operator contract for multiword response
*
*
* Goerli Testnet details:
* Link Token: 0x326C977E6efc84E512bB9C30f76E30c160eD06FB
* Oracle: 0xCC79157eb46F5624204f47AB42b3906cAA40eaB7 (Chainlink DevRel)
* jobId: 7da2702f37fd48e5b1b9a5715e3509b6
*
*/
constructor() ConfirmedOwner(msg.sender) {
setChainlinkToken(0x326C977E6efc84E512bB9C30f76E30c160eD06FB);
setChainlinkOracle(0xCC79157eb46F5624204f47AB42b3906cAA40eaB7);
jobId = '7da2702f37fd48e5b1b9a5715e3509b6';
fee = (1 * LINK_DIVISIBILITY) / 10; // 0,1 * 10**18 (Varies by network and job)
}
/**
* @notice Request variable bytes from the oracle
*/
function requestBytes() public {
Chainlink.Request memory req = buildChainlinkRequest(jobId, address(this), this.fulfillBytes.selector);
req.add(
'get',
'http://api.aviationstack.com/v1/flights?access_key=a6656fabf7fbe4fde6e4061f5be7042a&flight_number=611&airline_name=Qantas&flight_status=landed&limit=1'
);
req.add('path', 'data,0,flight_status');
sendChainlinkRequest(req, fee);
}
/**
* @notice Fulfillment function for variable bytes
* @dev This is called by the oracle. recordChainlinkFulfillment must be used.
*/
function fulfillBytes(bytes32 requestId, bytes memory bytesData) public recordChainlinkFulfillment(requestId) {
emit RequestFulfilled(requestId, bytesData);
data = bytesData;
flightStatus = string(data);
}
/**
* Allow withdraw of Link tokens from the contract
*/
function withdrawLink() public onlyOwner {
LinkTokenInterface link = LinkTokenInterface(chainlinkTokenAddress());
require(link.transfer(msg.sender, link.balanceOf(address(this))), 'Unable to transfer');
}
}
我遇到了类似的问题,您应该能够在没有字节到字符串函数的情况下执行此操作。对我有用的是:
_volume
参数重新定义为string memory
,以便可以将其分配给合约顶部volume
的字符串存储值。_volume
encode_mwr
,它在solidityfulfill函数参数中也应该是“_volume”。_volume
中定义为字符串的 encode_mwr
数据。这也可以扩展为在一次调用中返回 uint、int、string、bytes 混合类型的多个值。希望这对某人有帮助,如果我的回复格式不正确,抱歉,这是我提交给 stackoverflow 的第一个答案。
例如下面的 TOML 代码片段:
encode_mwr [type="ethabiencode"
abi="(bytes32 requestId, string _volume)"
data="{\\"requestId\\": $(decode_log.requestId), \\"_volume\\": $(volume_parse)}"
]
编辑的 Solidity 文件:
// SPDX-License-Identifier: MIT
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;
string public volume;
address private oracle;
bytes32 private jobId;
uint256 private fee;
/**
* Network: Kovan
* Oracle: 0xc57B33452b4F7BB189bB5AfaE9cc4aBa1f7a4FD8 (Chainlink Devrel
* Node)
* Job ID: d5270d1c311941d0b08bead21fea7747
* Fee: 0.1 LINK
*/
constructor() {
setPublicChainlinkToken();
oracle = 0xF405B99ACa8578B9eb989ee2b69D518aaDb90c1F;
jobId = "c51694e71fa94217b0f4a71b2a6b565a";
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":
// {
// "VOLUME24HOUR": xxx.xxx,
// }
// }
// }
// }
request.add("path", "RAW.ETH.USD.MARKET");
// // Multiply the result by 1000000000000000000 to remove decimals
// int timesAmount = 10**18;
// request.addInt("times", timesAmount);
// Sends the request
return sendChainlinkRequestTo(oracle, request, fee);
}
/**
* Receive the response in the form of uint256
*/
function fulfill(bytes32 _requestId, string memory _volume) public recordChainlinkFulfillment(_requestId)
{
volume = _volume;
}
// function withdrawLink() external {} - Implement a withdraw function to avoid locking your LINK in the contract
}
下面是一个工作示例,它将在以太坊 Sepolia 测试网上检索您的字符串对象。
以下 Chainlink 消费者合约使用函数
getResponseString()
将返回的 bytes
对象类型转换为 string
对象:
//SPDX-License-Identifier: MIT
pragma solidity ^0.8.7;
import "@chainlink/contracts/src/v0.8/ChainlinkClient.sol";
import "@chainlink/contracts/src/v0.8/ConfirmedOwner.sol";
/**
* LinkWell Nodes consumer contract example
*/
/**
* THIS IS AN EXAMPLE CONTRACT THAT USES UN-AUDITED CODE.
*/
contract LinkWellStringBytesConsumerContractExample is ChainlinkClient, ConfirmedOwner {
using Chainlink for Chainlink.Request;
address private oracleAddress;
bytes32 private jobId;
uint256 private fee;
constructor() ConfirmedOwner(msg.sender) {
// LinkWell Nodes oracle address and jobId
setChainlinkToken(0x779877A7B0D9E8603169DdbD7836e478b4624789);
setOracleAddress(0x0FaCf846af22BCE1C7f88D1d55A038F27747eD2B);
setJobId("8ced832954544a3c98543c94a51d6a8d");
setFeeInHundredthsOfLink(0); // 0 LINK
}
// Send a request to the Chainlink oracle
function request() public {
Chainlink.Request memory req = buildOperatorRequest(jobId, this.fulfill.selector);
// DEFINE THE REQUEST PARAMETERS (example)
req.add('method', 'GET');
req.add('url', 'https://min-api.cryptocompare.com/data/pricemultifull?fsyms=ETH&tsyms=USD');
req.add('headers', '["accept", "application/json"]');
req.add('body', '');
req.add('contact', 'anonymous');
// PROCESS THE RESULT (example)
req.add('path', 'RAW,ETH,USD,MARKET');
// Send the request to the Chainlink oracle
sendOperatorRequest(req, fee);
}
bytes public responseBytes;
// Receive the result from the Chainlink oracle
event RequestFulfilled(bytes32 indexed requestId);
function fulfill(bytes32 requestId, bytes memory bytesData) public recordChainlinkFulfillment(requestId) {
// Process the oracle response
// emit RequestFulfilled(requestId); // (optional) emits this event in the on-chain transaction logs, allowing Web3 applications to listen for this transaction
responseBytes = bytesData; // example value: 0x426974636f696e
}
// Retrieve the response data as a string
function getResponseString() public view onlyOwner returns (string memory) {
return string(responseBytes); // example value: Bitcoin
}
// Update oracle address
function setOracleAddress(address _oracleAddress) public onlyOwner {
oracleAddress = _oracleAddress;
setChainlinkOracle(_oracleAddress);
}
function getOracleAddress() public view onlyOwner returns (address) {
return oracleAddress;
}
// Update jobId
function setJobId(string memory _jobId) public onlyOwner {
jobId = bytes32(bytes(_jobId));
}
function getJobId() public view onlyOwner returns (string memory) {
return string(abi.encodePacked(jobId));
}
// Update fees
function setFeeInJuels(uint256 _feeInJuels) public onlyOwner {
fee = _feeInJuels;
}
function setFeeInHundredthsOfLink(uint256 _feeInHundredthsOfLink) public onlyOwner {
setFeeInJuels((_feeInHundredthsOfLink * LINK_DIVISIBILITY) / 100);
}
function getFeeInHundredthsOfLink() public view onlyOwner returns (uint256) {
return (fee * 100) / LINK_DIVISIBILITY;
}
function withdrawLink() public onlyOwner {
LinkTokenInterface link = LinkTokenInterface(chainlinkTokenAddress());
require(
link.transfer(msg.sender, link.balanceOf(address(this))),
"Unable to transfer"
);
}
}
如果您希望在以太坊 Sepolia 之外的其他测试网上复制此结果,您可以将预言机合约地址替换为相应测试网的地址。
其他测试网的Oracle合约地址如下:
0xd36c6B1777c7f3Db1B3201bDD87081A9045B7b46
0xd0EbC86a4f67654B654Feb0e615d7f5C139a6406
0xa57f0cEd49bB1ed7327f950B12a8419cFD01855f
0xd08FEb8203E76f836D74608595346ab6b0f768C9
0xB9C47B9609174716CE536324d4FbEad9292c1d3a
0x14bc7F6Da6cA3E072793c185e01a76E62341CC61
0x12A3d7759F745f4cb8EE8a647038c040cB8862A5
希望有帮助!