Tutorials

Using Ethereum tools: How to set gas price

With the v.1.8.0 changes, Klaytn now supports the following features for Ethereum Equivalence.

The Klaytn Team has picked out some of the most well-known, and widely used Ethereum tools to be used on Klaytn without any significant modifications. But Klaytn, unlike Ethereum, has a fixed gas price model. This means developers should take extra care when using Ethereum native tooling to be sure they have to set the right amount of gas when creating a transaction. This article will briefly explain some gas price related considerations when you are using Ethereum tools on Klaytn. As such, below we will explain how to set a Klaytn compatible gas price in web3.js, ethers.js, Hardhat and Truffle.

Background

With the introduction of EIP-1559 and the London hard fork, the gas price in Ethereum is flexibly determined in accordance with the base fee of the block. On the other hand, Klaytn has a fixed gas price (Baobab 750ston, Cypress 25ston at the time of writing).

If the fields relating to gas price, such as `gasPrice` or `max_priority_fee_per_gas`, `max_fee_per_gas`, are not defined, Ethereum tools will create a transaction using the default values generated by the library being used (usually web3.js or ethers.js). But as mentioned above, since Klaytn uses a fixed `gasPrice`, any default values generated by the library (which is set by matching the dynamic pricing model of Ethereum) will result in a transaction failure. This is why any fields relating to `gasPrice` must be explicitly defined when using Ethereum native development tools.

Below we would like to demonstrate how to set the `gasPrice` for the four tools: web3.js ethers.js, Truffle, and Hardhat. The `gasPrice` values used in our code samples are all 25ston, but remember that the fixed `gasPrice` may vary between networks.

web3.js

When you want to create a `legacy` Ethereum formatted transaction (a pre-EIP 1559 formatted transaction), explicitly include the `gasPrice` field.. and set it to the connecting network’s fixed gas price.

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)

If you want to create a `dynamic fee` formatted transaction (post EIP-1559, Ethereum Type 1 or Type 2 transaction), explicitly add the fields `maxFeePerGas` and `maxPriorityFeePerGas`, then set both to the connecting network’s fixed gas price.

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

Similar to the web3 case, if you want to create an Ethereum `legacy` formatted transaction, explicitly add the field `gasPrice` and populate with a fixed gas price value for the connected network.

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()

If you want to create a `dynamic fee` transaction, explicitly add the fields `maxFeePerGas` and `maxPriorityFeePerGas` and populate with fixed gas price rates.

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

There are two ways to set `gasPrice` on Hardhat.

  1. Define `gasPrice` to be used as the default value for all transactions in Hardhat.config.js
  2. Define the `gasPrice` fields in the individual transaction code itself.

1. Defining the values in `hardhat.config.js`

In the `networks` options of the `hardhat.config.js`, you can define and use the options to be used when you are connecting to the Klaytn blockchain network explicitly. For more details, please refer to the official hardhat documentation.

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

2. Defining the values in the transaction code

Hardhat supports both web3.js and ethers.js. You can use whichever library you prefer. For the instructions for each library, refer to the explanations above. If you define gas price directly within your transactions, these definitions will overwrite any values defined in the config.

Tips on network forking

You can fork archive mode nodes with Hardhat at any block. However, when forking full mode nodes, you have to set an appropriate block number that corresponds to the state storage cycle. By default full mode nodes set their state storage cycle at blocks at a multiple of 128. How you set a block when forking depends on what kind of node you are connecting to with your config assigned RPC URI.

Truffle

Just as with Hardhat, there are two ways to set `gasPrice` with Truffle.

  1. Define `gasPrice` to be used as the default value for all transactions in Truffle-config.js
  2. Define the `gasPrice` fields in the transaction code

Warning: If you want to use migration contracts that manage contract deployment history, we recommend using the first method (truffle-config.js). The second method cannot control the gas price at the time of calling the function that records history on the migration contract, which may prevent it from functioning normally.

1. Defining the values in truffle-config.js

In the `networks` options in `truffle-config.js`, you can define and use the options to be used when you are connecting to the blockchain network via Truffle. Unlike Hardhat, in Truffle, you must assign values for both pre and post EIP 1559 functionality by exclusively setting the `gasPrice`, `maxFeePerGas`, and `maxPriorityFeePerGas` fields. Please refer to the documentation for more information.

If you want to exclusively create `legacy` Ethereum formatted transactions in Truffle, explicitly add the `gasPrice` field with the network fixed gas price.

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: "*"
}
},
};

If you want to exclusively create `dynamic fee` formatted transactions, explicitly add the fields `maxFeePerGas` and `maxPriorityFeePerGas` fields with the network fixed gas price.

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. Defining the values in the transaction code

Truffle abstracts contracts, so you can easily deploy and call them. For more information, please refer to the official documentation.

If you look at the contract APIs provided on Truffle, you will see that you can add the transaction parameters. Here you can add the fields related to `gasPrice`.

If you want to create `legacy` Ethereum formatted transactions, add the `gasPrice` field.

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

If you want to create `dynamic fee` formatted transactions, add the fields `maxFeePerGas` and `maxPriorityFeePerGas`.

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

With the above changes, and the activation of Klaytn v1.8.0, Ethereum tooling will now work effortlessly with the Klaytn ecosystem. However, it should be noted that usage of the above tooling will strictly support the submission and processing of Ethereum formatted transactions within the `eth` namespace API offered by Klaytn.