본문 바로가기
블록체인 backEnd

업그레이더블 컨트랙트 hardhat testCode.01

by gun_poo 2023. 8. 28.

 코드를 설명하기 앞서 하드햇을 사용하였고 테스트 코드를 작성하고 돌려보니 세폴리아, 괴를리는 작업이 되지 않아 기본네트워크로 테스트하였다. (지원툴)

 

1. 배포 테스트

 각각을 아무렇게나 배포 하는 것이 아니라 얽혀있어 순서가 중요하다.

  1. LogicV1 배포
  2. proxy 배포
  3. LogicV2 배포
  4. upgrade
async function deployFixture() {
  const { owner, minter, recipient, admin } = await getSigners();
  const erc20Impl = await ethers.deployContract("ERC20Impl");
  await erc20Impl.waitForDeployment();
  const erc20V1Address = await erc20Impl.getAddress();

  const initialSupply = ethers.parseUnits("10000", 18); // 1,000,000 토큰

  //initialize setting minter_role = minter,
  const encodedInitializeData = erc20Impl.interface.encodeFunctionData(
    "initialize",
    ["BittoToken", "BITTO", initialSupply, minter.address]
  );
  const erc20Proxy = await ethers.deployContract("ERC20Proxy", [
    erc20V1Address,
    admin.address,
    encodedInitializeData,
  ]);
  await erc20Proxy.waitForDeployment();
  // console.log("Proxy contract : ", await erc20Proxy.getAddress());
  const proxyAddress = await erc20Proxy.getAddress();

  const transparentUpgradeableInstance = await ethers.getContractAt(
    "ITransparentUpgradeableProxy",
    proxyAddress,
    admin
  );
  const erc20ImplInstance = erc20Impl.attach(proxyAddress);

  //mint 권환 학인//
  const MINTER_ROLE = ethers.keccak256(ethers.toUtf8Bytes("MINTER_ROLE"));
  let hasAdminRole = await erc20ImplInstance.hasRole(
    MINTER_ROLE,
    minter.address
  );

  // console.log(hasAdminRole); // true or false

  const erc20ImplV2 = await ethers.deployContract("ERC20ImplV2");
  await erc20ImplV2.waitForDeployment();
  const erc20ImplV2Address = await erc20ImplV2.getAddress();
  const erc20ImplV2Instance = erc20ImplV2.attach(proxyAddress);
  return {
    erc20Impl,
    erc20V1Address,
    erc20Proxy,
    erc20ImplInstance,
    proxyAddress,
    erc20ImplV2,
    erc20ImplV2Instance,
    erc20ImplV2Address,
    transparentUpgradeableInstance,
  };
}

설명하기 앞서 배포 함수를 첨부한다.

함수를 전부 설명하지 않고 간단한 플로우만 설명하겠다. 양이 너무 많은 관계로. 필요한 부분만 자세히.

상세 순서

1. Erc20V1 배포

2. 프록시 컨트렉트 배포를 위한 컨스트럭터 

( address _logic, address _admin, bytes memory _data )

의  bytes memory _data 값이 필요하다.

_data 매개변수는 초기화 함수에 전달될 데이터이다.

일반적으로, 프록시 패턴을 사용하는 업그레이드 가능한 스마트 컨트랙트에서는 로직 컨트랙트가 initializer라 불리는 특별한 함수를 가지고 있다. 이 initializer 함수는 컨트랙트 배포 후 한 번만 호출되어야 하며, 일반적으로 상태 변수들을 설정하거나 필요한 초기 설정을 수행한다.

따라서, _data 매개변수에는 이러한 initializer 함수를 호출하기 위해 필요한 ABI 인코딩된 데이터가 들어간다.

 

 //initialize setting minter_role = minter,
  const encodedInitializeData = erc20Impl.interface.encodeFunctionData(
    "initialize",
    ["BittoToken", "BITTO", initialSupply, minter.address]
  );
  const erc20Proxy = await ethers.deployContract("ERC20Proxy", [
    erc20V1Address,
    admin.address,
    encodedInitializeData,
  ]);
  await erc20Proxy.waitForDeployment();

3. Erc20V2 배포 

4. upgrade 진행

 

우선 upgradeTo 함수는 proxy 컨트랙트가 상속하고 있는 컨트랙트의 인터페이스에 존재하기 때문에 "ITransparentUpgradeableProxy" 인터페이스를 가진 proxyAddress 위치에 있는 프록시 컨트랙을 참조하여 transparentUpgradeableInstance 객체를 생성한다. 그런 다음 transparentUpgradeableInstance을 사용해 업그레이드를 진행한다. 함수는 다음과 같다.

const proxyAddress = await erc20Proxy.getAddress();

  const transparentUpgradeableInstance = await ethers.getContractAt(
    "ITransparentUpgradeableProxy",
    proxyAddress,
    admin
  );
await transparentUpgradeableInstance.upgradeTo(erc20ImplV2Address);

 

기본적인 프록시 컨트랙트의 배포 테스트 과정은 이러하다. 

지원해주는 툴을 사용해서 describe에 필요한 함수들을 빼서 보내주면 된다!

const {
  loadFixture,
} = require("@nomicfoundation/hardhat-toolbox/network-helpers");
.
.
.
const { erc20ImplInstance } = await loadFixture(deployFixture);

 

다음장에서는 테스트코드에 대해 알아보겠다.

'블록체인 backEnd' 카테고리의 다른 글

Pool : first provide Liquidity  (0) 2023.10.08
DeFi Contract 작업  (0) 2023.10.03
database mysql sequelize setting  (1) 2023.09.03
업그레이더블 컨트랙트 샘플  (0) 2023.08.28
브릿지  (0) 2023.01.26

댓글