Полное руководство по Solidity

Смарт-контракты неизменяемы по умолчанию, то есть вы не можете изменить код смарт-контракта при их развертывании, если вы повторно развернете смарт-контракт, он сгенерирует новый адрес, и вы потеряете свои прежние данные смарт-контрактов.

Это совершенно нормально, если вы не собираетесь менять код своего смарт-контракта в любой момент.

Но если вы когда-нибудь в будущем измените код своего смарт-контракта, вам нужно подумать об эффективном способе переноса вашего смарт-контракта без потери данных и адреса контракта.

Существуют ручные способы переноса данных смарт-контрактов и принуждения пользователей к использованию вновь сгенерированного адреса путем отключения старого, но это трудоемкая задача.

В этой статье мы узнаем, как писать обновляемые смарт-контракты, используя обновляемые библиотеки OpenZeppelin и Truffle.

Давайте возьмем контракт Kickstarter в качестве варианта использования. Kickstarter — это платформа, которая позволяет пользователям создавать кампании для определенной цели, а другие пользователи могут вносить свой вклад в кампанию.

Предпосылки

  • Справедливое понимание Solidity и Truffle
  • Nodejs и нпм
  • ganache-cli или десктопное приложение Ганаш
  • Трюфель

Если у вас не установлены Node.js или npm, вам придется установить их, также установить ganache-cli или рабочий стол.

Я предпочту установить truffle глобально с помощью npm install -g truffle, но если вы решите установить его локально, все будет в порядке.

После установки создайте каталог проекта с именем по вашему выбору, откройте каталог в терминале и выполните эту команду:

truffle init

truffle init создаст для вас контракты и каталог миграции, а также файл truffle-config.js. Затем обновите truffle-config:

Если вы хотите использовать сеть ropsten, создайте файл .env и добавьте сетевые переменные ropsten.

После обновления файла конфигурации truffle установите необходимые зависимости npm:

npm install @openzeppelin/contracts-upgradeable @openzeppelin/truffle-upgrades @truffle/hdwallet-provider dotenv

Затем в папке с контрактами создайте два файла Kickstart.sol и KickstartFactory.sol.

Migration.sol был создан при запуске truffle init. Обновите контракт Migration нижеследующим. Он заимствован из примера, упомянутого в официальной документации трюфеля.

Вставьте следующий код в файл Kickstart.sol:

Если вы заметили, я использовал геттеры и сеттеры для доступа и изменения переменных контракта.

Это спецификация OpenZepplin для изменяемой изменяемой переменной смарт-контракта. Также нет функции конструктора, вместо этого использовалась инициализированная функция.

Подробнее об инициализаторах контрактов можно прочитать здесь.

Вставьте следующий код в файл KickstartFactory.sol:

В папке migrations:

// 1_initial_migration.js
const Migrations = artifacts.require("Migrations");
module.exports = function (deployer) {
  deployer.deploy(Migrations);
};

Truffle создаст эту первую начальную миграцию (1_initial_migration.js) для вас, когда вы запустите команду truffle init.

Создайте новый файл миграции в каталоге миграции 2_deploy_contracts.js:

// 2_deploy_contracts.js
const { deployProxy } = require('@openzeppelin/truffle-upgrades');
const Kickstart = artifacts.require("Kickstart");const KickstartFactory = artifacts.require("KickstartFactory");
/** Deploy contract using openzeppelin deployProxy, which will create a proxy address for you */
module.exports = async (deployer) => {
  const factory = await deployProxy(KickstartFactory, { deployer });
  const kickstart = await deployProxy(Kickstart, 
    [100,  '0x0000000000000000000000000000000000000000'], 
  { deployer   });
};

После вставки приведенного выше кода выполните следующие команды:

truffle compile
truffle migrate
// Or
truffle deploy // truffle deploy is an alias for truffle mograte

После успешной миграции с помощью truffle migrateзапустите:

truffle console

В консоли контракта выполните следующие команды:

// This will create KicstartFactory contract instance
let factory = await KickstartFactory.deployed()
// Create a new kickstart campaign
factory.createCampaign(100)
// Get the created campaign
factory.getDeployedCampaigns()
// Copy the address in the campaign list
// Create a kickstart instance by running this command
let kickstart = await Kickstart.deployed('0x11924C6967680124814fe7bFE0EB4a352CEB9Ef6')
// Replace the address with the address copied from the campaign list

Чтобы обновить контракт KicstartFactory и добавить новый function get DeployedCampaignsLength(), создайте новый файл в каталоге contracts и назовите его KickstartFactoryV2.sol.

Эта функция получит общее количество развернутых кампаний:

Создайте новый файл миграции 3_upgrade_contracts.js в каталоге migration, вставьте в файл следующий код.

// 3_upgrade_contracts.js
const { upgradeProxy } = require('@openzeppelin/truffle-upgrades');
const KickstartFactory = artifacts.require("KickstartFactory");
const KickstartFactoryV2 = artifacts.require("KickstartFactoryV2");
module.exports = async (deployer) => {
  const existing = await KickstartFactory.deployed();
  console.log('Existing Address ===', existing.address); 
  
  const instance = await upgradeProxy(
    existing.address,  KickstartFactoryV2, { deployer });
  console.log("Upgraded Address ===", instance.address);
};

Если вы заметили, на этот раз мы не развернули контракт KickstartFactory.

Вместо этого мы получили экземпляр уже развернутой версии и передали адрес новой версии, используя existing.addressв качестве первого параметра для функции updateProxy

После вставки предыдущего кода выполните следующие команды:

truffle compile
truffle migrate 
// Or
truffle deploy

Примечания

При создании обновляемых контрактов с помощью truffle никогда не пытайтесь перенести свой контракт с помощью reset flag (truffle migrate — reset), развертывание со сбросом удалит все ваши существующие состояния и данные контрактов, запустите новую миграцию, которая также изменит адрес ваших контрактов. .

Если вы хотите сбросить свои контракты в среде разработки, вы можете это сделать, но не рекомендуется использовать reset для контракта в рабочей среде.

Надеюсь, вы узнали, как создать обновляемый смарт-контракт Solidity с помощью трюфеля и openzeppelin обновляемых библиотек. Вы также можете создавать обновляемые смарт-контракты с openzeppelin и hardhat.

Клонируйте полный код на GitHub, также ознакомьтесь с моим Проектом Solidity kickstart GitHub Project, который представляет собой не обновляемую версию этого проекта с тестовыми примерами, а также имеет интерфейс для взаимодействия со смарт-контрактом ABIS.

Спасибо.