3

现在我正在使用@openzeppelin/truffle-upgrades将基本智能合约转换为可升级的智能合约

因此,我遵循了文档中的所有必需步骤,但仍然存在一个问题:

Truffle-Upgrades 要求我用初始化程序替换构造函数,这对我来说很好,但不适用于导入到我自己的智能合约中的智能合约,示例:

pragma solidity 0.6.6;

import "@chainlink/contracts/src/v0.6/VRFConsumerBase.sol";

contract Sample is VRFConsumerBase {
    
    address private owner;
    
    bytes32 internal keyHash;
    uint256 internal fee;
    
    constructor(address _owner)
        VRFConsumerBase(
            0xa555fC018435bef5A13C6c6870a9d4C11DEC329C, // VRF Coordinator
            0x84b9B910527Ad5C03A9Ca831909E21e236EA7b06  // LINK Token
        ) public
    {
        keyHash = 0xcaf3c3727e033261d383b315559476f48034c13b18f8cafed4d871abe5049186;
        fee = 0.1 * 10 ** 18; // 0.1 LINK (Varies by network)
        
        owner = _owner;
    }

    ...

因此松露抱怨:

../@chainlink/contracts/src/v0.6/VRFConsumerBase.sol:182: Contract `VRFConsumerBase` has a constructor
Define an initializer instead

由于它是第三方包,我无法替换它:)

是否有任何架构技巧/配置?

我浏览了几乎所有关于 chainlink/truffle 的文档,但没有找到解决这个问题的方法。

谢谢!

更新 1:

首先,我将 VRFConsumerBase 合同修改为:(我还删除了评论以保持简短......)

// SPDX-License-Identifier: MIT
pragma solidity 0.6.12;

import "@chainlink/contracts/src/v0.6/vendor/SafeMathChainlink.sol";

import "@chainlink/contracts/src/v0.6/interfaces/LinkTokenInterface.sol";

import "@chainlink/contracts/src/v0.6/VRFRequestIDBase.sol";

abstract contract VRFConsumerBaseUpgradable is VRFRequestIDBase {

  using SafeMathChainlink for uint256;

  function fulfillRandomness(bytes32 requestId, uint256 randomness)
    internal virtual;

  function requestRandomness(bytes32 _keyHash, uint256 _fee, uint256 _seed)
    internal returns (bytes32 requestId)
  {
    LINK.transferAndCall(vrfCoordinator, _fee, abi.encode(_keyHash, _seed));
    
    uint256 vRFSeed  = makeVRFInputSeed(_keyHash, _seed, address(this), nonces[_keyHash]);
    
    nonces[_keyHash] = nonces[_keyHash].add(1);
    return makeRequestId(_keyHash, vRFSeed);
  }

  // removed immutable keyword <--
  LinkTokenInterface internal LINK;
  // removed immutable keyword <--
  address private vrfCoordinator;

  mapping(bytes32 /* keyHash */ => uint256 /* nonce */) private nonces;

  // replaced constructor with initializer <--
  function initialize(address _vrfCoordinator, address _link) public {
    vrfCoordinator = _vrfCoordinator;
    LINK = LinkTokenInterface(_link);
  }

  function rawFulfillRandomness(bytes32 requestId, uint256 randomness) external {
    require(msg.sender == vrfCoordinator, "Only VRFCoordinator can fulfill");
    fulfillRandomness(requestId, randomness);
  }

}

我做了什么:

  • 我用初始化器替换了构造函数
  • 我从状态变量中删除了不可变关键字

接下来,我在我的文件系统中使用来自 @openzeppelin/contracts-upgradeable 的 Initializable 合约来防止智能合约多次执行初始化程序:

// SPDX-License-Identifier: MIT
pragma solidity 0.6.12;

abstract contract Initializable {

    bool private _initialized;

    bool private _initializing;

    modifier initializer() {
        require(_initializing || !_initialized, "Initializable: contract is already initialized");

        bool isTopLevelCall = !_initializing;
        if (isTopLevelCall) {
            _initializing = true;
            _initialized = true;
        }

        _;

        if (isTopLevelCall) {
            _initializing = false;
        }
    }
}

重要的:

我没有通过可靠的 import 语句导入 Initializable 合约。

相反,我手动复制了源代码并将编译器设置为 0.6.12,因为 @openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol 在 0.8.x 上运行

最后,我更新了我的合约以实现 Initializable 和新的 VRFConsumerBaseUpgradable 合约:

// SPDX-License-Identifier: MIT
pragma solidity 0.6.12;

import "./Initializable.sol";
import "./VRFConsumerBaseUpgradable.sol";

contract Sample is Initializable, VRFConsumerBaseUpgradable {

    bytes32 internal keyHash;
    uint256 internal fee;
    
    address private owner;
    
    function initialize(address _owner)
        public
        initializer
    {
        VRFConsumerBaseUpgradable.initialize(
            0xa555fC018435bef5A13C6c6870a9d4C11DEC329C, // VRF Coordinator
            0x84b9B910527Ad5C03A9Ca831909E21e236EA7b06  // LINK Token
        );

        keyHash = 0xcaf3c3727e033261d383b315559476f48034c13b18f8cafed4d871abe5049186;
        fee = 0.1 * 10 ** 18; 
        
        owner = _owner;
    }

    function getRandomNumber(uint256 userProvidedSeed) public returns (bytes32 requestId) {
        require(LINK.balanceOf(address(this)) >= fee, "Not enough LINK - fill contract with faucet");
        return requestRandomness(keyHash, fee, userProvidedSeed);
    }

    function fulfillRandomness(bytes32 requestId, uint256 randomness) internal override {
        // logic
    }

    ...
    
}

我测试了初始迁移以及通过松露进行的升级,它都有效,所以我认为这很好,我将把它留给未来的研究人员..

你怎么看?我应该为 VRFConsumerBaseUpgradable 创建一个合并请求吗?

4

0 回答 0