Compatible-with-Openzeooelin-upgrades

用于部署和管理可升级合约的 TronBox package TronBox 兼容该包迁移和测试代理相关的功能,因此使用 TronBox 可以为你的合约部署代理。

安装

npm install --save-dev @openzeppelin/truffle-upgrades

在 TronBox 中使用 @openzeppelin/truffle-upgrades 需要 TronBox V3.2.0 或之后的版本。

在 migrations 中使用

部署代理

若要在你的 migrations 中部署一个可升级的合约模式,可以使用 deployProxy 函数。 deployProxy 支持 UUPS(Universal Upgradeable Proxy Standard)transparent 模式的代理。

注意:为了适配 deployProxy 函数,请先设置 deployer.trufflePlugintrue

// migrations/NN_deploy_upgradeable_box.js
const { deployProxy } = require('@openzeppelin/truffle-upgrades');

const Box = artifacts.require('Box');

module.exports = async function (deployer) {
  try {
    // Setup tronbox deployer
    deployer.trufflePlugin = true;
    const instance = await deployProxy(Box, [42], { deployer });
    console.info('Deployed', instance.address);

    // Call proxy contract
    const box = await Box.deployed();
    const beforeValue = await box.value();
    console.info('Value before', beforeValue.toNumber());

    // Set new Value
    await box.setValue(beforeValue.toNumber() + 100);
    const afterValue = await box.value();
    console.info('Value after', afterValue.toNumber());
  } catch (error) {
    console.error('Transparent: deploy box error', error);
  }
};

deployProxy 会先自动检查 Box 合约是否可以安全升级,接着为 Box 部署一个实现合约(除非在之前的部署中已经有一个),然后再创建部署一个代理合约,并通过调用 initialize(42) 去初始化它。如果是 transparent 模式的代理,还会创建部署一个代理管理员合约(ProxyAdmin)。

Beacon 模式代理部署

Beacon 代理模式允许多个代理合约通过引用 Beacon 合约来共享同一个逻辑实现。TronBox 也兼容了Beacon 代理模式。所以,可以使用这个插件去部署 Beacon 模式的代理合约。
deployBeacon 用于部署一个 Beacon 管理合约,这是一个用于管理多个实现了相同接口的合约的中心合约。
deployBeaconProxy 用于部署一个或多个 Beacon 代理合约,并将其指向 Beacon 合约,以实现升级和维护服务。

注意:为了适配 deployBeacondeployBeaconProxy 函数,请先设置 deployer.trufflePlugintrue

// migrations/NN_deploy_upgradeable_box.js
const { deployBeacon, deployBeaconProxy } = require('@openzeppelin/truffle-upgrades');

const Box = artifacts.require('Box');

module.exports = async function (deployer) {
  try {
    // Setup tronbox deployer
    deployer.trufflePlugin = true;
    const beacon = await deployBeacon(Box, { deployer });
    console.info('Beacon deployed', beacon.address);
    const instance = await deployBeaconProxy(beacon, Box, [42], { deployer });
    console.info('Deployed', instance.address);

    // Call proxy contract
    const box = await Box.deployed();
    const beforeValue = await box.value();
    console.info('Value before', beforeValue.toNumber());

    // Set new Value
    await box.setValue(beforeValue.toNumber() + 100);
    const afterValue = await box.value();
    console.info('Value after', afterValue.toNumber());
  } catch (error) {
    console.error('Beacon: deploy box error', error);
  }
};

关于 upgradeProxy

TronBox 暂未兼容使用 upgradeProxy 函数将部署的实例升级到一个新的版本。如果需要升级代理合约的实例,可以参考以下的示例。
部署新的 BoxV2 实现合约,并将现有代理升级到新的实现。

UUPS

// migrations/MM_upgrade_uups_box.js
const TransparentUpgradeableProxy = artifacts.require(
  '@openzeppelin/upgrades-core/artifacts/@openzeppelin/contracts/proxy/transparent/TransparentUpgradeableProxy.sol/TransparentUpgradeableProxy.json'
);
const Box = artifacts.require('UUPSBox');
const BoxV2 = artifacts.require('UUPSBoxV2');

