viem
Last updated
Last updated
is a modular TypeScript library that allows developers to interact with abstractions over the JSON-RPC API, making it easy to interact with Ethereum nodes. Since Phron has an Ethereum-like API available that is fully compatible with Ethereum-style JSON RPC invocations, developers can leverage this compatibility to interact with Phron nodes. For more information on viem, check out their .
In this guide, you'll learn how to use viem to send a transaction and deploy a contract on the Phron TestNet.
For the examples in this guide, you will need to have the following:
An account with funds. You can get DEV tokens for testing on Phron once every 24 hours from the Phron Faucet
To test out the examples in this guide on Phron, you will need to have your own endpoint and API key, which you can get from one of the supported Endpoint Providers
NoteThe examples in this guide assume you have a MacOS or Ubuntu 22.04-based environment and will need to be adapted accordingly for Windows.
To get started, you'll need to create a basic TypeScript project. First, create a directory to store all of the files you'll be creating throughout this guide, and initialize the project with the following command:
For this guide, you'll need to install the viem library and the Solidity compiler. To install both packages, you can run the following command:
You can create a TypeScript configuration file by running:
NoteThis tutorial was created using Node.js v18.18.0.
You can create a viem client for reading chain data, like balances or contract data, using the createPublicClient
function, or you can create a viem client for writing chain data, like sending transactions, using the createWalletClient
function.
To create a client for reading chain data, you can take the following steps:
Import the createPublicClient
and http
functions from viem
and the network you want to interact with from viem/chains
. The chain can be any of the following: phron
Create the client
using the createPublicClient
function and pass in the network and the HTTP RPC endpoint
To create a client for writing chain data, you can take the following steps:
Import the createWalletClient
and http
functions from viem
, the privateKeyToAccount
function for loading your accounts via their private keys, and the network you want to interact with from viem/chains
. The chain can be any of the following: phron
Create your account using the privateKeyToAccount
function
Create the client
using the createWalletClient
function and pass in the account, network, and the HTTP RPC endpoint
NoteTo interact with browser-based wallets, you can use the following code to create an account:
During this section, you'll be creating a couple of scripts. The first one will be to check the balances of your accounts before trying to send a transaction. The second script will actually send the transaction.
You can also use the balance script to check the account balances after the transaction has been sent.
You'll only need one file to check the balances of both addresses before and after the transaction is sent. To get started, you can create a balances.ts
file by running:
Next, you will create the script for this file and complete the following steps:
Update your imports to include the createPublicClient
, http
, and formatEther
functions from viem
and the network you want to interact with from viem/chains
Set up a public viem client, which can be used for reading chain data, such as account balances
Define the addressFrom
and addressTo
variables
Create the asynchronous balances
function that wraps the publicClient.getBalance
method
Use the publicClient.getBalance
function to fetch the balances for the addressFrom
and addressTo
addresses. You can also leverage the formatEther
function to transform the balance into a more readable number (in GLMR, MOVR, or DEV)
Lastly, run the balances
function
To run the script and fetch the account balances, you can run the following command:
If successful, the balances for the origin and receiving address will be displayed in your terminal in DEV.
You'll only need one file to execute a transaction between accounts. For this example, you'll be transferring 1 DEV token from an origin address (from which you hold the private key) to another address. To get started, you can create a transaction.ts
file by running:
Next, you will create the script for this file and complete the following steps:
Update your imports to include the createWalletClient
, http
, and parseEther
functions from viem
, the privateKeyToAccount
function from viem/accounts
, and the network you want to interact with from viem/chains
Set up a viem wallet client for writing chain data, which can be used along with your private key to send transactions. Note: This is for example purposes only. Never store your private keys in a TypeScript file
Set up a public viem client for reading chain data, which will be used to wait for the transaction receipt
Define the addressTo
variable
Create the asynchronous send
function, which wraps the transaction object and the walletClient.sendTransaction
method
Use the walletClient.sendTransaction
function to sign and send the transaction. You'll need to pass in the transaction object, which only requires the recipient's address and the amount to send. Note that parseEther
can be used, which handles the necessary unit conversions from Ether to Wei, similar to using parseUnits(value, decimals)
. Use await
to wait until the transaction is processed and the transaction hash is returned
Use the publicClient.waitForTransactionReceipt
function to wait for the transaction receipt, signaling that the transaction has been completed. This is particularly helpful if you need the transaction receipt or if you're running the balances.ts
script directly after this one to check if the balances have been updated as expected
Lastly, run the send
function
To run the script, you can run the following command in your terminal:
If the transaction was successful, in your terminal you'll see the transaction hash has been printed out.
NoteViem requires that you prepend your private key with
0x
. Many wallets omit this0x
, so verify you've included it as you replaceINSERT_PRIVATE_KEY
.
You can also use the balances.ts
script to check that the balances for the origin and receiving accounts have changed. The entire workflow would look like this:
The contract you'll be compiling and deploying in the next couple of sections is a simple incrementer contract, arbitrarily named Incrementer.sol
. You can get started by creating a file for the contract:
Next, you can add the Solidity code to the file:
The constructor
function, which runs when the contract is deployed, sets the initial value of the number variable stored on-chain (the default is 0
). The increment
function adds the _value
provided to the current number, but a transaction needs to be sent, which modifies the stored data. Lastly, the reset
function resets the stored value to zero.
NoteThis contract is a simple example for illustration purposes only and does not handle values wrapping around.
In this section, you'll create a script that uses the Solidity compiler to output the bytecode and interface (ABI) for the Incrementer.sol
contract. To get started, you can create a compile.ts
file by running:
Next, you will create the script for this file and complete the following steps:
Import the fs
and solc
packages
Using the fs.readFileSync
function, you'll read and save the file contents of Incrementer.sol
to source
Build the input
object for the Solidity compiler by specifying the language
, sources
, and settings
to be used
Using the input
object, you can compile the contract using solc.compile
Extract the compiled contract file and export it to be used in the deployment script
With the script for compiling the Incrementer.sol
contract in place, you can then use the results to send a signed transaction that deploys it. To do so, you can create a file for the deployment script called deploy.ts
:
Next, you will create the script for this file and complete the following steps:
Update your imports to include the createPublicClient
, createWalletClient
, and http
functions from viem
, the privateKeyToAccount
function from viem/accounts
, the network you want to interact with from viem/chains
, and the contractFile
from the compile.ts
file you created in the Compile Contract Script section
Set up a viem wallet client for writing chain data, which will be used along with your private key to deploy the Incrementer
contract. Note: This is for example purposes only. Never store your private keys in a TypeScript file
Set up a public viem client for reading chain data, which will be used to read the transaction receipt for the deployment
Load the contract bytecode
and abi
for the compiled contract
Create the asynchronous deploy
function that will be used to deploy the contract via the walletClient.deployContract
method
Use the walletClient.deployContract
function to sign and send the transaction. You'll need to pass in the contract's ABI and bytecode, the account to deploy the transaction from, and the initial value for the incrementer. Use await
to wait until the transaction is processed and the transaction hash is returned
Use the publicClient.readContract
function to get the transaction receipt for the deployment. Use await
to wait until the transaction is processed and the contract address is returned
Lastly, run the deploy
function
To run the script, you can enter the following command into your terminal:
If successful, the contract's address will be displayed in the terminal.
Call methods are the type of interaction that doesn't modify the contract's storage (change variables), meaning no transaction needs to be sent. They simply read various storage variables of the deployed contract.
To get started, you can create a file and name it get.ts
:
Then you can take the following steps to create the script:
Update your imports to include the createPublicClient
and http
functions from viem
, the network you want to interact with from viem/chains
, and the contractFile
from the compile.ts
file you created in the Compile Contract Script section
Set up a public viem client for reading chain data, which will be used to read the current number of the Incrementer
contract
Create the contractAddress
variable using the address of the deployed contract and the abi
variable using the contractFile
from the compile.ts
file
Create the asynchronous get
function
Call the contract using the publicClient.readContract
function, passing in the abi
, the name of the function, the contractAddress
, and any arguments (if needed). You can use await
, which will return the value requested once the request promise resolves
Lastly, call the get
function
To run the script, you can enter the following command in your terminal:
If successful, the value will be displayed in the terminal.
Send methods are the type of interactions that modify the contract's storage (change variables), meaning a transaction needs to be signed and sent. In this section, you'll create two scripts: one to increment and one to reset the incrementer. To get started, you can create a file for each script and name them increment.ts
and reset.ts
:
Open the increment.ts
file and take the following steps to create the script:
Update your imports to include the createWalletClient
and http
functions from viem
, the network you want to interact with from viem/chains
, and the contractFile
from the compile.ts
file you created in the Compile Contract Script section
Set up a viem wallet client for writing chain data, which will be used along with your private key to send a transaction. Note: This is for example purposes only. Never store your private keys in a TypeScript file
Set up a public viem client for reading chain data, which will be used to wait for the transaction receipt
Create the contractAddress
variable using the address of the deployed contract, the abi
variable using the contractFile
from the compile.ts
file, and the _value
to increment the contract by
Create the asynchronous increment
function
Call the contract using the walletClient.writeContract
function, passing in the abi
, the name of the function, the contractAddress
, and the _value
. You can use await
, which will return the transaction hash once the request promise resolves
Use the publicClient.waitForTransactionReceipt
function to wait for the transaction receipt, signaling that the transaction has been completed. This is particularly helpful if you need the transaction receipt or if you're running the get.ts
script directly after this one to check that the current number has been updated as expected
Lastly, call the increment
function
To run the script, you can enter the following command in your terminal:
If successful, the transaction hash will be displayed in the terminal. You can use the get.ts
script alongside the increment.ts
script to make sure that value is changing as expected.
Next, you can open the reset.ts
file and take the following steps to create the script:
Update your imports to include the createWalletClient
and http
functions from viem
, the network you want to interact with from viem/chains
, and the contractFile
from the compile.ts
file you created in the Compile Contract Script section
Set up a viem wallet client for writing chain data, which will be used along with your private key to send a transaction. Note: This is for example purposes only. Never store your private keys in a TypeScript file
Set up a public viem client for reading chain data, which will be used to wait for the transaction receipt
Create the contractAddress
variable using the address of the deployed contract and the abi
variable using the contractFile
from the compile.ts
file to increment the contract by
Create the asynchronous reset
function
Call the contract using the walletClient.writeContract
function, passing in the abi
, the name of the function, the contractAddress
, and an empty array for the arguments. You can use await
, which will return the transaction hash once the request promise resolves
Use the publicClient.waitForTransactionReceipt
function to wait for the transaction receipt, signaling that the transaction has been completed. This is particularly helpful if you need the transaction receipt or if you're running the get.ts
script directly after this one to check that the current number has been reset to 0
Lastly, call the reset
function
To run the script, you can enter the following command in your terminal:
If successful, the transaction hash will be displayed in the terminal. You can use the get.ts
script alongside the reset.ts
script to make sure that value is changing as expected.
This tutorial is for educational purposes only. As such, any contracts or code created in this tutorial should not be used in production.The information presented herein has been provided by third parties and is made available solely for general information purposes. Phron does not endorse any project listed and described on the Phron Doc Website (https://docs.Phron.ai/). Phron does not warrant the accuracy, completeness or usefulness of this information. Any reliance you place on such information is strictly at your own risk. Phron disclaims all liability and responsibility arising from any reliance placed on this information by you or by anyone who may be informed of any of its contents. All statements and/or opinions expressed in these materials are solely the responsibility of the person or entity providing those materials and do not necessarily represent the opinion of Phron. The information should not be construed as professional or financial advice of any kind. Advice from a suitably qualified professional should always be sought in relation to any particular matter or circumstance. The information herein may link to or integrate with other websites operated or content provided by third parties, and such other websites may link to this website. Phron has no control over any such other websites or their content and will have no liability arising out of or related to such websites or their content. The existence of any such link does not constitute an endorsement of such websites, the content of the websites, or the operators of the websites. These links are being provided to you only as a convenience and you release and hold Phron harmless from any and all liability arising from your use of this information or the information provided by any third-party website or service.
Throughout this guide, you'll be creating a bunch of scripts that provide different functionality, such as sending a transaction, deploying a contract, and interacting with a deployed contract. In most of these scripts, you'll need to create a to interact with the network.