<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Taylor Caldwell</title>
    <description>The latest articles on DEV Community by Taylor Caldwell (@taycaldwell).</description>
    <link>https://dev.to/taycaldwell</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F356047%2Fea3feb1b-c11e-43e4-8538-74bf75b88eb8.png</url>
      <title>DEV Community: Taylor Caldwell</title>
      <link>https://dev.to/taycaldwell</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/taycaldwell"/>
    <language>en</language>
    <item>
      <title>Accessing real-time asset data on Abstract using Pyth Price Feeds</title>
      <dc:creator>Taylor Caldwell</dc:creator>
      <pubDate>Sat, 01 Feb 2025 02:44:37 +0000</pubDate>
      <link>https://dev.to/taycaldwell/accessing-real-time-asset-data-on-abstract-using-pyth-price-feeds-4eje</link>
      <guid>https://dev.to/taycaldwell/accessing-real-time-asset-data-on-abstract-using-pyth-price-feeds-4eje</guid>
      <description>&lt;p&gt;This tutorial will guide you through the process of creating a smart contract on Abstract that utilizes Pyth Network oracles to consume a price feed.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fe98n8stksek48dt3hxui.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fe98n8stksek48dt3hxui.jpg" alt="Image description" width="680" height="680"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  Objectives
&lt;/h2&gt;

&lt;p&gt;By the end of this tutorial you should be able to do the following:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Set up a smart contract project for Abstract using Foundry&lt;/li&gt;
&lt;li&gt;Install the Pyth smart contracts&lt;/li&gt;
&lt;li&gt;Consume a Pyth Network price feed within your smart contract&lt;/li&gt;
&lt;li&gt;Deploy and test your smart contracts on Abstract&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Prerequisites
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Foundry
&lt;/h3&gt;

&lt;p&gt;This tutorial requires you to have Foundry installed.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;From the command-line (terminal), run: &lt;code&gt;curl -L https://foundry.paradigm.xyz | bash&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Then run &lt;code&gt;foundryup&lt;/code&gt;, to install the latest (nightly) build of Foundry&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For more information, see the Foundry Book &lt;a href="https://book.getfoundry.sh/getting-started/installation" rel="noopener noreferrer"&gt;installation guide&lt;/a&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Metamask Wallet
&lt;/h3&gt;

&lt;p&gt;In order to deploy a smart contract, you will first need a crypto wallet. You can create a wallet by downloading the Metamask browser extension.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Download &lt;a href="https://metamask.io/download/" rel="noopener noreferrer"&gt;Metamask&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Wallet funds
&lt;/h3&gt;

&lt;p&gt;Deploying contracts to the blockchain requires a gas fee. Therefore, you will need to fund your wallet with ETH to cover those gas fees.&lt;/p&gt;

&lt;p&gt;For this tutorial, you will be deploying a contract to the Abstract Sepolia test network. You can fund your wallet with Abstract Sepolia ETH using a &lt;a href="https://docs.abs.xyz/tooling/bridges" rel="noopener noreferrer"&gt;bridge&lt;/a&gt; or &lt;a href="https://docs.abs.xyz/tooling/faucets" rel="noopener noreferrer"&gt;faucet&lt;/a&gt;.&lt;/p&gt;




&lt;h2&gt;
  
  
  What is Pyth Network?
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Pyth Network&lt;/strong&gt; focuses on ultra-low latency and real-time data, making it suitable for financial applications that require sub-second updates. Pyth's design emphasizes performance, and it is designed to provide data for a range of traditional and DeFi assets.&lt;/p&gt;




&lt;h2&gt;
  
  
  Creating a project
&lt;/h2&gt;

&lt;p&gt;Before you can begin writing smart contracts for Abstract and consuming Pyth price feeds, you need to set up your development environment by creating a Foundry project.&lt;/p&gt;

&lt;p&gt;To create a new Foundry project, first create a new directory:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;mkdir &lt;/span&gt;myproject
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then run:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;cd &lt;/span&gt;myproject
forge init
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This will create a Foundry project, which has the following basic layout:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;.&lt;/span&gt;
├── foundry.toml
├── script
 │   └── Counter.s.sol
├── src
 │   └── Counter.sol
└── &lt;span class="nb"&gt;test&lt;/span&gt;
    └── Counter.t.sol
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  Installing Pyth smart contracts
&lt;/h2&gt;

&lt;p&gt;To use Pyth price feeds within your project, you need to install Pyth oracle contracts as a project dependency using &lt;code&gt;forge install&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;To install Pyth oracle contracts, run:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;forge &lt;span class="nb"&gt;install &lt;/span&gt;pyth-network/pyth-sdk-solidity@v2.2.0 &lt;span class="nt"&gt;--no-git&lt;/span&gt; &lt;span class="nt"&gt;--no-commit&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Once installed, update your &lt;code&gt;foundry.toml&lt;/code&gt; file by appending the following line:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;remappings &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;'@pythnetwork/pyth-sdk-solidity/=lib/pyth-sdk-solidity'&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  Writing and compiling the Smart Contract
&lt;/h2&gt;

&lt;p&gt;Once your project has been created and dependencies have been installed, you can now start writing a smart contract.&lt;/p&gt;

&lt;p&gt;The Solidity code below defines a smart contract named &lt;code&gt;ExampleContract&lt;/code&gt;. The code uses the &lt;code&gt;IPyth&lt;/code&gt; interface from the &lt;a href="https://github.com/pyth-network/pyth-crosschain/tree/main/target_chains/ethereum/sdk/solidity" rel="noopener noreferrer"&gt;Pyth Solidity SDK&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;An instance of&lt;code&gt;IPyth&lt;/code&gt; is defined within the contract that provides functions for consuming Pyth price feeds. The constructor for the &lt;code&gt;IPyth&lt;/code&gt; interface expects a contract address to be provided. This address provided in the code example below (&lt;code&gt;0x47F2A9BDAd52d65b66287253cf5ca0D2b763b486&lt;/code&gt;) corresponds to the Pyth contract address for the Abstract Sepolia testnet.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Info:&lt;/strong&gt; Pyth also supports other EVM networks, such as Abstract Mainnet. For a list of all network contract addresses, visit the &lt;a href="https://docs.pyth.network/documentation/pythnet-price-feeds/evm" rel="noopener noreferrer"&gt;Pyth documentation&lt;/a&gt;.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The contract also contains a function named &lt;code&gt;getLatestPrice&lt;/code&gt;. This function takes a provided &lt;code&gt;priceUpdateData&lt;/code&gt; that is used to get updated price data, and returns the price given a &lt;code&gt;priceId&lt;/code&gt; of a price feed. The smart contract provided below uses a &lt;code&gt;priceId&lt;/code&gt; of &lt;code&gt;0xff61491a931112ddf1bd8147cd1b641375f79f5825126d665480874634fd0ace&lt;/code&gt;, which corresponds to the price feed for &lt;code&gt;ETH / USD&lt;/code&gt;.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Info:&lt;/strong&gt; Pyth provides a number of price feeds. For a list of available price feeds, visit the &lt;a href="https://pyth.network/developers/price-feed-ids#pyth-evm-stable" rel="noopener noreferrer"&gt;Pyth documentation&lt;/a&gt;.&lt;br&gt;
&lt;/p&gt;
&lt;/blockquote&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

import "@pythnetwork/pyth-sdk-solidity/IPyth.sol";
import "@pythnetwork/pyth-sdk-solidity/PythStructs.sol";

contract ExampleContract {
  IPyth pyth;

  /**
  * Network: Abstract Sepolia (testnet)
  * Address: 0x47F2A9BDAd52d65b66287253cf5ca0D2b763b486
  */
  constructor() {
    pyth = IPyth(0x47F2A9BDAd52d65b66287253cf5ca0D2b763b486);
  }

  function getLatestPrice(
    bytes[] calldata priceUpdateData
  ) public payable returns (PythStructs.Price memory) {
    // Update the prices to the latest available values and pay the required fee for it. The `priceUpdateData` data
    // should be retrieved from our off-chain Price Service API using the `pyth-evm-js` package.
    // See section "How Pyth Works on EVM Chains" below for more information.
    uint fee = pyth.getUpdateFee(priceUpdateData);
    pyth.updatePriceFeeds{ value: fee }(priceUpdateData);

    bytes32 priceID = 0xff61491a931112ddf1bd8147cd1b641375f79f5825126d665480874634fd0ace;
    // Read the current value of priceID, aborting the transaction if the price has not been updated recently.
    // Every chain has a default recency threshold which can be retrieved by calling the getValidTimePeriod() function on the contract.
    // Please see IPyth.sol for variants of this function that support configurable recency thresholds and other useful features.
    return pyth.getPrice(priceID);
  }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In your project, add the code provided above to a new file named &lt;code&gt;src/ExampleContract.sol&lt;/code&gt; and delete the &lt;code&gt;src/Counter.sol&lt;/code&gt; contract that was generated with the project (You can also delete the &lt;code&gt;test/Counter.t.sol&lt;/code&gt; and &lt;code&gt;script/Counter.s.sol&lt;/code&gt; files).&lt;/p&gt;

&lt;p&gt;To compile the new smart contract, run:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;forge build
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  Deploying the smart contract
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Setting up your wallet as the deployer
&lt;/h3&gt;

&lt;p&gt;Before you can deploy your smart contract to the Abstract network, you will need to set up a wallet to be used as the deployer.&lt;/p&gt;

&lt;p&gt;To do so, you can use the &lt;a href="https://book.getfoundry.sh/reference/cast/cast-wallet-import" rel="noopener noreferrer"&gt;&lt;code&gt;cast wallet import&lt;/code&gt;&lt;/a&gt; command to import the private key of the wallet into Foundry's securely encrypted keystore:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;cast wallet import deployer &lt;span class="nt"&gt;--interactive&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;After running the command above, you will be prompted to enter your private key, as well as a password for signing transactions.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Caution:&lt;/strong&gt; For instructions on how to get your private key from Metamask, visit the &lt;a href="https://support.metamask.io/configure/accounts/how-to-export-an-accounts-private-key/" rel="noopener noreferrer"&gt;Metamask Support page&lt;/a&gt;. &lt;strong&gt;It is critical that you do NOT commit this to a public repo&lt;/strong&gt;.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;To confirm that the wallet was imported as the &lt;code&gt;deployer&lt;/code&gt; account in your Foundry project, run:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;cast wallet list
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Setting up environment variables for Abstract Sepolia
&lt;/h3&gt;

&lt;p&gt;To setup your environment for deploying to the Abstract network, create an &lt;code&gt;.env&lt;/code&gt; file in the home directory of your project, and add the RPC URL for the Abstract Sepolia testnet:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;ABSTRACT_SEPOLIA_RPC="https://api.testnet.abs.xyz"
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Once the &lt;code&gt;.env&lt;/code&gt; file has been created, run the following command to load the environment variables in the current command line session:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;source&lt;/span&gt; .env
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Deploying the smart contract to Abstract Sepolia
&lt;/h3&gt;

&lt;p&gt;With your contract compiled and environment setup, you are ready to deploy the smart contract to the Abstract Sepolia Testnet!&lt;/p&gt;

&lt;p&gt;For deploying a single smart contract using Foundry, you can use the &lt;code&gt;forge create&lt;/code&gt; command. The command requires you to specify the smart contract you want to deploy, an RPC URL of the network you want to deploy to, and the account you want to deploy with.&lt;/p&gt;

&lt;p&gt;To deploy the &lt;code&gt;ExampleContract&lt;/code&gt; smart contract to the Abstract Sepolia test network, run the following command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;forge create ./src/ExampleContract.sol:ExampleContract &lt;span class="nt"&gt;--rpc-url&lt;/span&gt; &lt;span class="nv"&gt;$ABSTRACT_SEPOLIA_RPC&lt;/span&gt; &lt;span class="nt"&gt;--account&lt;/span&gt; deployer
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;When prompted, enter the password that you set earlier, when you imported your wallet's private key.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Info:&lt;/strong&gt; Your wallet must be funded with ETH on the Abstract Sepolia Testnet to cover the gas fees associated with the smart contract deployment. Otherwise, the deployment will fail.&lt;/p&gt;

&lt;p&gt;To get testnet ETH for Abstract Sepolia, see the prerequisites.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;After running the command above, the contract will be deployed on the Abstract Sepolia test network. You can view the deployment status and contract by using a &lt;a href="https://docs.abs.xyz/tooling/block-explorers" rel="noopener noreferrer"&gt;block explorer&lt;/a&gt;.&lt;/p&gt;




&lt;h2&gt;
  
  
  Interacting with the Smart Contract
&lt;/h2&gt;

&lt;p&gt;The &lt;code&gt;getLatestPrice(bytes[])&lt;/code&gt; function of the deployed contract takes a &lt;code&gt;priceUpdateData&lt;/code&gt; argument that is used to get the latest price. This data can be fetched using the Hermes web service. Hermes allows users to easily query for recent price updates via a REST API. Make a curl request to fetch the &lt;code&gt;priceUpdateData&lt;/code&gt; the &lt;code&gt;priceId&lt;/code&gt;, &lt;code&gt;0xff61491a931112ddf1bd8147cd1b641375f79f5825126d665480874634fd0ace&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;curl https://hermes.pyth.network/api/latest_vaas?ids[]=0xff61491a931112ddf1bd8147cd1b641375f79f5825126d665480874634fd0ace
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Once you have the &lt;code&gt;priceUpdateData&lt;/code&gt;, you can use Foundry’s &lt;code&gt;cast&lt;/code&gt; command-line tool to interact with the smart contract and call the &lt;code&gt;getLatestPrice(bytes[])&lt;/code&gt; function to fetch the latest price of ETH.&lt;/p&gt;

&lt;p&gt;To call the &lt;code&gt;getLatestPrice(bytes[])&lt;/code&gt; function of the smart contract, run the following command, replacing &lt;code&gt;&amp;lt;DEPLOYED_ADDRESS&amp;gt;&lt;/code&gt; with the address of your deployed contract, and &lt;code&gt;&amp;lt;PRICE_UPDATE_DATA&amp;gt;&lt;/code&gt; with the &lt;code&gt;priceUpdateData&lt;/code&gt; returned by the Hermes endpoint:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;cast call &amp;lt;DEPLOYED_ADDRESS&amp;gt; &lt;span class="nt"&gt;--rpc-url&lt;/span&gt; &lt;span class="nv"&gt;$ABSTRACT_SEPOLIA_RPC&lt;/span&gt; &lt;span class="s2"&gt;"getLatestPrice(bytes[])"&lt;/span&gt; &amp;lt;PRICE_UPDATE_DATA&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You should receive the latest &lt;code&gt;ETH / USD&lt;/code&gt; price in hexadecimal form.&lt;/p&gt;




&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;Congratulations! You have successfully deployed and interacted with a smart contract that consumes a Pyth Network oracle to access a real-time price feed on Abstract.&lt;/p&gt;

&lt;p&gt;To learn more about Oracles and using Pyth Network price feeds within your smart contracts on Abstract, check out the following resources:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://docs.abs.xyz/ecosystem/oracles" rel="noopener noreferrer"&gt;Oracles&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://docs.pyth.network/documentation/pythnet-price-feeds/evm" rel="noopener noreferrer"&gt;Pyth Network Price Feeds&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>tutorial</category>
      <category>crypto</category>
      <category>blockchain</category>
      <category>web3</category>
    </item>
    <item>
      <title>Sending messages from Abstract to other chains using LayerZero V2</title>
      <dc:creator>Taylor Caldwell</dc:creator>
      <pubDate>Sat, 01 Feb 2025 02:00:22 +0000</pubDate>
      <link>https://dev.to/taycaldwell/sending-messages-from-abstract-to-other-chains-using-layerzero-v2-18m3</link>
      <guid>https://dev.to/taycaldwell/sending-messages-from-abstract-to-other-chains-using-layerzero-v2-18m3</guid>
      <description>&lt;p&gt;This tutorial will guide you through the process of sending cross-chain message data from an Abstract smart contract to another smart contract on a different chain using LayerZero V2.&lt;/p&gt;




&lt;h2&gt;
  
  
  Objectives
&lt;/h2&gt;

&lt;p&gt;By the end of this tutorial you should be able to do the following:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Set up a smart contract project for Abstract using Foundry&lt;/li&gt;
&lt;li&gt;Install the LayerZero smart contracts as a dependency&lt;/li&gt;
&lt;li&gt;Use LayerZero to send messages and from smart contracts on Abstract to smart contracts on different chains&lt;/li&gt;
&lt;li&gt;Deploy and test your smart contracts on Abstract testnet&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Prerequisites
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Foundry
&lt;/h3&gt;

&lt;p&gt;This tutorial requires you to have Foundry installed.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;From the command-line (terminal), run: &lt;code&gt;curl -L https://foundry.paradigm.xyz | bash&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Then run &lt;code&gt;foundryup&lt;/code&gt;, to install the latest (nightly) build of Foundry&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For more information, see the Foundry Book &lt;a href="https://book.getfoundry.sh/getting-started/installation" rel="noopener noreferrer"&gt;installation guide&lt;/a&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Metamask Wallet
&lt;/h3&gt;

&lt;p&gt;In order to deploy a smart contract, you will first need a crypto wallet. You can create a wallet by downloading the Metamask browser extension.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Download &lt;a href="https://metamask.io/download/" rel="noopener noreferrer"&gt;Metamask&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Wallet funds
&lt;/h3&gt;

&lt;p&gt;Deploying contracts to the blockchain requires a gas fee. Therefore, you will need to fund your wallet with ETH to cover those gas fees.&lt;/p&gt;

&lt;p&gt;For this tutorial, you will be deploying a contract to the Abstract Sepolia test network. You can fund your wallet with Abstract Sepolia ETH using a &lt;a href="https://docs.abs.xyz/tooling/bridges" rel="noopener noreferrer"&gt;bridge&lt;/a&gt; or &lt;a href="https://docs.abs.xyz/tooling/faucets" rel="noopener noreferrer"&gt;faucet&lt;/a&gt;.&lt;/p&gt;




&lt;h2&gt;
  
  
  What is LayerZero?
&lt;/h2&gt;

&lt;p&gt;LayerZero is an interoperability protocol that allows developers to build applications (and tokens) that can connect to multiple blockchains. LayerZero defines these types of applications as "omnichain" applications.&lt;/p&gt;

&lt;p&gt;The LayerZero protocol is made up of immutable on-chain &lt;a href="https://docs.layerzero.network/v2/developers/evm/technical-reference/deployed-contracts" rel="noopener noreferrer"&gt;Endpoints&lt;/a&gt;, a configurable &lt;a href="https://docs.layerzero.network/explore/decentralized-verifier-networks" rel="noopener noreferrer"&gt;Security Stack&lt;/a&gt;, and a permissionless set of &lt;a href="https://docs.layerzero.network/v2/home/permissionless-execution/executors" rel="noopener noreferrer"&gt;Executors&lt;/a&gt; that transfer messages between chains.&lt;/p&gt;

&lt;h3&gt;
  
  
  High-level concepts
&lt;/h3&gt;

&lt;h4&gt;
  
  
  Endpoints
&lt;/h4&gt;

&lt;p&gt;Endpoints are immutable LayerZero smart contracts that implement a standardized interface for your own smart contracts to use and in order to manage security configurations and send and receive messages.&lt;/p&gt;

&lt;h4&gt;
  
  
  Security Stack (DVNs)
&lt;/h4&gt;

&lt;p&gt;The &lt;a href="https://docs.layerzero.network/explore/decentralized-verifier-networks" rel="noopener noreferrer"&gt;Security Stack&lt;/a&gt; is a configurable set of required and optional Decentralized Verifier Networks (DVNs). The DVNs are used to verify message payloads to ensure integrity of your application's messages.&lt;/p&gt;

&lt;h4&gt;
  
  
  Executors
&lt;/h4&gt;

&lt;p&gt;&lt;a href="https://docs.layerzero.network/v2/home/permissionless-execution/executors" rel="noopener noreferrer"&gt;Executors&lt;/a&gt; are responsible for initiating message delivery. They will automatically execute the &lt;code&gt;lzReceive&lt;/code&gt; function of the endpoint on the destination chain once a message has been verified by the Security Stack.&lt;/p&gt;




&lt;h2&gt;
  
  
  Creating a project
&lt;/h2&gt;

&lt;p&gt;Before you begin, you need to set up your smart contract development environment by creating a Foundry project.&lt;/p&gt;

&lt;p&gt;To create a new Foundry project, first create a new directory:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;mkdir &lt;/span&gt;myproject
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then run:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;cd &lt;/span&gt;myproject
forge init
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This will create a Foundry project with the following basic layout:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;.&lt;/span&gt;
├── foundry.toml
├── script
├── src
└── &lt;span class="nb"&gt;test&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Info:&lt;/strong&gt; You can delete the &lt;code&gt;src/Counter.sol&lt;/code&gt;, &lt;code&gt;test/Counter.t.sol&lt;/code&gt;, and &lt;code&gt;script/Counter.s.sol&lt;/code&gt; boilerplate files that were generated with the project, as you will not be needing them.&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  Installing the LayerZero smart contracts
&lt;/h2&gt;

&lt;p&gt;To use LayerZero within your Foundry project, you need to install the LayerZero smart contracts and their dependencies using &lt;code&gt;forge install&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;To install LayerZero smart contracts and their dependencies, run the following commands:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;forge &lt;span class="nb"&gt;install &lt;/span&gt;GNSPS/solidity-bytes-utils &lt;span class="nt"&gt;--no-commit&lt;/span&gt;
forge &lt;span class="nb"&gt;install &lt;/span&gt;OpenZeppelin/openzeppelin-contracts@v4.9.4 &lt;span class="nt"&gt;--no-commit&lt;/span&gt;
forge &lt;span class="nb"&gt;install &lt;/span&gt;LayerZero-Labs/LayerZero-v2 &lt;span class="nt"&gt;--no-commit&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Once installed, update your &lt;code&gt;foundry.toml&lt;/code&gt; file by appending the following lines:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;remappings &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt;
    &lt;span class="s1"&gt;'@openzeppelin/contracts/=lib/openzeppelin-contracts/contracts'&lt;/span&gt;,
    &lt;span class="s1"&gt;'solidity-bytes-utils/=lib/solidity-bytes-utils'&lt;/span&gt;,
    &lt;span class="s1"&gt;'@layerzerolabs/lz-evm-oapp-v2/=lib/LayerZero-v2/oapp'&lt;/span&gt;,
    &lt;span class="s1"&gt;'@layerzerolabs/lz-evm-protocol-v2/=lib/LayerZero-v2/protocol'&lt;/span&gt;,
    &lt;span class="s1"&gt;'@layerzerolabs/lz-evm-messagelib-v2/=lib/LayerZero-v2/messagelib'&lt;/span&gt;,
&lt;span class="o"&gt;]&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  Getting started with LayerZero
&lt;/h2&gt;

&lt;p&gt;LayerZero provides a smart contract standard called &lt;a href="https://docs.layerzero.network/v2/developers/evm/oapp/overview" rel="noopener noreferrer"&gt;OApp&lt;/a&gt; that is intended for omnichain messaging and configuration.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

import { OAppSender } from "./OAppSender.sol";
import { OAppReceiver, Origin } from "./OAppReceiver.sol";
import { OAppCore } from "./OAppCore.sol";

