Hardhat-deploy: سؤال حول نشر العقود القابلة للترقية

تم إنشاؤها على ٨ يونيو ٢٠٢١  ·  9تعليقات  ·  مصدر: wighawag/hardhat-deploy

ما هي الطريقة الصحيحة لنشر عقود OpenZeppelin القابلة للترقية؟
OpenZeppelin upgrdable لها وظيفة التهيئة الافتراضية () التي يتم استدعاؤها بواسطة البرنامج المساعد ترقيات hardhat.
لا توجد مكالمة تلقائية من hardhat-النشر ، فقط طريقة ما بعد الترقية التي قد يتم استدعاؤها.

هل يجب علي نشر العقود أولاً من خلال البرامج النصية في مجلد النشر ثم استدعاء وظائف التهيئة من بعض البرامج النصية خارج مجلد النشر؟ أم أن هناك طريقة لدمج وظيفة التهيئة () الاستدعاء من مجلد النشر نفسه؟

التعليق الأكثر فائدة

إعادة تهيئة الوظيفة للوكلاء

لقد أضفت خيارات جديدة (بدلاً من methodName الذي لا يزال متاحًا) في hardhat-publish 0.8.0

انظر https://github.com/wighawag/template-ethereum-contracts/blob/595c1b5ec9cdf1276f4d3a43b4825bcef78bd2cd/deploy/004_deploy_erc20_always_proxied_via_openzeppelin_proxy.ts#L12

اسمحوا لي أن أعرف إذا واجهت أي مشاكل

ال 9 كومينتر

الطريقة التي يفكر بها النشر الثابت في نشر البرنامج النصي بشكل افتراضي هي أنها غير فعالة. الأمر نفسه ينطبق على نشر الوكيل. هذا يجعله لطيفًا للتطوير / النشر لأنك تحتاج فقط إلى التفكير في الحالة التي تريدها وسيؤدي النشر الثابت إلى جعل كل شيء يصل إلى تلك الحالة ،

للإجابة على سؤالك ، ما أفعله عادةً هو جعل وظيفة التهيئة الخاصة بي غير فعالة أيضًا ، لذا بدلاً من رميها ، تخطي ببساطة إذا تم تهيئتها بالفعل. وبالتالي يمكنني إضافة هذه الوظيفة كوظيفة postUpgrade وكلها تعمل بشكل جيد. في التطوير يمكنني حتى تغيير وظيفة التهيئة للقيام بالأشياء عندما أقوم بالترقية إذا لزم الأمر.

لسيناريو أكثر تعقيدًا ، يمكنك تنظيم كل ترقية في برنامج نشر منفصل.

هناك ميزة غير موثقة تخضع للتغييرات: المعلمة upgradeIndex التي تتيح لك تحديد البرنامج النصي للنشر الذي يجب تنفيذه بالترتيب.

يعد هذا أمرًا رائعًا للاختبار حيث يمكنك اختبار وكيلك في أي وقت بين محفوظات الترقية والتأكد من جميع الأعمال.

شكرا على ردك السريع.
يبدو أنني تمكنت من جعل كل شيء يعمل بسلاسة. أستخدم deploy() ثم execute مع initialize وظيفة عقد OpenZeppelin Initializable . إرجاع execute() صحيح وهذا يجعله لا يعمل عندما أقوم بترقية العقود:

// deploy/01_deploy_skin_rewards.js

module.exports = async ({
  getNamedAccounts,
  deployments,
}) => {
  const {deploy} = deployments;
  const {deployer} = await getNamedAccounts();
  await deploy('SkinRewards', {
    from: deployer,
    proxy: {
      owner: deployer,
      proxyContract: 'OpenZeppelinTransparentProxy',
    },
    args: [],
    log: true,
  });
};
module.exports.tags = ['SkinRewards'];

وثم

// deploy/02_init_skin_rewards.js

require('dotenv').config();
const RewardPeriods = ethers.BigNumber.from(process.env.REWARD_PERIODS);
module.exports = async ({getNamedAccounts, deployments}) => {
  const { deployer } = await getNamedAccounts();
  const SnookGame = await deployments.get('SnookGame');
  const SnookState = await deployments.get('SnookState');
  const SnookToken = await deployments.get('SnookToken');
  const SkillToken = await deployments.get('SkillToken');
  const Afterdeath = await deployments.get('Afterdeath');
  const Treasury = await deployments.get('Treasury');

  await deployments.execute(
    'SkinRewards',
    {from:deployer},
    'initialize',
    RewardPeriods,
    Treasury.address,
    SnookGame.address,
    SnookState.address,
    SnookToken.address,
    SkillToken.address,
    Afterdeath.address
  );
  deployments.log('Initialized SkinRewards');
  return true;
};
module.exports.tags = ['initSkinRewards'];
module.exports.id = 'initSkinRewards';

هل يمكن اعتبار هذه الطريقة _ممارسة جيدة_؟ هل هو كيف سعيت إليه؟

كما ذكرت أعلاه ، في SkinRewards أرث من عقد OpenZeppelin Initializable الذي يحدد وظيفة initialize() ليتم استدعاؤها أولاً. لذلك لا أرى كيف يمكنني تشغيله بعد الترقية. هل يمكن ان توضح؟ شكرا

هذا يبدو جيدًا ، لكن العيب مقارنة باستخدام methodName ("postUpgrade") هو أنك تنفذ 2 tx بدلاً من 1

إذا جعلت وظيفة التهيئة الخاصة بك خاملة ، فيمكن استدعاؤها عدة مرات دون رمي عن طريق التأكد من أن المكالمة الإضافية لن تعدل الحالة (ببساطة عن طريق التخطي إذا كانت مهيأة بالفعل) ، ثم يمكنك استخدامها عبر خيارات methodName . سيتم تنفيذ النشر الأول أيضًا.

