> ## Documentation Index
> Fetch the complete documentation index at: https://docs.chainstack.com/llms.txt
> Use this file to discover all available pages before exploring further.

<AgentInstructions>

## Submitting Feedback

If you encounter incorrect, outdated, or confusing documentation on this page, submit feedback:

POST https://docs.chainstack.com/feedback

```json
{
  "path": "/docs/arbitrum-tutorial-l1-to-l2-messaging-smart-contract",
  "feedback": "Description of the issue"
}
```

Only submit feedback when you have something specific and actionable to report.

</AgentInstructions>

# Arbitrum: L1 to L2 messaging smart contract

> Send cross-chain messages from Ethereum L1 to Arbitrum L2 using the Arbitrum SDK and Chainstack nodes with a smart contract deployed via Hardhat.

<Warning>
  ### Deprecation notice

  As the Goerli testnet has been deprecated, this guide is for historical reference.
</Warning>

Sending a message from the Ethereum chain (L1) to the Arbitrum chain (L2) does not involve the state challenge period and is as fast as the block confirmation time on L1 and L2 combined.

In this tutorial, you will:

* Deploy greeter contracts on Ethereum and on Arbitrum.
* Send a message from the greeter contract deployed on Ethereum (L1) to the greeter contract deployed on Arbitrum (L2).

## Prerequisites

