The job spec deployed and running on Chainlink node is being successfully triggered and completed when called using the Solidity smart contract that is using the Oracle.sol
contract.
But, since the requirement is to return the large response (https://docs.chain.link/docs/large-responses/), so I have to use Operator.sol
contract instead of Oracle.sol
. Then, the job is not being called.
The deployed Operator contract is looking as:
The LINK Token and Owner addresses that I have used to deploy the Operator.sol
contract are:
The LINK Token address is basically taken from the official Chainlink doc (https://docs.chain.link/docs/fulfilling-requests/) mentioning the Kovan Testnet LINK token address:
And the owner address is taken from the Account address of the running Chainlink node:
And the Solidity smart contract code is:
//SPDX-License-Identifier: MIT
pragma solidity ^0.8.7;
import "@chainlink/contracts/src/v0.8/ChainlinkClient.sol";
contract GenericLargeResponse is ChainlinkClient {
using Chainlink for Chainlink.Request;
bytes public data;
constructor(
) {
setChainlinkToken(0xa36085F69e2889c224210F603D836748e7dC0088);
setChainlinkOracle(0x8114f13FaF377FFc7A5AD32fb8a1e448667b871D);
}
function requestBytes(
)
public
{
bytes32 specId = "a3d1b2c945244e44bdb412c5b5287df3";
uint256 payment = 100000000000000000;
Chainlink.Request memory req = buildChainlinkRequest(specId, address(this), this.fulfillBytes.selector);
req.add("data", "{\"agg_x\": \"agg_mean\", \"dataset_code\":\"MODIS/006/MOD14A1\", \"selected_band\":\"MaxFRP\", \"image_scale\":1000, \"start_date\":\"2021-09-01\", \"end_date\":\"2021-09-10\", \"geometry\":{\"type\":\"FeatureCollection\",\"features\":[{\"type\":\"Feature\",\"properties\":{\"id\":1},\"geometry\":{\"type\":\"Polygon\",\"coordinates\":[[[29.53125,19.642587534013032],[29.53125,27.059125784374068],[39.90234375,27.059125784374068],[39.90234375,19.642587534013032],[29.53125,19.642587534013032]]]}},{\"type\":\"Feature\",\"properties\":{\"id\":2},\"geometry\":{\"type\":\"Polygon\",\"coordinates\":[[[46.40625,13.752724664396988],[46.40625,20.138470312451155],[56.25,20.138470312451155],[56.25,13.752724664396988],[46.40625,13.752724664396988]]]}}]}}");
sendOperatorRequest(req, payment);
}
function fulfillBytes(
bytes32 requestId,
bytes memory bytesData
)
public
recordChainlinkFulfillment(requestId)
{
data = bytesData;
}
}
The contract is compiled and deployed successfully. But the requestBytes
function is unable to trigger the job-spec running on the Chainlink node.
PS: The function of the similar smart contract that is using the Oracle.sol
is successfully triggering the job-spec.
The TOML Job spec running on Chainlink node is:
type = "directrequest"
schemaVersion = 1
name = "shamba-fire-data"
contractAddress = "0x8114f13FaF377FFc7A5AD32fb8a1e448667b871D"
maxTaskDuration = "0s"
observationSource = """
decode_log [type="ethabidecodelog"
abi="OracleRequest(bytes32 indexed specId, address requester, bytes32 requestId, uint256 payment, address callbackAddr, bytes4 callbackFunctionId, uint256 cancelExpiration, uint256 dataVersion, bytes data)"
data="$(jobRun.logData)"
topics="$(jobRun.logTopics)"]
decode_cbor [type="cborparse" data="$(decode_log.data)"]
fetch [type="bridge" name="shamba-fire-bridge" requestData="{\\"id\\": $(jobSpec.externalJobID), \\"data\\":$(decode_cbor.data)}"]
parse [type="jsonparse" path="result,1,0" data="$(fetch)"]
encode_data [type="ethabiencode" abi="(uint256 value)" data="{ \\"value\\": $(parse) }"]
encode_tx [type="ethabiencode"
abi="fulfillOracleRequest2(bytes32 requestId, uint256 payment, address callbackAddress, bytes4 callbackFunctionId, uint256 expiration, bytes calldata data)"
data="{\\"requestId\\": $(decode_log.requestId), \\"payment\\": $(decode_log.payment), \\"callbackAddress\\": $(decode_log.callbackAddr), \\"callbackFunctionId\\": $(decode_log.callbackFunctionId), \\"expiration\\": $(decode_log.cancelExpiration), \\"data\\": $(encode_data)}"
]
submit_tx [type="ethtx" to="0x8114f13FaF377FFc7A5AD32fb8a1e448667b871D" data="$(encode_tx)"]
decode_log -> decode_cbor -> fetch -> parse -> encode_data -> encode_tx -> submit_tx
"""
externalJobID = "a3d1b2c9-4524-4e44-bdb4-12c5b5287df3"
Can anyone please point me in the right direction, like what I'm doing wrong in these steps due to which the smart contract is unable to trigger the job-spec ?
First of all, the owner address of the Operator.sol
should be the Metamask wallet Kovan testnet address (instead of the account address of the running Chainlink node) from which the transactions are being done.
Then, after the Operator.sol
being deployed successfully, call the setAuthorizedSenders
function of the Operator.sol
by passing in the account address of the running Chainlink node in the senders address[]
field like:
Then, the job-spec's encode_data
should be having requestId
parameter as well:
encode_data [type="ethabiencode" abi="(bytes32 requestId, uint256[][] value)" data="{ \\"requestId\\": $(decode_log.requestId), \\"value\\": $(parse) }"]
The entire job-spec should be:
type = "directrequest"
schemaVersion = 1
name = "shamba-fire-data"
contractAddress = "0xf4434feDd55D3d6573627F39fA39867b23f4Bf7F"
maxTaskDuration = "0s"
observationSource = """
decode_log [type="ethabidecodelog"
abi="OracleRequest(bytes32 indexed specId, address requester, bytes32 requestId, uint256 payment, address callbackAddr, bytes4 callbackFunctionId, uint256 cancelExpiration, uint256 dataVersion, bytes data)"
data="$(jobRun.logData)"
topics="$(jobRun.logTopics)"]
decode_cbor [type="cborparse" data="$(decode_log.data)"]
fetch [type="bridge" name="shamba-fire-bridge" requestData="{\\"id\\": $(jobSpec.externalJobID), \\"data\\":$(decode_cbor.data)}"]
parse [type="jsonparse" path="result" data="$(fetch)"]
encode_data [type="ethabiencode" abi="(bytes32 requestId, uint256[][] value)" data="{ \\"requestId\\": $(decode_log.requestId), \\"value\\": $(parse) }"]
encode_tx [type="ethabiencode"
abi="fulfillOracleRequest2(bytes32 requestId, uint256 payment, address callbackAddress, bytes4 callbackFunctionId, uint256 expiration, bytes calldata data)"
data="{\\"requestId\\": $(decode_log.requestId), \\"payment\\": $(decode_log.payment), \\"callbackAddress\\": $(decode_log.callbackAddr), \\"callbackFunctionId\\": $(decode_log.callbackFunctionId), \\"expiration\\": $(decode_log.cancelExpiration), \\"data\\": $(encode_data)}"
]
submit_tx [type="ethtx" to="0xf4434feDd55D3d6573627F39fA39867b23f4Bf7F" data="$(encode_tx)"]
decode_log -> decode_cbor -> fetch -> parse -> encode_data -> encode_tx -> submit_tx
"""
externalJobID = "66229880-79e1-43c6-9d9e-0eb4b668729d"
Similarly, the solidity smart contract code should be:
//SPDX-License-Identifier: MIT
pragma solidity ^0.8.7;
import "@chainlink/contracts/src/v0.8/ChainlinkClient.sol";
contract GenericLargeResponse is ChainlinkClient {
using Chainlink for Chainlink.Request;
uint256[][] public data;
constructor(
) {
setChainlinkToken(0xa36085F69e2889c224210F603D836748e7dC0088);
setChainlinkOracle(0xf4434feDd55D3d6573627F39fA39867b23f4Bf7F);
}
function requestBytes(
)
public
{
bytes32 specId = "6622988079e143c69d9e0eb4b668729d";
//0x3065666666656632313564353466316339663332623636376466613061346536;
uint256 payment = 1000000000000000000;
Chainlink.Request memory req = buildChainlinkRequest(specId, address(this), this.fulfillBytes.selector);
req.add("data", "{\"agg_x\": \"agg_mean\", \"dataset_code\":\"MODIS/006/MOD14A1\", \"selected_band\":\"MaxFRP\", \"image_scale\":1000, \"start_date\":\"2021-09-01\", \"end_date\":\"2021-09-10\", \"geometry\":{\"type\":\"FeatureCollection\",\"features\":[{\"type\":\"Feature\",\"properties\":{\"id\":1},\"geometry\":{\"type\":\"Polygon\",\"coordinates\":[[[29.53125,19.642587534013032],[29.53125,27.059125784374068],[39.90234375,27.059125784374068],[39.90234375,19.642587534013032],[29.53125,19.642587534013032]]]}},{\"type\":\"Feature\",\"properties\":{\"id\":2},\"geometry\":{\"type\":\"Polygon\",\"coordinates\":[[[46.40625,13.752724664396988],[46.40625,20.138470312451155],[56.25,20.138470312451155],[56.25,13.752724664396988],[46.40625,13.752724664396988]]]}}]}}");
sendOperatorRequest(req, payment);
}
function fulfillBytes(
bytes32 requestId,
uint256[][] memory bytesData
)
public
recordChainlinkFulfillment(requestId)
{
data = bytesData;
}
}