我的 Chainlink 请求没有得到满足?
My chainlink request isn't getting fulfilled?
谁能帮我调查一下为什么我的 Chainlink 请求没有得到满足。它们在我的测试中得到了满足(参见安全帽测试 etherscan 事件(https://kovan.etherscan.io/address/0x8Ae71A5a6c73dc87e0B9Da426c1b3B145a6F0d12#events). But they don't get fulfilled when I make them from my react app (see react app contract's etherscan events https://kovan.etherscan.io/address/0x6da2256a13fd36a884eb14185e756e89ffa695f8#events)。
相同的合约(不同的地址),相同的函数调用。
更新:
这是我在测试中调用它们的代码
const tx = await baseAgreement.connect(user).withdraw(
jobId,
oracleFee
);
这是我在 UI
中用来调用它们的代码
const signer = provider.getSigner();
const tx = await baseAgreement.connect(signer).withdraw(jobId, oracleFee);
这是我的 Solidity Chainlink 函数
function withdraw(
bytes32 _jobId,
uint256 _oracleFee
)
external
onlyContractActive()
returns(bytes32 requestId)
{
// check Link in this contract to see if we need to request more
checkLINK(_oracleFee);
// Build request
Chainlink.Request memory req = buildChainlinkRequest(_jobId, address(this), this.fulfillWithdraw.selector);
bytes memory url_bytes = abi.encodePacked(BASE_URL, mediaLink, API_KEY);
req.add("get", string(url_bytes));
req.add("path", "items.0.statistics.viewCount");
return sendChainlinkRequestTo(chainlinkOracleAddress(), req, _oracleFee);
}
/**
* @dev Callback for chainlink, this function pays the user
*/
function fulfillWithdraw(
bytes32 _requestId,
bytes32 _response
)
external
recordChainlinkFulfillment(_requestId)
{
// Convert api string response to an int
string memory _responseString = bytes32ToString(_response);
uint256 response = uint256(parseInt(_responseString, 0));
emit IntResponse(response);
// Pay the user
payUser(response);
}
function payUser(
uint256 _number
)
internal
{
// Calculate pay
uint256 budgetRemaining = getAgreementBalance();
uint256 accumulatedPay = budget - budgetRemaining;
uint256 pay = (payPerNumber * _number) - accumulatedPay;
if (pay > budgetRemaining) {
pay = budgetRemaining;
}
// Calculate platform fee
uint256 totalPlatformFee = (pay * PLATFORM_FEE) / 100;
// Transfer funds
paySomeone(payable(address(this)), user, pay-totalPlatformFee);
paySomeone(payable(address(this)), platformAddress, totalPlatformFee);
}
完整的合约代码可以在这里查看:https://github.com/colinsteidtmann/dapplu-contracts/blob/main/contracts/BaseAgreement.sol
更新 2:
我发现我的 UI 正在使用工厂合约和克隆模式(基于 EIP 1167 标准和 OpenZepplin 的克隆 https://docs.openzeppelin.com/contracts/4.x/api/proxy#Clones )部署我的合约。但是,我的安全帽测试是在没有工厂的情况下部署我的合约。一旦我让安全帽测试使用工厂合约部署合约,它们就会停止工作。那么,chainlink 是否不适用于代理合约和 EIP 1167 标准?
删除 MinimalClone.sol
中的协议变量,让用户在 init()
方法中将它们作为参数输入,或者像这样将它们硬编码到请求中:
Chainlink.Request memory req = buildChainlinkRequest(_jobId, address(this), this.fulfillWithdraw.selector);
req.add("get", "https://youtube.googleapis.com/youtube/v3/videos?part=statistics&id=aaaaaakey=aaaaa");
它不起作用的原因是代理合约不继承实施合约的状态,只是通过 delegatecall()
方法的逻辑。因此,在替换请求中的这些变量时,您的代理克隆实际上读取的是空白值。
参考:Here is a good article关于代理和委托调用的工作原理。
谁能帮我调查一下为什么我的 Chainlink 请求没有得到满足。它们在我的测试中得到了满足(参见安全帽测试 etherscan 事件(https://kovan.etherscan.io/address/0x8Ae71A5a6c73dc87e0B9Da426c1b3B145a6F0d12#events). But they don't get fulfilled when I make them from my react app (see react app contract's etherscan events https://kovan.etherscan.io/address/0x6da2256a13fd36a884eb14185e756e89ffa695f8#events)。
相同的合约(不同的地址),相同的函数调用。
更新:
这是我在测试中调用它们的代码
const tx = await baseAgreement.connect(user).withdraw(
jobId,
oracleFee
);
这是我在 UI
中用来调用它们的代码 const signer = provider.getSigner();
const tx = await baseAgreement.connect(signer).withdraw(jobId, oracleFee);
这是我的 Solidity Chainlink 函数
function withdraw(
bytes32 _jobId,
uint256 _oracleFee
)
external
onlyContractActive()
returns(bytes32 requestId)
{
// check Link in this contract to see if we need to request more
checkLINK(_oracleFee);
// Build request
Chainlink.Request memory req = buildChainlinkRequest(_jobId, address(this), this.fulfillWithdraw.selector);
bytes memory url_bytes = abi.encodePacked(BASE_URL, mediaLink, API_KEY);
req.add("get", string(url_bytes));
req.add("path", "items.0.statistics.viewCount");
return sendChainlinkRequestTo(chainlinkOracleAddress(), req, _oracleFee);
}
/**
* @dev Callback for chainlink, this function pays the user
*/
function fulfillWithdraw(
bytes32 _requestId,
bytes32 _response
)
external
recordChainlinkFulfillment(_requestId)
{
// Convert api string response to an int
string memory _responseString = bytes32ToString(_response);
uint256 response = uint256(parseInt(_responseString, 0));
emit IntResponse(response);
// Pay the user
payUser(response);
}
function payUser(
uint256 _number
)
internal
{
// Calculate pay
uint256 budgetRemaining = getAgreementBalance();
uint256 accumulatedPay = budget - budgetRemaining;
uint256 pay = (payPerNumber * _number) - accumulatedPay;
if (pay > budgetRemaining) {
pay = budgetRemaining;
}
// Calculate platform fee
uint256 totalPlatformFee = (pay * PLATFORM_FEE) / 100;
// Transfer funds
paySomeone(payable(address(this)), user, pay-totalPlatformFee);
paySomeone(payable(address(this)), platformAddress, totalPlatformFee);
}
完整的合约代码可以在这里查看:https://github.com/colinsteidtmann/dapplu-contracts/blob/main/contracts/BaseAgreement.sol
更新 2:
我发现我的 UI 正在使用工厂合约和克隆模式(基于 EIP 1167 标准和 OpenZepplin 的克隆 https://docs.openzeppelin.com/contracts/4.x/api/proxy#Clones )部署我的合约。但是,我的安全帽测试是在没有工厂的情况下部署我的合约。一旦我让安全帽测试使用工厂合约部署合约,它们就会停止工作。那么,chainlink 是否不适用于代理合约和 EIP 1167 标准?
删除 MinimalClone.sol
中的协议变量,让用户在 init()
方法中将它们作为参数输入,或者像这样将它们硬编码到请求中:
Chainlink.Request memory req = buildChainlinkRequest(_jobId, address(this), this.fulfillWithdraw.selector);
req.add("get", "https://youtube.googleapis.com/youtube/v3/videos?part=statistics&id=aaaaaakey=aaaaa");
它不起作用的原因是代理合约不继承实施合约的状态,只是通过 delegatecall()
方法的逻辑。因此,在替换请求中的这些变量时,您的代理克隆实际上读取的是空白值。
参考:Here is a good article关于代理和委托调用的工作原理。