module.exports = async function (deployer) {
  try {
    // Deploy the new BoxV2 implementation contract
    await deployer.deploy(BoxV2);

    // Upgrade proxy contract
    const proxyContract = await TransparentUpgradeableProxy.at(Box.address);
    await proxyContract.upgradeTo(BoxV2.address);
    console.info('Upgraded', Box.address);

    // Call proxy contract
    const box = await BoxV2.at(Box.address);
    const beforeValue = await box.value();
    console.info('Value before', beforeValue.toNumber());

    // Set new Value
    await box.setValue(beforeValue.toNumber() + 100);
    const afterValue = await box.value();
    console.info('Value after', afterValue.toNumber());

    // Read new V2 Value
    const beforeValueV2 = await box.valueV2();
    console.info('ValueV2 before', beforeValueV2.toNumber());

    // Set new V2 Value
    await box.setValueV2(beforeValueV2.toNumber() + 100);
    const afterValueV2 = await box.valueV2();
    console.info('ValueV2 after', afterValueV2.toNumber());
  } catch (error) {
    console.error('UUPS: upgrade box error', error);
  }
};

Transparent

// migrations/MM_upgrade_transparent_box.js
const { admin } = require('@openzeppelin/truffle-upgrades');
const ProxyAdmin = artifacts.require(
  '@openzeppelin/upgrades-core/artifacts/@openzeppelin/contracts/proxy/transparent/ProxyAdmin.sol/ProxyAdmin.json'
);
const Box = artifacts.require('TransparentBox');
const BoxV2 = artifacts.require('TransparentBoxV2');

module.exports = async function (deployer) {
  try {
    // Deploy the new BoxV2 implementation contract
    await deployer.deploy(BoxV2);

    // Upgrade proxy contract by admin
    const adminIns = await admin.getInstance();
    const adminContract = await ProxyAdmin.at(adminIns.address);
    await adminContract.upgrade(Box.address, BoxV2.address);
    console.info('Upgraded', Box.address);

    // Call proxy contract
    const box = await BoxV2.at(Box.address);
    const beforeValue = await box.value();
    console.info('Value before', beforeValue.toNumber());

    // Set new Value
    await box.setValue(beforeValue.toNumber() + 100);
    const afterValue = await box.value();
    console.info('Value after', afterValue.toNumber());

    // Read new V2 Value
    const beforeValueV2 = await box.valueV2();
    console.info('ValueV2 before', beforeValueV2.toNumber());

    // Set new V2 Value
    await box.setValueV2(beforeValueV2.toNumber() + 100);
    const afterValueV2 = await box.valueV2();
    console.info('ValueV2 after', afterValueV2.toNumber());
  } catch (error) {
    console.error('Transparent: upgrade box error', error);
  }
};

Beacon

当 Beacon 被升级时,所有指向它的 Beacon 代理都会使用新的合约实现。

// migrations/MM_upgrade_beacon_box.js
const UpgradeableBeacon = artifacts.require(
  '@openzeppelin/upgrades-core/artifacts/@openzeppelin/contracts/proxy/beacon/UpgradeableBeacon.sol/UpgradeableBeacon.json'
);
const { erc1967 } = require('@openzeppelin/truffle-upgrades');

const Box = artifacts.require('BeaconBox');
const BoxV2 = artifacts.require('BeaconBoxV2');

module.exports = async function (deployer) {
  try {
    // Deploy the new BoxV2 implementation contract
    await deployer.deploy(BoxV2);
    const beaconAddress = await erc1967.getBeaconAddress(Box.address);

    // Upgrade proxy contract
    const proxyContract = await UpgradeableBeacon.at(beaconAddress);
    await proxyContract.upgradeTo(BoxV2.address);
    console.info('Upgraded', Box.address);

    // Call proxy contract
    const box = await BoxV2.at(Box.address);
    const beforeValue = await box.value();
    console.info('Value before', beforeValue.toNumber());

    // Set new Value
    await box.setValue(beforeValue.toNumber() + 100);
    const afterValue = await box.value();
    console.info('Value after', afterValue.toNumber());

    // Read new V2 Value
    const beforeValueV2 = await box.valueV2();
    console.info('ValueV2 before', beforeValueV2.toNumber());

    // Set new V2 Value
    await box.setValueV2(beforeValueV2.toNumber() + 100);
    const afterValueV2 = await box.valueV2();
    console.info('ValueV2 after', afterValueV2.toNumber());
  } catch (error) {
    console.error('Beacon: upgrade box error', error);
  }
};