OpenZeppelin μ
κ·Έλ μ΄λ κ°λ₯ κ³μ½μ λ°°ν¬νλ μ¬λ°λ₯Έ λ°©λ²μ 무μμ
λκΉ?
OpenZeppelin upgrdableμλ hardhat μ
κ·Έλ μ΄λ νλ¬κ·ΈμΈμ μν΄ νΈμΆλλ κΈ°λ³Έ initialize() ν¨μκ° μμ΅λλ€.
hardhat-deployμμ μλ νΈμΆμ μμΌλ©° νΈμΆν μ μλ μ¬ν μ
κ·Έλ μ΄λ λ©μλλ§ μμ΅λλ€.
λ¨Όμ λ°°ν¬ ν΄λμ μ€ν¬λ¦½νΈλ₯Ό ν΅ν΄ κ³μ½μ λ°°ν¬ν λ€μ λ°°ν¬ ν΄λ μΈλΆμ μΌλΆ μ€ν¬λ¦½νΈμμ μ΄κΈ°ν κΈ°λ₯μ νΈμΆν΄μΌ ν©λκΉ? μλλ©΄ λ°°ν¬ ν΄λ μ체μμ νΈμΆνλ initialize() ν¨μλ₯Ό ν΅ν©νλ λ°©λ²μ΄ μμ΅λκΉ?
hardhat-deployκ° κΈ°λ³Έμ μΌλ‘ λ°°ν¬ μ€ν¬λ¦½νΈλ₯Ό κ³ λ €νλ λ°©μμ λ©±λ±μ±μ λλ€. νλ‘μ λ°°ν¬μλ λμΌνκ² μ μ©λ©λλ€. μ΄κ²μ λΉμ μ΄ μνλ μνμ λν΄μλ§ μκ°νλ©΄ λκ³ hardhat-deployκ° λͺ¨λ κ²μ κ·Έ μνμ λλ¬νλλ‘ λ§λ€ κ²μ΄λ―λ‘ κ°λ°/λ°°ν¬μ μ μ©ν©λλ€.
κ·Έλμ κ·νμ μ§λ¬Έμ λλ΅νκΈ° μν΄, μ κ° μΌλ°μ μΌλ‘ νλ μΌμ μ΄κΈ°ν κΈ°λ₯μ λ©±λ±μ±μΌλ‘ λ§λλ κ²μ΄λ―λ‘ μ΄λ―Έ μ΄κΈ°νλ κ²½μ° κ·Έλ₯ 건λλ°λ λμ λμ§μμμ€. λ°λΌμ ν΄λΉ κΈ°λ₯μ postUpgrade κΈ°λ₯μΌλ‘ μΆκ°ν μ μμΌλ©° λͺ¨λ μ μλν©λλ€. κ°λ° μ€μ νμν κ²½μ° μ κ·Έλ μ΄λν λ μμ μ μννλλ‘ μ΄κΈ°ν κΈ°λ₯μ λ³κ²½ν μλ μμ΅λλ€.
λ 볡μ‘ν μλ리μ€μ κ²½μ° κ° μ κ·Έλ μ΄λλ₯Ό λ³λμ λ°°ν¬ μ€ν¬λ¦½νΈλ‘ ꡬμ±ν μ μμ΅λλ€.
λ³κ²½λ μ μλ λ¬Έμνλμ§ μμ κΈ°λ₯μ΄ μμ΅λλ€. upgradeIndex
맀κ°λ³μλ₯Ό μ¬μ©νλ©΄ μμλλ‘ μ€νν΄μΌ νλ λ°°ν¬ μ€ν¬λ¦½νΈλ₯Ό μ§μ ν μ μμ΅λλ€.
μ κ·Έλ μ΄λ κΈ°λ‘ μ¬μ΄μ μ΄λ μμ μμλ yoru νλ‘μλ₯Ό ν μ€νΈνκ³ λͺ¨λ μλμ νμΈν μ μμΌλ―λ‘ ν μ€νΈμ μ ν©ν©λλ€.
λΉ λ₯Έ λ΅λ³ κ°μ¬ν©λλ€.
λͺ¨λ μμ
μ μννκ² μνν μ μμλ κ² κ°μ΅λλ€. OpenZeppelin Initializable
κΈ°λ³Έ κ³μ½μ initialize
deploy()
λ₯Ό μ¬μ©ν λ€μ execute
λ₯Ό μ¬μ©ν©λλ€. execute()
λ trueλ₯Ό λ°ννλ―λ‘ κ³μ½μ μ
κ·Έλ μ΄λν λ μ€νλμ§ μμ΅λλ€.
// 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
μμλ initialize()
ν¨μκ° λ¨Όμ νΈμΆλλλ‘ μ μνλ OpenZeppelinμ Initializable
κ³μ½μ μμν©λλ€. λ°λΌμ μ¬ν μ
κ·Έλ μ΄λλ₯Ό μ€ννλ λ°©λ²μ μ μ μμ΅λλ€. μ€λͺ
ν΄μ£Όμ€ μ μλμ? κ°μ¬ ν΄μ
μ’μ κ² κ°μ΅λλ€. methodName
("postUpgrade")λ₯Ό μ¬μ©νλ κ²κ³Ό λΉκ΅ν λ λ¨μ μ 1 λμ 2 txλ₯Ό μ€ννλ€λ κ²μ
λλ€.
μ΄κΈ°ν ν¨μλ₯Ό λ©±λ±μλ‘ λ§λ€λ©΄ μΆκ° νΈμΆμ΄ μνλ₯Ό μμ νμ§ μλμ§ νμΈνμ¬ λμ§μ§ μκ³ μ¬λ¬ λ² νΈμΆν μ μμ΅λλ€(μ΄λ―Έ μ΄κΈ°νλ κ²½μ° κ±΄λλ°κΈ°). κ·Έλ¬λ©΄ methodName
μ΅μ
μ ν΅ν΄ μ¬μ©ν μ μμ΅λλ€. . 첫 λ²μ§Έ λ°°ν¬μμλ μ€νλ©λλ€.
μΈμλ₯Ό μ¬μ©νκ³ λ°°ν¬ κΈ°λ₯μ΄ μ€μ λμ΄ νλ‘μ μ΅μ
μ λκ³ λ³κ²½ν μ μλ κ³μ½μ΄ μλνλλ‘ νκΈ° λλ¬Έμ methodName
#$ μ΅μ
μ μΈμμ args
μ΅μ
μ μ¬μ©ν©λλ€.
μ΄λ νλ‘μ ꡬνμ μμ±μμλ μ΄λ¬ν μΈμκ° μμ΄μΌ ν¨μ μλ―Έν©λλ€. νλ‘μ μμ΄ κ³μ½μ μ¬μ©νμ§ μμΌλ €λ©΄ μΈμλ‘ μ무 κ²λ ν μ μμ΅λλ€.
μ€μ λ‘ νΈμλ₯Ό μν΄ κ΅¬ν κ³μ½μ arg construtcorκ° 0μ΄λ©΄ μμ±μλ₯Ό μμ ν 무μνμ§λ§ κ·Έκ²μ΄ μ’μ μκ°μΈμ§ νμ ν μ μμ΅λλ€.
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'];
_μ΄κΈ°ν ν¨μλ₯Ό λ©±λ±μ±μΌλ‘ λ§λλ κ²½μ°, μ¦ μΆκ° νΈμΆμ΄ μνλ₯Ό μμ νμ§ μλμ§ νμΈνμ¬(μ΄λ―Έ μ΄κΈ°νλ κ²½μ° λ¨μν 건λλ°μ΄) throwνμ§ μκ³ μ¬λ¬ λ² νΈμΆν μ μμΌλ©΄ methodName μ΅μ μ ν΅ν΄ μ¬μ©ν μ μμ΅λλ€. 첫 λ²μ§Έ λ°°ν¬μμλ μ€νλ©λλ€._
μ¦, https://github.com/OpenZeppelin/openzeppelin-contracts-upgradeable/blob/release-v4.0/contracts/proxy/utils/Initializable.sol μμ initialize()
ν¨μλ₯Ό κ·Έλλ‘ μ¬μ©ν μ μμ΅λλ€. .
@freebyte μ°ΈμΌλ‘
λλ μ΄λ° μ’ λ₯μ νλμ μ»κΈ° μν΄ μ΅μ μ μΆκ°νλ κ²μ κ³ λ €ν κ²μ λλ€.
μ’μμ, κ°μ¬ν©λλ€!
λ λ€λ₯Έ μ§λ¬Έμ λ°°ν¬λ κ³μ½ μ¬μ©μ κ΄ν κ²μ λλ€. νΉν Uniswap μ λν΄ λ¬»κ³ μμ΅λλ€.
νλ¬κ·ΈμΈ λ¬Έμ μ μ΄ λΆλΆμμ λ°°ν¬λ Uniswap κ³μ½μ μ£Όμλ₯Ό μ 곡νλ λ°©λ²μ λ³Ό μ μμ΅λλ€. Uniswap NPMμ μν°ν©νΈκ° μλ build
ν΄λμ ν¨κ» μ 곡λμ§λ§ νλ¬κ·ΈμΈμ΄ νΉμ μ£Όμμ κ³μ½μ λν΄ μλλ‘ νλ €λ©΄ μ΄λ»κ² ν΄μΌ ν©λκΉ? μ°λ¦¬λ λ°°ν¬ μ€ν¬λ¦½νΈμμ etherλ₯Ό μ¬μ©νκ³ μΆμ§ μμ΅λλ€. κ·Έλ μ£ ?
λ€μ μ½λλ λ°°ν¬ μ€ν¬λ¦½νΈμμ μνλ κ²μ΄ μλλλ€.
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...
deployments
varμ Uniswap λ°°ν¬λ₯Ό κ°μ Έμ€λ €λ©΄ μ΄λ»κ² ν©λκΉ?
μ΄λ―Έ λ°°ν¬λ κ³μ½μ κ²½μ° ν΄λΉ λ°°ν¬ ν΄λμ νμΌμ λ§λλ κ²μ΄ κ°μ₯ μ’μ΅λλ€.
λ°λΌμ λ©μΈλ· uniswapμ κ²½μ° hardhat.config.jsμ λ©μΈλ· λ€νΈμν¬κ° ꡬμ±λμ΄ μλ€κ³ κ°μ νλ©΄ "deployments/mainnet/UniswapFactory.json" νμΌμ μμ±ν μ μμ΅λλ€. μ΅μν μ£Όμμ BI νλκ° νμν©λλ€.
κ·Έλ° λ€μ ν΄λΉ λ€νΈμν¬μ μμ λ λ°°ν¬λ₯Ό ν΅ν΄ μ‘μΈμ€ν μ μμ΅λλ€.
μν°ν©νΈ(uniswap λΉλ ν΄λ)μ μ‘μΈμ€νκ±°λ μ€ν¬λ¦½νΈλ₯Ό λ°°ν¬ν μ μλλ‘ κ°λ¦¬ν€λ λ¬Έμ λ§ν¬, κ·Έλ¬λ νμλ ν΄λΉ νλ‘μ νΈκ° μ΄λ¬ν λ°°ν¬ μ€ν¬λ¦½νΈλ₯Ό μ΄λκ°μ λ ΈμΆν κ²½μ°μλ§ μλν©λλ€.
https://github.com/wighawag/universal-forwarder μ κ°μ λ΄ νλ‘μ νΈμμ μ΄λ₯Ό μννμ¬ μ¬μ©μκ° npm ν¨ν€μ§λ₯Ό μ€μΉνκΈ°λ§ νλ©΄ μ 체 νλ‘μ νΈλ₯Ό ν μ€νΈ λλ μ체 λ€νΈμν¬μ λ°°ν¬ν μ μμ΅λλ€. κ·Έλ¬λ uniswapμ κ·Έκ²μ μ 곡νμ§ μμ΅λλ€
μμ²λ. μ λ§ κ°μ¬ν©λλ€.
νλ‘μμ λν μ¬μ΄κΈ°ν κΈ°λ₯
hardhat-deploy 0.8.0μ μ μ΅μ
(μμ§ μ¬μ© κ°λ₯ν methodName
λμ )μ μΆκ°νμ΅λλ€.
https://github.com/wighawag/template-ethereum-contracts/blob/595c1b5ec9cdf1276f4d3a43b4825bcef78bd2cd/deploy/004_deploy_erc20_always_proxied_via_openzeppelin#_proxy.ts λ₯Ό μ°Έμ‘°νμμμ€
λ¬Έμ κ° λ°μνλ©΄ μλ €μ£Όμμμ€.
κ°μ₯ μ μ©ν λκΈ
νλ‘μμ λν μ¬μ΄κΈ°ν κΈ°λ₯
hardhat-deploy 0.8.0μ μ μ΅μ (μμ§ μ¬μ© κ°λ₯ν
methodName
λμ )μ μΆκ°νμ΅λλ€.https://github.com/wighawag/template-ethereum-contracts/blob/595c1b5ec9cdf1276f4d3a43b4825bcef78bd2cd/deploy/004_deploy_erc20_always_proxied_via_openzeppelin#_proxy.ts λ₯Ό μ°Έμ‘°νμμμ€
λ¬Έμ κ° λ°μνλ©΄ μλ €μ£Όμμμ€.