现在我正在使用@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 创建一个合并请求吗?