Factory Contract (23/06/13)

nazzzo·2023년 6월 13일
0

mongodb+srv://root:root@cluster0.virefkw.mongodb.net/?retryWrites=true&w=majority

ㄴ DB URI

mongosh "mongodb+srv://cluster0.virefkw.mongodb.net" --username root --password root

ㄴ 터미널 접속 주소

0xFA2e0fBBE47B0dbe0B3c4caD0cC81a57F8A663d3
0x28C9fC2f5C973EEEb00e0692074f2569501078F3

0x01B428d2EcAA1b270e274642a908Ed18f5b2207a
0x029e785C643710C29E395999ABa610A11789C6F6

mongosh "mongodb+srv://cluster0.virefkw.mongodb.net" --username root --password root

https://nest-deploy-c764d61cc1b8.herokuapp.com/

{
    "_id": "649a60a71d3d844feb19c782",
    "id": 82,
    "from": "0x84a4EE69F600B6Df5C8866A373deb3D78E91FE20",
    "to": "0x01C10472f1486CBEe15F10204fA1243c12085a28",
    "NFTaddress": "0x9FC63e744239ab41AC097341Ba4147CA93cb6d3A",
    "tokenId": 1,
    "price": 3000000000000000,
    "event": "minted",
    "createdAt": "2023-06-27T04:08:07.433Z",
    "updatedAt": "2023-06-27T04:08:07.433Z",
    "__v": 0
},

1. 팩토리 컨트랙트


팩토리 컨트랙트는 다른 스마트 컨트랙트를 배포하기 위한 컨트랙트입니다


신발 공장이 신발을 일정한 기준에 맞추어 생산하는 것처럼
팩토리 컨트랙트가 생성하는 모든 인스턴스는 특정한 규칙(인터페이스)을 준수하는 것을 보장합니다
대규모 dApp에서도 많이 사용하는 패턴이라고 합니다


스마트 컨트랙트에 있어서 이 패턴의 핵심은 두 가지입니다

  • 동일한 컨트랙트로 어드레스가 다른 여러 인스턴스를 찍어낼 수 있다는 점
  • 한 번 정의하고 나면 원하는 위치(클라이언트 측)에서 새로운 클래스 인스턴스를 만들 수 있다는 점

컨트랙트

[Factory.sol]

// SPDX-License-Identifier: GPL-3.0
pragma solidity ^0.8.0;

import "./myNFT.sol";

contract myNFTFactory {
    event NFTCreated(address indexed nftAddress, address indexed creator);

    function createNFT(string memory name, string memory symbol) external {
        myNFT newNFT = new myNFT(name, symbol);
        emit NFTCreated(address(newNFT), msg.sender);
    }
}

이 팩토리 컨트랙트는 미리 정의한 NFT 컨트랙트의 배포 작업을 위한 별도의 컨트랙트입니다

해당 토큰 생성에 필요한 필수 인자(name, symbol, description 등등)를 똑같이 전달받도록 작성되었으며,
이후 클라이언트 측에서 createNFT함수를 호출하면, 새로운 토큰이 배포되는 과정에서
새로 만들어진 NFT의 컨트랙트 어드레스(CA)와 배포자의 어드레스(EOA) 정보를
이벤트를 통해서 전달받을 수 있는 구조가 되겠습니다


클라이언트

// 팩토리 컨트랙트 인스턴스 생성
const factoryContract = new ethers.Contract(factoryAddress, factoryABI, wallet);

// NFT 인스턴스 생성
async const createNFT = (name, symbol) =>? {
  try {
    // 팩토리 컨트랙트의 createNFT 함수 호출
    const transaction = await factoryContract.createNFT(name, symbol);

    // 이벤트 필터 설정 (NFTCreated 이벤트 필터)
    const filter = factoryContract.filters.NFTCreated();

    // 영수증 객체 반환받기
    const receipt = await transaction.wait();

    // 이벤트 가져오기
    const events = await factoryContract.queryFilter(filter, receipt.blockHash);

    // 생성된 NFT의 주소와 배포자 주소 출력
    const nftAddress = events[0].args.nftAddress;
    const creatorAddress = events[0].args.creator;
    console.log('NFT Address:', nftAddress);
    console.log('Creator Address:', creatorAddress);
  } catch (error) {
    console.error('Error:', error);
  }
}

// createNFT 함수 호출 (토큰 이름과 심볼)
createNFT('My NFT', 'NFT');



2. ContractFactory


사실 더 간단하게 해결할 수 있는 방법이 있습니다
자주 쓰이는 패턴이라 그런지 ethers.js에서는 이 팩토리 기능을 담은 클래스를 내장하고 있어서요


 const factory = new ethers.ContractFactory(abi, binary, signer);
 const newContract = await factory.deploy();
 await newContract.deployTransaction.wait(1);
 console.log(`Contract Address: ${contract.address}`);

ContractFactoryethers.js 라이브러리에서 제공하는, 컨트랙트 배포를 위한 기능을 담은 클래스입니다

위에서 사용한 방식과 가장 큰 차이점이 있다면,
ContractFactory 클래스를 사용할 때는 별도의 팩토리 컨트랙트가 필요하지 않기 때문에
이 클래스가 인스턴스 생성을 위해 요구하는 ABI와 바이너리는 토큰 컨트랙트에서부터 가져와야 한다는 것입니다

돌이켜보면 토큰 컨트랙트를 직접적으로 배포할 때는 해당 컨트랙트의 ABI와 CA값을 필요로 했었죠
(Contract(ABI, CA))

ContractFactory 클래스를 통한 토큰 배포도 마찬가지로 보입니다
내부적으로는 Contract 클래스에 동일한 ABI와 새로운 CA를 계속해서 심어주는 역할을 하도록 구현돼 있는 듯...


클라이언트

const handleSubmit = async (e: React.FormEvent<HTMLFormElement>) => {
    try {
        e.preventDefault();

        const network = 'http://localhost:8545';
        const provider = new ethers.JsonRpcProvider(network); // 가나쉬 네트워크 주입
        const signer = provider.getSigner(); // 배포자 어드레스를 찾아주는 메서드

      	// 팩토리 컨트랙트가 아닌 NFT 컨트랙트의 abi와 바이트코드가 필요
        const factory = await new ethers.ContractFactory(TokenABI.abi, TokenABI.bytecode, signer);
        const deployment = await factory.getDeployTransaction(
            // NFT 생성에 필요한 name과 symbol 인자
            name.value,
            symbol.value
        );
        const deployedTransaction = await signer.sendTransaction(deploymentTransaction);
        const receipt = await deployedTransaction.wait(); // 영수증 객체 반환

        const nftAddress = receipt.contractAddress;
        const creatorAddress = receipt.from;
        console.log("토큰 컨트랙트 주소:", nftAddress);
        console.log("토큰 배포자:", creatorAddress);
      	...
    }        

  • 간단하다는 것 외에 가스비가 절약된다는 장점도 있습니다

  • web3.js 쪽에서는 비슷한 메서드를 지원하지 않는 것 같습니다

0개의 댓글