* [Chainstack account](https://console.chainstack.com/) to deploy a [reliable Arbitrum RPC endpoint](https://chainstack.com/build-better-with-arbitrum/).
* [MetaMask](https://metamask.io/) to fund your account on L2 with GoerliETH.

## Overview

To get from zero to your first L1 to L2 message, do the following:

1. With Chainstack, create a public chain project.
2. With Chainstack, join the Ethereum Goerli testnet.
3. With Chainstack, join the Arbitrum Goerli testnet.
4. Set up your MetaMask to work through the Chainstack Ethereum and Arbitrum nodes.
5. Fund your account through a faucet on the Ethereum Goerli testnet and on the Arbitrum Goerli testnet.
6. Run the tutorial script to deploy the contracts on L1 and L2 and send the message from L1 to L2.

## Step-by-step

### Create a public chain project

See [Create a project](/docs/manage-your-project#create-a-project).

### Join the Ethereum and Arbitrum Goerli testnets

Deploy a node on the Ethereum Goerli testnet and a node on the Arbitrum Goerli testnet.

See [Join a public network](/docs/manage-your-networks).

### Get the access and credentials to your deployed nodes

See [View node access and credentials](/docs/manage-your-node#view-node-access-and-credentials).

### Set up MetaMask

See [Arbitrum tooling: MetaMask](/docs/arbitrum-tooling#metamask).

### Fund your account

Your account will need Goerli ether on both the Ethereum Goerli testnet and the Arbitrum Goerli testnet as you will deploy a contract on each of the chains.

* Ethereum Goerli faucet
* Arbitrum Goerli faucet: see [Nitro Goerli Rollup](https://developer.offchainlabs.com/public-chains) in the Arbitrum documentation

The default Arbitrum Goerli faucet may fund your account with 0.001 GoerliETH, which is not enough to deploy the greeter contract on L2.

If you do not have enough GoerliETH on L2, you may bridge some more from the Ethereum Goerli testnet using the [Arbitrum bridge](https://bridge.arbitrum.io/).

### Clone and prepare the tutorials repository

You will use the [Offchain Labs tutorials repository](https://github.com/OffchainLabs/arbitrum-tutorials) to deploy the contracts and send the message.

Clone the repository:

<CodeGroup>
  ```bash Shell theme={"system"}
  git clone https://github.com/OffchainLabs/arbitrum-tutorials.git
  ```
</CodeGroup>

Change to `arbitrum-tutorials/packages/greeter`.

Install dependencies by running `yarn`.

Set up the `.env` file by renaming the sample one in `arbitrum-tutorials/packages/greeter`:

<CodeGroup>
  ```bash Shell theme={"system"}
  cp .env-sample .env
  ```
</CodeGroup>

In the `.env` file, add your account key and the endpoints:

* DEVNET\_PRIVKEY — the private key of your account that has GoerliETH both on the Ethereum Goerli testnet and the Arbitrum Goerli testnet.
* L2RPC — the Chainstack HTTPS endpoint of your Arbitrum node deployed on the Arbitrum Goerli testnet.
* L1RPC — the Chainstack HTTPS endpoint of your Ethereum node deployed on the Ethereum Goerli testnet.

Example:

<CodeGroup>
  ```env env theme={"system"}
  DEVNET_PRIVKEY=YOUR_DEVNET_PRIVATE_KEY
  L2RPC=YOUR_CHAINSTACK_ENDPOINT
  L1RPC=YOUR_CHAINSTACK_ENDPOINT
  ```
</CodeGroup>

### Deploy the contract and send the message from L1 to L2

You are now all set to run the tutorial script that will deploy the greeter contracts and send a message from L1 to L2.

In `arbitrum-tutorials/packages/greeter`, run:

<CodeGroup>
  ```bash Shell theme={"system"}
  yarn run greeter
  ```
</CodeGroup>

The script will:

* Deploy the L1 greeter contract on the Ethereum Goerli testnet. Example: [0x9B4F541D6A82Beb594Ee2A1EfF14d88f2898176c](https://goerli.etherscan.io/address/0x9B4F541D6A82Beb594Ee2A1EfF14d88f2898176c).
* Deploy the L2 greeter contract on the Arbitrum Goerli testnet. Example: [0x890443aB733bd527F0036aEd3E249358a30Ff3ce](https://goerli-rollup-explorer.arbitrum.io/address/0x890443aB733bd527F0036aEd3E249358a30Ff3ce).
* On the L1 contract, [set the L2 contract address](https://goerli.etherscan.io/tx/0xbd20609976a96ce791eae71dae0e87a254f542eab1ab400ce8b4681cc4f6b5aa).
* On the L2 contract, [set the L1 contract address](https://goerli-rollup-explorer.arbitrum.io/tx/0x98dcfec500561985cdaf0f3933f1b361b3106edc055e0a2644c0f67396596d42/internal-transactions).
* Retrieve the current gas costs for the transaction off the [ArbRetryableTx contract on L2](https://goerli-rollup-explorer.arbitrum.io/address/0x000000000000000000000000000000000000006E/read-contract#address-tabs). See also Arbitrum documentation: [Messaging Between Layers](https://developer.offchainlabs.com/arbos/l1-to-l2-messaging).
* Using the retrieved gas cost values, [submit the message transaction on L1](https://goerli.etherscan.io/tx/0xa39ecbb53844d009dc121825c26b0608def2c4117d81a6ebeb6000fcf304ac9e). The transaction will send the message to the [inbox contract on L1](https://goerli.etherscan.io/address/0x6BEbC4925716945D46F0Ec336D5C2564F419682C#readProxyContract). See also Arbitrum documentation: [Contract addresses](https://developer.offchainlabs.com/useful-addresses).
* The transaction will then be submitted as a retryable ticket by the [ArbRetryableTx contract on L2](https://goerli-rollup-explorer.arbitrum.io/address/0x000000000000000000000000000000000000006E/). [Example](https://goerli-rollup-explorer.arbitrum.io/tx/0xac1f89c9d449145aaa6a715bfb7a678009654191b379c03d20bd0a27b8f6968f).
* Then the retryable ticket will be redeemed and change the state in the greeter contract on L2 with the message from the greeter contract on L1. [Example](https://goerli-rollup-explorer.arbitrum.io/tx/0x6c8dd56c1ef93064b7b219154327361c051588dfadf716cc23e9d5e3ed610814).

## Conclusion

This tutorial guided you through the basics of creating and deploying a simple greeter contract that sends a message from the Ethereum chain to the Arbitrum chain. The tutorial also provided the examples and an explanation of the step-by-step state changes and the contracts involved in the L1 to L2 messaging.

### About the author

<CardGroup>
  <Card title="Ake">
    <img src="https://mintcdn.com/chainstack/UN3rP7zhB69idvnC/images/docs/profile_images/1719912994363326464/8_Bi4fdM_400x400.jpg?fit=max&auto=format&n=UN3rP7zhB69idvnC&q=85&s=792a24ab1b4682406fa589c0ecd88e5d" alt="Ake" style={{width: '80px', height: '80px', borderRadius: '50%', objectFit: 'cover', display: 'block', margin: '0 auto'}} noZoom width="400" height="400" data-path="images/docs/profile_images/1719912994363326464/8_Bi4fdM_400x400.jpg" />

    <Icon icon="code" iconType="solid" /> Director of Developer Experience @ Chainstack
    <br /><Icon icon="screwdriver-wrench" iconType="solid" /> Talk to me all things Web3
    <br />20 years in technology | 8+ years in Web3 full time years experience

    <div style={{display: "flex", justifyContent: "center", gap: "12px"}}>
      <a href="https://github.com/akegaviar/" style={{textDecoration: "none", borderBottom: "none"}}>
        <Icon icon="github" iconType="brands" />
      </a>

      <a href="https://twitter.com/akegaviar" style={{textDecoration: "none", borderBottom: "none"}}>
        <Icon icon="twitter" iconType="brands" />
      </a>

      <a href="https://www.linkedin.com/in/ake/" style={{textDecoration: "none", borderBottom: "none"}}>
        <Icon icon="linkedin" iconType="brands" />
      </a>
    </div>
  </Card>
</CardGroup>
