Hardhat, infura로 Ropsten Ethereum testnet에 upgradeable contract 배포하기
본문 바로가기
Block Chain

Hardhat, infura로 Ropsten Ethereum testnet에 upgradeable contract 배포하기

by 쏠수있어ㅤ 2022. 9. 6.
반응형

 

 

 

Hardhat으로 ropsten testnet에 Upgradeable Contracts 배포하기 

 

webstrom 새로운 폴더 열고 

$ npm init 

-> package.json 생성됨

 

package.json  설치할 것 작성

{
  "name": "upgradeable",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "devDependencies": {
    "@nomiclabs/hardhat-ethers": "^2.0.3",
    "@nomiclabs/hardhat-etherscan": "^2.1.8",
    "@openzeppelin/hardhat-upgrades": "^1.12.0",
    "ethers": "^5.5.2",
    "hardhat": "^2.8.0"
  },
  "dependencies": {
    "@openzeppelin/contracts": "^4.4.1",
    "@openzeppelin/contracts-upgradeable": "^4.4.1"
  },
  "author": "",
  "license": "ISC"
}

 

모두 설치하기

$ npm i 

이 실패해서

$ npm i --force 

로 진행함 

 

$ npx hardhat 

으로 프로젝트 시작

 

 

upgradeable > contracts > box.sol & boxV2.sol 파일 생성 

box.sol = first version of smart contract 

 

box.sol 

* 특이점 : upgradeable contract 에는 constructor 가 올 수 없음 

// SPDX-License-Identifier: MIT
pragma solidity 0.8.10;

contract Box {
    uint public val;

    // constructor(uint _val) {
    //     val = _val;
    // }

    function initialize(uint _val) external {
        val = _val;
    }
}

 

boxV2.sol

// SPDX-License-Identifier: MIT
pragma solidity 0.8.10;

contract BoxV2 {
    uint public val;

    // function initialize(uint _val) external {
    //     val = _val;
    // }

    function inc() external {
        val += 1;
    }
}

여기선 initialize() 가 box.sol 첫번째 contract에 이미 있기때문에 주석처리 함 

 

 

hardhat.config.js 

require("@nomicfoundation/hardhat-toolbox");
require("@nomiclabs/hardhat-ethers");
require("@openzeppelin/hardhat-upgrades");
require("@nomiclabs/hardhat-etherscan");

/** @type import('hardhat/config').HardhatUserConfig */
module.exports = {
  solidity: "0.8.10",
  networks: {
    ropsten: {
      url: `https://ropsten.infura.io/v3/${process.env.INFURA_API_KEY}`, // infura에서 가져오는 api key
      accounts: [process.env.PRI_KEY] // 지갑의 private key !! ropsten 등 네트워크와 관련없이 그냥 내 지갑의 개인키
    }
  },
  etherscan: {
    apiKey: process.env.ETHERSCAN_API_KEY,  // 이더스캔에서 가져오는 api key
  },
};

 

 

scripts > deploy_box_v1.js 파일 생성 및 코드 작성

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

async function main() {
  const Box = await ethers.getContractFactory("Box");

  const box = await upgrades.deployProxy(Box, [42], {
    initializer: "initialize",
  });
  await box.deployed();

  console.log('Box deployed to :', box.address);
}

main()

Proxy로 배포하는 걸 가져온 Box 에 시작 함수는 initialize 인자값은 42 설정

 

 

이제 아래 명령어로 배포 실행 

env $(cat .env) npx hardhat run --network ropsten scripts/deploy_box_v1.js

결과 : 

Box deployed to : 0x869fd12A5367c3B3cF582690175cF5aD3E31638C

 

해당 주소를 받으면 etherscan ropsten testnet에 가서 배포된 거 확인해보기 

https://ropsten.etherscan.io/

 

 

배포한 계좌 주소 (내 이더 지갑 주소)로 검색하면 총 3개의 tx 이 생성되어 있고 각 contract name은 아래와 같다. 

 

TransparentUpgradeableProxy

ProxyAdmin

Box

 

upgradeable contract으로 하게되면 이렇게 3개가 나오나보다... 그 중에 마지막 Box는 직접 입력한 스마트 컨트렉트 이름이다. Box tx contract 를 누르면 verify하라고 나온다. 

 

hardhat을 사용해서 verify 하기

* 여기에 들어갈 contract address는 위에서 console.log로 나온 것이 아니라 creator 배포한 나의 지갑 주소로 들어가면 tx 3개가 나오고 거기 중 첫 tx 에 -> contract -> ByteCode로 나온 것 (verify and publish!) 라고 나온 tx의 주소를 넣어야함

env $(cat .env) npx hardhat verify --network ropsten [contract address (implemetaton one)]

 

 

verify 중  Error: ENOENT: no such file or directory, <- 요 에러가 나면 

env $(cat .env) npx hardhat clear

를 한 후 다시 시도하면 잘 된다. 

 

 

다시 해당 tx으로 가보면 bytecode -> 내가 작성한 solidity code들이 잘 보인다. 

 

Contract Name : TransparentUpgradeableProxy Tx로 들어가서 -> More Options -> Is this a proxy? 클릭 -> veryfy -> 하고 다시 contract 들어가면 Reas as Proxy , Write as Proxy 가 생긴다. 

 

Read as Proxy 하면 val -> 42가 나온다. 

요 42는 Proxy contract에 저장된 것 

 

 

 

 

 

이제 Box -> BoxV2 로 SmartContract 업그레이드 시키기 

scripts > upgrade_box_v2.js 파일 생성 및 코드 작성

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

const PROXY = '0x3C7cf16a985FC7cc64f13eC260f55601f4D93A4D';

async function main() {
    const BoxV2 = await ethers.getContractFactory("BoxV2");
    await upgrades.upgradeProxy(PROXY, BoxV2);

    console.log("Box upgraded"); 
}

main();

BoxV2 contract 가져와서 Proxy -> BoxV2로 업그레이드

 

hardhat 명령어 입력

env $(cat .env) npx hardhat run --network ropsten scripts/upgrade_box_v2.js

 



upgraded 

 

 

 

 

첫번째 tx : BoxV2 배포 

두번째 tx : upgrade proxy admin

upgrate() 함수로 implemetation box -> boxV2 로 업그레이드 함 

 

첫번째 tx verify by hardhat 하고 코드보면 Box2 contract 나옴 

 

이전 TransparentUpgradeableProxy tx로 돌아가서 다시 etherscan이 최신의 implement를 바라보도록 "More options" -> is this a Proxy ? 클릭 -> verify 

 

-> 다시 해당 proxy contract 에서 "Write as Proxy"  -> connect metatmask -> inc 함수 write 클릭 -> 그리고 이제 Read as Proxy를 클릭하면 43 이 되어 있음 ! 아까는 42 

 

 

 

 

Reference : https://www.youtube.com/watch?v=JgSj7IiE4jA 

반응형

댓글