Tutorials

클레이튼에서 이더리움 개발 도구 사용을 위한 Gas price 설정 방법

클레이튼은 v1.8.0부터 Ethereum Equivalance를 위해 아래의 기능을 제공합니다.

클레이튼 팀에서는 위의 Ethereum Equivalence를 위해 작업한 내용을 바탕으로 이더리움에서 널리 알려져있고 자주 사용되는 개발 도구를 별다른 수정없이 클레이튼에서 사용할 수 있도록 하였습니다. 단, 클레이튼은 이더리움과 달리 단일 gas price 정책을 사용하기에 트랜잭션 생성 시 정확한 gas price 값을 설정해야합니다.

지금부터는 이더리움의 대표적인 개발도구인 web3.js, ethers.js, hardhat 그리고 truffle 에서 gas price를 설정하는 방법에 대해 소개합니다.

배경설명

London hardfork이후 EIP-1559를 적용하여 Block의 base fee에 따라 유동적으로 Gas price가 결정되는 이더리움과 달리 클레이튼은 단일 gas price(문서 작성 시점 기준 Baobob 750 ston, Cypress 25 ston)를 사용합니다.

이더리움 툴들은 gas price와 관련된 필드들(gasPrice 혹은 max_priority_fee_pef_gas, max_fee_per_gas)을 설정하지 않을 경우, 개발 도구 내부에서 임의로 계산한 값을 부여해서 트랜잭션을 생성합니다. 하지만 위에서 언급했듯이 클레이튼은 고정된 gasPrice를 사용하기 때문에 라이브러리가 임의로 gasPrice를 계산하는 경우 트랜잭션 전송에 실패합니다. 그렇기 때문에 클레이튼에서 이더리움 개발 툴을 사용할 때에는 반드시 gasPrice와 관련된 필드들을 정의해야 합니다.

아래에서는 총 4가지 툴(web3.js ethers.js, Truffle, Hardhat)에서 gasPrice를 설정하는 방법에 대해 간단한 예제를 보여드리고자 합니다. 예제에서 사용된 gasPrice의 설정값은 모두 25ston입니다. 아래에서 사용되는 gasPrice는 네트워크마다 다르므로 트랜잭션을 전송하고자 하는 네트워크에서 사용하는 값으로 변경하시기 바랍니다.

web3.js

Legacy transaction으로 생성하고 싶을 경우 gasPrice필드를 넣습니다.

const url = `provider url`
const privateKey = `privateKey`
const web3 = new Web3(url)

const tx = await web3.eth.accounts.signTransaction({
           to: `0x8a726c5d1b9b7796df6836f24ef9ea50ab5178c6`,
           value: 90000000000,
           gasPrice: 25000000000,
           gas: 21000,
       }, privateKey)

const receipt = await web3.eth.sendSignedTransaction(tx.rawTransaction)

DynamicFee transaction으로 생성하고 싶을 경우 maxFeePerGas와 maxPriorityFeePerGas 필드를 넣습니다.

const url = `provider url`
const privateKey = `privateKey`
const web3 = new Web3(url)

const tx = await web3.eth.accounts.signTransaction({
           to: `0x8a726c5d1b9b7796df6836f24ef9ea50ab5178c6`,
           value: 90000000000,
           maxFeePerGas: 25000000000,
           maxPriorityFeePerGas: 25000000000,
           gas: 21000,
       }, privateKey)

const receipt = await web3.eth.sendSignedTransaction(tx.rawTransaction)

ethers.js

Legacy transaction으로 생성하고 싶을 경우 gasPrice필드를 넣습니다.

const url = `provider url`
const provider = new ethers.providers.JsonRpcProvider(url)
const wallet = new ethers.Wallet(privKey, provider)

const tx = await wallet.sendTransaction({
           to: account,
           value: 90000000000,
           gasPrice: 25000000000,
           gasLimit: 21000,
       })

const receipt = await tx.wait()

DynamicFee transaction으로 생성하고 싶을 경우 maxFeePerGas와 maxPriorityFeePerGas 필드를 넣습니다.

const url = `provider url`
const provider = new ethers.providers.JsonRpcProvider(url)
const wallet = new ethers.Wallet(privKey, provider)

const tx = await wallet.sendTransaction({
           to: account,
           value: 90000000000,
           maxFeePerGas: 25000000000,
           maxPriorityFeePerGas: 25000000000,
           gasLimit: 21000,
       })

const receipt = await tx.wait()

Hardhat

Hardhat에서 gasPrice를 설정하는 방법은 아래와 같이 두 가지가 있습니다.

  1. 매 트랜잭션마다 기본값으로 사용될 gasPrice를 Hardhat.config.js에 정의하는 방법
  2. transaction을 보내는 코드에 gasPrice관련 필드를 직접 정의하는 방법

1. Hardhat.config.js에 정의하는 방법