ملاحظة ، نظرًا لأنك تستخدم الوسائط ويتم إعداد وظيفة النشر بحيث يمكنك ببساطة إيقاف تشغيل خيار الوكيل والحصول على عقد عمل غير قابل للتغيير ، فإن الخيار methodName يستخدم خيارات args للحجة.
هذا يعني أن مُنشئ تنفيذ الوكيل يحتاج أيضًا إلى هذه الحجج. إذا كنت لا تنوي أبدًا استخدام العقد بدون وكيل ، فلا يمكنك فعل أي شيء مع الحجج.

في الواقع للراحة إذا كان عقد التنفيذ يحتوي على مُفسر صفري ، فإنه يتجاهل المُنشئ تمامًا ولكني لست متأكدًا من أنها كانت فكرة جيدة.

سيكون هذا البرنامج النصي مع الخيار methodName :

// deploy/01_deploy_skin_rewards.js

module.exports = async ({
  getNamedAccounts,
  deployments,
}) => {
  const {deploy} = deployments;
  const {deployer} = await getNamedAccounts();
  await deploy('SkinRewards', {
    from: deployer,
    proxy: {
      methodName: 'initialize`,
      owner: deployer,
      proxyContract: 'OpenZeppelinTransparentProxy',
    },
    args: [
      RewardPeriods,
      Treasury.address,
      SnookGame.address,
      SnookState.address,
      SnookToken.address,
      SkillToken.address,
      Afterdeath.address
    ],
    log: true,
  });
};
module.exports.tags = ['SkinRewards'];

_ إذا جعلت دالة التهيئة الخاصة بك idempotent ، أي يمكن استدعاؤها عدة مرات دون رمي عن طريق التأكد من أن المكالمة الإضافية لن تعدل الحالة (ببساطة عن طريق التخطي إذا كانت مهيأة بالفعل) ، فيمكنك استخدامها عبر خيارات methodName. سيتم تنفيذ النشر الأول أيضًا.

هذا يعني أنه لا يمكننا استخدام initialize() function AS-IS من https://github.com/OpenZeppelin/openzeppelin-contracts-upgradeable/blob/release-v4.0/contracts/proxy/utils/Initializable.sol .

تضمين التغريدة

سأفكر في إضافة خيار للحصول على هذا النوع من السلوك

رائع شكرا لك!

سؤال آخر حول استخدام العقود المنشورة. على وجه الخصوص ، أنا أطلب إعادة تنظيم Uniswap .

من هذا الجزء من مستندات البرنامج المساعد ، لا أرى كيف أقدم عنوان عقد Uniswap المنشور. Uniswap NPM يأتي بمجلد build مع القطع الأثرية ولكن كيف أجعل المكون الإضافي يعرف عن العقد في عنوان محدد؟ لا نريد استخدام الإيثرات في نص النشر ، أليس كذلك؟

الكود التالي ليس ما نريده في سكربت النشر:

const { ethers } = require("hardhat");

const UniswapV2FactoryArtifact = require('@uniswap/v2-core/build/UniswapV2Factory.json');
const UniswapV2FactoryAddress = '0x5C69bEe701ef814a2B6a3EDD4B1652CB9cc5aA6f';

module.exports = async ({getNamedAccounts, deployments}) => {
  const {deployer} = await getNamedAccounts();
  const UniswapFactory = await ethers.getContractAt(UniswapV2FactoryArtifact.abi, UniswapV2FactoryAddress);
// continue...

كيف يمكنني نشر Uniswap في deployments var؟

بالنسبة للعقود التي تم نشرها بالفعل ، فإن الأفضل هو إنشاء ملفات لها في مجلد عمليات النشر المقابل
لذلك بالنسبة لـ mainnet uniswap وبافتراض أن لديك شبكة mainnet مؤكدًا في hardhat.config.js ، يمكنك إنشاء ملف "النشر / mainnet / UniswapFactory.json". على الأقل يحتاج إلى عنوان ومجال أبي

ثم يمكنك الوصول إليها عبر عمليات النشر عندما تكون على تلك الشبكة

رابط المستند الذي تشير إليه للسماح لك بالوصول إلى العناصر الأثرية (مثل مجلد إنشاء uniswap) أو نشر البرنامج النصي ، لكن الأخير لا يعمل إلا إذا كشف المشروع المعني عن هذه البرامج النصية في مكان ما

أفعل ذلك في مشروعي الخاص مثل https://github.com/wighawag/universal-forwarder والذي يسمح للمستخدم ببساطة بتثبيت حزمة npm ويقومون بنشر المشروع بأكمله في الاختبار الخاص بهم أو على شبكتهم الخاصة. لكن uniswap لا يوفر ذلك

باهر. شكرا جزيلا.

إعادة تهيئة الوظيفة للوكلاء

لقد أضفت خيارات جديدة (بدلاً من methodName الذي لا يزال متاحًا) في hardhat-publish 0.8.0

انظر https://github.com/wighawag/template-ethereum-contracts/blob/595c1b5ec9cdf1276f4d3a43b4825bcef78bd2cd/deploy/004_deploy_erc20_always_proxied_via_openzeppelin_proxy.ts#L12

اسمحوا لي أن أعرف إذا واجهت أي مشاكل

هل كانت هذه الصفحة مفيدة؟
0 / 5 - 0 التقييمات

القضايا ذات الصلة

jsidorenko picture jsidorenko  ·  3تعليقات

smartcontracts picture smartcontracts  ·  20تعليقات

lepidotteri picture lepidotteri  ·  5تعليقات

tennox picture tennox  ·  4تعليقات

gitpusha picture gitpusha  ·  6تعليقات