Skip to content

Commit

Permalink
docs: add Foundry era test node tutorial (#87)
Browse files Browse the repository at this point in the history
- add tutorial for using era_test_node with Foundry to call swap router
contract for Uniswap
  • Loading branch information
bxpana authored Oct 2, 2024
1 parent 9d4dcdd commit 5e61a18
Show file tree
Hide file tree
Showing 2 changed files with 319 additions and 0 deletions.
290 changes: 290 additions & 0 deletions content/tutorials/foundry-era-test-node/10.index.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,290 @@
---
title: Interacting with Uniswap on a Fork of ZKsync Era Using era_test_node and Foundry
description: A step-by-step guide to set up a fork of ZKsync Era mainnet and interact with the Uniswap contract to perform token swaps using Foundry.
---

This tutorial shows you how to set up a local ZKsync Era environment using `era_test_node`,
leverage Foundry's `cast` tool to interact with contracts, and perform token swaps on Uniswap.
You'll learn how to:

1. Set up your development environment.
2. Streamline your workflow with environment variables.
3. Check balances using `cast call`.
4. Deposit ETH for WETH.
5. Transfer WETH to another address.
6. Swap WETH for an ERC20 token on Uniswap.

Let's get started!

---

## Prerequisites

- **Foundry**: Ethereum development toolkit. [Installation Guide](https://book.getfoundry.sh/getting-started/installation)
- **era_test_node**: In-memory node to fork ZKsync Era mainnet. [Installation Guide](https://docs.zksync.io/build/test-and-debug/in-memory-node#install-and-set-up-era_test_node)
- **Online Converters**:
- [ETH Converter](https://eth-converter.com/) for converting ETH values.
- [Hex to Decimal Converter](https://www.rapidtables.com/convert/number/hex-to-decimal.html) for number conversions.
- **ZKsync Era Explorer**:
- [ZKsync Era Explorer](https://era.zksync.io/) to view contracts.
- [Tokens List](https://explorer.zksync.io/tokens) to find token addresses.
- **Uniswap Pool Explorer**:
- [Uniswap Pools on ZKsync Era](https://app.uniswap.org/explore/pools/zksync) to find pools for swapping.
- **Price Conversion Tool**:
- [Kraken Convert](https://www.kraken.com/convert) to get current exchange rates.

::callout{icon="i-heroicons-exclamation-triangle"}
**Security Tip**: Never commit your private key to version control or share it publicly.
Ensure your `.env` file is excluded from source control. `.env` should be used for
development purposes only, see the [foundry keystore](https://docs.zksync.io/build/tooling/foundry/installation#private-key-setup-with-foundry-keystore)
section of the docs for a more secure way to manage your private keys.

::

---

## 1. Setting Up the Environment

### Fork ZKsync Era Mainnet

Start `era_test_node` and fork ZKsync Era mainnet:

```bash
era_test_node fork mainnet
```

For debug mode (provides more transaction details and requires version `v0.1.0-alpha.27` or higher):

```bash
era_test_node -d fork mainnet
```

---

## 2. Streamlining with Environment Variables

Create a new project directory and a `.env` file in your project directory to store environment variables:

```bash
ETH_RPC_URL=http://localhost:8011
PRIVATE_KEY=rich_wallet_private_key_here
ETH_GAS_LIMIT=10000000 # Optional
WETH=0x5AEa5775959fBC2557Cc8789bC1bf90A239D9a91
MY_ADDRESS=address_of_the_rich_wallet
SWAP_ROUTER=0x99c56385daBCE3E81d8499d0b8d0257aBC07E8A3
```

- **ETH_RPC_URL**: The URL of your local `era_test_node` instance.
- **PRIVATE_KEY**: One of the private keys from the `era_test_node` accounts.
- **ETH_GAS_LIMIT**: Optional gas limit for transactions.
- **WETH**: [WETH token address on ZKsync Era](https://era.zksync.network/address/0x5AEa5775959fBC2557Cc8789bC1bf90A239D9a91).
- **MY_ADDRESS**: The address of the rich wallet private key.
- **SWAP_ROUTER**: [Uniswap Swap Router contract address on ZKsync Era](https://docs.uniswap.org/contracts/v3/reference/deployments/ZKsync-deployments).

Run the following in your terminal in your project directory to load the environment variables:

```bash
source .env
```

::callout{icon="i-heroicons-exclamation-triangle"}
**Security Tip**: Never commit your private key to version control or share it publicly.
Ensure your `.env` file is excluded from source control. `.env` should be used for
development purposes only, see the [foundry keystore](https://docs.zksync.io/build/tooling/foundry/installation#private-key-setup-with-foundry-keystore)
section of the docs for a more secure way to manage your private keys.
::

---

## 3. Checking Balances

To check the ETH balance of an address:

```bash
cast balance $MY_ADDRESS
```

---

## 4. Depositing ETH for WETH

Deposit ETH and receive WETH by interacting with the WETH contract:

```bash
cast send $WETH "deposit()" --value 500000000000000000 --private-key $PRIVATE_KEY
```

- **Function**: `deposit()`
- **Value**: Amount of ETH to deposit (in wei). For example, `0.5 ETH` is `500000000000000000 wei`.

### Verify Your WETH Balance

Check your WETH balance:

```bash
cast call $WETH "balanceOf(address)(uint256)" $MY_ADDRESS
```

---

## 5. Transferring WETH

To transfer WETH to another address:

```bash
cast send $WETH "transfer(address,uint256)" <RECIPIENT_ADDRESS> <AMOUNT_TO_TRANSFER> --private-key $PRIVATE_KEY
```

- **`<RECIPIENT_ADDRESS>`**: The address to send WETH to.
- **`<AMOUNT_TO_TRANSFER>`**: Amount of WETH to transfer (in wei).

::callout{icon="i-heroicons-light-bulb"}
**Check**: Use `cast call` to verify the transfer.
::

---

## 6. Approving WETH for Swapping

Before swapping WETH on Uniswap, approve the Swap Router to spend your WETH:

```bash
cast send $WETH "approve(address,uint256)" $SWAP_ROUTER <AMOUNT_TO_APPROVE> --private-key $PRIVATE_KEY
```

- **`<AMOUNT_TO_APPROVE>`**: The amount of WETH you plan to swap (in wei).

---

## 7. Selecting an ERC20 Token and Swap Pair

### Find an ERC20 Token

- Use the [ZKsync Era Tokens List](https://explorer.zksync.io/tokens) to choose an ERC20 token.
- Set the ERC20 token address in your `.env` file:

```bash
ERC20=ERC20_TOKEN_ADDRESS_HERE
```

### Find the Uniswap Pool and Fee Tier

- Visit the [Uniswap Pools Explorer](https://app.uniswap.org/explore/pools/zksync) to find a pool for your token pair.
- Note the **fee tier** of the pool (e.g., `3000` for 0.3% fee).
- Set the fee in your `.env` file:

```bash
FEE=FEE_TIER_HERE
```

---

## 8. Swapping WETH for an ERC20 Token

We'll use the `exactInputSingle` function from the Uniswap Swap Router contract. This function accepts a struct as a parameter.

### `exactInputSingle` Function Details

```solidity
function exactInputSingle(ExactInputSingleParams calldata params)
external
payable
returns (uint256 amountOut);
```

**Struct Definition:**

```solidity
struct ExactInputSingleParams {
address tokenIn; // Token you're swapping from
address tokenOut; // Token you're swapping to
uint24 fee; // Fee tier of the pool
address recipient; // Address to receive output tokens
uint256 amountIn; // Amount of input tokens to swap
uint256 amountOutMinimum; // Minimum amount of output tokens to receive
uint160 sqrtPriceLimitX96; // Price limit for the swap (optional)
}
```

### Update the environment variables

Your `.env` file should now have the following variables:

```bash
ETH_RPC_URL=http://localhost:8011
PRIVATE_KEY=rich_wallet_private_key_here
ETH_GAS_LIMIT=10000000 # Optional
WETH=0x5AEa5775959fBC2557Cc8789bC1bf90A239D9a91
MY_ADDRESS=your_wallet_address_here
SWAP_ROUTER=0x99c56385daBCE3E81d8499d0b8d0257aBC07E8A3
ERC20=ERC20_TOKEN_ADDRESS_HERE
FEE=FEE_TIER_HERE
AMOUNT_IN=AMOUNT_OF_WETH_TO_SWAP_HERE
AMOUNT_OUT_MIN=MINIMUM_AMOUNT_OF_ERC20_TO_RECEIVE_HERE
SQRT_PRICE_LIMIT_X96=0
```

- **$AMOUNT_IN**: Amount of WETH to swap (in wei).
- **$AMOUNT_OUT_MIN**: Minimum amount of ERC20 tokens to receive (in wei). Use [Kraken Convert](https://www.kraken.com/convert) to estimate this amount.
- **$SQRT_PRICE_LIMIT_X96**: Set to `0` to accept current pool prices, or calculate based on desired price limit.

Load the environment variables:

```bash
source .env
```

### Execute the Swap Command

```bash
cast send $SWAP_ROUTER \
"exactInputSingle((address,address,uint24,address,uint256,uint256,uint160))" \
"($WETH,$ERC20,$FEE,$MY_ADDRESS,$AMOUNT_IN,$AMOUNT_OUT_MIN,$SQRT_PRICE_LIMIT_X96)" \
--value 0 --private-key $PRIVATE_KEY
```

::callout{icon="i-heroicons-information-circle"}
**Note**: If something goes wrong:

- Check your `.env` file for mistakes
- Reload the environment variables
- Check the logs in the terminal where you started `era_test_node`
::

---

## Notes and Tips

- **EOA Restrictions**: Externally Owned Accounts can't interact directly with Uniswap V3 Pool
contracts due to callback requirements. Use the Swap Router instead.
- **Understanding Tuples**: When calling functions that accept structs, parameters are passed
as tuples enclosed in parentheses and quotes to prevent shell parsing issues.
- **Token Decimals**: Ensure you're using the correct number of decimals for your ERC20 token.
- **Gas Limit**: If you encounter gas limit issues, set `ETH_GAS_LIMIT` in your `.env` file.
- **Approvals**: Always approve the Swap Router to spend your tokens before swapping.
- **Cast Send**: The `cast send` command is used to send transactions. `--value 0` is used
because we are swapping WETH for an ERC20 token, and we are not sending any ETH in this
transaction.
- **AI**: Utilize tools like ChatGPT for quick calculations andexplanations.

---

## Conclusion

You've successfully set up a local ZKsync Era environment, interacted with contracts using `cast`,
and performed a token swap on Uniswap. This setup allows you to test and develop smart contract
interactions in a controlled environment.

---

## Additional Resources

- **ZKsync Era Documentation**: [ZKsync Docs](https://docs.zksync.io/)
- **Foundry Book**: [Foundry Documentation](https://book.getfoundry.sh/)
- **Uniswap V3 Documentation**: [Uniswap Docs](https://docs.uniswap.org/)
- **ZKsync Era Explorer**: [ZKsync Era Explorer](https://era.zksync.network/)
- **Uniswap Pools on ZKsync Era**: [Uniswap Pools](https://app.uniswap.org/explore/pools/zksync)

---

**Happy coding and exploring ZKsync Era with Foundry and Cast!**
29 changes: 29 additions & 0 deletions content/tutorials/foundry-era-test-node/_dir.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
title: Interacting with Uniswap on a Fork of ZKsync Era Using era_test_node and Foundry
featured: false
authors:
- name: bxpana
url: https://github.com/bxpana
avatar: https://avatars.githubusercontent.com/u/42230936?v=4
github_repo: https://github.com/ZKsync-Community-Hub
tags:
- zksync-era
- foundry
- cast
- uniswap
- tutorial
summary: Set up a local ZKsync Era environment and perform token swaps using Foundry.
description: |
In this tutorial, you will set up a local ZKsync Era environment using era_test_node, leverage Foundry's cast tool to interact with contracts, and perform token swaps on Uniswap. You will learn how to check balances, deposit ETH for WETH, transfer WETH, and swap tokens using Uniswap's Swap Router.
what_you_will_learn:
- How to set up and fork a local ZKsync Era environment.
- How to use environment variables to streamline your workflow.
- How to check balances using cast.
- How to deposit ETH for WETH and transfer WETH.
- How to approve tokens and perform swaps on Uniswap using the Swap Router.
updated: 2024-09-26
tools:
- foundry
- era_test_node
- cast
- uniswap
- zksync-era-explorer

0 comments on commit 5e61a18

Please sign in to comment.