Hardhat.config의 networks options에는 Hardhat을 통해 블록체인 네트워크에 접속 시 사용할 옵션들을 정의하고 사용할 수 있습니다. 자세한 내용은 공식 문서를 참고 부탁드리겠습니다.

//Hardhat.config.jsmodule.exports = {
 networks: {
   Hardhat: {
        ...............
     }
   },
   klaytn: {
     url: "provider url",
     gasPrice: 25000000000,
     account: [...],
   }
 },

2. transaction을 보내는 코드에 직접 gasPrice관련 필드를 정의하는 방법

Hardhat은 web3.js와 ethers.js를 모두 지원하고 있습니다. 선호하시는 라이브러리를 사용하시면 되며, 각 라이브러리별 사용방법은 위 내용을 참고 부탁드리겠습니다

Network forking 기능 관련 Tip

Hardhat에서는 Archive mode 노드를 대상으로 forking 기능 사용을 가이드하고 있으며, 일반 Full mode 노드를 대상으로 사용할 때는 State 저장 주기에 맞는 블록번호 설정 (기본 설정 기준, 128의 배수인 블록번호 사용)이 필요합니다.

Truffle

Truffle도 Hardhat과 마찬가지로 gasPrice를 설정하는 방법은 아래와 같이 두 가지가 있습니다.

  1. 매 트랜잭션마다 기본값으로 사용될 gasPrice를 Truffle-config.js에 정의하는 방법
  2. transaction을 보내는 코드에 gasPrice관련 필드를 직접 정의하는 방법

주의: Contract의 배포 이력을 관리하는 Migration contract를 사용하시려면 첫번째 방법(Truffle-config.js 이용)을 권장드립니다. 두번째 방법은 컨트랙트 배포 이후 자동으로 Migration contract에 이력을 기록하는 함수를 호출하는 시점에 직접 gas price를 제어할 수 없기때문에 정상적으로 동작하지 않을 수 있습니다.

1. Truffle-config.js에 정의하는 방법

Truffle-config.js의 networks options에는 Truffle을 통해 블록체인 네트워크에 접속 시 사용할 옵션들을 정의하고 사용할 수 있습니다. Hardhat과는 달리 Truffle-config.js에 gasPrice와 DynamicFee에서 사용되는 maxFeePerGas, maxPriorityFeePerGas를 구분지어 정의할 수 있습니다.자세한 내용은 문서 참고 부탁드립니다.

매 트랜잭션을 Legacy transaction으로 생성하고 싶을 경우 gasPrice필드를 넣습니다.

module.exports = {
 networks: {
  development: {
    host: "127.0.0.1",
    port: 7545,
    network_id: "*"
  },
  klaytn: {
   provider: () =>
     new HDWalletProvider({
       providerOrUrl: "provider url",
       privateKeys: [],
     }),
     gas: 50000000,
     gasPrice: 25000000000,
     network_id: "*"
  }
 },
};

매 트랜잭션을 DynamicFee transaction으로 생성하고 싶을 경우 maxFeePerGas와 maxPriorityFeePerGas 필드를 넣습니다.

module.exports = {
 networks: {
  development: {
    host: "127.0.0.1",
    port: 7545,
    network_id: "*"
  },
  klaytn: {
   provider: () =>
     new HDWalletProvider({
       providerOrUrl: "provider url",
       privateKeys: [],
     }),
     gas: 50000000,
     maxFeePerGas: 25000000000,
     maxPriorityFeePerGas: 25000000000,
     network_id: "*"
  }
 },
};

2. transaction을 보내는 코드에 직접 gasPrice관련 필드를 정의하는 방법

Truffle은 contract를 추상화 시켜서 contract의 배포 및 함수 호출을 간단하게 할 수 있습니다. 자세한 내용은 공식 문서를 참고 부탁드리겠습니다.

Truffle에서 제공하는 컨트랙트의 API를 확인해보면 tx params를 넣을 수 있는 부분이 있습니다. 이 부분에 gasPrice와 관련된 필드를 넣으시면 됩니다.

Legacy transaction으로 생성하고 싶을 경우 gasPrice필드를 넣습니다.

deployer.deploy(MetaCoin, {gasPrice: 25000000000,
   from: ...,
   gas: ...,
 });

DynamicFee transaction으로 생성하고 싶을 경우 maxFeePerGas와 maxPriorityFeePerGas 필드를 넣습니다.

deployer.deploy(MetaCoin, {
   maxFeePerGas: 25000000000,
   maxPriorityFeePerGas: 25000000000,
   from: ...,
   gas: ...,
 });

이러한 변화들과 Klaytn v1.8.0 적용과 함께 이더리움의 도구들이 클레이튼 생태계에서도 문제없이 사용될 수 있을 것입니다. 위 도구들은 클레이튼의 eth 네임스페이스 API들 내 이더리움 타입 트랜잭션의 전송과 처리 만을 지원한다는 사실을 유념해주시기 바랍니다.