0

我有一个 Solidity 智能合约,它依赖于 Chainlink 预言机来获取外部数据,它有很多功能代码,不需要在每个合约的基础上复制,但确实会改变合约实例的状态,这就是我决定代理的原因使用委托调用的模式最有意义。在代理模式中,我只需为我的合约函数部署一次字节码,然后我的合约的所有其他实例将只委托调用实现合约,并且添加到区块链的唯一新信息将是实例字段那个具体的合同。

我能够部署一个实现合同并将我部署的代理指向它的功能,但是当我在代理上调用锁定功能时,我没有通过检查require(owner == msg.sender,"Owner only"),这没有意义,因为委托调用应该通过msg.sender并且我设置了所有者字段在msg.sender代理的构造函数中。如果我删除了要求,我可以在没有还原的情况下调用该函数,但是lockedanddebugAddr字段没有改变,即使锁定功能应该改变它们(我认为委托调用是在调用者的上下文中执行的?)。有谁知道我的代理和实施合同有什么问题?我猜这与内存布局或我用来进行委托调用的程序集有关,但我还没有达到可以使用我的谷歌搜索技能找出问题所在的水平,所以如果有人能发现我的代理在哪里合同不正确/格式错误,请告诉我。

谢谢,本

锁定功能代码片段

//Locks in the contract, buyer should have already provided data scientist an upload only API key and their model ID 
function lock() public returns (bool success)
{
    
    debugAddr = msg.sender;
    
    uint tempStamp = now;
    
    //THIS IS THE REQUIRE THAT FAILS WHEN IT SHOULDNT WHEN I UNCOMMENT THIS AND DEPLOY/RUN
    require(msg.sender == owner, "Only owner can lock contract.");
    
    //require(!locked, "Cannot lock contract that is already locked.");
    //require(buyer != address(0),"No buyer to lock.");
    //require(bytes(buyerModelName).length != 0,"No buyerModelName to lock.");
    //require((tempStamp - startTimestamp) < 158400,"Cannot lock contract that was entered by buyer over 44 hours ago.");
    //require((getWeekday(tempStamp) == 0) || (getWeekday(tempStamp) == 1 && getHour(tempStamp) < 14),"Contract can only be locked in between Sunday 00:00 UTC and Monday 14:00 UTC");
    
    LinkTokenInterface link = LinkTokenInterface(chainlinkTokenAddress());
    //require(link.balanceOf(address(this)) >= totalFee, "Contract requires 0.5 LINK total to operate once locked, current LINK balance is under 0.5.");
    
    locked = true;
    return true;
}

需要注释的代理合约(另见合约的 txs,你可以看到我调用 lock): https ://kovan.etherscan.io/address/0x1f805d559f6eb7d7b19bf0340db288503f448ae8 代理指向的实现合约 : https ://kovan.etherscan.io/地址/0xfb41ea6452da396279cbd9d9d8c136121e38fab6

需要未注释的代理合约(另请参阅合约的 txs,您可以看到我调用锁定和还原): https ://kovan.etherscan.io/address/0x2d59aa0c1dd9a77d592167c43f2e65adcb275bfe 代理指向的实现合约:0x20a1f27d69f7a257741eddaec43642194af0

代理代码和实现代码

参考代码:https ://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/proxy/Proxy.sol

代理:https ://github.com/benschreyer/Steak/blob/main/SteakQuarterly/ProxyPattern/SteakQuarterlyProxy.sol

重要说明 在我的代理中,我不想将合约声明为 ChainlinkClient,因为那时 ChainlinkClient 的函数将包含在代理中,这是不必要的,因为实现应该已经具有这些方法。相反,我只声明我自己的字段和 ChainlinkClient 。我觉得这是我的实施出错的主要地方,但我不确定需要改变什么/如果这甚至可行

实施:https ://github.com/benschreyer/Steak/blob/main/SteakQuarterly/ProxyPattern/SteakQuarterlyDelegate.sol

编辑:仍然失败的最小代码示例 该合约应该具有成为 ChainlinkClient 代理的最低要求,并且只有锁定功能和构造函数,我在 require(owner == msg.sender) 上得到相同的还原。如果我删除了要求,则对代理合约的锁定调用表示已确认,但代理的状态变量保持不变(debugAddr 为 0,locked 保持为假)

这是最小的示例代码(我部署在 0.6.12 编译的 remix IDE 上,使用 at 地址检索调用代理的锁定函数,并编译委托代码以便使用委托的 abi):https://github。 com/benschreyer/Steak/tree/main/MinimalCodeExample

编辑 2: 如果我删除了上面链接的代理和实现最小示例的 ChainlinkClient 部分/字段,我会得到一个代理合约,它可以正常工作并且可以接受在实现合约中定义的外部函数调用。

所以我现在的问题是如何编写支持 Chainlink GET 请求功能的代理和实现合约?我的代理需要定义或导入哪些字段/常量/事件/接口,我应该在哪里定义/导入它们以允许 Chainlink 工作?例如,如果我想让我的合约通过 Chainlink 从 API 中检索巴黎的温度,但同时也是一个代理,这样我就不必重新部署它的所有功能并节省 gas 价格。

一旦我将Chainlink添加到组合中,到目前为止我尝试过的任何东西(参见最小破坏示例)都不起作用,因为我不确定如何构造代理合约类,以便代理的存储和访问/写入将调用委托给执行队列。这是我删除 Chainlink 功能后工作的最小代码: https://github.com/benschreyer/Steak/tree/main/MinimalCodeExample/WorkingButNoChainlink 我的工作示例代理/实现模式合同的一个版本,但具有 Chainlink 功能或指针非常感谢代理合约需要哪些字段/事件/常量才能调用预言机。

4

1 回答 1

1

不要在代理类中定义 ChainlinkClient 的字段,而是编写一个包含 ChainlinkClient 字段的类 ChainlinkClientStorage,然后将您的代理声明为继承自 ChainlinkClientStorage

https://github.com/benschreyer/Steak/blob/main/SteakQuarterly/ProxyPattern/ChainlinkClientStorage.sol

https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/proxy/Proxy.sol

contract MyProxy is ChainlinkClientStorage, MyContractStorage{}
于 2021-05-27T03:47:08.857 回答