abstract contract OApp is OAppSender, OAppReceiver {
   constructor(address _endpoint) OAppCore(_endpoint, msg.sender) {}

   function oAppVersion() public pure virtual returns (uint64 senderVersion, uint64 receiverVersion) {
       senderVersion = SENDER_VERSION;
       receiverVersion = RECEIVER_VERSION;
   }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Info:&lt;/strong&gt; You can view the source code for this contract on &lt;a href="https://github.com/LayerZero-Labs/LayerZero-v2/blob/main/packages/layerzero-v2/evm/oapp/contracts/oapp/OApp.sol" rel="noopener noreferrer"&gt;GitHub&lt;/a&gt;.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;To get started using LayerZero, developers simply need to inherit from the &lt;a href="https://github.com/LayerZero-Labs/LayerZero-v2/blob/main/packages/layerzero-v2/evm/oapp/contracts/oapp/OApp.sol" rel="noopener noreferrer"&gt;OApp&lt;/a&gt; contract, and implement the following two inherited functions:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;_lzSend&lt;/code&gt;: A function used to send an omnichain message&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;_lzReceive&lt;/code&gt;: A function used to receive an omnichain message&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In this tutorial, you will be implementing the &lt;a href="https://docs.layerzero.network/v2/developers/evm/oapp/overview" rel="noopener noreferrer"&gt;OApp&lt;/a&gt; standard into your own project to add the capability to send messages from a smart contract on Abstract to a smart contract on Arbitrum.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Info:&lt;/strong&gt; An extension of the &lt;a href="https://docs.layerzero.network/v2/developers/evm/oapp/overview" rel="noopener noreferrer"&gt;OApp&lt;/a&gt; contract standard known as &lt;a href="https://docs.layerzero.network/v2/developers/evm/oft/quickstart" rel="noopener noreferrer"&gt;OFT&lt;/a&gt; is also available for supporting omnichain fungible token transfers.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Info:&lt;/strong&gt; For more information on transferring tokens across chains using LayerZero, visit the &lt;a href="https://docs.layerzero.network/v2/developers/evm/oft/quickstart" rel="noopener noreferrer"&gt;LayerZero documentation&lt;/a&gt;.&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  Writing the smart contract
&lt;/h2&gt;

&lt;p&gt;To get started, create a new Solidity smart contract file in your project's &lt;code&gt;src/&lt;/code&gt; directory named &lt;code&gt;ExampleContract.sol&lt;/code&gt;, and add the following content:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

import { OApp, Origin, MessagingFee } from "@layerzerolabs/lz-evm-oapp-v2/contracts/oapp/OApp.sol";

contract ExampleContract is OApp {
   constructor(address _endpoint, address _owner) OApp(_endpoint, _owner) {}
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The code snippet above defines a new smart contract named &lt;code&gt;ExampleContract&lt;/code&gt; that extends the &lt;code&gt;OApp&lt;/code&gt; contract standard.&lt;/p&gt;

&lt;p&gt;The contract's constructor expects two arguments:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;_endpoint&lt;/code&gt;: The &lt;a href="https://docs.layerzero.network/v2/home/protocol/layerzero-endpoint" rel="noopener noreferrer"&gt;LayerZero Endpoint&lt;/a&gt; &lt;code&gt;address&lt;/code&gt; for the chain the smart contract is deployed to.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;_owner&lt;/code&gt;: The &lt;code&gt;address&lt;/code&gt; of the owner of the smart contract.&lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Info:&lt;/strong&gt; &lt;a href="https://docs.layerzero.network/v2/home/protocol/layerzero-endpoint" rel="noopener noreferrer"&gt;LayerZero Endpoints&lt;/a&gt; are smart contracts that expose an interface for OApp contracts to manage security configurations and send and receive messages via the LayerZero protocol.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  Implementing message sending (&lt;code&gt;_lzSend&lt;/code&gt;)
&lt;/h3&gt;

&lt;p&gt;To send messages to another chain, your smart contract must call the &lt;code&gt;_lzSend&lt;/code&gt; function inherited from the &lt;a href="https://docs.layerzero.network/v2/developers/evm/oapp/overview" rel="noopener noreferrer"&gt;OApp&lt;/a&gt; contract.&lt;/p&gt;

&lt;p&gt;Add a new custom function named &lt;code&gt;sendMessage&lt;/code&gt; to your smart contract that has the following content:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;/// @notice Sends a message from the source chain to the destination chain.
/// @param _dstEid The endpoint ID of the destination chain.
/// @param _message The message to be sent.
/// @param _options The message execution options (e.g. gas to use on destination).
function sendMessage(uint32 _dstEid, string memory _message, bytes calldata _options) external payable {
   bytes memory _payload = abi.encode(_message); // Encode the message as bytes
   _lzSend(
       _dstEid,
       _payload,
       _options,
       MessagingFee(msg.value, 0), // Fee for the message (nativeFee, lzTokenFee)
       payable(msg.sender) // The refund address in case the send call reverts
   );
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;sendMessage&lt;/code&gt; function above calls the inherited &lt;code&gt;_lzSend&lt;/code&gt; function, while passing in the following expected data:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Name&lt;/th&gt;
&lt;th&gt;Type&lt;/th&gt;
&lt;th&gt;Description&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;_dstEid&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;uint32&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;The &lt;a href="https://docs.layerzero.network/v2/developers/evm/technical-reference/deployed-contracts" rel="noopener noreferrer"&gt;endpoint ID&lt;/a&gt; of the destination chain to send the message to.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;_payload&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;bytes&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;The message (encoded) to send.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;_options&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;bytes&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;
&lt;a href="https://docs.layerzero.network/v2/developers/evm/protocol-gas-settings/options" rel="noopener noreferrer"&gt;Additional options&lt;/a&gt; when sending the message, such as how much gas should be used when receiving the message.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;_fee&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;a href="https://github.com/LayerZero-Labs/LayerZero-v2/blob/c3213200dfe8fabbf7d92c685590d34e6e70da43/protocol/contracts/interfaces/ILayerZeroEndpointV2.sol#L24" rel="noopener noreferrer"&gt;&lt;code&gt;MessagingFee&lt;/code&gt;&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;The calculated fee for sending the message.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;_refundAddress&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;address&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;The &lt;code&gt;address&lt;/code&gt; that will receive any excess fee values sent to the endpoint in case the &lt;code&gt;_lzSend&lt;/code&gt; execution reverts.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h3&gt;
  
  
  Implementing gas fee estimation (&lt;code&gt;_quote&lt;/code&gt;)
&lt;/h3&gt;

&lt;p&gt;As shown in the table provided in the last section, the &lt;code&gt;_lzSend&lt;/code&gt; function expects an estimated gas &lt;a href="https://github.com/LayerZero-Labs/LayerZero-v2/blob/c3213200dfe8fabbf7d92c685590d34e6e70da43/protocol/contracts/interfaces/ILayerZeroEndpointV2.sol#L24" rel="noopener noreferrer"&gt;fee&lt;/a&gt; to be provided when sending a message (&lt;code&gt;_fee&lt;/code&gt;).&lt;/p&gt;

&lt;p&gt;Therefore, sending a message using the &lt;code&gt;sendMessage&lt;/code&gt; function of your contract, you first need to estimate the associated gas fees.&lt;/p&gt;

&lt;p&gt;There are multiple fees incurred when sending a message across chains using LayerZero, including: paying for gas on the source chain, fees paid to DVNs validating the message, and gas on the destination chain. Luckily, LayerZero bundles all of these fees together into a single fee to be paid by the &lt;code&gt;msg.sender&lt;/code&gt;, and LayerZero Endpoints expose a &lt;code&gt;_quote&lt;/code&gt; function to estimate this fee.&lt;/p&gt;

&lt;p&gt;Add a new function to your &lt;code&gt;ExampleContract&lt;/code&gt; contract called &lt;code&gt;estimateFee&lt;/code&gt; that calls the &lt;code&gt;_quote&lt;/code&gt; function, as shown below:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;/// @notice Estimates the gas associated with sending a message.
/// @param _dstEid The endpoint ID of the destination chain.
/// @param _message The message to be sent.
/// @param _options The message execution options (e.g. gas to use on destination).
/// @return nativeFee Estimated gas fee in native gas.
/// @return lzTokenFee Estimated gas fee in ZRO token.
function estimateFee(
   uint32 _dstEid,
   string memory _message,
   bytes calldata _options
) public view returns (uint256 nativeFee, uint256 lzTokenFee) {
   bytes memory _payload = abi.encode(_message);
   MessagingFee memory fee = _quote(_dstEid, _payload, _options, false);
   return (fee.nativeFee, fee.lzTokenFee);
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;estimateFee&lt;/code&gt; function above calls the inherited &lt;code&gt;_quote&lt;/code&gt; function, while passing in the following expected data:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Name&lt;/th&gt;
&lt;th&gt;Type&lt;/th&gt;
&lt;th&gt;Description&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;_dstEid&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;uint32&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;The &lt;a href="https://docs.layerzero.network/v2/developers/evm/technical-reference/deployed-contracts" rel="noopener noreferrer"&gt;endpoint ID&lt;/a&gt; of the destination chain the message will be sent to.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;_payload&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;bytes&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;The message (encoded) that will be sent.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;_options&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;bytes&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;
&lt;a href="https://docs.layerzero.network/v2/developers/evm/protocol-gas-settings/options" rel="noopener noreferrer"&gt;Additional options&lt;/a&gt; when sending the message, such as how much gas should be used when receiving the message.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;_payInLzToken&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;bool&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Boolean flag for which token to use when returning the fee (native or ZRO token).&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Info:&lt;/strong&gt; Your contract’s &lt;code&gt;estimateFee&lt;/code&gt; function should always be called immediately before calling &lt;code&gt;sendMessage&lt;/code&gt; to accurately estimate associated gas fees.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  Implementing message receiving (&lt;code&gt;_lzReceive&lt;/code&gt;)
&lt;/h3&gt;

&lt;p&gt;To receive messages on the destination chain, your smart contract must override the &lt;code&gt;_lzReceive&lt;/code&gt; function inherited from the &lt;a href="https://docs.layerzero.network/v2/developers/evm/oapp/overview" rel="noopener noreferrer"&gt;OApp&lt;/a&gt; contract.&lt;/p&gt;

&lt;p&gt;Add the following code snippet to your &lt;code&gt;ExampleContract&lt;/code&gt; contract to override the &lt;code&gt;_lzReceive&lt;/code&gt; function:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;/// @notice Entry point for receiving messages.
/// @param _origin The origin information containing the source endpoint and sender address.
///  - srcEid: The source chain endpoint ID.
///  - sender: The sender address on the src chain.
///  - nonce: The nonce of the message.
/// @param _guid The unique identifier for the received LayerZero message.
/// @param _message The payload of the received message.
/// @param _executor The address of the executor for the received message.
/// @param _extraData Additional arbitrary data provided by the corresponding executor.
function _lzReceive(
   Origin calldata _origin,
   bytes32 _guid,
   bytes calldata payload,
   address _executor,
   bytes calldata _extraData
   ) internal override {
       data = abi.decode(payload, (string));
       // other logic
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The overridden &lt;code&gt;_lzReceive&lt;/code&gt; function receives the following arguments when receiving a message:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Name&lt;/th&gt;
&lt;th&gt;Type&lt;/th&gt;
&lt;th&gt;Description&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;_origin&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;Origin&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;The origin information containing the source endpoint and sender address.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;_guid&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;bytes32&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;The unique identifier for the received LayerZero message.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;payload&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;bytes&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;The payload of the received message (encoded).&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;_executor&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;address&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;The &lt;code&gt;address&lt;/code&gt; of the &lt;a href="https://docs.layerzero.network/v2/home/permissionless-execution/executors" rel="noopener noreferrer"&gt;Executor&lt;/a&gt; for the received message.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;_extraData&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;bytes&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Additional arbitrary data provided by the corresponding &lt;a href="https://docs.layerzero.network/v2/home/permissionless-execution/executors" rel="noopener noreferrer"&gt;Executor&lt;/a&gt;.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Note that the overridden method decodes the message payload, and stores the string into a variable named &lt;code&gt;data&lt;/code&gt; that you can read from later to fetch the latest message.&lt;/p&gt;

&lt;p&gt;Add the &lt;code&gt;data&lt;/code&gt; field as a member variable to your contract:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;contract ExampleContract is OApp {

    // highlight-next-line
    string public data;

    constructor(address _endpoint) OApp(_endpoint, msg.sender) {}
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Info:&lt;/strong&gt; Overriding the &lt;code&gt;_lzReceive&lt;/code&gt; function allows you to provide any custom logic you wish when receiving messages, including making a call back to the source chain by invoking &lt;code&gt;_lzSend&lt;/code&gt;. Visit the LayerZero &lt;a href="https://docs.layerzero.network/v2/developers/evm/oapp/message-design-patterns" rel="noopener noreferrer"&gt;Message Design Patterns&lt;/a&gt; for common messaging flows.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  Final code
&lt;/h3&gt;

&lt;p&gt;Once you complete all of the steps above, your contract should look like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

import { OApp, Origin, MessagingFee } from "@layerzerolabs/lz-evm-oapp-v2/contracts/oapp/OApp.sol";

contract ExampleContract is OApp {

 string public data;

  constructor(address _endpoint) OApp(_endpoint, msg.sender) {}

  /// @notice Sends a message from the source chain to the destination chain.
  /// @param _dstEid The endpoint ID of the destination chain.
  /// @param _message The message to be sent.
  /// @param _options The message execution options (e.g. gas to use on destination).
  function sendMessage(uint32 _dstEid, string memory _message, bytes calldata _options) external payable {
     bytes memory _payload = abi.encode(_message); // Encode the message as bytes
     _lzSend(
           _dstEid,
           _payload,
           _options,
           MessagingFee(msg.value, 0), // Fee for the message (nativeFee, lzTokenFee)
           payable(msg.sender) // The refund address in case the send call reverts
     );
  }

  /// @notice Estimates the gas associated with sending a message.
  /// @param _dstEid The endpoint ID of the destination chain.
  /// @param _message The message to be sent.
  /// @param _options The message execution options (e.g. gas to use on destination).
  /// @return nativeFee Estimated gas fee in native gas.
  /// @return lzTokenFee Estimated gas fee in ZRO token.
  function estimateFee(
     uint32 _dstEid,
     string memory _message,
     bytes calldata _options
  ) public view returns (uint256 nativeFee, uint256 lzTokenFee) {
     bytes memory _payload = abi.encode(_message);
     MessagingFee memory fee = _quote(_dstEid, _payload, _options, false);
     return (fee.nativeFee, fee.lzTokenFee);
  }

  /// @notice Entry point for receiving messages.
  /// @param _origin The origin information containing the source endpoint and sender address.
  ///  - srcEid: The source chain endpoint ID.
  ///  - sender: The sender address on the src chain.
  ///  - nonce: The nonce of the message.
  /// @param _guid The unique identifier for the received LayerZero message.
  /// @param _message The payload of the received message.
  /// @param _executor The address of the executor for the received message.
  /// @param _extraData Additional arbitrary data provided by the corresponding executor.
  function _lzReceive(
     Origin calldata _origin,
     bytes32 _guid,
     bytes calldata payload,
     address _executor,
     bytes calldata _extraData
     ) internal override {
        data = abi.decode(payload, (string));
  }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  Compiling the smart contract
&lt;/h2&gt;

&lt;p&gt;Compile the smart contract to ensure it builds without any errors.&lt;/p&gt;

&lt;p&gt;To compile your smart contract, run:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;forge build
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  Deploying the smart contract
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Setting up your wallet as the deployer
&lt;/h3&gt;

&lt;p&gt;Before you can deploy your smart contract to various chains you will need to set up a wallet to be used as the deployer.&lt;/p&gt;

&lt;p&gt;To do so, you can use the &lt;a href="https://book.getfoundry.sh/reference/cast/cast-wallet-import" rel="noopener noreferrer"&gt;&lt;code&gt;cast wallet import&lt;/code&gt;&lt;/a&gt; command to import the private key of the wallet into Foundry's securely encrypted keystore:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;cast wallet import deployer &lt;span class="nt"&gt;--interactive&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;After running the command above, you will be prompted to enter your private key, as well as a password for signing transactions.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Caution:&lt;/strong&gt; For instructions on how to get your private key from Metamask, visit the &lt;a href="https://support.metamask.io/configure/accounts/how-to-export-an-accounts-private-key/" rel="noopener noreferrer"&gt;Metamask Support page&lt;/a&gt;.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;To confirm that the wallet was imported as the &lt;code&gt;deployer&lt;/code&gt; account in your Foundry project, run:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;cast wallet list
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Setting up environment variables
&lt;/h3&gt;

&lt;p&gt;To setup your environment, create an &lt;code&gt;.env&lt;/code&gt; file in the home directory of your project, and add the RPC URLs and &lt;a href="https://docs.layerzero.network/v2/developers/evm/technical-reference/deployed-contracts" rel="noopener noreferrer"&gt;LayerZero Endpoint&lt;/a&gt; information for both Abstract Sepolia Testnet and Arbitrum Sepolia Testnet:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;ABSTRACT_TESTNET_RPC&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"https://api.testnet.abs.xyz"&lt;/span&gt;
&lt;span class="nv"&gt;ABSTRACT_TESTNET_LZ_ENDPOINT&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;0x16c693A3924B947298F7227792953Cd6BBb21Ac8
&lt;span class="nv"&gt;ABSTRACT_TESTNET_LZ_ENDPOINT_ID&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;40313

&lt;span class="nv"&gt;ARBITRUM_TESTNET_RPC&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"https://sepolia-rollup.arbitrum.io/rpc"&lt;/span&gt;
&lt;span class="nv"&gt;ARBITRUM_TESTNET_LZ_ENDPOINT&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;0x6EDCE65403992e310A62460808c4b910D972f10f
&lt;span class="nv"&gt;ARBITRUM_TESTNET_LZ_ENDPOINT_ID&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;40231
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Once the &lt;code&gt;.env&lt;/code&gt; file has been created, run the following command to load the environment variables in the current command line session:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;source .env
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;With your contract compiled and environment setup, you are now ready to deploy the smart contract to different networks.&lt;/p&gt;

&lt;h3&gt;
  
  
  Deploying the smart contract to Abstract Testnet
&lt;/h3&gt;

&lt;p&gt;To deploy a smart contract using Foundry, you can use the &lt;code&gt;forge create&lt;/code&gt; command. The command requires you to specify the smart contract you want to deploy, an RPC URL of the network you want to deploy to, and the account you want to deploy with.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Info:&lt;/strong&gt; Your wallet must be funded with ETH on the Abstract Testnet and Arbitrum Testnet to cover the gas fees associated with the smart contract deployment. Otherwise, the deployment will fail.&lt;/p&gt;

&lt;p&gt;To get testnet ETH, see the prerequisites.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;To deploy the &lt;code&gt;ExampleContract&lt;/code&gt; smart contract to the Abstract Sepolia testnet, run the following command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;forge create ./src/ExampleContract.sol:ExampleContract &lt;span class="nt"&gt;--rpc-url&lt;/span&gt; &lt;span class="nv"&gt;$ABSTRACT_TESTNET_RPC&lt;/span&gt; &lt;span class="nt"&gt;--constructor-args&lt;/span&gt; &lt;span class="nv"&gt;$ABSTRACT_TESTNET_LZ_ENDPOINT&lt;/span&gt; &lt;span class="nt"&gt;--account&lt;/span&gt; deployer
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;When prompted, enter the password that you set earlier, when you imported your wallet's private key.&lt;/p&gt;

&lt;p&gt;After running the command above, the contract will be deployed on the Abstract Sepolia testnet. You can view the deployment status and contract by using a &lt;a href="https://dev.to/docs/tools/block-explorers"&gt;block explorer&lt;/a&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Deploying the smart contract to Arbitrum Testnet
&lt;/h3&gt;

&lt;p&gt;To deploy the &lt;code&gt;ExampleContract&lt;/code&gt; smart contract to the Arbitrum Sepolia testnet, run the following command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;forge create ./src/ExampleContract.sol:ExampleContract &lt;span class="nt"&gt;--rpc-url&lt;/span&gt; &lt;span class="nv"&gt;$ARBITRUM_TESTNET_RPC&lt;/span&gt; &lt;span class="nt"&gt;--constructor-args&lt;/span&gt; &lt;span class="nv"&gt;$ARBITRUM_TESTNET_LZ_ENDPOINT&lt;/span&gt; &lt;span class="nt"&gt;--account&lt;/span&gt; deployer
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;When prompted, enter the password that you set earlier, when you imported your wallet's private key.&lt;/p&gt;

&lt;p&gt;After running the command above, the contract will be deployed on the Arbitrum Sepolia testnet. You can view the deployment status and contract by using the &lt;a href="https://sepolia.arbiscan.io/" rel="noopener noreferrer"&gt;Arbitrum Sepolia block explorer&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Opening the messaging channels
&lt;/h2&gt;

&lt;p&gt;Once your contract has been deployed to Abstract Sepolia and Arbitrum Sepolia, you will need to open the messaging channels between the two contracts so that they can send and receive messages from one another. This is done by calling the &lt;code&gt;setPeer&lt;/code&gt; function on the contract.&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;setPeer&lt;/code&gt; function expects the following arguments:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Name&lt;/th&gt;
&lt;th&gt;Type&lt;/th&gt;
&lt;th&gt;Description&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;_eid&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;uint32&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;The &lt;a href="https://docs.layerzero.network/v2/developers/evm/technical-reference/deployed-contracts" rel="noopener noreferrer"&gt;endpoint ID&lt;/a&gt; of the destination chain.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;_peer&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;bytes32&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;The contract address of the OApp contract on the destination chain.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h3&gt;
  
  
  Setting the peers
&lt;/h3&gt;

&lt;p&gt;Foundry provides the &lt;code&gt;cast&lt;/code&gt; command-line tool that can be used to interact with deployed smart contracts and call their functions.&lt;/p&gt;

&lt;p&gt;To set the peer of your &lt;code&gt;ExampleContract&lt;/code&gt; contracts, you can use &lt;code&gt;cast&lt;/code&gt; to call the &lt;code&gt;setPeer&lt;/code&gt; function while providing the &lt;a href="https://docs.layerzero.network/v2/developers/evm/technical-reference/deployed-contracts" rel="noopener noreferrer"&gt;endpoint ID&lt;/a&gt; and address (in bytes) of the deployed contract on the respective destination chain.&lt;/p&gt;

&lt;p&gt;To set the peer of the Abstract Sepolia contract to the Arbitrum Sepolia contract, run the following command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;cast send &amp;lt;ABSTRACT_TESTNET_CONTRACT_ADDRESS&amp;gt; &lt;span class="nt"&gt;--rpc-url&lt;/span&gt; &lt;span class="nv"&gt;$ABSTRACT_TESTNET_RPC&lt;/span&gt; &lt;span class="s2"&gt;"setPeer(uint32, bytes32)"&lt;/span&gt; &lt;span class="nv"&gt;$ARBITRUM_TESTNET_LZ_ENDPOINT_ID&lt;/span&gt; &amp;lt;ARBITRUM_TESTNET_CONTRACT_ADDRESS&amp;gt; &lt;span class="nt"&gt;--account&lt;/span&gt; deployer
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Info:&lt;/strong&gt; Replace &lt;code&gt;&amp;lt;ABSTRACT_TESTNET_CONTRACT_ADDRESS&amp;gt;&lt;/code&gt; with the contract address of your deployed &lt;code&gt;ExampleContract&lt;/code&gt; contract on Abstract Sepolia, and&lt;code&gt;&amp;lt;ARBITRUM_TESTNET_CONTRACT_ADDRESS&amp;gt;&lt;/code&gt; with the contract address (as bytes) of your deployed &lt;code&gt;ExampleContract&lt;/code&gt; contract on Arbitrum Sepolia before running the provided &lt;code&gt;cast&lt;/code&gt; command.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;To set the peer of the Arbitrum Sepolia contract to the Abstract Sepolia contract, run the following command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;cast send &amp;lt;ARBITRUM_TESTNET_CONTRACT_ADDRESS&amp;gt; &lt;span class="nt"&gt;--rpc-url&lt;/span&gt; &lt;span class="nv"&gt;$ARBITRUM_TESTNET_RPC&lt;/span&gt; &lt;span class="s2"&gt;"setPeer(uint32, bytes32)"&lt;/span&gt; &lt;span class="nv"&gt;$ABSTRACT_TESTNET_LZ_ENDPOINT_ID&lt;/span&gt; &amp;lt;ABSTRACT_TESTNET_CONTRACT_ADDRESS&amp;gt; &lt;span class="nt"&gt;--account&lt;/span&gt; deployer
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Info:&lt;/strong&gt; Replace &lt;code&gt;&amp;lt;ARBITRUM_TESTNET_CONTRACT_ADDRESS&amp;gt;&lt;/code&gt; with the contract address of your deployed &lt;code&gt;ExampleContract&lt;/code&gt; contract on Arbitrum Sepolia, and&lt;code&gt;&amp;lt;ABSTRACT_TESTNET_CONTRACT_ADDRESS&amp;gt;&lt;/code&gt; with the contract address (as bytes) of your deployed &lt;code&gt;ExampleContract&lt;/code&gt; contract on Abstract Sepolia before running the provided &lt;code&gt;cast&lt;/code&gt; command.&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  Sending messages
&lt;/h2&gt;

&lt;p&gt;Once peers have been set on each contract, they are now able to send and receive messages from one another.&lt;/p&gt;

&lt;p&gt;Sending a message using the newly created &lt;code&gt;ExampleContract&lt;/code&gt; contract can be done in three steps:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Build &lt;a href="https://docs.layerzero.network/v2/developers/evm/protocol-gas-settings/options" rel="noopener noreferrer"&gt;message options&lt;/a&gt; to specify logic associated with the message transaction&lt;/li&gt;
&lt;li&gt;Call the &lt;code&gt;estimateFee&lt;/code&gt; function to estimate the gas fee for sending a message&lt;/li&gt;
&lt;li&gt;Call the &lt;code&gt;sendMessage&lt;/code&gt; function to send a message&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  Building message options
&lt;/h3&gt;

&lt;p&gt;The &lt;code&gt;estimateFee&lt;/code&gt; and &lt;code&gt;sendMessage&lt;/code&gt; custom functions of the &lt;code&gt;ExampleContract&lt;/code&gt; contract both require a &lt;a href="https://docs.layerzero.network/v2/developers/evm/protocol-gas-settings/options" rel="noopener noreferrer"&gt;message options&lt;/a&gt; (&lt;code&gt;_options&lt;/code&gt;) argument to be provided.&lt;/p&gt;

&lt;p&gt;Message options allow you to specify arbitrary logic as part of the message transaction, such as the gas amount the &lt;a href="https://docs.layerzero.network/v2/home/permissionless-execution/executors" rel="noopener noreferrer"&gt;Executor&lt;/a&gt; pays for message delivery, the order of message execution, or dropping an amount of gas to a destination address.&lt;/p&gt;

&lt;p&gt;LayerZero provides a &lt;a href="https://github.com/LayerZero-Labs/LayerZero-v2/blob/ccfd0d38f83ca8103b14ab9ca77f32e0419510ff/oapp/contracts/oapp/libs/OptionsBuilder.sol#L12" rel="noopener noreferrer"&gt;Solidity&lt;/a&gt; library and &lt;a href="https://docs.layerzero.network/v2/developers/evm/protocol-gas-settings/options" rel="noopener noreferrer"&gt;TypeScript SDK&lt;/a&gt; for building these message options.&lt;/p&gt;

&lt;p&gt;As an example, below is a Foundry script that uses OptionsBuilder from the Solidity library to generate message options (as &lt;code&gt;bytes&lt;/code&gt;) that set the gas amount that the Executor will pay upon message delivery to &lt;code&gt;200000&lt;/code&gt; wei:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;pragma solidity ^0.8.0;

import {Script, console2} from "forge-std/Script.sol";
import { OptionsBuilder } from "@layerzerolabs/lz-evm-oapp-v2/contracts/oapp/libs/OptionsBuilder.sol";

contract OptionsScript is Script {
    using OptionsBuilder for bytes;

    function setUp() public {}

    function run() public {
        bytes memory options = OptionsBuilder.newOptions().addExecutorLzReceiveOption(200000, 0);
        console2.logBytes(options);
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The output of this script results in:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;0x00030100110100000000000000000000000000030d40
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For this tutorial, rather than building and generating your own message options, you can use the bytes output provided above.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Info:&lt;/strong&gt; Covering all of the different message options in detail is out of scope for this tutorial. If you are interested in learning more about the different message options and how to build them, visit the &lt;a href="https://docs.layerzero.network/v2/developers/evm/protocol-gas-settings/options" rel="noopener noreferrer"&gt;LayerZero developer documentation&lt;/a&gt;.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  Estimating the gas fee
&lt;/h3&gt;

&lt;p&gt;Before you can send a message from your contract on Abstract Sepolia, you need to estimate the fee associated with sending the message. You can use the &lt;code&gt;cast&lt;/code&gt; command to call the &lt;code&gt;estimateFee()&lt;/code&gt; function of the &lt;code&gt;ExampleContract&lt;/code&gt; contract.&lt;/p&gt;

&lt;p&gt;To estimate the gas fee for sending a message from Abstract Sepolia to Arbitrum Sepolia, run the following command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;cast send &amp;lt;ABSTRACT_TESTNET_CONTRACT_ADDRESS&amp;gt; &lt;span class="nt"&gt;--rpc-url&lt;/span&gt; &lt;span class="nv"&gt;$ABSTRACT_TESTNET_RPC&lt;/span&gt; &lt;span class="s2"&gt;"estimateFee(uint32, string, bytes)"&lt;/span&gt; &lt;span class="nv"&gt;$ARBITRUM_TESTNET_LZ_ENDPOINT_ID&lt;/span&gt; &lt;span class="s2"&gt;"Hello World"&lt;/span&gt; 0x00030100110100000000000000000000000000030d40 &lt;span class="nt"&gt;--account&lt;/span&gt; deployer
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Info:&lt;/strong&gt; Replace &lt;code&gt;&amp;lt;ABSTRACT_TESTNET_CONTRACT_ADDRESS&amp;gt;&lt;/code&gt; with the contract address of your deployed &lt;code&gt;ExampleContract&lt;/code&gt; contract on Abstract Sepolia before running the provided &lt;code&gt;cast&lt;/code&gt; command.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The command above calls &lt;code&gt;estimateFee(uint32, string, bytes, bool)&lt;/code&gt;, while providing the required arguments, including: the endpoint ID of the destination chain, the text to send, and the message options (generated in the last section).&lt;/p&gt;

&lt;h3&gt;
  
  
  Sending the message
&lt;/h3&gt;

&lt;p&gt;Once you have fetched the estimated gas for sending your message, you can now call &lt;code&gt;sendMessage&lt;/code&gt; and provide the value returned as the &lt;code&gt;msg.value&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;For example, to send a message from Abstract Sepolia to Arbitrum Sepolia with an estimated gas fee, run the following command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;cast send &amp;lt;ABSTRACT_TESTNET_CONTRACT_ADDRESS&amp;gt; &lt;span class="nt"&gt;--rpc-url&lt;/span&gt; &lt;span class="nv"&gt;$ABSTRACT_TESTNET_RPC&lt;/span&gt; &lt;span class="nt"&gt;--value&lt;/span&gt; &amp;lt;GAS_ESTIMATE_IN_WEI&amp;gt; &lt;span class="s2"&gt;"sendMessage(uint32, string, bytes)"&lt;/span&gt; &lt;span class="nv"&gt;$ARBITRUM_TESTNET_LZ_ENDPOINT_ID&lt;/span&gt; &lt;span class="s2"&gt;"Hello World"&lt;/span&gt; 0x00030100110100000000000000000000000000030d40 &lt;span class="nt"&gt;--account&lt;/span&gt; deployer
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Info:&lt;/strong&gt; Replace &lt;code&gt;&amp;lt;ABSTRACT_TESTNET_CONTRACT_ADDRESS&amp;gt;&lt;/code&gt; with the contract address of your deployed &lt;code&gt;ExampleContract&lt;/code&gt; contract on Abstract Sepolia, and &lt;code&gt;&amp;lt;GAS_ESTIMATE_IN_WEI&amp;gt;&lt;/code&gt; with the gas estimate (in wei) returned by the call to estimateFee, before running the provided &lt;code&gt;cast&lt;/code&gt; command.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;You can view the status of your cross-chain transaction on &lt;a href="https://layerzeroscan.com/" rel="noopener noreferrer"&gt;LayerZero Scan&lt;/a&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Receiving the message
&lt;/h3&gt;

&lt;p&gt;Once the message has been sent and received on the destination chain, the _Receive function will be called on the &lt;code&gt;ExampleContract&lt;/code&gt; and the message payload will be stored in the contract's public &lt;code&gt;data&lt;/code&gt; variable.&lt;/p&gt;

&lt;p&gt;You can use the &lt;code&gt;cast&lt;/code&gt; command to read the latest message received by the &lt;code&gt;ExampleContract&lt;/code&gt; stored in the &lt;code&gt;data&lt;/code&gt; variable.&lt;/p&gt;

&lt;p&gt;To read the latest received message data that was sent to Arbitrum Sepolia from Abstract Sepolia, run the following command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;cast send &amp;lt;ARBITRUM_TESTNET_CONTRACT_ADDRESS&amp;gt; &lt;span class="nt"&gt;--rpc-url&lt;/span&gt; &lt;span class="nv"&gt;$ARBITRUM_TESTNET_RPC&lt;/span&gt; &lt;span class="s2"&gt;"data"&lt;/span&gt; &lt;span class="nt"&gt;--account&lt;/span&gt; deployer
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The returned data should match the message text payload you sent in your message.&lt;/p&gt;

&lt;p&gt;You can view the status of your cross-chain transaction on &lt;a href="https://layerzeroscan.com/" rel="noopener noreferrer"&gt;LayerZero Scan&lt;/a&gt;.&lt;/p&gt;




&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;Congratulations! You have successfully learned how to perform cross-chain messaging between Abstract and other chains (i.e. Arbitrum) using LayerZero V2.&lt;/p&gt;

&lt;p&gt;To learn more about cross-chain messaging and LayerZero V2, check out the following resources:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://docs.layerzero.network" rel="noopener noreferrer"&gt;LayerZero V2&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>tutorial</category>
      <category>blockchain</category>
      <category>web3</category>
      <category>crypto</category>
    </item>
    <item>
      <title>Deploying a smart contract to Abstract using Hardhat</title>
      <dc:creator>Taylor Caldwell</dc:creator>
      <pubDate>Mon, 27 Jan 2025 06:17:43 +0000</pubDate>
      <link>https://dev.to/taycaldwell/deploying-a-smart-contract-to-abstract-using-hardhat-4bco</link>
      <guid>https://dev.to/taycaldwell/deploying-a-smart-contract-to-abstract-using-hardhat-4bco</guid>
      <description>&lt;p&gt;This tutorial will guide you through deploying an NFT smart contract (ERC-721) on the Abstract test network using &lt;a href="https://hardhat.org/" rel="noopener noreferrer"&gt;Hardhat&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Hardhat is a developer tool that provides a simple way to deploy, test, and debug smart contracts.&lt;/p&gt;




&lt;h2&gt;
  
  
  Objectives
&lt;/h2&gt;

&lt;p&gt;By the end of this tutorial, you should be able to do the following:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Setup Hardhat for Abstract&lt;/li&gt;
&lt;li&gt;Create an NFT smart contract for Abstract&lt;/li&gt;
&lt;li&gt;Compile a smart contract for Abstract&lt;/li&gt;
&lt;li&gt;Deploy a smart contract to Abstract&lt;/li&gt;
&lt;li&gt;Interact with a smart contract deployed on Abstract&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Prerequisites
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Node v18+
&lt;/h3&gt;

&lt;p&gt;This tutorial requires you have Node version 18+ installed.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Download &lt;a href="https://nodejs.org/en/download/" rel="noopener noreferrer"&gt;Node v18+&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If you are using &lt;code&gt;nvm&lt;/code&gt; to manage your node versions, you can just run &lt;code&gt;nvm install 18&lt;/code&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Metamask Wallet
&lt;/h3&gt;

&lt;p&gt;In order to deploy a smart contract, you will first need a crypto wallet. You can create a wallet by downloading the Metamask browser extension.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Download &lt;a href="https://metamask.io/download/" rel="noopener noreferrer"&gt;Metamask&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Wallet funds
&lt;/h3&gt;

&lt;p&gt;Deploying contracts to the blockchain requires a gas fee. Therefore, you will need to fund your wallet with ETH to cover those gas fees.&lt;/p&gt;

&lt;p&gt;For this tutorial, you will be deploying a contract to the Abstract Sepolia test network. You can fund your wallet with Abstract Sepolia ETH using a &lt;a href="https://docs.abs.xyz/tooling/bridges" rel="noopener noreferrer"&gt;bridge&lt;/a&gt; or &lt;a href="https://docs.abs.xyz/tooling/faucets" rel="noopener noreferrer"&gt;faucet&lt;/a&gt;.&lt;/p&gt;




&lt;h2&gt;
  
  
  Creating a project
&lt;/h2&gt;

&lt;p&gt;Before you can begin deploying smart contracts to Abstract, you need to set up your development environment by creating a Node.js project.&lt;/p&gt;

&lt;p&gt;To create a new Node.js project, run:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm init &lt;span class="nt"&gt;--y&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Next, you will need to install Hardhat and create a new Hardhat project&lt;/p&gt;

&lt;p&gt;To install Hardhat, run:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;--save-dev&lt;/span&gt; hardhat
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;To create a new Hardhat project, run:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npx hardhat init
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Select &lt;code&gt;Create a TypeScript project&lt;/code&gt; then press &lt;em&gt;enter&lt;/em&gt; to confirm the project root.&lt;/p&gt;

&lt;p&gt;Select &lt;code&gt;y&lt;/code&gt; for both adding a &lt;code&gt;.gitignore&lt;/code&gt; and loading the sample project. It will take a moment for the project setup process to complete.&lt;/p&gt;




&lt;h2&gt;
  
  
  Configuring Hardhat with Abstract
&lt;/h2&gt;

&lt;p&gt;In order to deploy smart contracts to the Abstract network, you will need to configure your Hardhat project and add the Abstract network.&lt;/p&gt;

&lt;p&gt;To configure Hardhat to use Abstract, add Abstract as a network to your project's &lt;code&gt;hardhat.config.ts&lt;/code&gt; file:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;HardhatUserConfig&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;hardhat/config&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@nomicfoundation/hardhat-toolbox&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;dotenv&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;config&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;config&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;HardhatUserConfig&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;solidity&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;version&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;0.8.23&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="na"&gt;networks&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// for mainnet&lt;/span&gt;
    &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;abstract-mainnet&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;url&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;https://api.mainnet.abs.xyz&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;accounts&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;WALLET_KEY&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
      &lt;span class="na"&gt;gasPrice&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;1000000000&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="c1"&gt;// for testnet&lt;/span&gt;
    &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;abstract-testnet&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;url&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;https://api.testnet.abs.xyz&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;accounts&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;WALLET_KEY&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
      &lt;span class="na"&gt;gasPrice&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;1000000000&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="c1"&gt;// for local dev environment&lt;/span&gt;
    &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;abstract-local&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;url&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;http://localhost:8545&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;accounts&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;WALLET_KEY&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
      &lt;span class="na"&gt;gasPrice&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;1000000000&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="na"&gt;defaultNetwork&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;hardhat&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="nx"&gt;config&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Install Hardhat toolbox
&lt;/h3&gt;

&lt;p&gt;The above configuration uses the &lt;code&gt;@nomicfoundation/hardhat-toolbox&lt;/code&gt; plugin to bundle all the commonly used packages and Hardhat plugins recommended to start developing with Hardhat.&lt;/p&gt;

&lt;p&gt;To install &lt;code&gt;@nomicfoundation/hardhat-toolbox&lt;/code&gt;, run:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;--save-dev&lt;/span&gt; @nomicfoundation/hardhat-toolbox
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Loading environment variables
&lt;/h3&gt;

&lt;p&gt;The above configuration also uses &lt;a href="https://www.npmjs.com/package/dotenv" rel="noopener noreferrer"&gt;dotenv&lt;/a&gt; to load the &lt;code&gt;WALLET_KEY&lt;/code&gt; environment variable from a &lt;code&gt;.env&lt;/code&gt; file to &lt;code&gt;process.env.WALLET_KEY&lt;/code&gt;. You should use a similar method to avoid hardcoding your private keys within your source code.&lt;/p&gt;

&lt;p&gt;To install &lt;code&gt;dotenv&lt;/code&gt;, run:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;--save-dev&lt;/span&gt; dotenv
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Once you have &lt;code&gt;dotenv&lt;/code&gt; installed, you can create a &lt;code&gt;.env&lt;/code&gt; file with the following content:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;WALLET_KEY="&amp;lt;YOUR_PRIVATE_KEY&amp;gt;"
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Substituting &lt;code&gt;&amp;lt;YOUR_PRIVATE_KEY&amp;gt;&lt;/code&gt; with the private key for your wallet.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Caution:&lt;/strong&gt; &lt;code&gt;WALLET_KEY&lt;/code&gt; is the private key of the wallet to use when deploying a contract. For instructions on how to get your private key from Metamask, visit the &lt;a href="https://support.metamask.io/configure/accounts/how-to-export-an-accounts-private-key/" rel="noopener noreferrer"&gt;Metamask Support page&lt;/a&gt;. &lt;strong&gt;It is critical that you do NOT commit this to a public repo&lt;/strong&gt;.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  Local Networks
&lt;/h3&gt;

&lt;p&gt;For quick testing, such as if you want to add unit tests to the below NFT contract, you may wish to leave the &lt;code&gt;defaultNetwork&lt;/code&gt; as &lt;code&gt;'hardhat'&lt;/code&gt;.&lt;/p&gt;




&lt;h2&gt;
  
  
  Compiling the smart contract
&lt;/h2&gt;

&lt;p&gt;Below is a simple NFT smart contract (ERC-721) written in the Solidity programming language:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// SPDX-License-Identifier: MIT
pragma solidity ^0.8.23;

import "@openzeppelin/contracts/token/ERC721/ERC721.sol";

contract NFT is ERC721 {
    uint256 public currentTokenId;

    constructor() ERC721("NFT Name", "NFT") {}

    function mint(address recipient) public payable returns (uint256) {
        uint256 newItemId = ++currentTokenId;
        _safeMint(recipient, newItemId);
        return newItemId;
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The Solidity code above defines a smart contract named &lt;code&gt;NFT&lt;/code&gt;. The code uses the &lt;code&gt;ERC721&lt;/code&gt; interface provided by the &lt;a href="https://docs.openzeppelin.com/contracts/5.x/" rel="noopener noreferrer"&gt;OpenZeppelin Contracts library&lt;/a&gt; to create an NFT smart contract. OpenZeppelin allows developers to leverage battle-tested smart contract implementations that adhere to official ERC standards.&lt;/p&gt;

&lt;p&gt;To add the OpenZeppelin Contracts library to your project, run:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;--save&lt;/span&gt; @openzeppelin/contracts
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In your project, delete the &lt;code&gt;contracts/Lock.sol&lt;/code&gt; contract that was generated with the project and add the above code in a new file called &lt;code&gt;contracts/NFT.sol&lt;/code&gt;. (You can also delete the &lt;code&gt;test/Lock.ts&lt;/code&gt; test file, but you should add your own tests ASAP!).&lt;/p&gt;

&lt;p&gt;To compile the contract using Hardhat, run:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npx hardhat compile
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  Deploying the smart contract
&lt;/h2&gt;

&lt;p&gt;Once your contract has been successfully compiled, you can deploy the contract to the Abstract Sepolia test network.&lt;/p&gt;

&lt;p&gt;To deploy the contract to the Abstract Sepolia test network, you'll need to modify the &lt;code&gt;scripts/deploy.ts&lt;/code&gt; in your project:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;ethers&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;hardhat&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;nft&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;ethers&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;deployContract&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;NFT&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;nft&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;waitForDeployment&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

  &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;NFT Contract Deployed at &lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;nft&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;target&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;// We recommend this pattern to be able to use async/await everywhere&lt;/span&gt;
&lt;span class="c1"&gt;// and properly handle errors.&lt;/span&gt;
&lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="k"&gt;catch&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;exitCode&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You'll also need testnet ETH in your wallet. See the prerequisites if you haven't done that yet. Otherwise, the deployment attempt will fail.&lt;/p&gt;

&lt;p&gt;Finally, run:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npx hardhat run scripts/deploy.ts &lt;span class="nt"&gt;--network&lt;/span&gt; abstract-testnet
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The contract will be deployed on the Abstract Sepolia test network. You can view the deployment status and contract by using a &lt;a href="https://docs.abs.xyz/tooling/block-explorers" rel="noopener noreferrer"&gt;block explorer&lt;/a&gt; and searching for the address returned by your deploy script. If you've deployed an exact copy of the NFT contract above, it will already be verified and you'll be able to read and write to the contract using the web interface.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Info:&lt;/strong&gt; If you'd like to deploy to mainnet, you'll modify the command like so:&lt;/p&gt;


&lt;pre class="highlight shell"&gt;&lt;code&gt;npx hardhat run scripts/deploy.ts &lt;span class="nt"&gt;--network&lt;/span&gt; abstract-mainnet
&lt;/code&gt;&lt;/pre&gt;

&lt;/blockquote&gt;

&lt;p&gt;Regardless of the network you're deploying to, if you're deploying a new or modified contract, you'll need to verify it first.&lt;/p&gt;




&lt;h2&gt;
  
  
  Verifying the Smart Contract
&lt;/h2&gt;

&lt;p&gt;If you want to interact with your contract on the block explorer, you, or someone, needs to verify it first. The above contract has already been verified, so you should be able to view your version on a block explorer already. For the remainder of this tutorial, we'll walk through how to verify your contract on Abstract Sepolia testnet.&lt;/p&gt;

&lt;p&gt;In &lt;code&gt;hardhat.config.ts&lt;/code&gt;, configure Abstract Sepolia as a custom network. Add the following to your &lt;code&gt;HardhatUserConfig&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="nx"&gt;etherscan&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
   &lt;span class="nl"&gt;apiKey&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;abstract-testnet&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;PLACEHOLDER_STRING&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
   &lt;span class="p"&gt;},&lt;/span&gt;
   &lt;span class="nx"&gt;customChains&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
     &lt;span class="p"&gt;{&lt;/span&gt;
       &lt;span class="na"&gt;network&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;abstract-testnet&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
       &lt;span class="na"&gt;chainId&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;11124&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
       &lt;span class="na"&gt;urls&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="na"&gt;apiURL&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;https://api-sepolia.abscan.org/api&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;browserURL&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;https://sepolia.abscan.org/&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
       &lt;span class="p"&gt;}&lt;/span&gt;
     &lt;span class="p"&gt;}&lt;/span&gt;
   &lt;span class="p"&gt;]&lt;/span&gt;
 &lt;span class="p"&gt;},&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Info:&lt;/strong&gt; You can get your AbsScan API key from &lt;a href="https://abscan.org/myapikey" rel="noopener noreferrer"&gt;abscan.org&lt;/a&gt; when you sign up for an account.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Now, you can verify your contract. Grab the deployed address and run:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npx hardhat verify &lt;span class="nt"&gt;--network&lt;/span&gt; abstract-testnet &amp;lt;deployed address&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You should see an output similar to:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Nothing to compile
No need to generate any newer typings.
Successfully submitted source code for contract
contracts/NFT.sol:NFT at 0x1234567890ABCDEF01234567890ABCDEF0123456
for verification on the block explorer. Waiting for verification result...

Successfully verified contract NFT on Etherscan.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Info:&lt;/strong&gt; You can't re-verify a contract identical to one that has already been verified. If you attempt to do so, such as verifying the above contract, you'll get an error similar to:&lt;/p&gt;


&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Error in plugin @nomiclabs/hardhat-etherscan: The API responded with an unexpected message.
Contract verification may have succeeded and should be checked manually.
Message: Already Verified
&lt;/code&gt;&lt;/pre&gt;

&lt;/blockquote&gt;

&lt;p&gt;Search for your contract on &lt;a href="https://sepolia.abscan.org/" rel="noopener noreferrer"&gt;AbsScan&lt;/a&gt; to confirm it is verified.&lt;/p&gt;

&lt;h2&gt;
  
  
  Interacting with the Smart Contract
&lt;/h2&gt;

&lt;p&gt;If you verified on AbsScan, you can use the &lt;code&gt;Read Contract&lt;/code&gt; and &lt;code&gt;Write Contract&lt;/code&gt; tabs to interact with the deployed contract. You'll need to connect your wallet first, by clicking the Connect button.&lt;/p&gt;




</description>
      <category>tutorial</category>
      <category>blockchain</category>
      <category>crypto</category>
      <category>web3</category>
    </item>
    <item>
      <title>Deploying a smart contract to Abstract using Foundry</title>
      <dc:creator>Taylor Caldwell</dc:creator>
      <pubDate>Mon, 27 Jan 2025 06:04:48 +0000</pubDate>
      <link>https://dev.to/taycaldwell/deploying-a-smart-contract-to-abstract-using-foundry-2hdf</link>
      <guid>https://dev.to/taycaldwell/deploying-a-smart-contract-to-abstract-using-foundry-2hdf</guid>
      <description>&lt;p&gt;This article will provide an overview of the &lt;a href="https://book.getfoundry.sh/" rel="noopener noreferrer"&gt;Foundry&lt;/a&gt; development toolchain, and show you how to deploy a contract to &lt;strong&gt;Abstract Sepolia&lt;/strong&gt; testnet.&lt;/p&gt;

&lt;p&gt;Foundry is a powerful suite of tools to develop, test, and debug your smart contracts. It comprises several individual tools:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;forge&lt;/code&gt;: the main workhorse of Foundry — for developing, testing, compiling, and deploying smart contracts&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;cast&lt;/code&gt;: a command-line tool for performing Ethereum RPC calls (e.g., interacting with contracts, sending transactions, and getting onchain data)&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;anvil&lt;/code&gt;: a local testnet node, for testing contract behavior from a frontend or over RPC&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;chisel&lt;/code&gt;: a Solidity &lt;a href="https://en.wikipedia.org/wiki/Read%E2%80%93eval%E2%80%93print_loop" rel="noopener noreferrer"&gt;REPL&lt;/a&gt;, for trying out Solidity snippets on a local or forked network&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Foundry offers extremely fast feedback loops (due to the under-the-hood Rust implementation) and less context switching — because you'll be writing your contracts, tests, and deployment scripts &lt;strong&gt;All&lt;/strong&gt; in Solidity!&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Info:&lt;/strong&gt; For production / mainnet deployments the steps below in this tutorial will be almost identical, however, you'll want to ensure that you've configured &lt;code&gt;Abstract&lt;/code&gt; (mainnet) as the network rather than &lt;code&gt;Abstract Sepolia&lt;/code&gt; (testnet).&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  Objectives
&lt;/h2&gt;

&lt;p&gt;By the end of this tutorial, you should be able to do the following:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Setup Foundry for Abstract&lt;/li&gt;
&lt;li&gt;Create an NFT smart contract for Abstract&lt;/li&gt;
&lt;li&gt;Compile a smart contract for Abstract (using &lt;code&gt;forge&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;Deploy a smart contract to Abstract (also with &lt;code&gt;forge&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;Interact with a smart contract deployed on Abstract (using &lt;code&gt;cast&lt;/code&gt;)&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Prerequisites
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Foundry
&lt;/h3&gt;

&lt;p&gt;This tutorial requires you have Foundry installed.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;From the command-line (terminal), run: &lt;code&gt;curl -L https://foundry.paradigm.xyz | bash&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Then run &lt;code&gt;foundryup&lt;/code&gt;, to install the latest (nightly) build of Foundry&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For more information, see the Foundry Book &lt;a href="https://book.getfoundry.sh/getting-started/installation" rel="noopener noreferrer"&gt;installation guide&lt;/a&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Metamask Wallet
&lt;/h3&gt;

&lt;p&gt;In order to deploy a smart contract, you will first need a crypto wallet. You can create a wallet by downloading the Metamask browser extension.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Download &lt;a href="https://metamask.io/download/" rel="noopener noreferrer"&gt;Metamask&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Wallet funds
&lt;/h3&gt;

&lt;p&gt;Deploying contracts to the blockchain requires a gas fee. Therefore, you will need to fund your wallet with ETH to cover those gas fees.&lt;/p&gt;

&lt;p&gt;For this tutorial, you will be deploying a contract to the Abstract Sepolia test network. You can fund your wallet with Abstract Sepolia ETH using a &lt;a href="https://docs.abs.xyz/tooling/bridges" rel="noopener noreferrer"&gt;bridge&lt;/a&gt; or &lt;a href="https://docs.abs.xyz/tooling/faucets" rel="noopener noreferrer"&gt;faucet&lt;/a&gt;.&lt;/p&gt;




&lt;h2&gt;
  
  
  Creating a project
&lt;/h2&gt;

&lt;p&gt;Before you can begin deploying smart contracts to Abstract, you need to set up your development environment by creating a Foundry project.&lt;/p&gt;

&lt;p&gt;To create a new Foundry project, first create a new directory:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;mkdir &lt;/span&gt;myproject
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then run:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;cd &lt;/span&gt;myproject
forge init
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This will create a Foundry project, which has the following basic layout:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;.&lt;/span&gt;
├── foundry.toml
├── script
 │   └── Counter.s.sol
├── src
 │   └── Counter.sol
└── &lt;span class="nb"&gt;test&lt;/span&gt;
    └── Counter.t.sol
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  Compiling the smart contract
&lt;/h2&gt;

&lt;p&gt;Below is a simple NFT smart contract (&lt;a href="https://eips.ethereum.org/EIPS/eip-721" rel="noopener noreferrer"&gt;ERC-721&lt;/a&gt;) written in the Solidity programming language:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// SPDX-License-Identifier: MIT
pragma solidity ^0.8.23;

import "openzeppelin-contracts/contracts/token/ERC721/ERC721.sol";

contract NFT is ERC721 {
    uint256 public currentTokenId;

    constructor() ERC721("NFT Name", "NFT") {}

    function mint(address recipient) public payable returns (uint256) {
        uint256 newItemId = ++currentTokenId;
        _safeMint(recipient, newItemId);
        return newItemId;
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The Solidity code above defines a smart contract named &lt;code&gt;NFT&lt;/code&gt;. The code uses the &lt;code&gt;ERC721&lt;/code&gt; interface provided by the &lt;a href="https://docs.openzeppelin.com/contracts/5.x/" rel="noopener noreferrer"&gt;OpenZeppelin Contracts library&lt;/a&gt; to create an NFT smart contract. OpenZeppelin allows developers to leverage battle-tested smart contract implementations that adhere to official ERC standards.&lt;/p&gt;

&lt;p&gt;To add the OpenZeppelin Contracts library to your project, run:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;forge &lt;span class="nb"&gt;install &lt;/span&gt;openzeppelin/openzeppelin-contracts
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In your project, delete the &lt;code&gt;src/Counter.sol&lt;/code&gt; contract that was generated with the project and add the above code in a new file called &lt;code&gt;src/NFT.sol&lt;/code&gt;. (You can also delete the &lt;code&gt;test/Counter.t.sol&lt;/code&gt; and &lt;code&gt;script/Counter.s.sol&lt;/code&gt; files, but you should add your own tests ASAP!).&lt;/p&gt;

&lt;p&gt;To compile our basic NFT contract using Foundry, run:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;forge build
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  Configuring Foundry with Abstract
&lt;/h2&gt;

&lt;p&gt;Next, you will configure your Foundry project to deploy smart contracts to the Abstract network. First you'll store your private key in an encrypted keystore, then you'll add Abstract as a network.&lt;/p&gt;

&lt;h3&gt;
  
  
  Storing your private key
&lt;/h3&gt;

&lt;p&gt;The following command will import your private key to Foundry's secure keystore. You will be prompted to enter your private key, as well as a password for signing transactions:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;cast wallet import deployer &lt;span class="nt"&gt;--interactive&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Caution:&lt;/strong&gt; For instructions on how to get your private key from Metamask, visit the &lt;a href="https://support.metamask.io/configure/accounts/how-to-export-an-accounts-private-key/" rel="noopener noreferrer"&gt;Metamask Support page&lt;/a&gt;. &lt;strong&gt;It is critical that you do NOT commit this to a public repo&lt;/strong&gt;.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Run this command to confirm that the 'deployer' account is setup in Foundry:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;cast wallet list
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Adding Abstract as a network
&lt;/h3&gt;

&lt;p&gt;When verifying a contract with AbsScan, you need an API key. You can get your AbsScan API key from &lt;a href="https://abscan.org/myapikey" rel="noopener noreferrer"&gt;here&lt;/a&gt; after you sign up for an account.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Caution:&lt;/strong&gt; Although they're made by the same folks, Etherscan API keys will &lt;strong&gt;not&lt;/strong&gt; work on AbsScan!&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Now create a &lt;code&gt;.env&lt;/code&gt; file in the home directory of your project to add the Abstract network and an API key for verifying your contract on AbsScan:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;ABSTRACT_MAINNET_RPC="https://api.mainnet.abs.xyz"
ABSTRACT_TESTNET_RPC="https://api.testnet.abs.xyz"
ETHERSCAN_API_KEY="&amp;lt;YOUR API KEY&amp;gt;"
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; Even though you're using AbsScan your block explorer, Foundry expects the API key to be defined as &lt;code&gt;ETHERSCAN_API_KEY&lt;/code&gt;.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  Loading environment variables
&lt;/h3&gt;

&lt;p&gt;Now that you've created the above &lt;code&gt;.env&lt;/code&gt; file, run the following command to load the environment variables in the current command line session:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;source&lt;/span&gt; .env
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  Deploying the smart contract
&lt;/h2&gt;

&lt;p&gt;With your contract compiled and your environment configured, you are ready to deploy to the Abstract Sepolia test network!&lt;/p&gt;

&lt;p&gt;Today, you'll use the &lt;code&gt;forge create&lt;/code&gt; command, which is a straightforward way to deploy a single contract at a time. In the future, you may want to look into &lt;a href="https://book.getfoundry.sh/tutorials/solidity-scripting" rel="noopener noreferrer"&gt;&lt;code&gt;forge script&lt;/code&gt;&lt;/a&gt;, which enables scripting onchain transactions and deploying more complex smart contract projects.&lt;/p&gt;

&lt;p&gt;You'll need testnet ETH in your wallet. See the prerequisites if you haven't done that yet. Otherwise, the deployment attempt will fail.&lt;/p&gt;

&lt;p&gt;To deploy the contract to the Abstract Sepolia test network, run the following command. You will be prompted to enter the password that you set earlier, when you imported your private key:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;forge create ./src/NFT.sol:NFT &lt;span class="nt"&gt;--rpc-url&lt;/span&gt; &lt;span class="nv"&gt;$ABSTRACT_TESTNET_RPC&lt;/span&gt; &lt;span class="nt"&gt;--account&lt;/span&gt; deployer
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The contract will be deployed on the Abstract Sepolia test network. You can view the deployment status and contract by using a &lt;a href="https://docs.abs.xyz/tooling/block-explorers" rel="noopener noreferrer"&gt;block explorer&lt;/a&gt; and searching for the address returned by your deploy script. If you've deployed an exact copy of the NFT contract above, it will already be verified and you'll be able to read and write to the contract using the web interface.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Info:&lt;/strong&gt; If you'd like to deploy to mainnet, you'll modify the command like so:&lt;br&gt;
&lt;/p&gt;
&lt;/blockquote&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;forge create ./src/NFT.sol:NFT &lt;span class="nt"&gt;--rpc-url&lt;/span&gt; &lt;span class="nv"&gt;$ABSTRACT_MAINNET_RPC&lt;/span&gt; &lt;span class="nt"&gt;--account&lt;/span&gt; deployer
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Regardless of the network you're deploying to, if you're deploying a new or modified contract, you'll need to verify it.&lt;/p&gt;




&lt;h2&gt;
  
  
  Verifying the Smart Contract
&lt;/h2&gt;

&lt;p&gt;In web3, it's considered best practice to verify your contracts so that users and other developers can inspect the source code, and be sure that it matches the deployed bytecode on the blockchain.&lt;/p&gt;

&lt;p&gt;Further, if you want to allow others to interact with your contract using the block explorer, it first needs to be verified. The above contract has already been verified, so you should be able to view your version on a block explorer already, but we'll still walk through how to verify a contract on Abstract Sepolia testnet.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Info:&lt;/strong&gt; Remember, you need an API key from AbsScan to verify your contracts. You can get your API key from &lt;a href="https://abscan.org/myapikey" rel="noopener noreferrer"&gt;the AbsScan site&lt;/a&gt; after you sign up for an account.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Grab the deployed address and run:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;forge verify-contract &amp;lt;DEPLOYED_ADDRESS&amp;gt; ./src/NFT.sol:NFT &lt;span class="nt"&gt;--chain&lt;/span&gt; 11124 &lt;span class="nt"&gt;--watch&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You should see an output similar to:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Start verifying contract `0x1234567890ABCDEF01234567890ABCDEF0123456` deployed on abstract-testnet

Submitting verification for [src/NFT.sol:NFT] 0x1234567890ABCDEF01234567890ABCDEF0123456.
Submitted contract for verification:
        Response: `OK`
        https://sepolia.abscan.org/address/0x1234567890ABCDEF01234567890ABCDEF0123456
Contract verification status:
Response: `NOTOK`
Details: `Pending in queue`
Contract verification status:
Response: `OK`
Details: `Pass - Verified`
Contract successfully verified
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Search for your contract on &lt;a href="https://sepolia.abscan.org" rel="noopener noreferrer"&gt;AbsScan&lt;/a&gt; to confirm it is verified.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Info:&lt;/strong&gt; You can't re-verify a contract identical to one that has already been verified. If you attempt to do so, such as verifying the above contract, you'll get an error similar to:&lt;/p&gt;


&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Start verifying contract `0x1234567890ABCDEF01234567890ABCDEF0123456` deployed on abstract-testnet

Contract [src/NFT.sol:NFT] "0x1234567890ABCDEF01234567890ABCDEF0123456" is already verified. Skipping verification.
&lt;/code&gt;&lt;/pre&gt;

&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Interacting with the Smart Contract
&lt;/h2&gt;

&lt;p&gt;If you verified on AbsScan, you can use the &lt;code&gt;Read Contract&lt;/code&gt; and &lt;code&gt;Write Contract&lt;/code&gt; sections under the &lt;code&gt;Contract&lt;/code&gt; tab to interact with the deployed contract. To use &lt;code&gt;Write Contract&lt;/code&gt;, you'll need to connect your wallet first, by clicking the &lt;code&gt;Connect to Web3&lt;/code&gt; button (sometimes this can be a little finicky, and you'll need to click &lt;code&gt;Connect&lt;/code&gt; twice before it shows your wallet is successfully connected).&lt;/p&gt;

&lt;p&gt;To practice using the &lt;code&gt;cast&lt;/code&gt; command-line tool which Foundry provides, you'll perform a call without publishing a transaction (a read), then sign and publish a transaction (a write).&lt;/p&gt;

&lt;h3&gt;
  
  
  Performing a call
&lt;/h3&gt;

&lt;p&gt;A key component of the Foundry toolkit, &lt;code&gt;cast&lt;/code&gt; enables us to interact with contracts, send transactions, and get onchain data using Ethereum RPC calls. First you will perform a call from your account, without publishing a transaction.&lt;/p&gt;

&lt;p&gt;From the command-line, run:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;cast call &amp;lt;DEPLOYED_ADDRESS&amp;gt; &lt;span class="nt"&gt;--rpc-url&lt;/span&gt; &lt;span class="nv"&gt;$ABSTRACT_TESTNET_RPC&lt;/span&gt; &lt;span class="s2"&gt;"balanceOf(address)"&lt;/span&gt; &amp;lt;YOUR_ADDRESS_HERE&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You should receive &lt;code&gt;0x0000000000000000000000000000000000000000000000000000000000000000&lt;/code&gt; in response, which equals &lt;code&gt;0&lt;/code&gt; in hexadecimal. And that makes sense — while you've deployed the NFT contract, no NFTs have been minted yet and therefore your account's balance is zero.&lt;/p&gt;

&lt;h3&gt;
  
  
  Signing and publishing a transaction
&lt;/h3&gt;

&lt;p&gt;Now, sign and publish a transaction, calling the &lt;code&gt;mint(address)&lt;/code&gt; function on the NFT contract you just deployed.&lt;/p&gt;

&lt;p&gt;Run the following command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;cast send &amp;lt;DEPLOYED_ADDRESS&amp;gt; &lt;span class="nt"&gt;--rpc-url&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nv"&gt;$ABSTRACT_TESTNET_RPC&lt;/span&gt; &lt;span class="s2"&gt;"mint(address)"&lt;/span&gt; &amp;lt;YOUR_ADDRESS_HERE&amp;gt; &lt;span class="nt"&gt;--account&lt;/span&gt; deployer
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Info:&lt;/strong&gt; Note that in this &lt;code&gt;cast send&lt;/code&gt; command, you had to include your private key, but this is not required for &lt;code&gt;cast call&lt;/code&gt;, because that's for calling view-only contract functions and therefore you don't need to sign anything.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;If successful, Foundry will respond with information about the transaction, including the &lt;code&gt;blockNumber&lt;/code&gt;, &lt;code&gt;gasUsed&lt;/code&gt;, and &lt;code&gt;transactionHash&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Finally, let's confirm that you did indeed mint yourself one NFT. If you run the first &lt;code&gt;cast call&lt;/code&gt; command again, you should see that your balance increased from 0 to 1:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;cast call &amp;lt;DEPLOYED_ADDRESS&amp;gt; &lt;span class="nt"&gt;--rpc-url&lt;/span&gt; &lt;span class="nv"&gt;$ABSTRACT_TESTNET_RPC&lt;/span&gt; &lt;span class="s2"&gt;"balanceOf(address)"&lt;/span&gt; &amp;lt;YOUR_ADDRESS_HERE&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And the response: &lt;code&gt;0x0000000000000000000000000000000000000000000000000000000000000001&lt;/code&gt; (&lt;code&gt;1&lt;/code&gt; in hex) — congratulations, you deployed a contract and minted an NFT with Foundry!&lt;/p&gt;




&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;Phew, that was a lot! You learned how to setup a project, deploy to Abstract, and interact with our smart contract using Foundry. The process is the same for real networks, just more expensive — and of course, you'll want to invest time and effort testing your contracts, to reduce the likelihood of user-impacting bugs before deploying.&lt;/p&gt;

&lt;p&gt;For all things Foundry, check out the &lt;a href="https://book.getfoundry.sh/" rel="noopener noreferrer"&gt;Foundry book&lt;/a&gt;, or head to the official Telegram &lt;a href="https://t.me/foundry_rs" rel="noopener noreferrer"&gt;dev chat&lt;/a&gt; or &lt;a href="https://t.me/foundry_support" rel="noopener noreferrer"&gt;support chat&lt;/a&gt;.&lt;/p&gt;




</description>
      <category>smartcontract</category>
      <category>blockchain</category>
      <category>crypto</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>Generating random numbers contracts on Base using Supra dVRF</title>
      <dc:creator>Taylor Caldwell</dc:creator>
      <pubDate>Mon, 27 Jan 2025 04:29:13 +0000</pubDate>
      <link>https://dev.to/taycaldwell/generating-random-numbers-contracts-on-base-using-supra-dvrf-3c4c</link>
      <guid>https://dev.to/taycaldwell/generating-random-numbers-contracts-on-base-using-supra-dvrf-3c4c</guid>
      <description>&lt;p&gt;This tutorial will guide you through the process of creating a smart contract on Base that utilizes Supra dVRF to serve random numbers using an onchain randomness generation mechanism directly within your smart contracts.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; This tutorial was originally published and authored by &lt;a href="https://x.com/taycaldwell" rel="noopener noreferrer"&gt;@taycaldwell&lt;/a&gt; on &lt;a href="https://docs.base.org" rel="noopener noreferrer"&gt;https://docs.base.org&lt;/a&gt;. You can find the original tutorial &lt;a href="https://docs.base.org/tutorials/oracles-supra-vrf" rel="noopener noreferrer"&gt;here&lt;/a&gt;.&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  Objectives
&lt;/h2&gt;

&lt;p&gt;By the end of this tutorial you should be able to do the following:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Set up a smart contract project for Base using Foundry&lt;/li&gt;
&lt;li&gt;Install the Supra dVRF as a dependency&lt;/li&gt;
&lt;li&gt;Use Supra dVRF within your smart contract&lt;/li&gt;
&lt;li&gt;Deploy and test your smart contracts on Base&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Prerequisites
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Foundry
&lt;/h3&gt;

&lt;p&gt;This tutorial requires you to have Foundry installed.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;From the command-line (terminal), run: &lt;code&gt;curl -L https://foundry.paradigm.xyz | bash&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Then run &lt;code&gt;foundryup&lt;/code&gt;, to install the latest (nightly) build of Foundry&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For more information, see the Foundry Book &lt;a href="https://book.getfoundry.sh/getting-started/installation" rel="noopener noreferrer"&gt;installation guide&lt;/a&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Coinbase Wallet
&lt;/h3&gt;

&lt;p&gt;In order to deploy a smart contract, you will first need a wallet. You can create a wallet by downloading the Coinbase Wallet browser extension.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Download &lt;a href="https://chrome.google.com/webstore/detail/coinbase-wallet-extension/hnfanknocfeofbddgcijnmhnfnkdnaad?hl=en" rel="noopener noreferrer"&gt;Coinbase Wallet&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Wallet funds
&lt;/h3&gt;

&lt;p&gt;Deploying contracts to the blockchain requires a gas fee. Therefore, you will need to fund your wallet with ETH to cover those gas fees.&lt;/p&gt;

&lt;p&gt;For this tutorial, you will be deploying a contract to the Base Sepolia test network. You can fund your wallet with Base Sepolia ETH using one of the faucets listed on the Base &lt;a href="https://docs.base.org/tools/network-faucets" rel="noopener noreferrer"&gt;Network Faucets&lt;/a&gt; page.&lt;/p&gt;

&lt;h3&gt;
  
  
  Supra wallet registration
&lt;/h3&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Caution:&lt;/strong&gt; Supra dVRF V2 requires subscription to the service with a customer controlled wallet address to act as the main reference.&lt;/p&gt;

&lt;p&gt;Therefore you must register your wallet with the Supra team if you plan to consume Supra dVRF V2 within your smart contracts.&lt;/p&gt;

&lt;p&gt;Please refer to the &lt;a href="https://docs.supra.com/oracles/dvrf/vrf-subscription-model" rel="noopener noreferrer"&gt;Supra documentation&lt;/a&gt; for the latest steps on how to register your wallet for their service.&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  What is a Verifiable Random Function (VRF)?
&lt;/h2&gt;

&lt;p&gt;A Verifiable Random Function (VRF) provides a solution for generating random outcomes in a manner that is both decentralized and verifiably recorded onchain. VRFs are crucial for applications where randomness integrity is paramount, such as in gaming or prize drawings.&lt;/p&gt;

&lt;p&gt;Supra dVRF provides a decentralized VRF that ensures that the outcomes are not only effectively random but also responsive, scalable, and easily verifiable, thereby addressing the unique needs of onchain applications for trustworthy and transparent randomness.&lt;/p&gt;




&lt;h2&gt;
  
  
  Creating a project
&lt;/h2&gt;

&lt;p&gt;Before you can begin writing smart contracts for Base, you need to set up your development environment by creating a Foundry project.&lt;/p&gt;

&lt;p&gt;To create a new Foundry project, first create a new directory:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;mkdir &lt;/span&gt;myproject
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then run:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;cd &lt;/span&gt;myproject
forge init
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This will create a Foundry project, which has the following basic layout:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;.&lt;/span&gt;
├── foundry.toml
├── script
 │   └── Counter.s.sol
├── src
 │   └── Counter.sol
└── &lt;span class="nb"&gt;test&lt;/span&gt;
    └── Counter.t.sol
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  Writing the Smart Contract
&lt;/h2&gt;

&lt;p&gt;Once your Foundry project has been created, you can now start writing a smart contract.&lt;/p&gt;

&lt;p&gt;The Solidity code below defines a basic contract named &lt;code&gt;RNGContract&lt;/code&gt;. The smart contract's constructor takes in a single &lt;code&gt;address&lt;/code&gt; and assigns it to a member variable named &lt;code&gt;supraAddr&lt;/code&gt;. This address corresponds to the &lt;a href="https://docs.supra.com/oracles/data-feeds/pull-oracle/networks" rel="noopener noreferrer"&gt;contract address&lt;/a&gt; of the Supra Router Contract that will be used to generate random numbers. The contract address of the Supra Router Contract on Base Sepolia testnet is &lt;code&gt;0x99a021029EBC90020B193e111Ae2726264a111A2&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;The contract also assigns the contract deployer (&lt;code&gt;msg.sender&lt;/code&gt;) to a member variable named &lt;code&gt;supraClientAddress&lt;/code&gt;. This should be the client wallet address that is registered and whitelisted to use Supra VRF (see: Prerequisites).&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

contract RNGContract {
    address supraAddr;
    address supraClientAddress;

    constructor(address supraSC) {
        supraAddr = supraSC;
        supraClientAddress = msg.sender;
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In your project, add the code provided above to a new file named &lt;code&gt;src/ExampleContract.sol&lt;/code&gt;, and delete the &lt;code&gt;src/Counter.sol&lt;/code&gt; contract that was generated with the project. (you can also delete the &lt;code&gt;test/Counter.t.sol&lt;/code&gt; and &lt;code&gt;script/Counter.s.sol&lt;/code&gt; files).&lt;/p&gt;

&lt;p&gt;The following sections will guide you step-by-step on how to update your contract to generate random numbers using the Supra Router contract.&lt;/p&gt;

&lt;h3&gt;
  
  
  Adding the Supra Router Contract interface
&lt;/h3&gt;

&lt;p&gt;In order to help your contract (the requester contract) interact with the Supra Router contract and understand what methods it can call, you will need to add the following interface to your contract file.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;interface ISupraRouter {
    function generateRequest(string memory _functionSig, uint8 _rngCount, uint256 _numConfirmations, uint256 _clientSeed, address _clientWalletAddress) external returns(uint256);
    function generateRequest(string memory _functionSig, uint8 _rngCount, uint256 _numConfirmations, address _clientWalletAddress) external returns(uint256);
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;ISupraRouter&lt;/code&gt; interface defines a &lt;code&gt;generateRequest&lt;/code&gt; function. This function is used to create a request for random numbers. The &lt;code&gt;generateRequest&lt;/code&gt; function is defined twice, because one of the definitions allows for an optional &lt;code&gt;_clientSeed&lt;/code&gt; (defaults to &lt;code&gt;0&lt;/code&gt;) for additional unpredictability.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Info:&lt;/strong&gt; Alternatively, you can add the &lt;code&gt;ISupraRouter&lt;/code&gt; interface in a separate interface file and inherit the interface in your contract.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  Adding a request function
&lt;/h3&gt;

&lt;p&gt;Once you have defined the &lt;code&gt;ISupraRouter&lt;/code&gt;, you are ready to add the logic to your smart contract for requesting random numbers.&lt;/p&gt;

&lt;p&gt;For Supra dVRF, adding logic for requesting random numbers requires two functions:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A request function&lt;/li&gt;
&lt;li&gt;A callback function&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The request function is a custom function defined by the developer. There are no requirements when it comes to the signature of the request function.&lt;/p&gt;

&lt;p&gt;The following code is an example of a request function named &lt;code&gt;rng&lt;/code&gt; that requests random numbers using the Supra Router Contract. Add this function to your smart contract:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;function rng() external returns (uint256) {
    // Amount of random numbers to request
    uint8 rngCount = 5;
    // Amount of confirmations before the request is considered complete/final
    uint256 numConfirmations = 1;
    uint256 nonce = ISupraRouter(supraAddr).generateRequest(
        "requestCallback(uint256,uint256[])",
        rngCount,
        numConfirmations,
        supraClientAddress
    );
    return nonce;
    // store nonce if necessary (e.g., in a hashmap)
    // this can be used to track parameters related to the request in a lookup table
    // these can be accessed inside the callback since the response from supra will include the nonce
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;rng&lt;/code&gt; function above requests &lt;code&gt;5&lt;/code&gt; random numbers (defined by &lt;code&gt;rngCount&lt;/code&gt;), and waits &lt;code&gt;1&lt;/code&gt; confirmation (defined by &lt;code&gt;numConfirmations&lt;/code&gt;) before considering the result to be final. It makes this request by calling the &lt;code&gt;generateRequest&lt;/code&gt; function of the Supra Router contract, while providing a callback function with the signature &lt;code&gt;requestCallback(uint256,uint256[])&lt;/code&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Adding a callback function
&lt;/h3&gt;

&lt;p&gt;As seen in the previous section, the &lt;code&gt;generateRequest&lt;/code&gt; method of the Supra Router contract expects a signature for a callback function. This callback function must be of the form: &lt;code&gt;uint256 nonce, uint256[] calldata rngList&lt;/code&gt;, and must include validation code, such that only the Supra Router contract can call the function.&lt;/p&gt;

&lt;p&gt;To do this, add the following callback function (&lt;code&gt;requestCallback&lt;/code&gt;) to your smart contract:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;function requestCallback(uint256 _nonce ,uint256[] _rngList) external {
    require(msg.sender == supraAddr, "Only the Supra Router can call this function.");
    uint8 i = 0;
    uint256[] memory x = new uint256[](rngList.length);
    rngForNonce[nonce] = x;
    for(i=0; i&amp;lt;rngList.length;i++){
        rngForNonce[nonce][i] = rngList[i] % 100;
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Once a random number is generated, &lt;code&gt;requestCallback&lt;/code&gt; is executed by the Supra Router. The code above stores the resulting random numbers list in a map named &lt;code&gt;rngForNonce&lt;/code&gt; using the &lt;code&gt;_nonce&lt;/code&gt; argument. Because of this, you will need to add the following mapping to your contract:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;mapping (uint256 =&amp;gt; uint256[] ) rngForNonce;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Adding a function to view the result
&lt;/h3&gt;

&lt;p&gt;To fetch resulting random numbers based on their associated &lt;code&gt;nonce&lt;/code&gt;, you add a third function:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;function viewRngForNonce(uint256 nonce) external view returns (uint256[] memory) {
    return rngForNonce[nonce];
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Final smart contract code
&lt;/h3&gt;

&lt;p&gt;After following all the steps above, your smart contract code should look like the following:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

interface ISupraRouter {
    function generateRequest(string memory _functionSig, uint8 _rngCount, uint256 _numConfirmations, uint256 _clientSeed, address _clientWalletAddress) external returns (uint256);
    function generateRequest(string memory _functionSig, uint8 _rngCount, uint256 _numConfirmations, address _clientWalletAddress) external returns (uint256);
}

contract RNGContract {
    address supraAddr;
    address supraClientAddress;

    mapping (uint256 =&amp;gt; uint256[]) rngForNonce;

    constructor(address supraSC) {
        supraAddr = supraSC;
        supraClientAddress = msg.sender;
    }

    function rng() external returns (uint256) {
        // Amount of random numbers to request
        uint8 rngCount = 5;
        // Amount of confirmations before the request is considered complete/final
        uint256 numConfirmations = 1;
        uint256 nonce = ISupraRouter(supraAddr).generateRequest(
            "requestCallback(uint256,uint256[])",
            rngCount,
            numConfirmations,
            supraClientAddress
        );
        return nonce;
    }

    function requestCallback(uint256 _nonce, uint256[] memory _rngList) external {
        require(msg.sender == supraAddr, "Only the Supra Router can call this function.");
        uint8 i = 0;
        uint256[] memory x = new uint256[](_rngList.length);
        rngForNonce[_nonce] = x;
        for (i = 0; i &amp;lt; _rngList.length; i++) {
            rngForNonce[_nonce][i] = _rngList[i] % 100;
        }
    }

    function viewRngForNonce(uint256 nonce) external view returns (uint256[] memory) {
        return rngForNonce[nonce];
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Caution:&lt;/strong&gt; You must whitelist this smart contract under the wallet address you registered with Supra, and deposit funds to be paid for the gas fees associated with transactions for your callback function.&lt;/p&gt;

&lt;p&gt;Follow the &lt;a href="https://supraoracles.com/docs/vrf/v2-guide#step-1-create-the-supra-router-contract-interface-1" rel="noopener noreferrer"&gt;guidance steps&lt;/a&gt; provided by Supra for whitelisting your contract and depositing funds.&lt;/p&gt;

&lt;p&gt;If you have not yet registered your wallet with Supra, see the Prerequisites section.&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  Compiling the Smart Contract
&lt;/h2&gt;

&lt;p&gt;To compile your smart contract code, run:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;forge build
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  Deploying the smart contract
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Setting up your wallet as the deployer
&lt;/h3&gt;

&lt;p&gt;Before you can deploy your smart contract to the Base network, you will need to set up a wallet to be used as the deployer.&lt;/p&gt;

&lt;p&gt;To do so, you can use the &lt;a href="https://book.getfoundry.sh/reference/cast/cast-wallet-import" rel="noopener noreferrer"&gt;&lt;code&gt;cast wallet import&lt;/code&gt;&lt;/a&gt; command to import the private key of the wallet into Foundry's securely encrypted keystore:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;cast wallet import deployer &lt;span class="nt"&gt;--interactive&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;After running the command above, you will be prompted to enter your private key, as well as a password for signing transactions.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Caution:&lt;/strong&gt; For instructions on how to get your private key from Coinbase Wallet, visit the &lt;a href="https://docs.cloud.coinbase.com/wallet-sdk/docs/developer-settings#show-private-key" rel="noopener noreferrer"&gt;Coinbase Wallet documentation&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;It is critical that you do NOT commit this to a public repo&lt;/strong&gt;.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;To confirm that the wallet was imported as the &lt;code&gt;deployer&lt;/code&gt; account in your Foundry project, run:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;cast wallet list
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Setting up environment variables for Base Sepolia
&lt;/h3&gt;

&lt;p&gt;To setup your environment for deploying to the Base network, create an &lt;code&gt;.env&lt;/code&gt; file in the home directory of your project, and add the RPC URL for the Base Sepolia testnet, as well as the Supra Router contract address for Base Sepolia testnet:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;BASE_SEPOLIA_RPC="https://sepolia.base.org"
ISUPRA_ROUTER_ADDRESS=0x99a021029EBC90020B193e111Ae2726264a111A2
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Once the &lt;code&gt;.env&lt;/code&gt; file has been created, run the following command to load the environment variables in the current command line session:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;source&lt;/span&gt; .env
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Deploying the smart contract to Base Sepolia
&lt;/h3&gt;

&lt;p&gt;With your contract compiled and environment setup, you are ready to deploy the smart contract to the Base Sepolia Testnet!&lt;/p&gt;

&lt;p&gt;For deploying a single smart contract using Foundry, you can use the &lt;code&gt;forge create&lt;/code&gt; command. The command requires you to specify the smart contract you want to deploy, an RPC URL of the network you want to deploy to, and the account you want to deploy with.&lt;/p&gt;

&lt;p&gt;To deploy the &lt;code&gt;RNGContract&lt;/code&gt; smart contract to the Base Sepolia test network, run the following command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;forge create ./src/RNGContract.sol:RNGContract &lt;span class="nt"&gt;--rpc-url&lt;/span&gt; &lt;span class="nv"&gt;$BASE_SEPOLIA_RPC&lt;/span&gt; &lt;span class="nt"&gt;--constructor-args&lt;/span&gt; &lt;span class="nv"&gt;$ISUPRA_ROUTER_ADDRESS&lt;/span&gt; &lt;span class="nt"&gt;--account&lt;/span&gt; deployer
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;When prompted, enter the password that you set earlier, when you imported your wallet’s private key.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Info:&lt;/strong&gt; Your wallet must be funded with ETH on the Base Sepolia Testnet to cover the gas fees associated with the smart contract deployment. Otherwise, the deployment will fail.&lt;/p&gt;

&lt;p&gt;To get testnet ETH for Base Sepolia, see the prerequisites.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;After running the command above, the contract will be deployed on the Base Sepolia test network. You can view the deployment status and contract by using a &lt;a href="https://dev.to/docs/tools/block-explorers"&gt;block explorer&lt;/a&gt;.&lt;/p&gt;




&lt;h2&gt;
  
  
  Interacting with the Smart Contract
&lt;/h2&gt;

&lt;p&gt;Foundry provides the &lt;code&gt;cast&lt;/code&gt; command-line tool that can be used to interact with the smart contract that was deployed and call the &lt;code&gt;getLatestPrice()&lt;/code&gt; function to fetch the latest price of ETH.&lt;/p&gt;

&lt;p&gt;To call the &lt;code&gt;getLatestPrice()&lt;/code&gt; function of the smart contract, run:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;cast call &amp;lt;DEPLOYED_ADDRESS&amp;gt; &lt;span class="nt"&gt;--rpc-url&lt;/span&gt; &lt;span class="nv"&gt;$BASE_SEPOLIA_RPC&lt;/span&gt; &lt;span class="s2"&gt;"rng()"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You should receive a &lt;code&gt;nonce&lt;/code&gt; value.&lt;/p&gt;

&lt;p&gt;You can use this &lt;code&gt;nonce&lt;/code&gt; value to call the &lt;code&gt;viewRngForNonce(uint256)&lt;/code&gt; function to get the resulting list of randomly generated numbers:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;cast call &amp;lt;DEPLOYED_ADDRESS&amp;gt; &lt;span class="nt"&gt;--rpc-url&lt;/span&gt; &lt;span class="nv"&gt;$BASE_SEPOLIA_RPC&lt;/span&gt; &lt;span class="s2"&gt;"viewRngForNonce(uint256)"&lt;/span&gt; &amp;lt;NONCE&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;Congratulations! You have successfully deployed and interacted with a smart contract that generates a list of random numbers using Supra dVRF on the Base blockchain network.&lt;/p&gt;

&lt;p&gt;To learn more about VRF and using Supra dVRF to generate random numbers within your smart contracts on Base, check out the following resources:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://docs.base.org/tools/oracles" rel="noopener noreferrer"&gt;Oracles&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://supraoracles.com/docs/vrf/v2-guide" rel="noopener noreferrer"&gt;Supra dVRF - Developer Guide V2&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>tutorial</category>
      <category>blockchain</category>
      <category>cryptocurrency</category>
      <category>web3</category>
    </item>
    <item>
      <title>Accessing real-time asset data on Base using Pyth Price Feeds</title>
      <dc:creator>Taylor Caldwell</dc:creator>
      <pubDate>Mon, 27 Jan 2025 04:29:05 +0000</pubDate>
      <link>https://dev.to/taycaldwell/accessing-real-time-asset-data-on-base-using-pyth-price-feeds-hoo</link>
      <guid>https://dev.to/taycaldwell/accessing-real-time-asset-data-on-base-using-pyth-price-feeds-hoo</guid>
      <description>&lt;p&gt;This tutorial will guide you through the process of creating a smart contract on Base that utilizes Pyth Network oracles to consume a price feed.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; This tutorial was originally published and authored by &lt;a href="https://x.com/taycaldwell" rel="noopener noreferrer"&gt;@taycaldwell&lt;/a&gt; on &lt;a href="https://docs.base.org" rel="noopener noreferrer"&gt;https://docs.base.org&lt;/a&gt;. You can find the original tutorial &lt;a href="https://docs.base.org/tutorials/oracles-pyth-price-feeds" rel="noopener noreferrer"&gt;here&lt;/a&gt;.&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  Objectives
&lt;/h2&gt;

&lt;p&gt;By the end of this tutorial you should be able to do the following:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Set up a smart contract project for Base using Foundry&lt;/li&gt;
&lt;li&gt;Install the Pyth smart contracts&lt;/li&gt;
&lt;li&gt;Consume a Pyth Network price feed within your smart contract&lt;/li&gt;
&lt;li&gt;Deploy and test your smart contracts on Base&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Prerequisites
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Foundry
&lt;/h3&gt;

&lt;p&gt;This tutorial requires you to have Foundry installed.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;From the command-line (terminal), run: &lt;code&gt;curl -L https://foundry.paradigm.xyz | bash&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Then run &lt;code&gt;foundryup&lt;/code&gt;, to install the latest (nightly) build of Foundry&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For more information, see the Foundry Book &lt;a href="https://book.getfoundry.sh/getting-started/installation" rel="noopener noreferrer"&gt;installation guide&lt;/a&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Coinbase Wallet
&lt;/h3&gt;

&lt;p&gt;In order to deploy a smart contract, you will first need a wallet. You can create a wallet by downloading the Coinbase Wallet browser extension.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Download &lt;a href="https://chrome.google.com/webstore/detail/coinbase-wallet-extension/hnfanknocfeofbddgcijnmhnfnkdnaad?hl=en" rel="noopener noreferrer"&gt;Coinbase Wallet&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Wallet funds
&lt;/h3&gt;

&lt;p&gt;Deploying contracts to the blockchain requires a gas fee. Therefore, you will need to fund your wallet with ETH to cover those gas fees.&lt;/p&gt;

&lt;p&gt;For this tutorial, you will be deploying a contract to the Base Sepolia test network. You can fund your wallet with Base Sepolia ETH using one of the faucets listed on the Base &lt;a href="https://docs.base.org/tools/network-faucets" rel="noopener noreferrer"&gt;Network Faucets&lt;/a&gt; page.&lt;/p&gt;




&lt;h2&gt;
  
  
  What is Pyth Network?
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Pyth Network&lt;/strong&gt; focuses on ultra-low latency and real-time data, making it suitable for financial applications that require sub-second updates. Pyth's design emphasizes performance, and it is designed to provide data for a range of traditional and DeFi assets.&lt;/p&gt;




&lt;h2&gt;
  
  
  Creating a project
&lt;/h2&gt;

&lt;p&gt;Before you can begin writing smart contracts for Base and consuming Pyth price feeds, you need to set up your development environment by creating a Foundry project.&lt;/p&gt;

&lt;p&gt;To create a new Foundry project, first create a new directory:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;mkdir &lt;/span&gt;myproject
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then run:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;cd &lt;/span&gt;myproject
forge init
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This will create a Foundry project, which has the following basic layout:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;.&lt;/span&gt;
├── foundry.toml
├── script
 │   └── Counter.s.sol
├── src
 │   └── Counter.sol
└── &lt;span class="nb"&gt;test&lt;/span&gt;
    └── Counter.t.sol
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  Installing Pyth smart contracts
&lt;/h2&gt;

&lt;p&gt;To use Pyth price feeds within your project, you need to install Pyth oracle contracts as a project dependency using &lt;code&gt;forge install&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;To install Pyth oracle contracts, run:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;forge &lt;span class="nb"&gt;install &lt;/span&gt;pyth-network/pyth-sdk-solidity@v2.2.0 &lt;span class="nt"&gt;--no-git&lt;/span&gt; &lt;span class="nt"&gt;--no-commit&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Once installed, update your &lt;code&gt;foundry.toml&lt;/code&gt; file by appending the following line:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;remappings &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;'@pythnetwork/pyth-sdk-solidity/=lib/pyth-sdk-solidity'&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  Writing and compiling the Smart Contract
&lt;/h2&gt;

&lt;p&gt;Once your project has been created and dependencies have been installed, you can now start writing a smart contract.&lt;/p&gt;

&lt;p&gt;The Solidity code below defines a smart contract named &lt;code&gt;ExampleContract&lt;/code&gt;. The code uses the &lt;code&gt;IPyth&lt;/code&gt; interface from the &lt;a href="https://github.com/pyth-network/pyth-crosschain/tree/main/target_chains/ethereum/sdk/solidity" rel="noopener noreferrer"&gt;Pyth Solidity SDK&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;An instance of&lt;code&gt;IPyth&lt;/code&gt; is defined within the contract that provides functions for consuming Pyth price feeds. The constructor for the &lt;code&gt;IPyth&lt;/code&gt; interface expects a contract address to be provided. This address provided in the code example below (&lt;code&gt;0xA2aa501b19aff244D90cc15a4Cf739D2725B5729&lt;/code&gt;) corresponds to the Pyth contract address for the Base Sepolia testnet.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Info:&lt;/strong&gt; Pyth also supports other EVM networks, such as Base Mainnet. For a list of all network contract addresses, visit the &lt;a href="https://docs.pyth.network/documentation/pythnet-price-feeds/evm" rel="noopener noreferrer"&gt;Pyth documentation&lt;/a&gt;.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The contract also contains a function named &lt;code&gt;getLatestPrice&lt;/code&gt;. This function takes a provided &lt;code&gt;priceUpdateData&lt;/code&gt; that is used to get updated price data, and returns the price given a &lt;code&gt;priceId&lt;/code&gt; of a price feed. The smart contract provided below uses a &lt;code&gt;priceId&lt;/code&gt; of &lt;code&gt;0xff61491a931112ddf1bd8147cd1b641375f79f5825126d665480874634fd0ace&lt;/code&gt;, which corresponds to the price feed for &lt;code&gt;ETH / USD&lt;/code&gt;.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Info:&lt;/strong&gt; Pyth provides a number of price feeds. For a list of available price feeds, visit the &lt;a href="https://pyth.network/developers/price-feed-ids#pyth-evm-stable" rel="noopener noreferrer"&gt;Pyth documentation&lt;/a&gt;.&lt;br&gt;
&lt;/p&gt;
&lt;/blockquote&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

import "@pythnetwork/pyth-sdk-solidity/IPyth.sol";
import "@pythnetwork/pyth-sdk-solidity/PythStructs.sol";

contract ExampleContract {
  IPyth pyth;

  /**
  * Network: Base Sepolia (testnet)
  * Address: 0xA2aa501b19aff244D90cc15a4Cf739D2725B5729
  */
  constructor() {
    pyth = IPyth(0xA2aa501b19aff244D90cc15a4Cf739D2725B5729);
  }

  function getLatestPrice(
    bytes[] calldata priceUpdateData
  ) public payable returns (PythStructs.Price memory) {
    // Update the prices to the latest available values and pay the required fee for it. The `priceUpdateData` data
    // should be retrieved from our off-chain Price Service API using the `pyth-evm-js` package.
    // See section "How Pyth Works on EVM Chains" below for more information.
    uint fee = pyth.getUpdateFee(priceUpdateData);
    pyth.updatePriceFeeds{ value: fee }(priceUpdateData);

    bytes32 priceID = 0xff61491a931112ddf1bd8147cd1b641375f79f5825126d665480874634fd0ace;
    // Read the current value of priceID, aborting the transaction if the price has not been updated recently.
    // Every chain has a default recency threshold which can be retrieved by calling the getValidTimePeriod() function on the contract.
    // Please see IPyth.sol for variants of this function that support configurable recency thresholds and other useful features.
    return pyth.getPrice(priceID);
  }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In your project, add the code provided above to a new file named &lt;code&gt;src/ExampleContract.sol&lt;/code&gt; and delete the &lt;code&gt;src/Counter.sol&lt;/code&gt; contract that was generated with the project (You can also delete the &lt;code&gt;test/Counter.t.sol&lt;/code&gt; and &lt;code&gt;script/Counter.s.sol&lt;/code&gt; files).&lt;/p&gt;

&lt;p&gt;To compile the new smart contract, run:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;forge build
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  Deploying the smart contract
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Setting up your wallet as the deployer
&lt;/h3&gt;

&lt;p&gt;Before you can deploy your smart contract to the Base network, you will need to set up a wallet to be used as the deployer.&lt;/p&gt;

&lt;p&gt;To do so, you can use the &lt;a href="https://book.getfoundry.sh/reference/cast/cast-wallet-import" rel="noopener noreferrer"&gt;&lt;code&gt;cast wallet import&lt;/code&gt;&lt;/a&gt; command to import the private key of the wallet into Foundry's securely encrypted keystore:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;cast wallet import deployer &lt;span class="nt"&gt;--interactive&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;After running the command above, you will be prompted to enter your private key, as well as a password for signing transactions.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Caution:&lt;/strong&gt; For instructions on how to get your private key from Coinbase Wallet, visit the &lt;a href="https://docs.cloud.coinbase.com/wallet-sdk/docs/developer-settings#show-private-key" rel="noopener noreferrer"&gt;Coinbase Wallet documentation&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;It is critical that you do NOT commit this to a public repo&lt;/strong&gt;.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;To confirm that the wallet was imported as the &lt;code&gt;deployer&lt;/code&gt; account in your Foundry project, run:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;cast wallet list
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Setting up environment variables for Base Sepolia
&lt;/h3&gt;

&lt;p&gt;To setup your environment for deploying to the Base network, create an &lt;code&gt;.env&lt;/code&gt; file in the home directory of your project, and add the RPC URL for the Base Sepolia testnet:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;BASE_SEPOLIA_RPC="https://sepolia.base.org"
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Once the &lt;code&gt;.env&lt;/code&gt; file has been created, run the following command to load the environment variables in the current command line session:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;source&lt;/span&gt; .env
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Deploying the smart contract to Base Sepolia
&lt;/h3&gt;

&lt;p&gt;With your contract compiled and environment setup, you are ready to deploy the smart contract to the Base Sepolia Testnet!&lt;/p&gt;

&lt;p&gt;For deploying a single smart contract using Foundry, you can use the &lt;code&gt;forge create&lt;/code&gt; command. The command requires you to specify the smart contract you want to deploy, an RPC URL of the network you want to deploy to, and the account you want to deploy with.&lt;/p&gt;

&lt;p&gt;To deploy the &lt;code&gt;ExampleContract&lt;/code&gt; smart contract to the Base Sepolia test network, run the following command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;forge create ./src/ExampleContract.sol:ExampleContract &lt;span class="nt"&gt;--rpc-url&lt;/span&gt; &lt;span class="nv"&gt;$BASE_SEPOLIA_RPC&lt;/span&gt; &lt;span class="nt"&gt;--account&lt;/span&gt; deployer
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;When prompted, enter the password that you set earlier, when you imported your wallet's private key.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Info:&lt;/strong&gt; Your wallet must be funded with ETH on the Base Sepolia Testnet to cover the gas fees associated with the smart contract deployment. Otherwise, the deployment will fail.&lt;/p&gt;

&lt;p&gt;To get testnet ETH for Base Sepolia, see the prerequisites.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;After running the command above, the contract will be deployed on the Base Sepolia test network. You can view the deployment status and contract by using a &lt;a href="https://dev.to/docs/tools/block-explorers"&gt;block explorer&lt;/a&gt;.&lt;/p&gt;




&lt;h2&gt;
  
  
  Interacting with the Smart Contract
&lt;/h2&gt;

&lt;p&gt;The &lt;code&gt;getLatestPrice(bytes[])&lt;/code&gt; function of the deployed contract takes a &lt;code&gt;priceUpdateData&lt;/code&gt; argument that is used to get the latest price. This data can be fetched using the Hermes web service. Hermes allows users to easily query for recent price updates via a REST API. Make a curl request to fetch the &lt;code&gt;priceUpdateData&lt;/code&gt; the &lt;code&gt;priceId&lt;/code&gt;, &lt;code&gt;0xff61491a931112ddf1bd8147cd1b641375f79f5825126d665480874634fd0ace&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;curl https://hermes.pyth.network/api/latest_vaas?ids[]=0xff61491a931112ddf1bd8147cd1b641375f79f5825126d665480874634fd0ace
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Once you have the &lt;code&gt;priceUpdateData&lt;/code&gt;, you can use Foundry’s &lt;code&gt;cast&lt;/code&gt; command-line tool to interact with the smart contract and call the &lt;code&gt;getLatestPrice(bytes[])&lt;/code&gt; function to fetch the latest price of ETH.&lt;/p&gt;

&lt;p&gt;To call the &lt;code&gt;getLatestPrice(bytes[])&lt;/code&gt; function of the smart contract, run the following command, replacing &lt;code&gt;&amp;lt;DEPLOYED_ADDRESS&amp;gt;&lt;/code&gt; with the address of your deployed contract, and &lt;code&gt;&amp;lt;PRICE_UPDATE_DATA&amp;gt;&lt;/code&gt; with the &lt;code&gt;priceUpdateData&lt;/code&gt; returned by the Hermes endpoint:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;cast call &amp;lt;DEPLOYED_ADDRESS&amp;gt; &lt;span class="nt"&gt;--rpc-url&lt;/span&gt; &lt;span class="nv"&gt;$BASE_SEPOLIA_RPC&lt;/span&gt; &lt;span class="s2"&gt;"getLatestPrice(bytes[])"&lt;/span&gt; &amp;lt;PRICE_UPDATE_DATA&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You should receive the latest &lt;code&gt;ETH / USD&lt;/code&gt; price in hexadecimal form.&lt;/p&gt;




&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;Congratulations! You have successfully deployed and interacted with a smart contract that consumes a Pyth Network oracle to access a real-time price feed on Base.&lt;/p&gt;

&lt;p&gt;To learn more about Oracles and using Pyth Network price feeds within your smart contracts on Base, check out the following resources:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://docs.base.org/tools/oracles" rel="noopener noreferrer"&gt;Oracles&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://docs.pyth.network/documentation/pythnet-price-feeds/evm" rel="noopener noreferrer"&gt;Pyth Network Price Feeds&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>tutorial</category>
      <category>blockchain</category>
      <category>cryptocurrency</category>
      <category>web3</category>
    </item>
    <item>
      <title>Accessing real-world data on Base using Chainlink Data Feeds</title>
      <dc:creator>Taylor Caldwell</dc:creator>
      <pubDate>Mon, 27 Jan 2025 04:28:56 +0000</pubDate>
      <link>https://dev.to/taycaldwell/accessing-real-world-data-on-base-using-chainlink-data-feeds-1kh3</link>
      <guid>https://dev.to/taycaldwell/accessing-real-world-data-on-base-using-chainlink-data-feeds-1kh3</guid>
      <description>&lt;p&gt;This tutorial will guide you through the process of creating a smart contract on Base that utilizes Chainlink Data Feeds to access real-world data, such as asset prices, directly from your smart contracts.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; This tutorial was originally published and authored by &lt;a href="https://x.com/taycaldwell" rel="noopener noreferrer"&gt;@taycaldwell&lt;/a&gt; on &lt;a href="https://docs.base.org" rel="noopener noreferrer"&gt;https://docs.base.org&lt;/a&gt;. You can find the original tutorial &lt;a href="https://docs.base.org/tutorials/oracles-chainlink-price-feeds" rel="noopener noreferrer"&gt;here&lt;/a&gt;.&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  Objectives
&lt;/h2&gt;

&lt;p&gt;By the end of this tutorial you should be able to do the following:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Set up a smart contract project for Base using Foundry&lt;/li&gt;
&lt;li&gt;Install the Chainlink smart contracts&lt;/li&gt;
&lt;li&gt;Consume a Chainlink price data feed within your smart contract&lt;/li&gt;
&lt;li&gt;Deploy and test your smart contracts on Base&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Prerequisites
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Foundry
&lt;/h3&gt;

&lt;p&gt;This tutorial requires you to have Foundry installed.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;From the command-line (terminal), run: &lt;code&gt;curl -L https://foundry.paradigm.xyz | bash&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Then run &lt;code&gt;foundryup&lt;/code&gt;, to install the latest (nightly) build of Foundry&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For more information, see the Foundry Book &lt;a href="https://book.getfoundry.sh/getting-started/installation" rel="noopener noreferrer"&gt;installation guide&lt;/a&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Coinbase Wallet
&lt;/h3&gt;

&lt;p&gt;In order to deploy a smart contract, you will first need a wallet. You can create a wallet by downloading the Coinbase Wallet browser extension.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Download &lt;a href="https://chrome.google.com/webstore/detail/coinbase-wallet-extension/hnfanknocfeofbddgcijnmhnfnkdnaad?hl=en" rel="noopener noreferrer"&gt;Coinbase Wallet&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Wallet funds
&lt;/h3&gt;

&lt;p&gt;Deploying contracts to the blockchain requires a gas fee. Therefore, you will need to fund your wallet with ETH to cover those gas fees.&lt;/p&gt;

&lt;p&gt;For this tutorial, you will be deploying a contract to the Base Goerli test network. You can fund your wallet with Base Goerli ETH using one of the faucets listed on the Base &lt;a href="https://docs.base.org/tools/network-faucets" rel="noopener noreferrer"&gt;Network Faucets&lt;/a&gt; page.&lt;/p&gt;




&lt;h2&gt;
  
  
  What are Chainlink Data Feeds?
&lt;/h2&gt;

&lt;p&gt;Accurate price data is essential in DeFi applications. However, blockchain networks lack the capability to directly fetch external real-world data, leading to the "&lt;a href="https://chain.link/education-hub/oracle-problem" rel="noopener noreferrer"&gt;Oracle Problem&lt;/a&gt;".&lt;/p&gt;

&lt;p&gt;Chainlink Data Feeds offer a solution to this problem by serving as a secure middleware layer that bridges the gap between real-world asset prices and onchain smart contracts.&lt;/p&gt;




&lt;h2&gt;
  
  
  Creating a project
&lt;/h2&gt;

&lt;p&gt;Before you can begin writing smart contracts for Base and consuming Chainlink data feeds, you need to set up your development environment by creating a Foundry project.&lt;/p&gt;

&lt;p&gt;To create a new Foundry project, first create a new directory:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;mkdir &lt;/span&gt;myproject
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then run:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;cd &lt;/span&gt;myproject
forge init
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This will create a Foundry project, which has the following basic layout:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;.&lt;/span&gt;
├── foundry.toml
├── script
 │   └── Counter.s.sol
├── src
 │   └── Counter.sol
└── &lt;span class="nb"&gt;test&lt;/span&gt;
    └── Counter.t.sol
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  Installing Chainlink smart contracts
&lt;/h2&gt;

&lt;p&gt;To use Chainlink's data feeds within your project, you need to install Chainlink smart contracts as a project dependency using &lt;code&gt;forge install&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;To install Chainlink smart contracts, run:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;forge &lt;span class="nb"&gt;install &lt;/span&gt;smartcontractkit/chainlink &lt;span class="nt"&gt;--no-commit&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Once installed, update your &lt;code&gt;foundry.toml&lt;/code&gt; file by appending the following line:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;remappings &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;'@chainlink/contracts/=lib/chainlink/contracts'&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  Writing and compiling the Smart Contract
&lt;/h2&gt;

&lt;p&gt;Once your project has been created and dependencies have been installed, you can now start writing a smart contract.&lt;/p&gt;

&lt;p&gt;The Solidity code below defines a smart contract named &lt;code&gt;DataConsumerV3&lt;/code&gt;. The code uses the &lt;code&gt;AggregatorV3Interface&lt;/code&gt; interface from the &lt;a href="https://docs.chain.link/data-feeds/api-reference#aggregatorv3interface" rel="noopener noreferrer"&gt;Chainlink contracts library&lt;/a&gt; to provide access to price feed data.&lt;/p&gt;

&lt;p&gt;The smart contract passes an address to &lt;code&gt;AggregatorV3Interface&lt;/code&gt;. This address (&lt;code&gt;0xcD2A119bD1F7DF95d706DE6F2057fDD45A0503E2&lt;/code&gt;) corresponds to the &lt;code&gt;ETH/USD&lt;/code&gt; price feed on the Base Goerli network.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Info:&lt;/strong&gt; Chainlink provides a number of price feeds for Base. For a list of available price feeds on Base, visit the &lt;a href="https://docs.chain.link/data-feeds/price-feeds/addresses/?network=base&amp;amp;page=1" rel="noopener noreferrer"&gt;Chainlink documentation&lt;/a&gt;.&lt;br&gt;
&lt;/p&gt;
&lt;/blockquote&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;   // SPDX-License-Identifier: MIT
   pragma solidity ^0.8.0;

   import "@chainlink/contracts/src/v0.8/shared/interfaces/AggregatorV3Interface.sol";

   contract DataConsumerV3 {
       AggregatorV3Interface internal priceFeed;

      /**
       * Network: Base Goerli
       * Aggregator: ETH/USD
       * Address: 0xcD2A119bD1F7DF95d706DE6F2057fDD45A0503E2
       */
       constructor() {
           priceFeed = AggregatorV3Interface(0xcD2A119bD1F7DF95d706DE6F2057fDD45A0503E2);
       }

       function getLatestPrice() public view returns (int) {
           (
               /* uint80 roundID */,
               int price,
               /* uint startedAt */,
               /* uint timeStamp */,
               /* uint80 answeredInRound */
           ) = priceFeed.latestRoundData();
           return price;
       }
   }
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In your project, add the code provided above to a new file named &lt;code&gt;src/DataConsumerV3.sol&lt;/code&gt;, and delete the &lt;code&gt;src/Counter.sol&lt;/code&gt; contract that was generated with the project. (you can also delete the &lt;code&gt;test/Counter.t.sol&lt;/code&gt; and &lt;code&gt;script/Counter.s.sol&lt;/code&gt; files).&lt;/p&gt;

&lt;p&gt;To compile the new smart contract, run:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;forge build
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  Deploying the smart contract
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Setting up your wallet as the deployer
&lt;/h3&gt;

&lt;p&gt;Before you can deploy your smart contract to the Base network, you will need to set up a wallet to be used as the deployer.&lt;/p&gt;

&lt;p&gt;To do so, you can use the &lt;a href="https://book.getfoundry.sh/reference/cast/cast-wallet-import" rel="noopener noreferrer"&gt;&lt;code&gt;cast wallet import&lt;/code&gt;&lt;/a&gt; command to import the private key of the wallet into Foundry's securely encrypted keystore:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;cast wallet import deployer &lt;span class="nt"&gt;--interactive&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;After running the command above, you will be prompted to enter your private key, as well as a password for signing transactions.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Caution:&lt;/strong&gt;  For instructions on how to get your private key from Coinbase Wallet, visit the &lt;a href="https://docs.cloud.coinbase.com/wallet-sdk/docs/developer-settings#show-private-key" rel="noopener noreferrer"&gt;Coinbase Wallet documentation&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;It is critical that you do NOT commit this to a public repo&lt;/strong&gt;.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;To confirm that the wallet was imported as the &lt;code&gt;deployer&lt;/code&gt; account in your Foundry project, run:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;cast wallet list
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Setting up environment variables for Base Goerli
&lt;/h3&gt;

&lt;p&gt;To setup your environment for deploying to the Base network, create an &lt;code&gt;.env&lt;/code&gt; file in the home directory of your project, and add the RPC URL for the Base Goerli testnet:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;BASE_GOERLI_RPC="https://goerli.base.org"
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Once the &lt;code&gt;.env&lt;/code&gt; file has been created, run the following command to load the environment variables in the current command line session:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;source&lt;/span&gt; .env
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Deploying the smart contract to Base Goerli
&lt;/h3&gt;

&lt;p&gt;With your contract compiled and environment setup, you are ready to deploy the smart contract to the Base Goerli Testnet!&lt;/p&gt;

&lt;p&gt;For deploying a single smart contract using Foundry, you can use the &lt;code&gt;forge create&lt;/code&gt; command. The command requires you to specify the smart contract you want to deploy, an RPC URL of the network you want to deploy to, and the account you want to deploy with.&lt;/p&gt;

&lt;p&gt;To deploy the &lt;code&gt;DataConsumerV3&lt;/code&gt; smart contract to the Base Goerli test network, run the following command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;forge create ./src/DataConsumerV3.sol:DataConsumerV3 &lt;span class="nt"&gt;--rpc-url&lt;/span&gt; &lt;span class="nv"&gt;$BASE_GOERLI_RPC&lt;/span&gt; &lt;span class="nt"&gt;--account&lt;/span&gt; deployer
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;When prompted, enter the password that you set earlier, when you imported your wallet's private key.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Info:&lt;/strong&gt;  Your wallet must be funded with ETH on the Base Goerli Testnet to cover the gas fees associated with the smart contract deployment. Otherwise, the deployment will fail.&lt;/p&gt;

&lt;p&gt;To get testnet ETH for Base Goerli, see the prerequisites.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;After running the command above, the contract will be deployed on the Base Goerli test network. You can view the deployment status and contract by using a &lt;a href="https://dev.to/docs/tools/block-explorers"&gt;block explorer&lt;/a&gt;.&lt;/p&gt;




&lt;h2&gt;
  
  
  Interacting with the Smart Contract
&lt;/h2&gt;

&lt;p&gt;Foundry provides the &lt;code&gt;cast&lt;/code&gt; command-line tool that can be used to interact with the smart contract that was deployed and call the &lt;code&gt;getLatestPrice()&lt;/code&gt; function to fetch the latest price of ETH.&lt;/p&gt;

&lt;p&gt;To call the &lt;code&gt;getLatestPrice()&lt;/code&gt; function of the smart contract, run:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;cast call &amp;lt;DEPLOYED_ADDRESS&amp;gt; &lt;span class="nt"&gt;--rpc-url&lt;/span&gt; &lt;span class="nv"&gt;$BASE_GOERLI_RPC&lt;/span&gt; &lt;span class="s2"&gt;"getLatestPrice()"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You should receive the latest &lt;code&gt;ETH / USD&lt;/code&gt; price in hexadecimal form.&lt;/p&gt;




&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;Congratulations! You have successfully deployed and interacted with a smart contract that consumes a Chainlink price feed on the Base blockchain network.&lt;/p&gt;

&lt;p&gt;To learn more about Oracles and using Chainlink to access real-world data within your smart contracts on Base, check out the following resources:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://docs.base.org/tools/oracles" rel="noopener noreferrer"&gt;Oracles&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://docs.chain.link/data-feeds/price-feeds/addresses?network=base&amp;amp;page=1&amp;amp;search=#networks" rel="noopener noreferrer"&gt;Chainlink Data Feeds on Base&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>tutorial</category>
      <category>blockchain</category>
      <category>cryptocurrency</category>
      <category>web3</category>
    </item>
    <item>
      <title>Sending messages from Base to other chains using LayerZero V2</title>
      <dc:creator>Taylor Caldwell</dc:creator>
      <pubDate>Mon, 27 Jan 2025 04:28:48 +0000</pubDate>
      <link>https://dev.to/taycaldwell/sending-messages-from-base-to-other-chains-using-layerzero-v2-557g</link>
      <guid>https://dev.to/taycaldwell/sending-messages-from-base-to-other-chains-using-layerzero-v2-557g</guid>
      <description>&lt;p&gt;This tutorial will guide you through the process of sending cross-chain message data from a Base smart contract to another smart contract on a different chain using LayerZero V2.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; This tutorial was originally published and authored by &lt;a href="https://x.com/taycaldwell" rel="noopener noreferrer"&gt;@taycaldwell&lt;/a&gt; on &lt;a href="https://docs.base.org" rel="noopener noreferrer"&gt;https://docs.base.org&lt;/a&gt;. You can find the original tutorial &lt;a href="https://docs.base.org/tutorials/cross-chain-with-layerzero" rel="noopener noreferrer"&gt;here&lt;/a&gt;.&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  Objectives
&lt;/h2&gt;

&lt;p&gt;By the end of this tutorial you should be able to do the following:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Set up a smart contract project for Base using Foundry&lt;/li&gt;
&lt;li&gt;Install the LayerZero smart contracts as a dependency&lt;/li&gt;
&lt;li&gt;Use LayerZero to send messages and from smart contracts on Base to smart contracts on different chains&lt;/li&gt;
&lt;li&gt;Deploy and test your smart contracts on Base testnet&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Prerequisites
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Foundry
&lt;/h3&gt;

&lt;p&gt;This tutorial requires you to have Foundry installed.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;From the command-line (terminal), run: &lt;code&gt;curl -L https://foundry.paradigm.xyz | bash&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Then run &lt;code&gt;foundryup&lt;/code&gt;, to install the latest (nightly) build of Foundry&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For more information, see the Foundry Book &lt;a href="https://book.getfoundry.sh/getting-started/installation" rel="noopener noreferrer"&gt;installation guide&lt;/a&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Coinbase Wallet
&lt;/h3&gt;

&lt;p&gt;In order to deploy a smart contract, you will first need a wallet. You can create a wallet by downloading the Coinbase Wallet browser extension.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Download &lt;a href="https://chrome.google.com/webstore/detail/coinbase-wallet-extension/hnfanknocfeofbddgcijnmhnfnkdnaad?hl=en" rel="noopener noreferrer"&gt;Coinbase Wallet&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Wallet funds
&lt;/h3&gt;

&lt;p&gt;To complete this tutorial, you will need to fund a wallet with ETH on Base Goerli and Optimism Goerli.&lt;/p&gt;

&lt;p&gt;The ETH is required for covering gas fees associated with deploying smart contracts to each network.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;To fund your wallet with ETH on Base Goerli, visit a faucet listed on the &lt;a href="https://dev.to/docs/tools/network-faucets"&gt;Base Faucets&lt;/a&gt; page.&lt;/li&gt;
&lt;li&gt;To fund your wallet with ETH on Optimism Goerli, visit a faucet listed on the &lt;a href="https://docs.optimism.io/builders/tools/faucets" rel="noopener noreferrer"&gt;Optimism Faucets&lt;/a&gt; page.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  What is LayerZero?
&lt;/h2&gt;

&lt;p&gt;LayerZero is an interoperability protocol that allows developers to build applications (and tokens) that can connect to multiple blockchains. LayerZero defines these types of applications as "omnichain" applications.&lt;/p&gt;

&lt;p&gt;The LayerZero protocol is made up of immutable on-chain &lt;a href="https://docs.layerzero.network/v2/developers/evm/technical-reference/deployed-contracts" rel="noopener noreferrer"&gt;Endpoints&lt;/a&gt;, a configurable &lt;a href="https://docs.layerzero.network/explore/decentralized-verifier-networks" rel="noopener noreferrer"&gt;Security Stack&lt;/a&gt;, and a permissionless set of &lt;a href="https://docs.layerzero.network/v2/home/permissionless-execution/executors" rel="noopener noreferrer"&gt;Executors&lt;/a&gt; that transfer messages between chains.&lt;/p&gt;

&lt;h3&gt;
  
  
  High-level concepts
&lt;/h3&gt;

&lt;h4&gt;
  
  
  Endpoints
&lt;/h4&gt;

&lt;p&gt;Endpoints are immutable LayerZero smart contracts that implement a standardized interface for your own smart contracts to use and in order to manage security configurations and send and receive messages.&lt;/p&gt;

&lt;h4&gt;
  
  
  Security Stack (DVNs)
&lt;/h4&gt;

&lt;p&gt;The &lt;a href="https://docs.layerzero.network/explore/decentralized-verifier-networks" rel="noopener noreferrer"&gt;Security Stack&lt;/a&gt; is a configurable set of required and optional Decentralized Verifier Networks (DVNs). The DVNs are used to verify message payloads to ensure integrity of your application's messages.&lt;/p&gt;

&lt;h4&gt;
  
  
  Executors
&lt;/h4&gt;

&lt;p&gt;&lt;a href="https://docs.layerzero.network/v2/home/permissionless-execution/executors" rel="noopener noreferrer"&gt;Executors&lt;/a&gt; are responsible for initiating message delivery. They will automatically execute the &lt;code&gt;lzReceive&lt;/code&gt; function of the endpoint on the destination chain once a message has been verified by the Security Stack.&lt;/p&gt;




&lt;h2&gt;
  
  
  Creating a project
&lt;/h2&gt;

&lt;p&gt;Before you begin, you need to set up your smart contract development environment by creating a Foundry project.&lt;/p&gt;

&lt;p&gt;To create a new Foundry project, first create a new directory:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;mkdir &lt;/span&gt;myproject
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then run:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;cd &lt;/span&gt;myproject
forge init
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This will create a Foundry project with the following basic layout:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;.&lt;/span&gt;
├── foundry.toml
├── script
├── src
└── &lt;span class="nb"&gt;test&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Info:&lt;/strong&gt; You can delete the &lt;code&gt;src/Counter.sol&lt;/code&gt;, &lt;code&gt;test/Counter.t.sol&lt;/code&gt;, and &lt;code&gt;script/Counter.s.sol&lt;/code&gt; boilerplate files that were generated with the project, as you will not be needing them.&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  Installing the LayerZero smart contracts
&lt;/h2&gt;

&lt;p&gt;To use LayerZero within your Foundry project, you need to install the LayerZero smart contracts and their dependencies using &lt;code&gt;forge install&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;To install LayerZero smart contracts and their dependencies, run the following commands:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;forge &lt;span class="nb"&gt;install &lt;/span&gt;GNSPS/solidity-bytes-utils &lt;span class="nt"&gt;--no-commit&lt;/span&gt;
forge &lt;span class="nb"&gt;install &lt;/span&gt;OpenZeppelin/openzeppelin-contracts@v4.9.4 &lt;span class="nt"&gt;--no-commit&lt;/span&gt;
forge &lt;span class="nb"&gt;install &lt;/span&gt;LayerZero-Labs/LayerZero-v2 &lt;span class="nt"&gt;--no-commit&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Once installed, update your &lt;code&gt;foundry.toml&lt;/code&gt; file by appending the following lines:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;remappings &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt;
    &lt;span class="s1"&gt;'@openzeppelin/contracts/=lib/openzeppelin-contracts/contracts'&lt;/span&gt;,
    &lt;span class="s1"&gt;'solidity-bytes-utils/=lib/solidity-bytes-utils'&lt;/span&gt;,
    &lt;span class="s1"&gt;'@layerzerolabs/lz-evm-oapp-v2/=lib/LayerZero-v2/oapp'&lt;/span&gt;,
    &lt;span class="s1"&gt;'@layerzerolabs/lz-evm-protocol-v2/=lib/LayerZero-v2/protocol'&lt;/span&gt;,
    &lt;span class="s1"&gt;'@layerzerolabs/lz-evm-messagelib-v2/=lib/LayerZero-v2/messagelib'&lt;/span&gt;,
&lt;span class="o"&gt;]&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  Getting started with LayerZero
&lt;/h2&gt;

&lt;p&gt;LayerZero provides a smart contract standard called &lt;a href="https://docs.layerzero.network/v2/developers/evm/oapp/overview" rel="noopener noreferrer"&gt;OApp&lt;/a&gt; that is intended for omnichain messaging and configuration.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

import { OAppSender } from "./OAppSender.sol";
import { OAppReceiver, Origin } from "./OAppReceiver.sol";
import { OAppCore } from "./OAppCore.sol";

abstract contract OApp is OAppSender, OAppReceiver {
   constructor(address _endpoint) OAppCore(_endpoint, msg.sender) {}

   function oAppVersion() public pure virtual returns (uint64 senderVersion, uint64 receiverVersion) {
       senderVersion = SENDER_VERSION;
       receiverVersion = RECEIVER_VERSION;
   }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Info:&lt;/strong&gt; You can view the source code for this contract on &lt;a href="https://github.com/LayerZero-Labs/LayerZero-v2/blob/main/packages/layerzero-v2/evm/oapp/contracts/oapp/OApp.sol" rel="noopener noreferrer"&gt;GitHub&lt;/a&gt;.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;To get started using LayerZero, developers simply need to inherit from the &lt;a href="https://github.com/LayerZero-Labs/LayerZero-v2/blob/main/packages/layerzero-v2/evm/oapp/contracts/oapp/OApp.sol" rel="noopener noreferrer"&gt;OApp&lt;/a&gt; contract, and implement the following two inherited functions:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;_lzSend&lt;/code&gt;: A function used to send an omnichain message&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;_lzReceive&lt;/code&gt;: A function used to receive an omnichain message&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In this tutorial, you will be implementing the &lt;a href="https://docs.layerzero.network/v2/developers/evm/oapp/overview" rel="noopener noreferrer"&gt;OApp&lt;/a&gt; standard into your own project to add the capability to send messages from a smart contract on Base to a smart contract on Optimism.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Info:&lt;/strong&gt; An extension of the &lt;a href="https://docs.layerzero.network/v2/developers/evm/oapp/overview" rel="noopener noreferrer"&gt;OApp&lt;/a&gt; contract standard known as &lt;a href="https://docs.layerzero.network/v2/developers/evm/oft/quickstart" rel="noopener noreferrer"&gt;OFT&lt;/a&gt; is also available for supporting omnichain fungible token transfers.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Info:&lt;/strong&gt; For more information on transferring tokens across chains using LayerZero, visit the &lt;a href="https://docs.layerzero.network/v2/developers/evm/oft/quickstart" rel="noopener noreferrer"&gt;LayerZero documentation&lt;/a&gt;.&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  Writing the smart contract
&lt;/h2&gt;

&lt;p&gt;To get started, create a new Solidity smart contract file in your project's &lt;code&gt;src/&lt;/code&gt; directory named &lt;code&gt;ExampleContract.sol&lt;/code&gt;, and add the following content:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

import { OApp, Origin, MessagingFee } from "@layerzerolabs/lz-evm-oapp-v2/contracts/oapp/OApp.sol";

contract ExampleContract is OApp {
   constructor(address _endpoint, address _owner) OApp(_endpoint, _owner) {}
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The code snippet above defines a new smart contract named &lt;code&gt;ExampleContract&lt;/code&gt; that extends the &lt;code&gt;OApp&lt;/code&gt; contract standard.&lt;/p&gt;

&lt;p&gt;The contract's constructor expects two arguments:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;_endpoint&lt;/code&gt;: The &lt;a href="https://docs.layerzero.network/v2/home/protocol/layerzero-endpoint" rel="noopener noreferrer"&gt;LayerZero Endpoint&lt;/a&gt; &lt;code&gt;address&lt;/code&gt; for the chain the smart contract is deployed to.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;_owner&lt;/code&gt;: The &lt;code&gt;address&lt;/code&gt; of the owner of the smart contract.&lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Info:&lt;/strong&gt; &lt;a href="https://docs.layerzero.network/v2/home/protocol/layerzero-endpoint" rel="noopener noreferrer"&gt;LayerZero Endpoints&lt;/a&gt; are smart contracts that expose an interface for OApp contracts to manage security configurations and send and receive messages via the LayerZero protocol.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  Implementing message sending (&lt;code&gt;_lzSend&lt;/code&gt;)
&lt;/h3&gt;

&lt;p&gt;To send messages to another chain, your smart contract must call the &lt;code&gt;_lzSend&lt;/code&gt; function inherited from the &lt;a href="https://docs.layerzero.network/v2/developers/evm/oapp/overview" rel="noopener noreferrer"&gt;OApp&lt;/a&gt; contract.&lt;/p&gt;

&lt;p&gt;Add a new custom function named &lt;code&gt;sendMessage&lt;/code&gt; to your smart contract that has the following content:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;/// @notice Sends a message from the source chain to the destination chain.
/// @param _dstEid The endpoint ID of the destination chain.
/// @param _message The message to be sent.
/// @param _options The message execution options (e.g. gas to use on destination).
function sendMessage(uint32 _dstEid, string memory _message, bytes calldata _options) external payable {
   bytes memory _payload = abi.encode(_message); // Encode the message as bytes
   _lzSend(
       _dstEid,
       _payload,
       _options,
       MessagingFee(msg.value, 0), // Fee for the message (nativeFee, lzTokenFee)
       payable(msg.sender) // The refund address in case the send call reverts
   );
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;sendMessage&lt;/code&gt; function above calls the inherited &lt;code&gt;_lzSend&lt;/code&gt; function, while passing in the following expected data:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Name&lt;/th&gt;
&lt;th&gt;Type&lt;/th&gt;
&lt;th&gt;Description&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;_dstEid&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;uint32&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;The &lt;a href="https://docs.layerzero.network/v2/developers/evm/technical-reference/deployed-contracts" rel="noopener noreferrer"&gt;endpoint ID&lt;/a&gt; of the destination chain to send the message to.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;_payload&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;bytes&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;The message (encoded) to send.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;_options&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;bytes&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;
&lt;a href="https://docs.layerzero.network/v2/developers/evm/protocol-gas-settings/options" rel="noopener noreferrer"&gt;Additional options&lt;/a&gt; when sending the message, such as how much gas should be used when receiving the message.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;_fee&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;a href="https://github.com/LayerZero-Labs/LayerZero-v2/blob/c3213200dfe8fabbf7d92c685590d34e6e70da43/protocol/contracts/interfaces/ILayerZeroEndpointV2.sol#L24" rel="noopener noreferrer"&gt;&lt;code&gt;MessagingFee&lt;/code&gt;&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;The calculated fee for sending the message.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;_refundAddress&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;address&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;The &lt;code&gt;address&lt;/code&gt; that will receive any excess fee values sent to the endpoint in case the &lt;code&gt;_lzSend&lt;/code&gt; execution reverts.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h3&gt;
  
  
  Implementing gas fee estimation (&lt;code&gt;_quote&lt;/code&gt;)
&lt;/h3&gt;

&lt;p&gt;As shown in the table provided in the last section, the &lt;code&gt;_lzSend&lt;/code&gt; function expects an estimated gas &lt;a href="https://github.com/LayerZero-Labs/LayerZero-v2/blob/c3213200dfe8fabbf7d92c685590d34e6e70da43/protocol/contracts/interfaces/ILayerZeroEndpointV2.sol#L24" rel="noopener noreferrer"&gt;fee&lt;/a&gt; to be provided when sending a message (&lt;code&gt;_fee&lt;/code&gt;).&lt;/p&gt;

&lt;p&gt;Therefore, sending a message using the &lt;code&gt;sendMessage&lt;/code&gt; function of your contract, you first need to estimate the associated gas fees.&lt;/p&gt;

&lt;p&gt;There are multiple fees incurred when sending a message across chains using LayerZero, including: paying for gas on the source chain, fees paid to DVNs validating the message, and gas on the destination chain. Luckily, LayerZero bundles all of these fees together into a single fee to be paid by the &lt;code&gt;msg.sender&lt;/code&gt;, and LayerZero Endpoints expose a &lt;code&gt;_quote&lt;/code&gt; function to estimate this fee.&lt;/p&gt;

&lt;p&gt;Add a new function to your &lt;code&gt;ExampleContract&lt;/code&gt; contract called &lt;code&gt;estimateFee&lt;/code&gt; that calls the &lt;code&gt;_quote&lt;/code&gt; function, as shown below:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;/// @notice Estimates the gas associated with sending a message.
/// @param _dstEid The endpoint ID of the destination chain.
/// @param _message The message to be sent.
/// @param _options The message execution options (e.g. gas to use on destination).
/// @return nativeFee Estimated gas fee in native gas.
/// @return lzTokenFee Estimated gas fee in ZRO token.
function estimateFee(
   uint32 _dstEid,
   string memory _message,
   bytes calldata _options
) public view returns (uint256 nativeFee, uint256 lzTokenFee) {
   bytes memory _payload = abi.encode(_message);
   MessagingFee memory fee = _quote(_dstEid, _payload, _options, false);
   return (fee.nativeFee, fee.lzTokenFee);
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;estimateFee&lt;/code&gt; function above calls the inherited &lt;code&gt;_quote&lt;/code&gt; function, while passing in the following expected data:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Name&lt;/th&gt;
&lt;th&gt;Type&lt;/th&gt;
&lt;th&gt;Description&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;_dstEid&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;uint32&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;The &lt;a href="https://docs.layerzero.network/v2/developers/evm/technical-reference/deployed-contracts" rel="noopener noreferrer"&gt;endpoint ID&lt;/a&gt; of the destination chain the message will be sent to.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;_payload&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;bytes&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;The message (encoded) that will be sent.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;_options&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;bytes&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;
&lt;a href="https://docs.layerzero.network/v2/developers/evm/protocol-gas-settings/options" rel="noopener noreferrer"&gt;Additional options&lt;/a&gt; when sending the message, such as how much gas should be used when receiving the message.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;_payInLzToken&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;bool&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Boolean flag for which token to use when returning the fee (native or ZRO token).&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Info:&lt;/strong&gt; Your contract’s &lt;code&gt;estimateFee&lt;/code&gt; function should always be called immediately before calling &lt;code&gt;sendMessage&lt;/code&gt; to accurately estimate associated gas fees.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  Implementing message receiving (&lt;code&gt;_lzReceive&lt;/code&gt;)
&lt;/h3&gt;

&lt;p&gt;To receive messages on the destination chain, your smart contract must override the &lt;code&gt;_lzReceive&lt;/code&gt; function inherited from the &lt;a href="https://docs.layerzero.network/v2/developers/evm/oapp/overview" rel="noopener noreferrer"&gt;OApp&lt;/a&gt; contract.&lt;/p&gt;

&lt;p&gt;Add the following code snippet to your &lt;code&gt;ExampleContract&lt;/code&gt; contract to override the &lt;code&gt;_lzReceive&lt;/code&gt; function:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;/// @notice Entry point for receiving messages.
/// @param _origin The origin information containing the source endpoint and sender address.
///  - srcEid: The source chain endpoint ID.
///  - sender: The sender address on the src chain.
///  - nonce: The nonce of the message.
/// @param _guid The unique identifier for the received LayerZero message.
/// @param _message The payload of the received message.
/// @param _executor The address of the executor for the received message.
/// @param _extraData Additional arbitrary data provided by the corresponding executor.
function _lzReceive(
   Origin calldata _origin,
   bytes32 _guid,
   bytes calldata payload,
   address _executor,
   bytes calldata _extraData
   ) internal override {
       data = abi.decode(payload, (string));
       // other logic
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The overridden &lt;code&gt;_lzReceive&lt;/code&gt; function receives the following arguments when receiving a message:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Name&lt;/th&gt;
&lt;th&gt;Type&lt;/th&gt;
&lt;th&gt;Description&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;_origin&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;Origin&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;The origin information containing the source endpoint and sender address.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;_guid&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;bytes32&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;The unique identifier for the received LayerZero message.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;payload&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;bytes&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;The payload of the received message (encoded).&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;_executor&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;address&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;The &lt;code&gt;address&lt;/code&gt; of the &lt;a href="https://docs.layerzero.network/v2/home/permissionless-execution/executors" rel="noopener noreferrer"&gt;Executor&lt;/a&gt; for the received message.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;_extraData&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;bytes&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Additional arbitrary data provided by the corresponding &lt;a href="https://docs.layerzero.network/v2/home/permissionless-execution/executors" rel="noopener noreferrer"&gt;Executor&lt;/a&gt;.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Note that the overridden method decodes the message payload, and stores the string into a variable named &lt;code&gt;data&lt;/code&gt; that you can read from later to fetch the latest message.&lt;/p&gt;

&lt;p&gt;Add the &lt;code&gt;data&lt;/code&gt; field as a member variable to your contract:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;contract ExampleContract is OApp {

    // highlight-next-line
    string public data;

    constructor(address _endpoint) OApp(_endpoint, msg.sender) {}
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Info:&lt;/strong&gt; Overriding the &lt;code&gt;_lzReceive&lt;/code&gt; function allows you to provide any custom logic you wish when receiving messages, including making a call back to the source chain by invoking &lt;code&gt;_lzSend&lt;/code&gt;. Visit the LayerZero &lt;a href="https://docs.layerzero.network/v2/developers/evm/oapp/message-design-patterns" rel="noopener noreferrer"&gt;Message Design Patterns&lt;/a&gt; for common messaging flows.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  Final code
&lt;/h3&gt;

&lt;p&gt;Once you complete all of the steps above, your contract should look like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

import { OApp, Origin, MessagingFee } from "@layerzerolabs/lz-evm-oapp-v2/contracts/oapp/OApp.sol";

contract ExampleContract is OApp {

 string public data;

  constructor(address _endpoint) OApp(_endpoint, msg.sender) {}

  /// @notice Sends a message from the source chain to the destination chain.
  /// @param _dstEid The endpoint ID of the destination chain.
  /// @param _message The message to be sent.
  /// @param _options The message execution options (e.g. gas to use on destination).
  function sendMessage(uint32 _dstEid, string memory _message, bytes calldata _options) external payable {
     bytes memory _payload = abi.encode(_message); // Encode the message as bytes
     _lzSend(
           _dstEid,
           _payload,
           _options,
           MessagingFee(msg.value, 0), // Fee for the message (nativeFee, lzTokenFee)
           payable(msg.sender) // The refund address in case the send call reverts
     );
  }

  /// @notice Estimates the gas associated with sending a message.
  /// @param _dstEid The endpoint ID of the destination chain.
  /// @param _message The message to be sent.
  /// @param _options The message execution options (e.g. gas to use on destination).
  /// @return nativeFee Estimated gas fee in native gas.
  /// @return lzTokenFee Estimated gas fee in ZRO token.
  function estimateFee(
     uint32 _dstEid,
     string memory _message,
     bytes calldata _options
  ) public view returns (uint256 nativeFee, uint256 lzTokenFee) {
     bytes memory _payload = abi.encode(_message);
     MessagingFee memory fee = _quote(_dstEid, _payload, _options, false);
     return (fee.nativeFee, fee.lzTokenFee);
  }

  /// @notice Entry point for receiving messages.
  /// @param _origin The origin information containing the source endpoint and sender address.
  ///  - srcEid: The source chain endpoint ID.
  ///  - sender: The sender address on the src chain.
  ///  - nonce: The nonce of the message.
  /// @param _guid The unique identifier for the received LayerZero message.
  /// @param _message The payload of the received message.
  /// @param _executor The address of the executor for the received message.
  /// @param _extraData Additional arbitrary data provided by the corresponding executor.
  function _lzReceive(
     Origin calldata _origin,
     bytes32 _guid,
     bytes calldata payload,
     address _executor,
     bytes calldata _extraData
     ) internal override {
        data = abi.decode(payload, (string));
  }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  Compiling the smart contract
&lt;/h2&gt;

&lt;p&gt;Compile the smart contract to ensure it builds without any errors.&lt;/p&gt;

&lt;p&gt;To compile your smart contract, run:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;forge build
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  Deploying the smart contract
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Setting up your wallet as the deployer
&lt;/h3&gt;

&lt;p&gt;Before you can deploy your smart contract to various chains you will need to set up a wallet to be used as the deployer.&lt;/p&gt;

&lt;p&gt;To do so, you can use the &lt;a href="https://book.getfoundry.sh/reference/cast/cast-wallet-import" rel="noopener noreferrer"&gt;&lt;code&gt;cast wallet import&lt;/code&gt;&lt;/a&gt; command to import the private key of the wallet into Foundry's securely encrypted keystore:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;cast wallet import deployer &lt;span class="nt"&gt;--interactive&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;After running the command above, you will be prompted to enter your private key, as well as a password for signing transactions.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Caution:&lt;/strong&gt; For instructions on how to get your private key from Coinbase Wallet, visit the &lt;a href="https://docs.cloud.coinbase.com/wallet-sdk/docs/developer-settings#show-private-key" rel="noopener noreferrer"&gt;Coinbase Wallet documentation&lt;/a&gt;. &lt;strong&gt;It is critical that you do NOT commit this to a public repo&lt;/strong&gt;.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;To confirm that the wallet was imported as the &lt;code&gt;deployer&lt;/code&gt; account in your Foundry project, run:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;cast wallet list
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Setting up environment variables
&lt;/h3&gt;

&lt;p&gt;To setup your environment, create an &lt;code&gt;.env&lt;/code&gt; file in the home directory of your project, and add the RPC URLs and &lt;a href="https://docs.layerzero.network/v2/developers/evm/technical-reference/deployed-contracts" rel="noopener noreferrer"&gt;LayerZero Endpoint&lt;/a&gt; information for both Base Goerli and Optimism Goerli testnets:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;BASE_GOERLI_RPC&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"https://goerli.base.org"&lt;/span&gt;
&lt;span class="nv"&gt;BASE_GOERLI_LZ_ENDPOINT&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;0x464570adA09869d8741132183721B4f0769a0287
&lt;span class="nv"&gt;BASE_GOERLI_LZ_ENDPOINT_ID&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;40184

&lt;span class="nv"&gt;OPTIMISM_GOERLI_RPC&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"https://goerli.optimism.io"&lt;/span&gt;
&lt;span class="nv"&gt;OPTIMISM_GOERLI_LZ_ENDPOINT&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;0x464570adA09869d8741132183721B4f0769a0287
&lt;span class="nv"&gt;OPTIMISM_GOERLI_LZ_ENDPOINT_ID&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;40132
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Once the &lt;code&gt;.env&lt;/code&gt; file has been created, run the following command to load the environment variables in the current command line session:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;source .env
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;With your contract compiled and environment setup, you are now ready to deploy the smart contract to different networks.&lt;/p&gt;

&lt;h3&gt;
  
  
  Deploying the smart contract to Base Goerli
&lt;/h3&gt;

&lt;p&gt;To deploy a smart contract using Foundry, you can use the &lt;code&gt;forge create&lt;/code&gt; command. The command requires you to specify the smart contract you want to deploy, an RPC URL of the network you want to deploy to, and the account you want to deploy with.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Info:&lt;/strong&gt; Your wallet must be funded with ETH on the Base Goerli and Optimism Goerli to cover the gas fees associated with the smart contract deployment. Otherwise, the deployment will fail.&lt;/p&gt;

&lt;p&gt;To get testnet ETH, see the prerequisites.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;To deploy the &lt;code&gt;ExampleContract&lt;/code&gt; smart contract to the Base Goerli testnet, run the following command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;forge create ./src/ExampleContract.sol:ExampleContract &lt;span class="nt"&gt;--rpc-url&lt;/span&gt; &lt;span class="nv"&gt;$BASE_GOERLI_RPC&lt;/span&gt; &lt;span class="nt"&gt;--constructor-args&lt;/span&gt; &lt;span class="nv"&gt;$BASE_GOERLI_LZ_ENDPOINT&lt;/span&gt; &lt;span class="nt"&gt;--account&lt;/span&gt; deployer
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;When prompted, enter the password that you set earlier, when you imported your wallet's private key.&lt;/p&gt;

&lt;p&gt;After running the command above, the contract will be deployed on the Base Goerli test network. You can view the deployment status and contract by using a &lt;a href="https://dev.to/docs/tools/block-explorers"&gt;block explorer&lt;/a&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Deploying the smart contract to Optimism Goerli
&lt;/h3&gt;

&lt;p&gt;To deploy the &lt;code&gt;ExampleContract&lt;/code&gt; smart contract to the Optimism Goerli testnet, run the following command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;forge create ./src/ExampleContract.sol:ExampleContract &lt;span class="nt"&gt;--rpc-url&lt;/span&gt; &lt;span class="nv"&gt;$OPTIMISM_GOERLI_RPC&lt;/span&gt; &lt;span class="nt"&gt;--constructor-args&lt;/span&gt; &lt;span class="nv"&gt;$OPTIMISM_GOERLI_LZ_ENDPOINT&lt;/span&gt; &lt;span class="nt"&gt;--account&lt;/span&gt; deployer
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;When prompted, enter the password that you set earlier, when you imported your wallet's private key.&lt;/p&gt;

&lt;p&gt;After running the command above, the contract will be deployed on the Optimism Goerli test network. You can view the deployment status and contract by using the &lt;a href="https://goerli-optimism.etherscan.io/" rel="noopener noreferrer"&gt;OP Goerli block explorer&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Opening the messaging channels
&lt;/h2&gt;

&lt;p&gt;Once your contract has been deployed to Base Goerli and Optimism Goerli, you will need to open the messaging channels between the two contracts so that they can send and receive messages from one another. This is done by calling the &lt;code&gt;setPeer&lt;/code&gt; function on the contract.&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;setPeer&lt;/code&gt; function expects the following arguments:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Name&lt;/th&gt;
&lt;th&gt;Type&lt;/th&gt;
&lt;th&gt;Description&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;_eid&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;uint32&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;The &lt;a href="https://docs.layerzero.network/v2/developers/evm/technical-reference/deployed-contracts" rel="noopener noreferrer"&gt;endpoint ID&lt;/a&gt; of the destination chain.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;_peer&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;bytes32&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;The contract address of the OApp contract on the destination chain.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h3&gt;
  
  
  Setting the peers
&lt;/h3&gt;

&lt;p&gt;Foundry provides the &lt;code&gt;cast&lt;/code&gt; command-line tool that can be used to interact with deployed smart contracts and call their functions.&lt;/p&gt;

&lt;p&gt;To set the peer of your &lt;code&gt;ExampleContract&lt;/code&gt; contracts, you can use &lt;code&gt;cast&lt;/code&gt; to call the &lt;code&gt;setPeer&lt;/code&gt; function while providing the &lt;a href="https://docs.layerzero.network/v2/developers/evm/technical-reference/deployed-contracts" rel="noopener noreferrer"&gt;endpoint ID&lt;/a&gt; and address (in bytes) of the deployed contract on the respective destination chain.&lt;/p&gt;

&lt;p&gt;To set the peer of the Base Goerli contract to the Optimism Goerli contract, run the following command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;cast send &amp;lt;BASE_GOERLI_CONTRACT_ADDRESS&amp;gt; &lt;span class="nt"&gt;--rpc-url&lt;/span&gt; &lt;span class="nv"&gt;$BASE_GOERLI_RPC&lt;/span&gt; &lt;span class="s2"&gt;"setPeer(uint32, bytes32)"&lt;/span&gt; &lt;span class="nv"&gt;$OPTIMISM_GOERLI_LZ_ENDPOINT_ID&lt;/span&gt; &amp;lt;OPTIMISM_GOERLI_CONTRACT_ADDRESS&amp;gt; &lt;span class="nt"&gt;--account&lt;/span&gt; deployer
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Info:&lt;/strong&gt; Replace &lt;code&gt;&amp;lt;BASE_GOERLI_CONTRACT_ADDRESS&amp;gt;&lt;/code&gt; with the contract address of your deployed &lt;code&gt;ExampleContract&lt;/code&gt; contract on Base Goerli, and&lt;code&gt;&amp;lt;OPTIMISM_GOERLI_CONTRACT_ADDRESS&amp;gt;&lt;/code&gt; with the contract address (as bytes) of your deployed &lt;code&gt;ExampleContract&lt;/code&gt; contract on Optimism Goerli before running the provided &lt;code&gt;cast&lt;/code&gt; command.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;To set the peer of the Optimism Goerli contract to the Base Goerli contract, run the following command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;cast send &amp;lt;OPTIMISM_GOERLI_CONTRACT_ADDRESS&amp;gt; &lt;span class="nt"&gt;--rpc-url&lt;/span&gt; &lt;span class="nv"&gt;$OPTIMISM_GOERLI_RPC&lt;/span&gt; &lt;span class="s2"&gt;"setPeer(uint32, bytes32)"&lt;/span&gt; &lt;span class="nv"&gt;$BASE_GOERLI_LZ_ENDPOINT_ID&lt;/span&gt; &amp;lt;BASE_GOERLI_CONTRACT_ADDRESS&amp;gt; &lt;span class="nt"&gt;--account&lt;/span&gt; deployer
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Info:&lt;/strong&gt; Replace &lt;code&gt;&amp;lt;OPTIMISM_GOERLI_CONTRACT_ADDRESS&amp;gt;&lt;/code&gt; with the contract address of your deployed &lt;code&gt;ExampleContract&lt;/code&gt; contract on Optimism Goerli, and&lt;code&gt;&amp;lt;BASE_GOERLI_CONTRACT_ADDRESS&amp;gt;&lt;/code&gt; with the contract address (as bytes) of your deployed &lt;code&gt;ExampleContract&lt;/code&gt; contract on Base Goerli before running the provided &lt;code&gt;cast&lt;/code&gt; command.&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  Sending messages
&lt;/h2&gt;

&lt;p&gt;Once peers have been set on each contract, they are now able to send and receive messages from one another.&lt;/p&gt;

&lt;p&gt;Sending a message using the newly created &lt;code&gt;ExampleContract&lt;/code&gt; contract can be done in three steps:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Build &lt;a href="https://docs.layerzero.network/v2/developers/evm/protocol-gas-settings/options" rel="noopener noreferrer"&gt;message options&lt;/a&gt; to specify logic associated with the message transaction&lt;/li&gt;
&lt;li&gt;Call the &lt;code&gt;estimateFee&lt;/code&gt; function to estimate the gas fee for sending a message&lt;/li&gt;
&lt;li&gt;Call the &lt;code&gt;sendMessage&lt;/code&gt; function to send a message&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  Building message options
&lt;/h3&gt;

&lt;p&gt;The &lt;code&gt;estimateFee&lt;/code&gt; and &lt;code&gt;sendMessage&lt;/code&gt; custom functions of the &lt;code&gt;ExampleContract&lt;/code&gt; contract both require a &lt;a href="https://docs.layerzero.network/v2/developers/evm/protocol-gas-settings/options" rel="noopener noreferrer"&gt;message options&lt;/a&gt; (&lt;code&gt;_options&lt;/code&gt;) argument to be provided.&lt;/p&gt;

&lt;p&gt;Message options allow you to specify arbitrary logic as part of the message transaction, such as the gas amount the &lt;a href="https://docs.layerzero.network/v2/home/permissionless-execution/executors" rel="noopener noreferrer"&gt;Executor&lt;/a&gt; pays for message delivery, the order of message execution, or dropping an amount of gas to a destination address.&lt;/p&gt;

&lt;p&gt;LayerZero provides a &lt;a href="https://github.com/LayerZero-Labs/LayerZero-v2/blob/ccfd0d38f83ca8103b14ab9ca77f32e0419510ff/oapp/contracts/oapp/libs/OptionsBuilder.sol#L12" rel="noopener noreferrer"&gt;Solidity&lt;/a&gt; library and &lt;a href="https://docs.layerzero.network/v2/developers/evm/protocol-gas-settings/options" rel="noopener noreferrer"&gt;TypeScript SDK&lt;/a&gt; for building these message options.&lt;/p&gt;

&lt;p&gt;As an example, below is a Foundry script that uses OptionsBuilder from the Solidity library to generate message options (as &lt;code&gt;bytes&lt;/code&gt;) that set the gas amount that the Executor will pay upon message delivery to &lt;code&gt;200000&lt;/code&gt; wei:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;pragma solidity ^0.8.0;

import {Script, console2} from "forge-std/Script.sol";
import { OptionsBuilder } from "@layerzerolabs/lz-evm-oapp-v2/contracts/oapp/libs/OptionsBuilder.sol";

contract OptionsScript is Script {
    using OptionsBuilder for bytes;

    function setUp() public {}

    function run() public {
        bytes memory options = OptionsBuilder.newOptions().addExecutorLzReceiveOption(200000, 0);
        console2.logBytes(options);
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The output of this script results in:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;0x00030100110100000000000000000000000000030d40
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For this tutorial, rather than building and generating your own message options, you can use the bytes output provided above.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Info:&lt;/strong&gt; Covering all of the different message options in detail is out of scope for this tutorial. If you are interested in learning more about the different message options and how to build them, visit the &lt;a href="https://docs.layerzero.network/v2/developers/evm/protocol-gas-settings/options" rel="noopener noreferrer"&gt;LayerZero developer documentation&lt;/a&gt;.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  Estimating the gas fee
&lt;/h3&gt;

&lt;p&gt;Before you can send a message from your contract on Base Goerli, you need to estimate the fee associated with sending the message. You can use the &lt;code&gt;cast&lt;/code&gt; command to call the &lt;code&gt;estimateFee()&lt;/code&gt; function of the &lt;code&gt;ExampleContract&lt;/code&gt; contract.&lt;/p&gt;

&lt;p&gt;To estimate the gas fee for sending a message from Base Goerli to Optimism Goerli, run the following command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;cast send &amp;lt;BASE_GOERLI_CONTRACT_ADDRESS&amp;gt; &lt;span class="nt"&gt;--rpc-url&lt;/span&gt; &lt;span class="nv"&gt;$BASE_GOERLI_RPC&lt;/span&gt; &lt;span class="s2"&gt;"estimateFee(uint32, string, bytes)"&lt;/span&gt; &lt;span class="nv"&gt;$OPTIMISM_GOERLI_LZ_ENDPOINT_ID&lt;/span&gt; &lt;span class="s2"&gt;"Hello World"&lt;/span&gt; 0x00030100110100000000000000000000000000030d40 &lt;span class="nt"&gt;--account&lt;/span&gt; deployer
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Info:&lt;/strong&gt; Replace &lt;code&gt;&amp;lt;BASE_GOERLI_CONTRACT_ADDRESS&amp;gt;&lt;/code&gt; with the contract address of your deployed &lt;code&gt;ExampleContract&lt;/code&gt; contract on Base Goerli before running the provided &lt;code&gt;cast&lt;/code&gt; command.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The command above calls &lt;code&gt;estimateFee(uint32, string, bytes, bool)&lt;/code&gt;, while providing the required arguments, including: the endpoint ID of the destination chain, the text to send, and the message options (generated in the last section).&lt;/p&gt;

&lt;h3&gt;
  
  
  Sending the message
&lt;/h3&gt;

&lt;p&gt;Once you have fetched the estimated gas for sending your message, you can now call &lt;code&gt;sendMessage&lt;/code&gt; and provide the value returned as the &lt;code&gt;msg.value&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;For example, to send a message from Base Goerli to Optimism Goerli with an estimated gas fee, run the following command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;cast send &amp;lt;BASE_GOERLI_CONTRACT_ADDRESS&amp;gt; &lt;span class="nt"&gt;--rpc-url&lt;/span&gt; &lt;span class="nv"&gt;$BASE_GOERLI_RPC&lt;/span&gt; &lt;span class="nt"&gt;--value&lt;/span&gt; &amp;lt;GAS_ESTIMATE_IN_WEI&amp;gt; &lt;span class="s2"&gt;"sendMessage(uint32, string, bytes)"&lt;/span&gt; &lt;span class="nv"&gt;$OPTIMISM_GOERLI_LZ_ENDPOINT_ID&lt;/span&gt; &lt;span class="s2"&gt;"Hello World"&lt;/span&gt; 0x00030100110100000000000000000000000000030d40 &lt;span class="nt"&gt;--account&lt;/span&gt; deployer
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Info:&lt;/strong&gt; Replace &lt;code&gt;&amp;lt;BASE_GOERLI_CONTRACT_ADDRESS&amp;gt;&lt;/code&gt; with the contract address of your deployed &lt;code&gt;ExampleContract&lt;/code&gt; contract on Base Goerli, and &lt;code&gt;&amp;lt;GAS_ESTIMATE_IN_WEI&amp;gt;&lt;/code&gt; with the gas estimate (in wei) returned by the call to estimateFee, before running the provided &lt;code&gt;cast&lt;/code&gt; command.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;You can view the status of your cross-chain transaction on &lt;a href="https://layerzeroscan.com/" rel="noopener noreferrer"&gt;LayerZero Scan&lt;/a&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Receiving the message
&lt;/h3&gt;

&lt;p&gt;Once the message has been sent and received on the destination chain, the _Receive function will be called on the &lt;code&gt;ExampleContract&lt;/code&gt; and the message payload will be stored in the contract's public &lt;code&gt;data&lt;/code&gt; variable.&lt;/p&gt;

&lt;p&gt;You can use the &lt;code&gt;cast&lt;/code&gt; command to read the latest message received by the &lt;code&gt;ExampleContract&lt;/code&gt; stored in the &lt;code&gt;data&lt;/code&gt; variable.&lt;/p&gt;

&lt;p&gt;To read the latest received message data that was sent to Optimism Goerli from Base Goerli, run the following command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;cast send &amp;lt;OPTIMISM_GOERLI_CONTRACT_ADDRESS&amp;gt; &lt;span class="nt"&gt;--rpc-url&lt;/span&gt; &lt;span class="nv"&gt;$OPTIMISM_GOERLI_RPC&lt;/span&gt; &lt;span class="s2"&gt;"data"&lt;/span&gt; &lt;span class="nt"&gt;--account&lt;/span&gt; deployer
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The returned data should match the message text payload you sent in your message.&lt;/p&gt;

&lt;p&gt;You can view the status of your cross-chain transaction on &lt;a href="https://layerzeroscan.com/" rel="noopener noreferrer"&gt;LayerZero Scan&lt;/a&gt;.&lt;/p&gt;




&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;Congratulations! You have successfully learned how to perform cross-chain messaging between Base and other chains (i.e. Optimism) using LayerZero V2.&lt;/p&gt;

&lt;p&gt;To learn more about cross-chain messaging and LayerZero V2, check out the following resources:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://dev.to/docs/tools/cross-chain"&gt;Cross-chain&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://docs.layerzero.network" rel="noopener noreferrer"&gt;LayerZero V2&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;




</description>
      <category>tutorial</category>
      <category>blockchain</category>
      <category>cryptocurrency</category>
      <category>web3</category>
    </item>
    <item>
      <title>Sending messages and tokens from Base to other chains using Chainlink CCIP</title>
      <dc:creator>Taylor Caldwell</dc:creator>
      <pubDate>Mon, 27 Jan 2025 04:28:40 +0000</pubDate>
      <link>https://dev.to/taycaldwell/sending-messages-and-tokens-from-base-to-other-chains-using-chainlink-ccip-497</link>
      <guid>https://dev.to/taycaldwell/sending-messages-and-tokens-from-base-to-other-chains-using-chainlink-ccip-497</guid>
      <description>&lt;p&gt;This tutorial will guide you through the process of sending messages and tokens from a Base smart contract to another smart contract on a different chain using Chainlink's Cross-chain Interoperability Protocol (CCIP).&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; This tutorial was originally published and authored by &lt;a href="https://x.com/taycaldwell" rel="noopener noreferrer"&gt;@taycaldwell&lt;/a&gt; on &lt;a href="https://docs.base.org" rel="noopener noreferrer"&gt;https://docs.base.org&lt;/a&gt;. You can find the original tutorial &lt;a href="https://docs.base.org/tutorials/cross-chain-with-ccip" rel="noopener noreferrer"&gt;here&lt;/a&gt;.&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  Objectives
&lt;/h2&gt;

&lt;p&gt;By the end of this tutorial you should be able to do the following:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Set up a smart contract project for Base using Foundry&lt;/li&gt;
&lt;li&gt;Install Chainlink CCIP as a dependency&lt;/li&gt;
&lt;li&gt;Use Chainlink CCIP within your smart contract to send messages and/or tokens to contracts on other different chains&lt;/li&gt;
&lt;li&gt;Deploy and test your smart contracts on Base testnet&lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Info:&lt;/strong&gt; Chainlink CCIP is in an “Early Access” development stage, meaning some of the functionality described within this tutorial is under development and may change in later versions.&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  Prerequisites
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Foundry
&lt;/h3&gt;

&lt;p&gt;This tutorial requires you to have Foundry installed.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;From the command-line (terminal), run: &lt;code&gt;curl -L https://foundry.paradigm.xyz | bash&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Then run &lt;code&gt;foundryup&lt;/code&gt;, to install the latest (nightly) build of Foundry&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For more information, see the Foundry Book &lt;a href="https://book.getfoundry.sh/getting-started/installation" rel="noopener noreferrer"&gt;installation guide&lt;/a&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Coinbase Wallet
&lt;/h3&gt;

&lt;p&gt;In order to deploy a smart contract, you will first need a wallet. You can create a wallet by downloading the Coinbase Wallet browser extension.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Download &lt;a href="https://chrome.google.com/webstore/detail/coinbase-wallet-extension/hnfanknocfeofbddgcijnmhnfnkdnaad?hl=en" rel="noopener noreferrer"&gt;Coinbase Wallet&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Wallet funds
&lt;/h3&gt;

&lt;p&gt;For this tutorial you will need to fund your wallet with both ETH and LINK on Base Goerli and Optimism Goerli.&lt;/p&gt;

&lt;p&gt;The ETH is required for covering gas fees associated with deploying smart contracts to the blockchain, and the LINK token is required to pay for associated fees when using CCIP.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;To fund your wallet with ETH on Base Goerli, visit a faucet listed on the &lt;a href="https://docs.base.org/tools/network-faucets" rel="noopener noreferrer"&gt;Base Faucets&lt;/a&gt; page.&lt;/li&gt;
&lt;li&gt;To fund your wallet with ETH on Optimism Goerli, visit a faucet listed on the &lt;a href="https://docs.optimism.io/builders/tools/faucets" rel="noopener noreferrer"&gt;Optimism Faucets&lt;/a&gt; page.&lt;/li&gt;
&lt;li&gt;To fund your wallet with LINK, visit the &lt;a href="https://faucets.chain.link/base-sepolia" rel="noopener noreferrer"&gt;Chainlink Faucet&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Info:&lt;/strong&gt; If you are interested in building on Mainnet, you will need to &lt;a href="https://chainlinkcommunity.typeform.com/ccip-form?#ref_id=ccip_docs" rel="noopener noreferrer"&gt;apply for Chainlink CCIP mainnet access&lt;/a&gt;.&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  What is Chainlink CCIP?
&lt;/h2&gt;

&lt;p&gt;Chainlink CCIP (Cross-chain Interoperability Protocol) provides a solution for sending message data and transferring tokens across different chains.&lt;/p&gt;

&lt;p&gt;The primary way for users to interface with Chainlink CCIP is through smart contracts known as &lt;a href="https://docs.chain.link/ccip/architecture#router" rel="noopener noreferrer"&gt;Routers&lt;/a&gt;. A Router contract is responsible for initiating cross-chain interactions.&lt;/p&gt;

&lt;p&gt;Users can interact with &lt;a href="https://docs.chain.link/ccip/architecture#router" rel="noopener noreferrer"&gt;Routers&lt;/a&gt; to perform the following cross-chain capabilities:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Capability&lt;/th&gt;
&lt;th&gt;Description&lt;/th&gt;
&lt;th&gt;Supported receivers&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Arbitrary messaging&lt;/td&gt;
&lt;td&gt;Send arbitrary (encoded) data from one chain to another.&lt;/td&gt;
&lt;td&gt;Smart contracts only&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Token transfers&lt;/td&gt;
&lt;td&gt;Send tokens from one chain to another.&lt;/td&gt;
&lt;td&gt;Smart contracts or EOAs&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Programmable token transfers&lt;/td&gt;
&lt;td&gt;Send tokens and arbitrary (encoded) data from one chain to another, in a single transaction.&lt;/td&gt;
&lt;td&gt;Smart contracts only&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Danger:&lt;/strong&gt; Externally owned accounts (EOAs) on EVM blockchains are unable to receive message data, because of this, only smart contracts are supported as receivers when sending arbitrary messages or programmable token transfers. Any attempt to send a programmable token transfer (data and tokens) to an EOA, will result in only the tokens being received.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  High-level concepts
&lt;/h3&gt;

&lt;p&gt;Although &lt;a href="https://docs.chain.link/ccip/architecture#router" rel="noopener noreferrer"&gt;Routers&lt;/a&gt; are the primary interface users will interact with when using CCIP, this section will cover what happens after instructions for a cross-chain interaction are sent to a Router.&lt;/p&gt;

&lt;h4&gt;
  
  
  OnRamps
&lt;/h4&gt;

&lt;p&gt;Once a Router receives an instruction for a cross-chain interaction, it passes it on to another contract known as an &lt;a href="https://docs.chain.link/ccip/architecture#onramp" rel="noopener noreferrer"&gt;OnRamp&lt;/a&gt;. OnRamps are responsible for a variety of tasks, including: verifying message size and gas limits, preserving the sequencing of messages, managing any fee payments, and interacting with the &lt;a href="https://docs.chain.link/ccip/architecture#token-pools" rel="noopener noreferrer"&gt;token pool&lt;/a&gt; to &lt;code&gt;lock&lt;/code&gt; or &lt;code&gt;burn&lt;/code&gt; tokens if a token transfer is being made.&lt;/p&gt;

&lt;h4&gt;
  
  
  OffRamps
&lt;/h4&gt;

&lt;p&gt;The destination chain will have a contract known as an &lt;a href="https://docs.chain.link/ccip/architecture#offramp" rel="noopener noreferrer"&gt;OffRamp&lt;/a&gt;. OffRamps are responsible for a variety of tasks, including: ensuring the authenticity of a message, making sure each transaction is only executed once, and transmitting received messages to the Router contract on the destination chain.&lt;/p&gt;

&lt;h4&gt;
  
  
  Token pools
&lt;/h4&gt;

&lt;p&gt;A &lt;a href="https://docs.chain.link/ccip/architecture#token-pools" rel="noopener noreferrer"&gt;token pool&lt;/a&gt; is an abstraction layer over ERC-20 tokens that facilitates OnRamp and OffRamp token-related operations. They are configured to use either a &lt;code&gt;Lock and Unlock&lt;/code&gt; or &lt;code&gt;Burn and Mint&lt;/code&gt; mechanism, depending on the type of token.&lt;/p&gt;

&lt;p&gt;For example, because blockchain-native gas tokens (i.e. ETH, MATIC, AVAX) can only be minted on their native chains, a &lt;code&gt;Lock and Mint&lt;/code&gt; mechanism must be used. This mechanism locks the token at the source chain, and mints a synthetic asset on the destination chain.&lt;/p&gt;

&lt;p&gt;In contrast, tokens that can be minted on multiple chains (i.e. USDC, USDT, FRAX, etc.), token pools can use a &lt;code&gt;Burn and Mint&lt;/code&gt; mechanism, where the token is burnt on the source chain and minted on the destination chain.&lt;/p&gt;

&lt;h4&gt;
  
  
  Risk Management Network
&lt;/h4&gt;

&lt;p&gt;Between instructions for a cross-chain interaction making its way from an OnRamp on the source chain to an OffRamp on the destination chain, it will pass through the &lt;a href="https://docs.chain.link/ccip/concepts#risk-management-network" rel="noopener noreferrer"&gt;Risk Management Network&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;The Risk Management Network is a secondary validation service built using a variety of offchain and onchain components, with the responsibilities of monitoring all chains against abnormal activities.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Info:&lt;/strong&gt; A deep-dive on the technical details of each of these components is too much to cover in this tutorial, but if interested you can learn more by visiting the &lt;a href="https://docs.chain.link/ccip/architecture" rel="noopener noreferrer"&gt;Chainlink documentation&lt;/a&gt;.&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  Creating a project
&lt;/h2&gt;

&lt;p&gt;Before you begin, you need to set up your smart contract development environment. You can setup a development environment using tools like &lt;a href="https://dev.to/docs/tools/hardhat"&gt;Hardhat&lt;/a&gt; or &lt;a href="https://dev.to/docs/tools/foundry"&gt;Foundry&lt;/a&gt;. For this tutorial you will use Foundry.&lt;/p&gt;

&lt;p&gt;To create a new Foundry project, first create a new directory:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;mkdir &lt;/span&gt;myproject
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then run:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;cd &lt;/span&gt;myproject
forge init
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This will create a Foundry project with the following basic layout:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;.&lt;/span&gt;
├── foundry.toml
├── script
├── src
└── &lt;span class="nb"&gt;test&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Info:&lt;/strong&gt; You can delete the &lt;code&gt;src/Counter.sol&lt;/code&gt;, &lt;code&gt;test/Counter.t.sol&lt;/code&gt;, and &lt;code&gt;script/Counter.s.sol&lt;/code&gt; boilerplate files that were generated with the project, as you will not be needing them.&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  Installing Chainlink smart contracts
&lt;/h2&gt;

&lt;p&gt;To use Chainlink CCIP within your Foundry project, you need to install Chainlink CCIP smart contracts as a project dependency using &lt;code&gt;forge install&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;To install Chainlink CCIP smart contracts, run:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;forge &lt;span class="nb"&gt;install &lt;/span&gt;smartcontractkit/ccip &lt;span class="nt"&gt;--no-commit&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Once installed, update your &lt;code&gt;foundry.toml&lt;/code&gt; file by appending the following line:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;remappings &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;'@chainlink/contracts-ccip/=lib/ccip/contracts'&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  Writing the smart contracts
&lt;/h2&gt;

&lt;p&gt;The most basic use case for Chainlink CCIP is to send data and/or tokens between smart contracts on different blockchains.&lt;/p&gt;

&lt;p&gt;To accomplish this, in this tutorial, you will need to create two separate smart contracts:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;Sender&lt;/code&gt; contract: A smart contract that interacts with CCIP to send data and tokens.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;Receiver&lt;/code&gt; contract: A smart contract that interacts with CCIP to receive data and tokens.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Creating a Sender contract
&lt;/h3&gt;

&lt;p&gt;The code snippet below is for a basic smart contract that uses CCIP to send data:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;pragma solidity ^0.8.0;

import {IRouterClient} from "@chainlink/contracts-ccip/src/v0.8/ccip/interfaces/IRouterClient.sol";
import {OwnerIsCreator} from "@chainlink/contracts-ccip/src/v0.8/shared/access/OwnerIsCreator.sol";
import {Client} from "@chainlink/contracts-ccip/src/v0.8/ccip/libraries/Client.sol";
import {IERC20} from "@chainlink/contracts-ccip/src/v0.8/vendor/openzeppelin-solidity/v4.8.3/contracts/token/ERC20/IERC20.sol";

contract Sender is OwnerIsCreator {

   IRouterClient private router;
   IERC20 private linkToken;

   /// @notice Initializes the contract with the router and LINK token address.
   /// @param _router The address of the router contract.
   /// @param _link The address of the link contract.
   constructor(address _router, address _link) {
       router = IRouterClient(_router);
       linkToken = IERC20(_link);
   }

   /// @notice Sends data to receiver on the destination chain.
   /// @param destinationChainSelector The identifier (aka selector) for the destination blockchain.
   /// @param receiver The address of the recipient on the destination blockchain.
   /// @param text The string text to be sent.
   /// @return messageId The ID of the message that was sent.
   function sendMessage(
       uint64 destinationChainSelector,
       address receiver,
       string calldata text
   ) external onlyOwner returns (bytes32 messageId) {
       Client.EVM2AnyMessage memory message = Client.EVM2AnyMessage({
           receiver: abi.encode(receiver), // Encode receiver address
           data: abi.encode(text), // Encode text to send
           tokenAmounts: new Client.EVMTokenAmount[](0), // Empty array indicating no tokens are being sent
           extraArgs: Client._argsToBytes(
               Client.EVMExtraArgsV1({gasLimit: 200_000}) // Set gas limit
           ),
           feeToken: address(linkToken) // Set the LINK as the feeToken address
       });

       // Get the fee required to send the message
       uint256 fees = router.getFee(
           destinationChainSelector,
           message
       );

       // Revert if contract does not have enough LINK tokens for sending a message
       require(linkToken.balanceOf(address(this)) &amp;gt; fees, "Not enough LINK balance");

       // Approve the Router to transfer LINK tokens on contract's behalf in order to pay for fees in LINK
       linkToken.approve(address(router), fees);

       // Send the message through the router
       messageId = router.ccipSend(destinationChainSelector, message);

       // Return the messageId
       return messageId;
   }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Create a new file under your project's &lt;code&gt;src/&lt;/code&gt; directory named &lt;code&gt;Sender.sol&lt;/code&gt; and copy the code above into the file.&lt;/p&gt;

&lt;h4&gt;
  
  
  Code walkthrough
&lt;/h4&gt;

&lt;p&gt;The sections below provide a detailed explanation for the code for the &lt;code&gt;Sender&lt;/code&gt; contract provided above.&lt;/p&gt;

&lt;h5&gt;
  
  
  Initializing the contract
&lt;/h5&gt;

&lt;p&gt;In order to send data using CCIP, the &lt;code&gt;Sender&lt;/code&gt; contract will need access to the following dependencies:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;The &lt;code&gt;Router&lt;/code&gt; contract&lt;/strong&gt;: This contract serves as the primary interface when using CCIP to send and receive messages and tokens.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;The fee token contract&lt;/strong&gt;: This contract serves as the contract for the token that will be used to pay fees when sending messages and tokens. For this tutorial, the contract address for LINK token is used.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The &lt;code&gt;Router&lt;/code&gt; contract address and LINK token address are passed in as parameters to the contract's constructor and stored as member variables for later for sending messages and paying any associated fees.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;contract Sender is OwnerIsCreator {

   IRouterClient private router;
   IERC20 private linkToken;

   /// @notice Initializes the contract with the router and LINK token address.
   /// @param _router The address of the router contract.
   /// @param _link The address of the link contract.
   constructor(address _router, address _link) {
       router = IRouterClient(_router);
       linkToken = IERC20(_link);
   }
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;Router&lt;/code&gt; contract provides two important methods that can be used when sending messages using CCIP:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;getFee&lt;/code&gt;: Given a chain selector and message, returns the fee amount required to send the message.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;ccipSend&lt;/code&gt;: Given a chain selector and message, sends the message through the router and returns an associated message ID.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The next section describes how these methods are utilized to send a message to another chain.&lt;/p&gt;

&lt;h5&gt;
  
  
  Sending a message
&lt;/h5&gt;

&lt;p&gt;The &lt;code&gt;Sender&lt;/code&gt; contract defines a custom method named &lt;code&gt;sendMessage&lt;/code&gt; that utilizes the methods described above in order to:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Construct a message using the &lt;code&gt;EVM2AnyMessage&lt;/code&gt; method provided by the &lt;code&gt;Client&lt;/code&gt; CCIP library, using the following data:

&lt;ol&gt;
&lt;li&gt;
&lt;code&gt;receiver&lt;/code&gt;: The receiver contract address (encoded).&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;data&lt;/code&gt;: The text data to send with the message (encoded).&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;tokenAmounts&lt;/code&gt;: The amount of tokens to send with the message. For sending just an arbitrary message this field is defined as an empty array (&lt;code&gt;new Client.EVMTokenAmount[](0)&lt;/code&gt;), indicating that no tokens will be sent.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;extraArgs&lt;/code&gt;: Extra arguments associated with the message, such as &lt;code&gt;gasLimit&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;feeToken&lt;/code&gt;: The &lt;code&gt;address&lt;/code&gt; of the token to be used for paying fees.&lt;/li&gt;
&lt;/ol&gt;


&lt;/li&gt;

&lt;li&gt;Get the fees required to send the message using the &lt;code&gt;getFee&lt;/code&gt; method provided by the &lt;code&gt;Router&lt;/code&gt; contract.&lt;/li&gt;

&lt;li&gt;Check that the contract holds an adequate amount of tokens to cover the fee. If not, revert the transaction.&lt;/li&gt;

&lt;li&gt;Approve the &lt;code&gt;Router&lt;/code&gt; contract to transfer tokens on the &lt;code&gt;Sender&lt;/code&gt; contracts behalf in order to cover the fees.&lt;/li&gt;

&lt;li&gt;Send the message to a specified chain using the &lt;code&gt;Router&lt;/code&gt; contract's &lt;code&gt;ccipSend&lt;/code&gt; method.&lt;/li&gt;

&lt;li&gt;Return a unique ID associated with the sent message.
&lt;/li&gt;

&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;/// @param receiver The address of the recipient on the destination blockchain.
/// @param text The string text to be sent.
/// @return messageId The ID of the message that was sent.
function sendMessage(
    uint64 destinationChainSelector,
    address receiver,
    string calldata text
) external onlyOwner returns (bytes32 messageId) {
    Client.EVM2AnyMessage memory message = Client.EVM2AnyMessage({
        receiver: abi.encode(receiver), // Encode receiver address
        data: abi.encode(text), // Encode text to send
        tokenAmounts: new Client.EVMTokenAmount[](0), // Empty array indicating no tokens are being sent
        extraArgs: Client._argsToBytes(
            Client.EVMExtraArgsV1({gasLimit: 200_000}) // Set gas limit
        ),
        feeToken: address(linkToken) // Set the LINK as the feeToken address
    });

    // Get the fee required to send the message
    uint256 fees = router.getFee(
        destinationChainSelector,
        message
    );

    // Revert if contract does not have enough LINK tokens for sending a message
    require(linkToken.balanceOf(address(this)) &amp;gt; fees, "Not enough LINK balance");

    // Approve the Router to transfer LINK tokens on contract's behalf in order to pay for fees in LINK
    linkToken.approve(address(router), fees);
    // Send the message through the router
    messageId = router.ccipSend(destinationChainSelector, message);

    // Return the messageId
    return messageId;
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Creating a Receiver contract
&lt;/h3&gt;

&lt;p&gt;The code snippet below is for a basic smart contract that uses CCIP to receive data:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;pragma solidity ^0.8.0;

import {Client} from "@chainlink/contracts-ccip/src/v0.8/ccip/libraries/Client.sol";
import {CCIPReceiver} from "@chainlink/contracts-ccip/src/v0.8/ccip/applications/CCIPReceiver.sol";

contract Receiver is CCIPReceiver {

   bytes32 private _messageId;
   string private _text;

   /// @notice Constructor - Initializes the contract with the router address.
   /// @param router The address of the router contract.
   constructor(address router) CCIPReceiver(router) {}

   /// @notice Handle a received message
   /// @param message The cross-chain message being received.
   function _ccipReceive(
       Client.Any2EVMMessage memory message
   ) internal override {
       _messageId = message.messageId; // Store the messageId
       _text = abi.decode(message.data, (string)); // Decode and store the message text
   }

    /// @notice Gets the last received message.
    /// @return messageId The ID of the last received message.
    /// @return text The last received text.
    function getMessage()
        external
        view
        returns (bytes32 messageId, string memory text)
    {
        return (_messageId, _text);
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Create a new file under your project’s &lt;code&gt;src/&lt;/code&gt; directory named &lt;code&gt;Receiver.sol&lt;/code&gt; and copy the code above into the file.&lt;/p&gt;

&lt;h4&gt;
  
  
  Code walkthrough
&lt;/h4&gt;

&lt;p&gt;The sections below provide a detailed explanation for the code for the &lt;code&gt;Receiver&lt;/code&gt; contract provided above.&lt;/p&gt;

&lt;h5&gt;
  
  
  Initializing the contract
&lt;/h5&gt;

&lt;p&gt;In order to receive data using CCIP, the &lt;code&gt;Receiver&lt;/code&gt; contract will need to extend to the&lt;code&gt;CCIPReceiver&lt;/code&gt; interface. Extending this interface allows the &lt;code&gt;Receiver&lt;/code&gt; contract to initialize the contract with the router address from the constructor, as seen below:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import {CCIPReceiver} from "@chainlink/contracts-ccip/src/v0.8/ccip/applications/CCIPReceiver.sol";

contract Receiver is CCIPReceiver {

   /// @notice Constructor - Initializes the contract with the router address.
   /// @param router The address of the router contract.
   constructor(address router) CCIPReceiver(router) {}
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h5&gt;
  
  
  Receiving a message
&lt;/h5&gt;

&lt;p&gt;Extending the &lt;code&gt;CCIPReceiver&lt;/code&gt; interface also allows the &lt;code&gt;Receiver&lt;/code&gt; contract to override the &lt;code&gt;_ccipReceive&lt;/code&gt; handler method for when a message is received and define custom logic.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;/// @notice Handle a received message
/// @param message The cross-chain message being received.
function _ccipReceive(
    Client.Any2EVMMessage memory message
) internal override {
    // Add custom logic here
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;Receiver&lt;/code&gt; contract in this tutorial provides custom logic that stores the &lt;code&gt;messageId&lt;/code&gt; and &lt;code&gt;text&lt;/code&gt; (decoded) as member variables.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;contract Receiver is CCIPReceiver {

   bytes32 private _messageId;
   string private _text;

   /// @notice Constructor - Initializes the contract with the router address.
   /// @param router The address of the router contract.
   constructor(address router) CCIPReceiver(router) {}

   /// @notice Handle a received message
   /// @param message The cross-chain message being received.
   function _ccipReceive(
       Client.Any2EVMMessage memory message
   ) internal override {
       _messageId = message.messageId; // Store the messageId
       _text = abi.decode(message.data, (string)); // Decode and store the message text
   }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h5&gt;
  
  
  Retrieving a message
&lt;/h5&gt;

&lt;p&gt;The &lt;code&gt;Receiver&lt;/code&gt; contract defines a custom method named &lt;code&gt;getMessage&lt;/code&gt; that returns the details of the last received message &lt;code&gt;_messagId&lt;/code&gt; and &lt;code&gt;_text&lt;/code&gt;. This method can be called to fetch the message data details after the &lt;code&gt;_ccipReceive&lt;/code&gt; receives a new message.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;/// @notice Gets the last received message.
/// @return messageId The ID of the last received message.
/// @return text The last received text.
function getMessage()
    external
    view
    returns (bytes32 messageId, string memory text)
{
    return (_messageId, _text);
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  Compiling the smart contracts
&lt;/h2&gt;

&lt;p&gt;To compile your smart contracts, run:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;forge build
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  Deploying the smart contract
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Setting up your wallet as the deployer
&lt;/h3&gt;

&lt;p&gt;Before you can deploy your smart contract to the Base network, you will need to set up a wallet to be used as the deployer.&lt;/p&gt;

&lt;p&gt;To do so, you can use the &lt;a href="https://book.getfoundry.sh/reference/cast/cast-wallet-import" rel="noopener noreferrer"&gt;&lt;code&gt;cast wallet import&lt;/code&gt;&lt;/a&gt; command to import the private key of the wallet into Foundry's securely encrypted keystore:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;cast wallet import deployer &lt;span class="nt"&gt;--interactive&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;After running the command above, you will be prompted to enter your private key, as well as a password for signing transactions.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Caution:&lt;/strong&gt; For instructions on how to get your private key from Coinbase Wallet, visit the &lt;a href="https://docs.cloud.coinbase.com/wallet-sdk/docs/developer-settings#show-private-key" rel="noopener noreferrer"&gt;Coinbase Wallet documentation&lt;/a&gt;. &lt;strong&gt;It is critical that you do NOT commit this to a public repo&lt;/strong&gt;.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;To confirm that the wallet was imported as the &lt;code&gt;deployer&lt;/code&gt; account in your Foundry project, run:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;cast wallet list
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Setting up environment variables
&lt;/h3&gt;

&lt;p&gt;To setup your environment, create an &lt;code&gt;.env&lt;/code&gt; file in the home directory of your project, and add the RPC URLs, &lt;a href="https://docs.chain.link/ccip/supported-networks/v1_2_0/testnet" rel="noopener noreferrer"&gt;CCIP chain selectors&lt;/a&gt;, &lt;a href="https://docs.chain.link/ccip/supported-networks/v1_2_0/testnet" rel="noopener noreferrer"&gt;CCIP router addresses&lt;/a&gt;, and &lt;a href="https://docs.chain.link/resources/link-token-contracts" rel="noopener noreferrer"&gt;LINK token addresses&lt;/a&gt; for both Base Goerli and Optimism Goerli testnets:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;BASE_GOERLI_RPC&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"https://goerli.base.org"&lt;/span&gt;
&lt;span class="nv"&gt;OPTIMISM_GOERLI_RPC&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"https://goerli.optimism.io"&lt;/span&gt;

&lt;span class="nv"&gt;BASE_GOERLI_CHAIN_SELECTOR&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;5790810961207155433
&lt;span class="nv"&gt;OPTIMISM_GOERLI_CHAIN_SELECTOR&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;2664363617261496610

&lt;span class="nv"&gt;BASE_GOERLI_ROUTER_ADDRESS&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"0x80AF2F44ed0469018922c9F483dc5A909862fdc2"&lt;/span&gt;
&lt;span class="nv"&gt;OPTIMISM_GOERLI_ROUTER_ADDRESS&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"0xcc5a0B910D9E9504A7561934bed294c51285a78D"&lt;/span&gt;

&lt;span class="nv"&gt;BASE_GOERLI_LINK_ADDRESS&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"0x6D0F8D488B669aa9BA2D0f0b7B75a88bf5051CD3"&lt;/span&gt;
&lt;span class="nv"&gt;OPTIMISM_GOERLI_LINK_ADDRESS&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"0xdc2CC710e42857672E7907CF474a69B63B93089f"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Once the &lt;code&gt;.env&lt;/code&gt; file has been created, run the following command to load the environment variables in the current command line session:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;source&lt;/span&gt; .env
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Deploying the smart contracts
&lt;/h3&gt;

&lt;p&gt;With your contracts compiled and environment setup, you are ready to deploy the smart contracts.&lt;/p&gt;

&lt;p&gt;To deploy a smart contract using Foundry, you can use the &lt;code&gt;forge create&lt;/code&gt; command. The command requires you to specify the smart contract you want to deploy, an RPC URL of the network you want to deploy to, and the account you want to deploy with.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Info:&lt;/strong&gt; Your wallet must be funded with ETH on the Base Goerli and Optimism Goerli to cover the gas fees associated with the smart contract deployment. Otherwise, the deployment will fail.&lt;/p&gt;

&lt;p&gt;To get testnet ETH for Base Goerli and Optimism Goerli, see the prerequisites.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h4&gt;
  
  
  Deploying the Sender contract to Base Goerli
&lt;/h4&gt;

&lt;p&gt;To deploy the &lt;code&gt;Sender&lt;/code&gt; smart contract to the Base Goerli testnet, run the following command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;forge create ./src/Sender.sol:Sender &lt;span class="nt"&gt;--rpc-url&lt;/span&gt; &lt;span class="nv"&gt;$BASE_GOERLI_RPC&lt;/span&gt; &lt;span class="nt"&gt;--constructor-args&lt;/span&gt; &lt;span class="nv"&gt;$BASE_GOERLI_ROUTER_ADDRESS&lt;/span&gt; &lt;span class="nv"&gt;$BASE_GOERLI_LINK_ADDRESS&lt;/span&gt; &lt;span class="nt"&gt;--account&lt;/span&gt; deployer
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;When prompted, enter the password that you set earlier, when you imported your wallet's private key.&lt;/p&gt;

&lt;p&gt;After running the command above, the contract will be deployed on the Base Goerli test network. You can view the deployment status and contract by using a &lt;a href="https://dev.to/docs/tools/block-explorers"&gt;block explorer&lt;/a&gt;.&lt;/p&gt;

&lt;h4&gt;
  
  
  Deploying the Receiver contract to Optimism Goerli
&lt;/h4&gt;

&lt;p&gt;To deploy the &lt;code&gt;Receiver&lt;/code&gt; smart contract to the Optimism Goerli testnet, run the following command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;forge create ./src/Receiver.sol:Receiver &lt;span class="nt"&gt;--rpc-url&lt;/span&gt; &lt;span class="nv"&gt;$OPTIMISM_GOERLI_RPC&lt;/span&gt; &lt;span class="nt"&gt;--constructor-args&lt;/span&gt; &lt;span class="nv"&gt;$OPTIMISM_GOERLI_ROUTER_ADDRESS&lt;/span&gt; &lt;span class="nt"&gt;--account&lt;/span&gt; deployer
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;When prompted, enter the password that you set earlier, when you imported your wallet's private key.&lt;/p&gt;

&lt;p&gt;After running the command above, the contract will be deployed on the Optimism Goerli test network. You can view the deployment status and contract by using the &lt;a href="https://goerli-optimism.etherscan.io/" rel="noopener noreferrer"&gt;OP Goerli block explorer&lt;/a&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Funding your smart contracts
&lt;/h3&gt;

&lt;p&gt;In order to pay for the fees associated with sending messages, the &lt;code&gt;Sender&lt;/code&gt; contract will need to hold a balance of LINK tokens.&lt;/p&gt;

&lt;p&gt;Fund your contract directly from your wallet, or by running the following &lt;code&gt;cast&lt;/code&gt; command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;cast send &lt;span class="nv"&gt;$BASE_GOERLI_LINK_ADDRESS&lt;/span&gt; &lt;span class="nt"&gt;--rpc-url&lt;/span&gt; &lt;span class="nv"&gt;$BASE_GOERLI_RPC&lt;/span&gt; &lt;span class="s2"&gt;"transfer(address,uint256)"&lt;/span&gt; &amp;lt;SENDER_CONTRACT_ADDRESS&amp;gt; 5 &lt;span class="nt"&gt;--account&lt;/span&gt; deployer
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The above command sends &lt;code&gt;5&lt;/code&gt; LINK tokens on Base Goerli testnet to the &lt;code&gt;Sender&lt;/code&gt; contract.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Info:&lt;/strong&gt; Replace &lt;code&gt;&amp;lt;SENDER_CONTRACT_ADDRESS&amp;gt;&lt;/code&gt; with the contract address of your deployed &lt;code&gt;Sender&lt;/code&gt; contract before running the provided &lt;code&gt;cast&lt;/code&gt; command.&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  Interacting with the smart contract
&lt;/h2&gt;

&lt;p&gt;Foundry provides the &lt;code&gt;cast&lt;/code&gt; command-line tool that can be used to interact with deployed smart contracts and call their functions.&lt;/p&gt;

&lt;h3&gt;
  
  
  Sending data
&lt;/h3&gt;

&lt;p&gt;The &lt;code&gt;cast&lt;/code&gt; command can be used to call the &lt;code&gt;sendMessage(uint64, address, string)&lt;/code&gt; function on the &lt;code&gt;Sender&lt;/code&gt; contract deployed to Base Goerli in order to send message data to the &lt;code&gt;Receiver&lt;/code&gt; contract on Optimism Goerli.&lt;/p&gt;

&lt;p&gt;To call the &lt;code&gt;sendMessage(uint64, address, string)&lt;/code&gt; function of the &lt;code&gt;Sender&lt;/code&gt; smart contract, run:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;cast send &amp;lt;SENDER_CONTRACT_ADDRESS&amp;gt; &lt;span class="nt"&gt;--rpc-url&lt;/span&gt; &lt;span class="nv"&gt;$BASE_GOERLI_RPC&lt;/span&gt; &lt;span class="s2"&gt;"sendMessage(uint64, address, string)"&lt;/span&gt; &lt;span class="nv"&gt;$OPTIMISM_GOERLI_CHAIN_SELECTOR&lt;/span&gt; &amp;lt;RECEIVER_CONTRACT_ADDRESS&amp;gt; &lt;span class="s2"&gt;"Based"&lt;/span&gt; &lt;span class="nt"&gt;--account&lt;/span&gt; deployer
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The command above calls the &lt;code&gt;sendMessage(uint64, address, string)&lt;/code&gt; to send a message. The parameters passed in to the method include: The chain selector to the destination chain (Optimism Goerli), the &lt;code&gt;Receiver&lt;/code&gt; contract address, and the text data to be included in the message (&lt;code&gt;Based&lt;/code&gt;).&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Info:&lt;/strong&gt; Replace &lt;code&gt;&amp;lt;SENDER_CONTRACT_ADDRESS&amp;gt;&lt;/code&gt; and &lt;code&gt;&amp;lt;RECEIVER_CONTRACT_ADDRESS&amp;gt;&lt;/code&gt; with the contract addresses of your deployed &lt;code&gt;Sender&lt;/code&gt; and &lt;code&gt;Receiver&lt;/code&gt; contracts respectively before running the provided &lt;code&gt;cast&lt;/code&gt; command.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;After running the command, a unique &lt;code&gt;messageId&lt;/code&gt; should be returned.&lt;/p&gt;

&lt;p&gt;Once the transaction has been finalized, it will take a few minutes for CCIP to deliver the data to Optimism Goerli and call the &lt;code&gt;ccipReceive&lt;/code&gt; function on the &lt;code&gt;Receiver&lt;/code&gt; contract.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Info:&lt;/strong&gt; You can use the &lt;a href="https://ccip.chain.link/" rel="noopener noreferrer"&gt;CCIP explorer&lt;/a&gt; to see the status of the CCIP transaction.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  Receiving data
&lt;/h3&gt;

&lt;p&gt;The &lt;code&gt;cast&lt;/code&gt; command can also be used to call the &lt;code&gt;getMessage()&lt;/code&gt; function on the &lt;code&gt;Receiver&lt;/code&gt; contract deployed to Optimism Goerli in order to read the received message data.&lt;/p&gt;

&lt;p&gt;To call the &lt;code&gt;getMessage()&lt;/code&gt; function of the &lt;code&gt;Receiver&lt;/code&gt; smart contract, run:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;cast send &amp;lt;RECEIVER_CONTRACT_ADDRESS&amp;gt; &lt;span class="nt"&gt;--rpc-url&lt;/span&gt; &lt;span class="nv"&gt;$OPTIMISM_GOERLI_RPC&lt;/span&gt; &lt;span class="s2"&gt;"getMessage()"&lt;/span&gt; &lt;span class="nt"&gt;--account&lt;/span&gt; deployer
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Info:&lt;/strong&gt; Replace &lt;code&gt;&amp;lt;RECEIVER_CONTRACT_ADDRESS&amp;gt;&lt;/code&gt; with the contract addresses of your deployed &lt;code&gt;Receiver&lt;/code&gt; contract before running the provided &lt;code&gt;cast&lt;/code&gt; command.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;After running the command, the &lt;code&gt;messageId&lt;/code&gt; and &lt;code&gt;text&lt;/code&gt; of the last received message should be returned.&lt;/p&gt;

&lt;p&gt;If the transaction fails, ensure the status of your &lt;code&gt;ccipSend&lt;/code&gt; transaction has been finalized. You can using the &lt;a href="https://ccip.chain.link/" rel="noopener noreferrer"&gt;CCIP explorer&lt;/a&gt;.&lt;/p&gt;




&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;Congratulations! You have successfully learned how to perform cross-chain messaging on Base using Chainlink CCIP.&lt;/p&gt;

&lt;p&gt;To learn more about cross-chain messaging and Chainlink CCIP, check out the following resources:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://docs.base.org/docs/tools/cross-chain" rel="noopener noreferrer"&gt;Cross-chain&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://docs.chain.link/ccip" rel="noopener noreferrer"&gt;Chainlink CCIP&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;




</description>
      <category>tutorial</category>
      <category>blockchain</category>
      <category>cryptocurrency</category>
      <category>web3</category>
    </item>
    <item>
      <title>Account Abstraction on Base using Biconomy</title>
      <dc:creator>Taylor Caldwell</dc:creator>
      <pubDate>Mon, 27 Jan 2025 04:28:32 +0000</pubDate>
      <link>https://dev.to/taycaldwell/account-abstraction-on-base-using-biconomy-3k2f</link>
      <guid>https://dev.to/taycaldwell/account-abstraction-on-base-using-biconomy-3k2f</guid>
      <description>&lt;p&gt;This tutorial will guide you through the process of implementing Account Abstraction in your Base projects using Biconomy paymasters, bundlers, and smart accounts.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; This tutorial was originally published and authored by &lt;a href="https://x.com/taycaldwell" rel="noopener noreferrer"&gt;@taycaldwell&lt;/a&gt; on &lt;a href="https://docs.base.org" rel="noopener noreferrer"&gt;https://docs.base.org&lt;/a&gt;. You can find the original tutorial &lt;a href="https://docs.base.org/tutorials/account-abstraction-with-biconomy" rel="noopener noreferrer"&gt;here&lt;/a&gt;.&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  Objectives
&lt;/h2&gt;

&lt;p&gt;By the end of this tutorial you should be able to do the following:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Set up a smart contract project for Base using &lt;a href="https://book.getfoundry.sh/" rel="noopener noreferrer"&gt;Foundry&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Set up a Next.js frontend project using &lt;code&gt;create next-app&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Setup user login and authentication using &lt;a href="https://particle.network/" rel="noopener noreferrer"&gt;Particle Network&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Setup a &lt;a href="https://biconomy.io/" rel="noopener noreferrer"&gt;Biconomy&lt;/a&gt; paymaster and bundler&lt;/li&gt;
&lt;li&gt;Create a gasless transaction&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Prerequisites
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Foundry
&lt;/h3&gt;

&lt;p&gt;This tutorial requires you to have Foundry installed.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;From the command-line (terminal), run: &lt;code&gt;curl -L https://foundry.paradigm.xyz | bash&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Then run &lt;code&gt;foundryup&lt;/code&gt;, to install the latest (nightly) build of Foundry&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For more information, see the Foundry Book &lt;a href="https://book.getfoundry.sh/getting-started/installation" rel="noopener noreferrer"&gt;installation guide&lt;/a&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Coinbase Wallet
&lt;/h3&gt;

&lt;p&gt;This tutorial requires you to have a wallet. You can create a wallet by downloading the Coinbase Wallet browser extension:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Download &lt;a href="https://chrome.google.com/webstore/detail/coinbase-wallet-extension/hnfanknocfeofbddgcijnmhnfnkdnaad?hl=en" rel="noopener noreferrer"&gt;Coinbase Wallet&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Wallet funds
&lt;/h3&gt;

&lt;p&gt;To complete this tutorial, you will need to fund a wallet with ETH on Base Goerli.&lt;/p&gt;

&lt;p&gt;The ETH is required for covering gas fees associated with deploying smart contracts to the network.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;To fund your wallet with ETH on Base Goerli, visit a faucet listed on the &lt;a href="https://docs.base.org/tools/network-faucets" rel="noopener noreferrer"&gt;Base Faucets&lt;/a&gt; page.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  What is Biconomy?
&lt;/h2&gt;

&lt;p&gt;Biconomy is a toolkit that offers a full-stack solution for Account Abstraction, including smart accounts, paymasters for sponsoring gas fees, and bundlers for bundling user operations into a single transaction.&lt;/p&gt;

&lt;h3&gt;
  
  
  High-level concepts
&lt;/h3&gt;

&lt;h4&gt;
  
  
  Account Abstraction
&lt;/h4&gt;

&lt;p&gt;Account Abstraction (&lt;a href="https://eips.ethereum.org/EIPS/eip-4337" rel="noopener noreferrer"&gt;ERC-4337&lt;/a&gt;) allows users to use Smart Contract wallets instead of traditional Externally Owned Account (EOA) wallets.&lt;/p&gt;

&lt;h4&gt;
  
  
  Smart Accounts
&lt;/h4&gt;

&lt;p&gt;A smart account (also known as a smart contract wallet) is a wallet that stores and manages digital assets (ERC-20 tokens, NFTs, etc.) using a smart contract.&lt;/p&gt;

&lt;h4&gt;
  
  
  User Operations
&lt;/h4&gt;

&lt;p&gt;A user operation is a pseudo-transaction object sent by a smart account that describes a transaction to be sent. Multiple user operations are eventually bundled together and initiated as a single real transaction by a bundler.&lt;/p&gt;

&lt;h4&gt;
  
  
  Paymaster
&lt;/h4&gt;

&lt;p&gt;A paymaster is a special smart contract that allows applications to “sponsor user operations”, meaning it will pay for the gas fees associated with the resulting transaction.&lt;/p&gt;

&lt;h4&gt;
  
  
  Bundler
&lt;/h4&gt;

&lt;p&gt;A special node that monitors a mempool of user operations and bundles multiple user operations into a single transaction.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Info:&lt;/strong&gt; To learn more about Account Abstraction and the concepts outlined above, see &lt;a href="https://eips.ethereum.org/EIPS/eip-4337" rel="noopener noreferrer"&gt;ERC-4337&lt;/a&gt;.&lt;/p&gt;




&lt;h2&gt;
  
  
  Creating and deploying a smart contract
&lt;/h2&gt;

&lt;p&gt;Before you begin, you need to set up a smart contract development environment using Foundry.&lt;/p&gt;

&lt;p&gt;To create a new project, first create a new directory named &lt;code&gt;myproject&lt;/code&gt;, and change it to your current working directory:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;mkdir &lt;/span&gt;myproject
&lt;span class="nb"&gt;cd &lt;/span&gt;myproject
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Creating a Foundry project
&lt;/h3&gt;

&lt;p&gt;Next, within the &lt;code&gt;myproject&lt;/code&gt; directory create a new directory named &lt;code&gt;contracts&lt;/code&gt;, and change it to your current working directory:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;mkdir &lt;/span&gt;contracts
&lt;span class="nb"&gt;cd &lt;/span&gt;contracts
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then create a new Foundry project by running the following command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;forge init
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This will create a Foundry project with the following basic layout:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;.&lt;/span&gt;
├── foundry.toml
├── script
├── src
└── &lt;span class="nb"&gt;test&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Info::&lt;/strong&gt; The command creates a boilerplate Solidity smart contract file named &lt;code&gt;src/Counter.sol&lt;/code&gt;. This is the primary contract you will use for this tutorial.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  Compiling the smart contract
&lt;/h3&gt;

&lt;p&gt;Compile the smart contract to ensure it builds without any errors.&lt;/p&gt;

&lt;p&gt;To compile your smart contract, run:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;forge build
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Setting up a wallet as the deployer
&lt;/h3&gt;

&lt;p&gt;Before you can deploy your smart contract to various chains you will need to set up a wallet to be used as the deployer.&lt;/p&gt;

&lt;p&gt;To do so, you can use the &lt;a href="https://book.getfoundry.sh/reference/cast/cast-wallet-import" rel="noopener noreferrer"&gt;&lt;code&gt;cast wallet import&lt;/code&gt;&lt;/a&gt; command to import the private key of the wallet into Foundry's securely encrypted keystore:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;cast wallet import deployer &lt;span class="nt"&gt;--interactive&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;After running the command above, you will be prompted to enter your private key, as well as a password for signing transactions.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Caution:&lt;/strong&gt; For instructions on how to get your private key from Coinbase Wallet, visit the &lt;a href="https://docs.cloud.coinbase.com/wallet-sdk/docs/developer-settings#show-private-key" rel="noopener noreferrer"&gt;Coinbase Wallet documentation&lt;/a&gt;. &lt;strong&gt;It is critical that you do NOT commit this to a public repo.&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;To confirm that the wallet was imported as the &lt;code&gt;deployer&lt;/code&gt; account in your Foundry project, run:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;cast wallet list
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Deploying the smart contract
&lt;/h3&gt;

&lt;p&gt;To deploy the smart contract, you can use the &lt;code&gt;forge create&lt;/code&gt; command. The command requires you to specify the smart contract you want to deploy, an RPC URL of the network you want to deploy to, and the account you want to deploy with.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Info:&lt;/strong&gt; Your wallet must be funded with ETH on the Base Goerli testnet to cover the gas fees associated with the smart contract deployment. Otherwise, the deployment will fail.&lt;/p&gt;

&lt;p&gt;To get testnet ETH, see the prerequisites.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;To deploy the smart contract to the Base Goerli testnet, run the following command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;forge create ./src/Counter.sol:Counter &lt;span class="nt"&gt;--rpc-url&lt;/span&gt; https://goerli.base.org &lt;span class="nt"&gt;--account&lt;/span&gt; deployer
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;When prompted, enter the password that you set earlier, when you imported your wallet’s private key.&lt;/p&gt;

&lt;p&gt;After running the command above, the contract will be deployed on the Base Goerli test network. You can view the deployment status and contract by using a &lt;a href="https://dev.to/docs/tools/block-explorers"&gt;block explorer&lt;/a&gt;.&lt;/p&gt;




&lt;h2&gt;
  
  
  Setting up the Paymaster and Bundler
&lt;/h2&gt;

&lt;p&gt;To setup the paymaster and bundler for your project, you will need to visit the &lt;a href="https://dashboard.biconomy.io/" rel="noopener noreferrer"&gt;Biconomy Dashboard&lt;/a&gt; and complete the following steps.&lt;/p&gt;

&lt;h3&gt;
  
  
  Registering a paymaster
&lt;/h3&gt;

&lt;p&gt;Add and register a Paymaster by completing the following steps:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Visit the sign in to the &lt;a href="https://dashboard.biconomy.io/" rel="noopener noreferrer"&gt;Biconomy Dashboard&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;From the dashboard, select the &lt;strong&gt;Paymasters&lt;/strong&gt; tab and click &lt;strong&gt;Add your first Paymaster&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Provide a &lt;strong&gt;Name&lt;/strong&gt; for your paymaster&lt;/li&gt;
&lt;li&gt;Select &lt;strong&gt;Base Goerli&lt;/strong&gt; from the &lt;strong&gt;Network&lt;/strong&gt; dropdown&lt;/li&gt;
&lt;li&gt;Click &lt;strong&gt;Register&lt;/strong&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;You should now have a registered Biconomy paymaster.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Info:&lt;/strong&gt; The &lt;strong&gt;API Key&lt;/strong&gt; and &lt;strong&gt;Paymaster URL&lt;/strong&gt; for the paymaster are provided under the &lt;strong&gt;Overview&lt;/strong&gt; tab in the &lt;a href="https://dashboard.biconomy.io/" rel="noopener noreferrer"&gt;Biconomy Dashboard&lt;/a&gt;.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  Setting up the paymaster gas tank
&lt;/h3&gt;

&lt;p&gt;Set up and fund the paymaster's gas tank by completing the following steps:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;From the &lt;a href="https://dashboard.biconomy.io/" rel="noopener noreferrer"&gt;dashboard&lt;/a&gt;, navigate to the &lt;strong&gt;Paymasters&lt;/strong&gt; tab&lt;/li&gt;
&lt;li&gt;Click &lt;strong&gt;Setup gas tank&lt;/strong&gt; on the paymaster&lt;/li&gt;
&lt;li&gt;Navigate to &lt;strong&gt;Gas-Tank &amp;gt; Deposit&lt;/strong&gt;, and click &lt;strong&gt;Set up gas tank&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Sign the message with your connected wallet to set up the gas tank&lt;/li&gt;
&lt;li&gt;Click &lt;strong&gt;Go to deposit&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Enter the amount of ETH you wish to deposit&lt;/li&gt;
&lt;li&gt;Click &lt;strong&gt;Deposit&lt;/strong&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;ETH should now be deposited into the gas tank for your paymaster. You can visit the Withdraw tab at a later time if you wish to withdraw the funds.&lt;/p&gt;

&lt;h3&gt;
  
  
  Setting up the paymaster policies
&lt;/h3&gt;

&lt;p&gt;Set up and fund the paymaster's gas tank by completing the following steps:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;From the &lt;a href="https://dashboard.biconomy.io/" rel="noopener noreferrer"&gt;dashboard&lt;/a&gt;, navigate to the &lt;strong&gt;Paymasters&lt;/strong&gt; tab&lt;/li&gt;
&lt;li&gt;Select the paymaster to configure&lt;/li&gt;
&lt;li&gt;Navigate to &lt;strong&gt;Policies &amp;gt; Contracts&lt;/strong&gt;, and click &lt;strong&gt;Add your first contract&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Add the &lt;strong&gt;Name&lt;/strong&gt; and the &lt;strong&gt;Smart contract address&lt;/strong&gt; for your contract&lt;/li&gt;
&lt;li&gt;Select the &lt;strong&gt;increment&lt;/strong&gt; and &lt;strong&gt;setNumber&lt;/strong&gt; write methods as methods to sponsor&lt;/li&gt;
&lt;li&gt;Click &lt;strong&gt;Add Smart Contract&lt;/strong&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  Setting up a bundler
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;Visit the sign in to the &lt;a href="https://dashboard.biconomy.io/" rel="noopener noreferrer"&gt;Biconomy Dashboard&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;From the dashboard, select the &lt;strong&gt;Bundlers&lt;/strong&gt; tab&lt;/li&gt;
&lt;/ol&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Info:&lt;/strong&gt; At the time of writing this tutorial, the Bundler service is still under development, however a &lt;strong&gt;Bundler URL&lt;/strong&gt; is provided for testing out UserOperations on test networks. You can specify the chain ID &lt;strong&gt;84531&lt;/strong&gt; to use the Bundler URL on &lt;strong&gt;Base Goerli&lt;/strong&gt; testnet.&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  Setting up the frontend
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Creating a Next.js project
&lt;/h3&gt;

&lt;p&gt;After you set up your paymaster and bundler from the Biconomy Dashboard, the next step is to create a Next.js project for your app's frontend.&lt;/p&gt;

&lt;p&gt;From the root of the &lt;code&gt;myproject&lt;/code&gt; directory of your project, create a new Next.js project by running the following command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;yarn create next-app
&lt;span class="nb"&gt;cd &lt;/span&gt;my-app
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Installing the dependencies
&lt;/h3&gt;

&lt;p&gt;To use the paymaster and bundler that were setup from the Biconomy Dashboard, you will need to add a few dependencies to your Next.js project.&lt;/p&gt;

&lt;p&gt;To install Biconomy as a dependency to your project, run the following command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;yarn add @biconomy/account @biconomy/bundler @biconomy/common @biconomy/core-types @biconomy/paymaster ethers@5.7.2
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Creating Biconomy smart accounts requires a signer from an &lt;a href="https://eips.ethereum.org/EIPS/eip-1193" rel="noopener noreferrer"&gt;EIP-1193&lt;/a&gt; provider. Biconomy works with a variety of different social login and embedded wallet onboarding solutions that provide access to a signer that can be used for creating smart accounts. In this tutorial, you will use &lt;a href="https://particle.network/" rel="noopener noreferrer"&gt;Particle Network&lt;/a&gt; for user authentication and getting a smart account signer.&lt;/p&gt;

&lt;p&gt;To install Particle Network as a dependency to your project, run the following command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;yarn add @biconomy/particle-auth
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Updating the boilerplate code
&lt;/h3&gt;

&lt;p&gt;The main page (&lt;code&gt;page.tsx&lt;/code&gt;) of the Next.js project created when running the &lt;code&gt;yarn create next-app&lt;/code&gt; command contains a &lt;code&gt;Home&lt;/code&gt; component. This component comes with a lot of code that is unnecessary for this tutorial.&lt;/p&gt;

&lt;p&gt;Replace the content of the &lt;code&gt;page.tsx&lt;/code&gt; file with the following simplified code:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;use client&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;styles&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./page.module.css&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;Home&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;main&lt;/span&gt; &lt;span class="nx"&gt;className&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;styles&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;main&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;div&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/div&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/main&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;  &lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  Adding social login using Particle Network
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Setting up Particle Network
&lt;/h3&gt;

&lt;p&gt;To get started adding social login into the app using Particle Network, import and initialize the Biconomy Particle Auth module in the &lt;code&gt;page.tsx&lt;/code&gt; file as shown below:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;use client&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;styles&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./page.module.css&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="c1"&gt;// highlight-next-line&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;ParticleAuthModule&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;ParticleProvider&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@biconomy/particle-auth&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="c1"&gt;// highlight-start&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;PARTICLE_PROJECT_ID&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;YOUR_PARTICLE_PROJECT_ID&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;PARTICLE_CLIENT_ID&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;YOUR_PARTICLE_CLIENT_ID&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;PARTICLE_APP_ID&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;YOUR_PARTICLE_APP_ID&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;particle&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;ParticleAuthModule&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;ParticleNetwork&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;projectId&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;PARTICLE_PROJECT_ID&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;clientKey&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;PARTICLE_CLIENT_ID&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;appId&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;PARTICLE_APP_ID&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;wallet&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;displayWalletEntry&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="c1"&gt;// highlight-end&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;Home&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;main&lt;/span&gt; &lt;span class="nx"&gt;className&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;styles&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;main&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;div&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/div&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/main&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;  &lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Info:&lt;/strong&gt; You will need to sign up for a Particle Network account and replace the values of &lt;code&gt;PARTICLE_PROJECT_ID&lt;/code&gt;, &lt;code&gt;PARTICLE_CLIENT_ID&lt;/code&gt;, and &lt;code&gt;PARTICLE_APP_ID&lt;/code&gt; with your own project ID, client ID, and app ID respectively. You can find this information on the &lt;a href="https://dashboard.particle.network/#/applications" rel="noopener noreferrer"&gt;Particle Network Dashboard&lt;/a&gt;.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  Adding login functionality
&lt;/h3&gt;

&lt;p&gt;Next, add a Login button and &lt;code&gt;login&lt;/code&gt; function that triggers the Particle Network login flow and gets a &lt;code&gt;Web3Provider&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;use client&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;styles&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./page.module.css&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;ParticleAuthModule&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;ParticleProvider&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@biconomy/particle-auth&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="c1"&gt;// highlight-next-line&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;ethers&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;ethers&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;PARTICLE_PROJECT_ID&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;YOUR_PARTICLE_PROJECT_ID&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;PARTICLE_CLIENT_ID&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;YOUR_PARTICLE_CLIENT_ID&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;PARTICLE_APP_ID&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;YOUR_PARTICLE_APP_ID&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;particle&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;ParticleAuthModule&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;ParticleNetwork&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;projectId&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;PARTICLE_PROJECT_ID&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;clientKey&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;PARTICLE_CLIENT_ID&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;appId&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;PARTICLE_APP_ID&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;wallet&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;displayWalletEntry&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;Home&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c1"&gt;// highlight-start&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;login&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;userInfo&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;particle&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;auth&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;login&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
      &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;particleProvider&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;ParticleProvider&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;particle&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;auth&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
      &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;web3Provider&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;ethers&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;providers&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Web3Provider&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;particleProvider&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;any&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;catch &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;};&lt;/span&gt;
  &lt;span class="c1"&gt;// highlight-end&lt;/span&gt;

  &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;main&lt;/span&gt; &lt;span class="nx"&gt;className&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;styles&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;main&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;div&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="c1"&gt;// highlight-next-line&lt;/span&gt;
        &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;button&lt;/span&gt; &lt;span class="nx"&gt;onClick&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;login&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="nx"&gt;Login&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/button&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;      &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/div&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/main&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;  &lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  Creating Smart Accounts using Biconomy
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Initializing the paymaster and bundler
&lt;/h3&gt;

&lt;p&gt;Before you can implement the rest of the login flow and create a smart account for the logged in user, you will need to specify a paymaster and bundler.&lt;/p&gt;

&lt;p&gt;To initialize the paymaster and bundler, add the following lines of code:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;use client&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;styles&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./page.module.css&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;ParticleAuthModule&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;ParticleProvider&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@biconomy/particle-auth&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;ethers&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;ethers&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="c1"&gt;// highlight-start&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;IBundler&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;Bundler&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@biconomy/bundler&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;IPaymaster&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;BiconomyPaymaster&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@biconomy/paymaster&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;ChainId&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@biconomy/core-types&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;DEFAULT_ENTRYPOINT_ADDRESS&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@biconomy/account&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="c1"&gt;// highlight-end&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;PARTICLE_PROJECT_ID&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;YOUR_PARTICLE_PROJECT_ID&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;PARTICLE_CLIENT_ID&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;YOUR_PARTICLE_CLIENT_ID&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;PARTICLE_APP_ID&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;YOUR_PARTICLE_APP_ID&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="c1"&gt;// highlight-start&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;PAYMASTER_URL&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;YOUR_PAYMASTER_URL&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;BUNDLER_URL&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;YOUR_BUNDLER_URL&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="c1"&gt;// highlight-end&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;particle&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;ParticleAuthModule&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;ParticleNetwork&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;projectId&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;PARTICLE_PROJECT_ID&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;clientKey&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;PARTICLE_CLIENT_ID&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;appId&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;PARTICLE_APP_ID&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;wallet&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;displayWalletEntry&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="c1"&gt;// highlight-start&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;paymaster&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;IPaymaster&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;BiconomyPaymaster&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;paymasterUrl&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;PAYMASTER_URL&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;bundler&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;IBundler&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Bundler&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;chainId&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;ChainId&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;BASE_GOERLI_TESTNET&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;entryPointAddress&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;DEFAULT_ENTRYPOINT_ADDRESS&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;bundlerUrl&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;BUNDLER_URL&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="c1"&gt;// highlight-end&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;Home&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;login&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;userInfo&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;particle&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;auth&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;login&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
      &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;particleProvider&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;ParticleProvider&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;particle&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;auth&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
      &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;web3Provider&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;ethers&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;providers&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Web3Provider&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;particleProvider&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;any&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;catch &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;};&lt;/span&gt;

  &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;main&lt;/span&gt; &lt;span class="nx"&gt;className&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;styles&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;main&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;div&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;button&lt;/span&gt; &lt;span class="nx"&gt;onClick&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;login&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="nx"&gt;Login&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/button&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;      &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/div&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/main&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;  &lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Info:&lt;/strong&gt; Replace the values of &lt;code&gt;PAYMASTER_URL&lt;/code&gt;, &lt;code&gt;BUNDLER_URL&lt;/code&gt; with the URLs for your paymaster and bundler respectively. You can find this information on the &lt;a href="https://dashboard.biconomy.io/" rel="noopener noreferrer"&gt;Biconomy Dashboard&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  Creating the smart account
&lt;/h3&gt;

&lt;p&gt;Once the paymaster and bundler instances have been created, you’re ready to create a smart account for the user that is logging in.&lt;/p&gt;

&lt;p&gt;You can use the &lt;code&gt;BiconomySmartAccountV2.create&lt;/code&gt; function to create a new smart account for the user.&lt;/p&gt;

&lt;p&gt;To create a smart account for the user on Base Goerli testnet that uses the Biconomy paymaster and bundler add the following code:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="p"&gt;...&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="c1"&gt;// highlight-start&lt;/span&gt;
  &lt;span class="nx"&gt;BiconomySmartAccountV2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="c1"&gt;// highlight-end&lt;/span&gt;
  &lt;span class="nx"&gt;DEFAULT_ENTRYPOINT_ADDRESS&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@biconomy/account&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="c1"&gt;// highlight-start&lt;/span&gt;
 &lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;ECDSAOwnershipValidationModule&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;DEFAULT_ECDSA_OWNERSHIP_MODULE&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@biconomy/modules&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="c1"&gt;// highlight-end&lt;/span&gt;

&lt;span class="p"&gt;...&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;Home&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;

&lt;span class="p"&gt;...&lt;/span&gt;

  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;login&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;userInfo&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;particle&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;auth&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;login&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
      &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;particleProvider&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;ParticleProvider&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;particle&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;auth&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
      &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;web3Provider&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;ethers&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;providers&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Web3Provider&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="nx"&gt;particleProvider&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;any&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="p"&gt;);&lt;/span&gt;

      &lt;span class="c1"&gt;// highlight-start&lt;/span&gt;
      &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;validationModule&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;ECDSAOwnershipValidationModule&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;create&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
        &lt;span class="na"&gt;signer&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;web3Provider&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getSigner&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
        &lt;span class="na"&gt;moduleAddress&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;DEFAULT_ECDSA_OWNERSHIP_MODULE&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="p"&gt;});&lt;/span&gt;

      &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;biconomySmartAccount&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;BiconomySmartAccountV2&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;create&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
        &lt;span class="na"&gt;chainId&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;ChainId&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;BASE_GOERLI_TESTNET&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;bundler&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;bundler&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;paymaster&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;paymaster&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;entryPointAddress&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;DEFAULT_ENTRYPOINT_ADDRESS&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;defaultValidationModule&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;validationModule&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;activeValidationModule&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;validationModule&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="p"&gt;});&lt;/span&gt;

      &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;accountAddress&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;biconomySmartAccount&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getAccountAddress&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
      &lt;span class="c1"&gt;// highlight-end&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;catch &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
   &lt;span class="p"&gt;};&lt;/span&gt;


  &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;main&lt;/span&gt; &lt;span class="nx"&gt;className&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;styles&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;main&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;div&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;button&lt;/span&gt; &lt;span class="nx"&gt;onClick&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;login&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="nx"&gt;Login&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/button&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;      &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/div&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/main&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;  &lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Saving the provider and smart account to state
&lt;/h3&gt;

&lt;p&gt;Later in this tutorial, you will use the &lt;code&gt;provider&lt;/code&gt; and user’s &lt;code&gt;smartAccount&lt;/code&gt; to execute transactions on the deployed smart contract. Store the &lt;code&gt;provider&lt;/code&gt; and &lt;code&gt;smartAccount&lt;/code&gt; to React state so you can use it later.&lt;/p&gt;

&lt;p&gt;To store the &lt;code&gt;provider&lt;/code&gt; and &lt;code&gt;smartAccount&lt;/code&gt;, add the following code:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="p"&gt;...&lt;/span&gt;
&lt;span class="c1"&gt;// highlight-next-line&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;useState&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;react&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="p"&gt;...&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;Home&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;

  &lt;span class="c1"&gt;// highlight-start&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;loading&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;setLoading&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useState&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;provider&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;setProvider&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useState&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;smartAccount&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;setSmartAccount&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useState&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;address&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;setAddress&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useState&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;''&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="c1"&gt;// highlight-end&lt;/span&gt;
&lt;span class="p"&gt;...&lt;/span&gt;

  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;login&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nf"&gt;setLoading&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
      &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;userInfo&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;particle&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;auth&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;login&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
      &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;particleProvider&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;ParticleProvider&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;particle&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;auth&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
      &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;web3Provider&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;ethers&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;providers&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Web3Provider&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="nx"&gt;particleProvider&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;any&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="p"&gt;);&lt;/span&gt;

      &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;validationModule&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;ECDSAOwnershipValidationModule&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;create&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
        &lt;span class="na"&gt;signer&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;web3Provider&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getSigner&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
        &lt;span class="na"&gt;moduleAddress&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;DEFAULT_ECDSA_OWNERSHIP_MODULE&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="p"&gt;});&lt;/span&gt;


      &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;biconomySmartAccount&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;BiconomySmartAccountV2&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;create&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
        &lt;span class="na"&gt;chainId&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;ChainId&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;BASE_GOERLI_TESTNET&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;bundler&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;bundler&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;paymaster&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;paymaster&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;entryPointAddress&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;DEFAULT_ENTRYPOINT_ADDRESS&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;defaultValidationModule&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;validationModule&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;activeValidationModule&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;validationModule&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="p"&gt;});&lt;/span&gt;

      &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;accountAddress&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;biconomySmartAccount&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getAccountAddress&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
      &lt;span class="c1"&gt;// highlight-start&lt;/span&gt;
      &lt;span class="nf"&gt;setProvider&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;web3Provider&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
      &lt;span class="nf"&gt;setSmartAccount&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;biconomySmartAccount&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
      &lt;span class="nf"&gt;setAddress&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;accountAddress&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
      &lt;span class="nf"&gt;setLoading&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
      &lt;span class="c1"&gt;// highlight-end&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;catch &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
   &lt;span class="p"&gt;};&lt;/span&gt;

   &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;main&lt;/span&gt; &lt;span class="nx"&gt;className&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;styles&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;main&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;div&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="c1"&gt;// highlight-start&lt;/span&gt;
      &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;loading&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;address&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;button&lt;/span&gt; &lt;span class="nx"&gt;onClick&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;login&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="nx"&gt;Login&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/button&amp;gt;&lt;/span&gt;&lt;span class="err"&gt;}
&lt;/span&gt;      &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;loading&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;p&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="nx"&gt;Loading&lt;/span&gt;&lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/p&amp;gt;&lt;/span&gt;&lt;span class="err"&gt;}
&lt;/span&gt;      &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;address&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;h2&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="nx"&gt;Smart&lt;/span&gt; &lt;span class="nx"&gt;Account&lt;/span&gt; &lt;span class="na"&gt;Address&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;address&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/h2&amp;gt;&lt;/span&gt;&lt;span class="err"&gt;}
&lt;/span&gt;      &lt;span class="c1"&gt;// highlight-end&lt;/span&gt;
      &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/div&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/main&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;  &lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Info:&lt;/strong&gt; The code above is also updated to hide and display the login button and smart account address of the user, depending on if the user is logged in or not.&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  Executing a gasless transaction
&lt;/h2&gt;

&lt;p&gt;Now that the app is able to create smart accounts for each logged in user, lets provide the ability for a user to interact with the deployed smart contract.&lt;/p&gt;

&lt;h3&gt;
  
  
  Creating a Counter component
&lt;/h3&gt;

&lt;p&gt;To allow users to interact with the deployed &lt;code&gt;Counter&lt;/code&gt; smart contract, create a new directory named &lt;code&gt;src/components&lt;/code&gt; and create a new file named &lt;code&gt;Counter.tsx&lt;/code&gt; with the following content:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;use client&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;React&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;useState&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;useEffect&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;react&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;ethers&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;ethers&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;PaymasterMode&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@biconomy/paymaster&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;abi&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;../utils/abi.json&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;CONTRACT_ADDRESS&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;YOUR_CONTRACT_ADDRESS&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;Counter&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;smartAccount&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;provider&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;number&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;setNumber&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useState&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;contract&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;setContract&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useState&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="nf"&gt;useEffect&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;counterContract&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;ethers&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Contract&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;CONTRACT_ADDRESS&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;abi&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;provider&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nf"&gt;setContract&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;counterContract&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="p"&gt;[]);&lt;/span&gt;

  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;getNumber&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;currentNumber&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;contract&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;number&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="nf"&gt;setNumber&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;currentNumber&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;toNumber&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;
  &lt;span class="p"&gt;};&lt;/span&gt;

  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;increment&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;incrementTx&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;ethers&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;utils&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Interface&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;function increment()&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]);&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;data&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;incrementTx&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;encodeFunctionData&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;increment&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;transaction&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;to&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;CONTRACT_ADDRESS&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;data&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;};&lt;/span&gt;

    &lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;userOp&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;smartAccount&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;buildUserOp&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="nx"&gt;transaction&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="na"&gt;paymasterServiceData&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
          &lt;span class="na"&gt;mode&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;PaymasterMode&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;SPONSORED&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="p"&gt;},&lt;/span&gt;
      &lt;span class="p"&gt;});&lt;/span&gt;
      &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;userOpResponse&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;smartAccount&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;sendUserOp&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;userOp&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
      &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;transactionDetails&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;userOpResponse&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;wait&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
      &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Transaction details:&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;transactionDetails&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
      &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Transaction hash:&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;transactionDetails&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;receipt&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;transactionHash&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;catch &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Error executing transaction:&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;};&lt;/span&gt;

  &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="o"&gt;&amp;lt;&amp;gt;&lt;/span&gt;
      &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;div&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="nx"&gt;Current&lt;/span&gt; &lt;span class="nx"&gt;number&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;number&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/div&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;      &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;button&lt;/span&gt; &lt;span class="nx"&gt;onClick&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;increment&lt;/span&gt;&lt;span class="p"&gt;()}&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="nx"&gt;Increment&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/button&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;  &lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Info:&lt;/strong&gt; Replace the value of &lt;code&gt;CONTRACT_ADDRESS&lt;/code&gt; with the address for your deployed &lt;code&gt;Counter.sol&lt;/code&gt; contract.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h4&gt;
  
  
  Code explanation
&lt;/h4&gt;

&lt;p&gt;The code above is a simple React component that interacts with the deployed &lt;code&gt;Counter&lt;/code&gt; smart contract.&lt;/p&gt;

&lt;p&gt;A contract instance is initialized and stored in React state when the component first renders&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nf"&gt;useEffect&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;counterContract&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;ethers&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Contract&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;contractAddress&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;abi&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;provider&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="nf"&gt;setContract&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;counterContract&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="p"&gt;[]);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The component also has two functions called &lt;code&gt;getNumber&lt;/code&gt; and &lt;code&gt;increment&lt;/code&gt;. &lt;code&gt;getNumber&lt;/code&gt; reads the &lt;code&gt;number&lt;/code&gt; member variable of the smart contract, and &lt;code&gt;increment&lt;/code&gt; makes a call to the &lt;code&gt;increment&lt;/code&gt; function of the smart contract:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;getNumber&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;currentNumber&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;contract&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;number&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="nf"&gt;setNumber&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;currentNumber&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;toNumber&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;increment&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;incrementTx&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;ethers&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;utils&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Interface&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;function increment()&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]);&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;data&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;incrementTx&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;encodeFunctionData&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;increment&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;transaction&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;to&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;contractAddress&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;data&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;};&lt;/span&gt;

  &lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;userOp&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;smartAccount&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;buildUserOp&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="nx"&gt;transaction&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;paymasterServiceData&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="na"&gt;mode&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;PaymasterMode&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;SPONSORED&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="p"&gt;});&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;userOpResponse&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;smartAccount&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;sendUserOp&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;userOp&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;transactionDetails&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;userOpResponse&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;wait&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;catch &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Error executing transaction:&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Adding the contract ABI
&lt;/h3&gt;

&lt;p&gt;Initializing a contract instance requires the contract's &lt;a href="https://docs.soliditylang.org/en/latest/abi-spec.html" rel="noopener noreferrer"&gt;Application Binary Interface&lt;/a&gt; (ABI) to be provided. The code for the Counter component in the previous section imports a file called &lt;code&gt;abi.json&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;abi&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;../utils/abi.json&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This file does not exist yet, so you will need to add it.&lt;/p&gt;

&lt;p&gt;To add the ABI, create a new directory named &lt;code&gt;src/utils&lt;/code&gt; and create a new file named &lt;code&gt;abi.json&lt;/code&gt; with the following content:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"inputs"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"internalType"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"uint256"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"newNumber"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"uint256"&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"setNumber"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"outputs"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[],&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"stateMutability"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"nonpayable"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"function"&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"inputs"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[],&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"increment"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"outputs"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[],&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"stateMutability"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"nonpayable"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"function"&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"inputs"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[],&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"number"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"outputs"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"internalType"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"uint256"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;""&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"uint256"&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"stateMutability"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"view"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"function"&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Info:&lt;/strong&gt; If your deployed contract is verified, you can also get the ABI for the contract from &lt;a href="https://goerli.basescan.org/" rel="noopener noreferrer"&gt;BaseScan&lt;/a&gt;.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  Updating the Home component
&lt;/h3&gt;

&lt;p&gt;Now that the &lt;code&gt;Counter&lt;/code&gt; component has been created, add it to the Home component, and pass it the &lt;code&gt;provider&lt;/code&gt; and user's &lt;code&gt;smartAccount&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="p"&gt;...&lt;/span&gt;
&lt;span class="c1"&gt;// highlight-next-line&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;Counter&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@/component/Counter&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;Home&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;

&lt;span class="p"&gt;...&lt;/span&gt;

   &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;main&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;div&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;loading&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;address&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;button&lt;/span&gt; &lt;span class="nx"&gt;onClick&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;login&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="nx"&gt;Login&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/button&amp;gt;&lt;/span&gt;&lt;span class="err"&gt;}
&lt;/span&gt;      &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;loading&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;p&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="nx"&gt;Loading&lt;/span&gt;&lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/p&amp;gt;&lt;/span&gt;&lt;span class="err"&gt;}
&lt;/span&gt;      &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;address&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;h2&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="nx"&gt;Smart&lt;/span&gt; &lt;span class="nx"&gt;Account&lt;/span&gt; &lt;span class="na"&gt;Address&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;address&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/h2&amp;gt;&lt;/span&gt;&lt;span class="err"&gt;}
&lt;/span&gt;      &lt;span class="c1"&gt;// highlight-next-line&lt;/span&gt;
      &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;Counter&lt;/span&gt; &lt;span class="nx"&gt;smartAccount&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;smartAccount&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="nx"&gt;provider&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;provider&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="sr"&gt;/&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;      &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/div&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/main&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;  &lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Executing the transaction
&lt;/h3&gt;

&lt;p&gt;With all of the components set up, you are ready to run and test the app by logging in and executing a gasless transaction.&lt;/p&gt;

&lt;p&gt;Perform the following steps:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Run the application by running &lt;code&gt;yarn dev&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Click the Login button to login and create a smart account&lt;/li&gt;
&lt;li&gt;Once logged in, click the &lt;strong&gt;Increment&lt;/strong&gt; button to execute the &lt;code&gt;increment()&lt;/code&gt; function of the smart contract&lt;/li&gt;
&lt;li&gt;Upon a successful transaction, observe the number update.&lt;/li&gt;
&lt;/ol&gt;




&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;Congratulations! You have successfully learned how to implement Account Abstraction in your Base projects using Biconomy.&lt;/p&gt;

&lt;p&gt;To learn more about Account Abstraction and Biconomy, check out the following resources:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://docs.biconomy.io/" rel="noopener noreferrer"&gt;Biconomy Documentation&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://docs.base.org/tools/account-abstraction" rel="noopener noreferrer"&gt;Account Abstraction on Base&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>tutorial</category>
      <category>blockchain</category>
      <category>web3</category>
      <category>cryptocurrency</category>
    </item>
    <item>
      <title>Building an onchain app on Base using thirdweb</title>
      <dc:creator>Taylor Caldwell</dc:creator>
      <pubDate>Mon, 27 Jan 2025 04:28:22 +0000</pubDate>
      <link>https://dev.to/taycaldwell/building-an-onchain-app-on-base-using-thirdweb-2be3</link>
      <guid>https://dev.to/taycaldwell/building-an-onchain-app-on-base-using-thirdweb-2be3</guid>
      <description>&lt;p&gt;In this tutorial you will learn how to build an app on Base using the &lt;a href="https://portal.thirdweb.com/" rel="noopener noreferrer"&gt;thirdweb&lt;/a&gt; platform.&lt;/p&gt;

&lt;p&gt;To achieve this, you will deploy a smart contract for a NFT collection and create an NFT gallery app for viewing the metadata details of each NFT within the collection.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; This tutorial was originally published and authored by &lt;a href="https://x.com/taycaldwell" rel="noopener noreferrer"&gt;@taycaldwell&lt;/a&gt; on &lt;a href="https://docs.base.org" rel="noopener noreferrer"&gt;https://docs.base.org&lt;/a&gt;. You can find the original tutorial &lt;a href="https://docs.base.org/tutorials/build-with-thirdweb" rel="noopener noreferrer"&gt;here&lt;/a&gt;.&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  Objectives
&lt;/h2&gt;

&lt;p&gt;By the end of this tutorial, you should be able to:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Create an NFT collection and mint new NFTs using thirdweb.&lt;/li&gt;
&lt;li&gt;Develop an NFT gallery app using a prebuilt thirdweb templates.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Prerequisites
&lt;/h2&gt;

&lt;h3&gt;
  
  
  1. Setting Up a Coinbase Wallet
&lt;/h3&gt;

&lt;p&gt;To begin developing an app on Base, you first need to set up a web3 wallet. We recommend using the Coinbase Wallet, which can be easily created by downloading the Coinbase Wallet browser extension.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://chrome.google.com/webstore/detail/coinbase-wallet-extension/hnfanknocfeofbddgcijnmhnfnkdnaad?hl=en" rel="noopener noreferrer"&gt;Download Coinbase Wallet&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  2. Wallet Funding
&lt;/h3&gt;

&lt;p&gt;Blockchain transactions, including deploying smart contracts, necessitate a gas fee. Therefore, you will need to fund your wallet with ETH to cover those gas fees.&lt;/p&gt;

&lt;p&gt;For this tutorial, you will be deploying a contract to the Base Sepolia test network. You can fund your wallet with Base Sepolia ETH using one of the faucets listed on the Base &lt;a href="https://docs.base.org/tools/network-faucets" rel="noopener noreferrer"&gt;Network Faucets&lt;/a&gt; page.&lt;/p&gt;




&lt;h2&gt;
  
  
  Creating an NFT Collection
&lt;/h2&gt;

&lt;p&gt;Before developing an app, you need to create an NFT collection via thirdweb.&lt;/p&gt;

&lt;p&gt;Follow these steps to set up your NFT collection:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Visit the &lt;a href="https://thirdweb.com/dashboard" rel="noopener noreferrer"&gt;thirdweb dashboard&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;Click the &lt;strong&gt;Connect Wallet&lt;/strong&gt; button located in the upper right corner to connect your wallet.&lt;/li&gt;
&lt;li&gt;From the dashboard, select &lt;strong&gt;&lt;a href="https://thirdweb.com/explore" rel="noopener noreferrer"&gt;Browse contracts&lt;/a&gt;&lt;/strong&gt; to explore a list of deployable smart contracts.&lt;/li&gt;
&lt;li&gt;Navigate to the &lt;strong&gt;NFTs&lt;/strong&gt; section and select the &lt;strong&gt;&lt;a href="https://thirdweb.com/thirdweb.eth/TokenERC721" rel="noopener noreferrer"&gt;NFT Collection&lt;/a&gt;&lt;/strong&gt; smart contract.&lt;/li&gt;
&lt;li&gt;Click the &lt;strong&gt;Deploy now&lt;/strong&gt; button.&lt;/li&gt;
&lt;li&gt;Provide the required details for your NFT collection:

&lt;ol&gt;
&lt;li&gt;Contract metadata (i.e. image, name, symbol, description)&lt;/li&gt;
&lt;li&gt;Network (Choose &lt;strong&gt;Base Sepolia Testnet&lt;/strong&gt;)&lt;/li&gt;
&lt;/ol&gt;


&lt;/li&gt;

&lt;li&gt;Click &lt;strong&gt;Deploy Now&lt;/strong&gt;.&lt;/li&gt;

&lt;/ol&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F2vrpnfxnoiqxxzzfuw4c.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F2vrpnfxnoiqxxzzfuw4c.png" alt="Thirdweb Deploy Contract" width="800" height="1489"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Info:&lt;/strong&gt; For production / mainnet deployments select &lt;code&gt;Base&lt;/code&gt; (mainnet) as the network rather than &lt;code&gt;Base Sepolia&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Post-deployment, you can manage your smart contract via the &lt;a href="https://thirdweb.com/dashboard/contracts" rel="noopener noreferrer"&gt;thirdweb dashboard&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Currently, your NFT Collection lacks NFTs. To populate our upcoming NFT Gallery app, we will need to create several NFTs.&lt;/p&gt;

&lt;p&gt;Follow the steps below to mint new NFTs:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Visit the &lt;a href="https://thirdweb.com/dashboard" rel="noopener noreferrer"&gt;thirdweb dashboard&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;From the dashboard, select &lt;strong&gt;&lt;a href="https://thirdweb.com/dashboard/contracts" rel="noopener noreferrer"&gt;View contracts&lt;/a&gt;&lt;/strong&gt; to view all your previously deployed contracts.&lt;/li&gt;
&lt;li&gt;Select the NFT Collection smart contract you deployed.&lt;/li&gt;
&lt;li&gt;Navigate to the &lt;strong&gt;NFTs&lt;/strong&gt; tab on the left-hand sidebar.&lt;/li&gt;
&lt;li&gt;Click &lt;strong&gt;Mint&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Fill in the metadata details for the NFT (name, media, description, properties).&lt;/li&gt;
&lt;li&gt;Click &lt;strong&gt;Mint NFT&lt;/strong&gt;.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Repeat these steps to mint as many NFTs as you'd like.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F6nnvab3h97css5ggilju.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F6nnvab3h97css5ggilju.png" alt="Thirdweb Mint NFT" width="800" height="1195"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  Building an NFT Gallery App
&lt;/h2&gt;

&lt;p&gt;With an NFT Collection in place, it's time to construct an NFT Gallery App. The &lt;a href="https://portal.thirdweb.com/cli" rel="noopener noreferrer"&gt;thirdweb CLI&lt;/a&gt; provides various prebuilt and starter &lt;a href="https://portal.thirdweb.com/templates" rel="noopener noreferrer"&gt;templates&lt;/a&gt; for popular app use-cases, which can significantly expedite your app development process.&lt;/p&gt;

&lt;p&gt;In this tutorial, we'll use the &lt;a href="https://portal.thirdweb.com/cli" rel="noopener noreferrer"&gt;thirdweb CLI&lt;/a&gt; to generate a new app project using the &lt;a href="https://github.com/thirdweb-example/nft-gallery" rel="noopener noreferrer"&gt;NFT Gallery template&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Run the following command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npx thirdweb create &lt;span class="nt"&gt;--template&lt;/span&gt; nft-gallery
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;By default, the template is configured for an NFT collection on the Ethereum Mainnet. We will modify the code to adapt our NFT collection on the Base Sepolia Testnet.&lt;/p&gt;

&lt;p&gt;Follow these steps to update the template:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Open the project using your preferred code editor.&lt;/li&gt;
&lt;li&gt;Open the &lt;code&gt;src/consts/parameters.ts&lt;/code&gt; file.

&lt;ol&gt;
&lt;li&gt;Update the &lt;code&gt;contractAddress&lt;/code&gt; variable to your NFT collection's contract address (found on the thirdweb dashboard).&lt;/li&gt;
&lt;li&gt;Update the &lt;code&gt;chain&lt;/code&gt; variable to &lt;code&gt;base-sepolia&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Update the &lt;code&gt;blockExplorer&lt;/code&gt; variable to &lt;code&gt;https://sepolia.basescan.org&lt;/code&gt;.&lt;/li&gt;
&lt;/ol&gt;


&lt;/li&gt;

&lt;li&gt;Open the &lt;code&gt;src/main.tsx&lt;/code&gt; file.&lt;/li&gt;

&lt;li&gt;Replace the file contents with the following code:
&lt;/li&gt;

&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;    &lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;React&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;react&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;ReactDOM&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;react-dom/client&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;App&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;./App&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;./index.css&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;ThirdwebProvider&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;@thirdweb-dev/react&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;BaseSepoliaTestnet&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;@thirdweb-dev/chains&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;


&lt;span class="nx"&gt;ReactDOM&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;createRoot&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getElementById&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;root&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nx"&gt;HTMLElement&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;render&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;React&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;StrictMode&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;ThirdwebProvider&lt;/span&gt; &lt;span class="nx"&gt;activeChain&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;BaseSepoliaTestnet&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;App&lt;/span&gt; &lt;span class="o"&gt;/&amp;gt;&lt;/span&gt;
    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/ThirdwebProvider&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;  &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/React.StrictMode&amp;gt;&lt;/span&gt;&lt;span class="err"&gt;,
&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The above code imports and uses &lt;code&gt;BaseSepoliaTestnet&lt;/code&gt; to be the &lt;code&gt;activeChain&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Info:&lt;/strong&gt; For production / mainnet deployments, update the information above so that the &lt;code&gt;chain&lt;/code&gt; variable is &lt;code&gt;base&lt;/code&gt; (step ii), the &lt;code&gt;blockExplorer&lt;/code&gt; is &lt;code&gt;https://basescan.org&lt;/code&gt; (step iii), and update both instances of &lt;code&gt;BaseSepoliaTestnet&lt;/code&gt; to &lt;code&gt;Base&lt;/code&gt; in the example javascript code.&lt;/p&gt;




&lt;h2&gt;
  
  
  Running the Application
&lt;/h2&gt;

&lt;p&gt;With the updated Base Sepolia Testnet chain and your NFT collection's address, you can view your NFT collection from the application.&lt;/p&gt;

&lt;p&gt;To start the application, run the following command from the root directory:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;yarn dev
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;Congratulations on reaching the end of this tutorial! You've now learned how to create an NFT collection using Thirdweb, mint new NFTs, and build an NFT gallery app on the Base blockchain!&lt;/p&gt;

&lt;p&gt;As a next step, check out other prebuilt &lt;a href="https://thirdweb.com/explore" rel="noopener noreferrer"&gt;smart contracts&lt;/a&gt; and starter &lt;a href="https://portal.thirdweb.com/templates" rel="noopener noreferrer"&gt;templates&lt;/a&gt; provided by the &lt;a href="https://portal.thirdweb.com" rel="noopener noreferrer"&gt;thirdweb&lt;/a&gt; platform that can help you build your next onchain app on Base.&lt;/p&gt;




</description>
      <category>tutorial</category>
      <category>cryptocurrency</category>
      <category>blockchain</category>
      <category>web3</category>
    </item>
    <item>
      <title>Running a Base Node</title>
      <dc:creator>Taylor Caldwell</dc:creator>
      <pubDate>Mon, 27 Jan 2025 04:28:12 +0000</pubDate>
      <link>https://dev.to/taycaldwell/running-a-base-node-4cd1</link>
      <guid>https://dev.to/taycaldwell/running-a-base-node-4cd1</guid>
      <description>&lt;p&gt;This tutorial will walk you through setting up your own &lt;a href="https://github.com/base-org/node" rel="noopener noreferrer"&gt;Base Node&lt;/a&gt;.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; This tutorial was originally published and authored by &lt;a href="https://x.com/taycaldwell" rel="noopener noreferrer"&gt;@taycaldwell&lt;/a&gt; on &lt;a href="https://docs.base.org" rel="noopener noreferrer"&gt;https://docs.base.org&lt;/a&gt;. You can find the original tutorial &lt;a href="https://docs.base.org/tutorials/run-a-base-node" rel="noopener noreferrer"&gt;here&lt;/a&gt;.&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  Objectives
&lt;/h2&gt;

&lt;p&gt;By the end of this tutorial you should be able to:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Deploy and sync a Base node&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Prerequisites
&lt;/h2&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Caution:&lt;/strong&gt; Running a node is time consuming, resource expensive, and potentially costly. If you don't already know why you want to run your own node, you probably don't need to.&lt;/p&gt;

&lt;p&gt;If you're just getting started and need an RPC URL, you can use our free endpoints:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Mainnet&lt;/strong&gt;: &lt;code&gt;https://mainnet.base.org&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Testnet (Sepolia)&lt;/strong&gt;: &lt;code&gt;https://sepolia.base.org&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; Our RPCs are rate-limited, they are not suitable for production apps.&lt;/p&gt;

&lt;p&gt;If you're looking to harden your app and avoid rate-limiting for your users, please check out one of our &lt;a href="https://dev.to/docs/tools/node-providers"&gt;partners&lt;/a&gt;.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  Hardware requirements
&lt;/h3&gt;

&lt;p&gt;We recommend you have this configuration to run a node:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;8-Core CPU&lt;/li&gt;
&lt;li&gt;at least 16 GB RAM&lt;/li&gt;
&lt;li&gt;a locally attached NVMe SSD drive&lt;/li&gt;
&lt;li&gt;adequate storage capacity to accommodate both the snapshot restoration process (if restoring from snapshot) and chain data, ensuring a minimum of (2 * current_chain_size) + snapshot_size + 20%_buffer&lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Info:&lt;/strong&gt; If utilizing Amazon Elastic Block Store (EBS), ensure timing buffered disk reads are fast enough in order to avoid latency issues alongside the rate of new blocks added to Base during the initial synchronization process; &lt;code&gt;io2 block express&lt;/code&gt; is recommended.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  Docker
&lt;/h3&gt;

&lt;p&gt;This tutorial assumes you are familiar with &lt;a href="https://www.docker.com/" rel="noopener noreferrer"&gt;Docker&lt;/a&gt; and have it running on your machine.&lt;/p&gt;

&lt;h3&gt;
  
  
  L1 RPC URL
&lt;/h3&gt;

&lt;p&gt;You'll need your own L1 RPC URL. This can be one that you run yourself, or via a third-party provider, such as our &lt;a href="https://dev.to/docs/tools/node-providers"&gt;partners&lt;/a&gt;.&lt;/p&gt;




&lt;h2&gt;
  
  
  Running a Node
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;Clone the &lt;a href="https://github.com/base-org/node" rel="noopener noreferrer"&gt;repo&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;Ensure you have an Ethereum L1 full node RPC available (not Base), and set &lt;code&gt;OP_NODE_L1_ETH_RPC&lt;/code&gt; &amp;amp; &lt;code&gt;OP_NODE_L1_BEACON&lt;/code&gt; (in the &lt;code&gt;.env.*&lt;/code&gt; file if using &lt;code&gt;docker-compose&lt;/code&gt;). If running your own L1 node, it needs to be synced before Base will be able to fully sync.&lt;/li&gt;
&lt;li&gt;Uncomment the line relevant to your network (&lt;code&gt;.env.sepolia&lt;/code&gt;, or &lt;code&gt;.env.mainnet&lt;/code&gt;) under the 2 &lt;code&gt;env_file&lt;/code&gt; keys in &lt;code&gt;docker-compose.yml&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Run &lt;code&gt;docker compose up&lt;/code&gt;. Confirm you get a response from:
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl &lt;span class="nt"&gt;-d&lt;/span&gt; &lt;span class="s1"&gt;'{"id":0,"jsonrpc":"2.0","method":"eth_getBlockByNumber","params":["latest",false]}'&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-H&lt;/span&gt; &lt;span class="s2"&gt;"Content-Type: application/json"&lt;/span&gt; http://localhost:8545
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Caution:&lt;/strong&gt; Syncing your node may take &lt;strong&gt;days&lt;/strong&gt; and will consume a vast amount of your requests quota. Be sure to monitor usage and up your plan if needed.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  Snapshots
&lt;/h3&gt;

&lt;p&gt;If you're a prospective or current Base Node operator and would like to restore from a snapshot to save time on the initial sync, it's possible to always get the latest available snapshot of the Base chain on mainnet and/or testnet by using the following CLI commands. The snapshots are updated every week.&lt;/p&gt;

&lt;h4&gt;
  
  
  Restoring from snapshot
&lt;/h4&gt;

&lt;p&gt;In the home directory of your Base Node, create a folder named &lt;code&gt;geth-data&lt;/code&gt; or &lt;code&gt;reth-data&lt;/code&gt;. If you already have this folder, remove it to clear the existing state and then recreate it. Next, run the following code and wait for the operation to complete.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Info:&lt;/strong&gt; Public Geth Archive Snapshots were deprecated on &lt;em&gt;December 15th, 2024&lt;/em&gt; and recommend switching to Reth going forward. We will continue to maintain the Reth archive snapshot.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Network&lt;/th&gt;
&lt;th&gt;Client&lt;/th&gt;
&lt;th&gt;Snapshot Type&lt;/th&gt;
&lt;th&gt;Command&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Testnet&lt;/td&gt;
&lt;td&gt;Geth&lt;/td&gt;
&lt;td&gt;Full&lt;/td&gt;
&lt;td&gt;&lt;code&gt;wget https://sepolia-full-snapshots.base.org/$(curl https://sepolia-full-snapshots.base.org/latest)&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Testnet&lt;/td&gt;
&lt;td&gt;Geth&lt;/td&gt;
&lt;td&gt;Archive&lt;/td&gt;
&lt;td&gt;No longer supported&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Testnet&lt;/td&gt;
&lt;td&gt;Reth&lt;/td&gt;
&lt;td&gt;Archive&lt;/td&gt;
&lt;td&gt;&lt;code&gt;wget https://sepolia-reth-archive-snapshots.base.org/$(curl https://sepolia-reth-archive-snapshots.base.org/latest)&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Mainnet&lt;/td&gt;
&lt;td&gt;Geth&lt;/td&gt;
&lt;td&gt;Full&lt;/td&gt;
&lt;td&gt;&lt;code&gt;wget https://mainnet-full-snapshots.base.org/$(curl https://mainnet-full-snapshots.base.org/latest)&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Mainnet&lt;/td&gt;
&lt;td&gt;Geth&lt;/td&gt;
&lt;td&gt;Archive&lt;/td&gt;
&lt;td&gt;No longer supported&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Mainnet&lt;/td&gt;
&lt;td&gt;Reth&lt;/td&gt;
&lt;td&gt;Archive&lt;/td&gt;
&lt;td&gt;&lt;code&gt;wget https://mainnet-reth-archive-snapshots.base.org/$(curl https://mainnet-reth-archive-snapshots.base.org/latest)&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;You'll then need to untar the downloaded snapshot and place the &lt;code&gt;geth&lt;/code&gt; or &lt;code&gt;reth&lt;/code&gt; subfolder inside of it in the &lt;code&gt;geth-data&lt;/code&gt; or &lt;code&gt;reth-data&lt;/code&gt; folder you created (unless you changed the location of your data directory).&lt;/p&gt;

&lt;p&gt;Return to the root of your Base node folder and start your node.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;cd ..
docker compose up --build
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Your node should begin syncing from the last block in the snapshot.&lt;/p&gt;

&lt;p&gt;Check the latest block to make sure you're syncing from the snapshot and that it restored correctly. If so, you can remove the snapshot archive that you downloaded.&lt;/p&gt;

&lt;h3&gt;
  
  
  Syncing
&lt;/h3&gt;

&lt;p&gt;You can monitor the progress of your sync with:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;echo &lt;/span&gt;Latest synced block behind by: &lt;span class="k"&gt;$((&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;&lt;span class="nb"&gt;date&lt;/span&gt; +%s&lt;span class="si"&gt;)&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  curl &lt;span class="nt"&gt;-d&lt;/span&gt; &lt;span class="s1"&gt;'{"id":0,"jsonrpc":"2.0","method":"optimism_syncStatus"}'&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-H&lt;/span&gt; &lt;span class="s2"&gt;"Content-Type: application/json"&lt;/span&gt; http://localhost:7545 | &lt;span class="se"&gt;\&lt;/span&gt;
  jq &lt;span class="nt"&gt;-r&lt;/span&gt; .result.unsafe_l2.timestamp&lt;span class="si"&gt;)&lt;/span&gt;&lt;span class="o"&gt;)/&lt;/span&gt;&lt;span class="m"&gt;60&lt;/span&gt;&lt;span class="k"&gt;))&lt;/span&gt; minutes
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You'll also know that the sync hasn't completed if you get &lt;code&gt;Error: nonce has already been used&lt;/code&gt; if you try to deploy using your node.&lt;/p&gt;




</description>
      <category>tutorial</category>
      <category>blockchain</category>
      <category>web3</category>
      <category>cryptocurrency</category>
    </item>
  </channel>
</rss>
