Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

docs: test daily spend limit tutorial #56

Merged
merged 2 commits into from
Aug 29, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions .github/workflows/playwright.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ jobs:
tutorial:
- "tests/erc20-paymaster.spec.ts"
- "tests/how-to-test-contracts.spec.ts"
- "tests/daily-spend-limit.spec.ts"

steps:
- uses: actions/checkout@v4
Expand All @@ -21,6 +22,11 @@ jobs:
- uses: actions/setup-node@v4
- name: Install Playwright Browsers
run: bun playwright install chromium --with-deps
- name: Install Era Test Node
run: |
curl --proto '=https' -sSf https://raw.githubusercontent.com/matter-labs/era-test-node/main/scripts/install.sh > install.sh
chmod +x install.sh
sudo ./install.sh
- name: Run test for ${{ matrix.tutorial }}
run: |
export TERM=xterm-256color
Expand Down
166 changes: 145 additions & 21 deletions content/tutorials/daily-spend-limit-account/10.index.md
Original file line number Diff line number Diff line change
Expand Up @@ -42,32 +42,51 @@ with the smart contracts in this project.

1. Initiate a new project by running the command:

:test-action{actionId="initialize-project"}

```sh
npx zksync-cli create custom-spendlimit-tutorial --template hardhat_solidity
```

This creates a new ZKsync Era project called `custom-spendlimit-tutorial` with a with a few example contracts.
This creates a new ZKsync Era project called `custom-spendlimit-tutorial` with a few example contracts.

1. Navigate into the project directory:

:test-action{actionId="wait-for-init"}
:test-action{actionId="move-into-project"}

```sh
cd custom-spendlimit-tutorial
```

1. For the purposes of this tutorial, we don't need the example contracts related files. So, proceed by removing all the
files inside the `/contracts` and `/deploy` folders manually or by running the following commands:

:test-action{actionId="delete-template-files"}

```sh
rm -rf ./contracts/*
rm -rf ./deploy/*
```

1. Add the ZKsync and OpenZeppelin contract libraries:

```sh
yarn add -D @matterlabs/zksync-contracts @openzeppelin/contracts@4.9.5
:test-action{actionId="install-deps"}

::code-group

```bash [npm]
npm install -D @matterlabs/zksync-contracts @openzeppelin/contracts@4.9.5 @matterlabs/hardhat-zksync-deploy@1.3.0
```

```bash [yarn]
yarn add -D @matterlabs/zksync-contracts @openzeppelin/contracts@4.9.5 @matterlabs/hardhat-zksync-deploy@1.3.0
```

::

:test-action{actionId="wait-for-install"}

::callout{icon="i-heroicons-exclamation-triangle"}
This project does not use the latest version available of
`@openzeppelin/contracts`. Make sure you install the specific version mentioned above.
Expand All @@ -76,6 +95,8 @@ with the smart contracts in this project.
1. Include the `isSystem: true` setting in the `zksolc` section of the `hardhat.config.ts` configuration file to allow
interaction with system contracts:

:test-action{actionId="hardhat-config"}

```typescript [hardhat.config.ts]
import { HardhatUserConfig } from "hardhat/config";

Expand Down Expand Up @@ -117,6 +138,9 @@ with the smart contracts in this project.
export default config;
```

:test-action{actionId="start-local-node"}
:test-action{actionId="deploy-to-local-node"}

## Design

Now let’s dive into the design and implementation of the daily spending limit feature.
Expand Down Expand Up @@ -337,6 +361,12 @@ limit.available -= _amount;

1. In the folder `contracts`, add a file called `SpendLimit.sol`

:test-action{actionId="add-spend-limit-file"}

```sh
touch contracts/SpendLimit.sol
```

1. Copy/paste the complete code below.

::callout{icon="i-heroicons-exclamation-triangle"}
Expand All @@ -345,6 +375,9 @@ limit.available -= _amount;
forget to change the value before deploying the contract.
::

:test-action{actionId="open-spend-limit-code-panel"}
:test-action{actionId="spend-limit-contract"}

::drop-panel
::panel{label="SpendLimit.sol"}

Expand Down Expand Up @@ -481,6 +514,12 @@ The main difference is that our account has a single signer.

1. Create a file `Account.sol` in the `contracts` folder.

:test-action{actionId="account-contract-file"}

```sh
touch contracts/Account.sol
```

2. Copy/paste the code below.

The account implements the [IAccount](https://docs.zksync.io/build/developer-reference/account-abstraction/design#iaccount-interface) interface
Expand All @@ -491,6 +530,9 @@ Since we are building an account with signers, we should also implement
The `isValidSignature` method will take care of verifying the signature and making sure the extracted address matches
with the owner of the account.

:test-action{actionId="open-account-code-panel"}
:test-action{actionId="add-account-contract"}

::drop-panel
::panel{label="Account.sol"}

Expand Down Expand Up @@ -749,7 +791,17 @@ bytes from transaction calldata.

The `AAFactory.sol` contract is responsible for deploying instances of the `Account.sol` contract.

1. Create the `AAFactory.sol` file in the `contracts` folder and copy/paste the code below.
1. Create the `AAFactory.sol` file in the `contracts` folder.

:test-action{actionId="aa-factory-file"}

```sh
touch contracts/AAFactory.sol
```

1. Copy/paste the code below.

:test-action{actionId="aa-factory-contract"}

```solidity [AAFactory.sol]
// SPDX-License-Identifier: MIT
Expand Down Expand Up @@ -795,16 +847,35 @@ contract AAFactory {

1. Compile the contracts from the project root.

```sh
yarn hardhat compile
:test-action{actionId="compile"}

::code-group

```bash [npm]
npm run compile
```

```bash [yarn]
yarn compile
```

1. Create a file named `deploy/deployFactoryAccount.ts`. Then, copy and paste the following code into it. Remember to
::

1. Create a file named `deploy/deploy.ts`. Then, copy and paste the following code into it. Remember to
add your `DEPLOYER_PRIVATE_KEY` to the .env file.

:test-action{actionId="create-deploy-factory-script-file"}

```sh
touch deploy/deploy.ts
```

The script deploys the factory, creates a new smart contract account, and funds it with some ETH.

```typescript [deploy/deployFactoryAccount.ts]
:test-action{actionId="modify-env-file"}
:test-action{actionId="deploy-factory-script"}

```typescript [deploy/deploy.ts]
import { utils, Wallet, Provider } from "zksync-ethers";
import * as ethers from "ethers";
import { HardhatRuntimeEnvironment } from "hardhat/types";
Expand All @@ -818,7 +889,7 @@ contract AAFactory {

export default async function (hre: HardhatRuntimeEnvironment) {
// @ts-ignore target zkSyncSepoliaTestnet in config file which can be testnet or local
const provider = new Provider(hre.config.networks.zkSyncSepoliaTestnet.url);
const provider = new Provider(hre.network.config.url);
const wallet = new Wallet(DEPLOYER_PRIVATE_KEY, provider);
const deployer = new Deployer(hre, wallet);
const factoryArtifact = await deployer.loadArtifact("AAFactory");
Expand Down Expand Up @@ -864,10 +935,20 @@ contract AAFactory {

1. Run the script.

```sh
yarn hardhat deploy-zksync --script deployFactoryAccount.ts
:test-action{actionId="run-deploy-script"}

::code-group

```bash [npm]
npm run deploy
```

```bash [yarn]
yarn deploy
```

::

You should see the following:

```txt
Expand All @@ -886,12 +967,24 @@ address in order to track transactions and changes in the balance.

1. Create the file `setLimit.ts` in the `deploy` folder and copy/paste the example code below.

:test-action{actionId="wait-for-script"}
:test-action{actionId="create-set-limit-script"}

```sh
touch deploy/setLimit.ts
```

1. Replace `<DEPLOYED_ACCOUNT_ADDRESS>` and `<DEPLOYED_ACCOUNT_OWNER_PRIVATE_KEY>` with the output from the previous
section in your `.env` file.

:test-action{actionId="get-deployed-account-address"}
:test-action{actionId="get-private-key"}

To enable the daily spending limit, we execute the `setSpendingLimit` function with two parameters: token address and limit amount.
The token address is `ETH_ADDRESS` and the limit parameter is `0.0005` in the example below (and can be any amount).

:test-action{actionId="set-limit-script"}

```typescript [setLimit.ts]
import { utils, Wallet, Provider, Contract, EIP712Signer, types } from "zksync-ethers";
import * as ethers from "ethers";
Expand All @@ -908,7 +1001,7 @@ address in order to track transactions and changes in the balance.

export default async function (hre: HardhatRuntimeEnvironment) {
// @ts-ignore target zkSyncSepoliaTestnet in config file which can be testnet or local
const provider = new Provider(hre.config.networks.zkSyncSepoliaTestnet.url);
const provider = new Provider(hre.network.config.url);

const owner = new Wallet(DEPLOYED_ACCOUNT_OWNER_PRIVATE_KEY, provider);

Expand Down Expand Up @@ -956,10 +1049,20 @@ address in order to track transactions and changes in the balance.

1. Run the script.

```sh
:test-action{actionId="run-set-limit-script"}

::code-group

```bash [npx]
npx hardhat deploy-zksync --script setLimit.ts
```

```bash [yarn]
yarn hardhat deploy-zksync --script setLimit.ts
```

::

You should see the following output:

```text
Expand All @@ -977,10 +1080,19 @@ Let's test the `SpendLimit` contract works to make it refuse ETH transfers that
1. Create `transferETH.ts` and copy/paste the example code below, replacing the placeholder constants as before and
adding an account address for `RECEIVER_ACCOUNT`.

```typescript [transferETH.ts]
:test-action{actionId="add-receiver-account"}
:test-action{actionId="create-transfer-script"}

```sh
touch deploy/transferETH.ts
```

:test-action{actionId="add-transfer-script"}

```typescript [deploy/transferETH.ts]
import { utils, Wallet, Provider, Contract, EIP712Signer, types } from "zksync-ethers";
import * as ethers from "ethers";
import { HardhatRuntimeEnvironment } from "hardhat/types";
import type { HardhatRuntimeEnvironment } from "hardhat/types";

// load env file
import dotenv from "dotenv";
Expand All @@ -994,7 +1106,7 @@ Let's test the `SpendLimit` contract works to make it refuse ETH transfers that

export default async function (hre: HardhatRuntimeEnvironment) {
// @ts-ignore target zkSyncSepoliaTestnet in config file which can be testnet or local
const provider = new Provider(hre.config.networks.zkSyncSepoliaTestnet.url);
const provider = new Provider(hre.network.config.url);

const owner = new Wallet(DEPLOYED_ACCOUNT_OWNER_PRIVATE_KEY, provider);

Expand Down Expand Up @@ -1034,11 +1146,13 @@ Let's test the `SpendLimit` contract works to make it refuse ETH transfers that
console.log("Available today: ", limitData.available.toString());

// L1 timestamp tends to be undefined in latest blocks. So it should find the latest L1 Batch first.
let l1BatchRange = await provider.getL1BatchBlockRange(await provider.getL1BatchNumber());
let l1TimeStamp = (await provider.getBlock(l1BatchRange[1])).l1BatchTimestamp;
if (hre.network.config.ethNetwork !== 'localhost') {
let l1BatchRange = await provider.getL1BatchBlockRange(await provider.getL1BatchNumber());
let l1TimeStamp = (await provider.getBlock(l1BatchRange[1])).l1BatchTimestamp;

console.log("L1 timestamp: ", l1TimeStamp);
console.log("Limit will reset on timestamp: ", limitData.resetTime.toString());
console.log('L1 timestamp: ', l1TimeStamp);
console.log('Limit will reset on timestamp: ', limitData.resetTime.toString());
}

// actually do the ETH transfer
console.log("Sending ETH transfer from smart contract account");
Expand All @@ -1064,10 +1178,20 @@ Let's test the `SpendLimit` contract works to make it refuse ETH transfers that

1. Run the script to attempt to make a transfer.

```shell
:test-action{actionId="run-transfer-script"}

::code-group

```bash [npx]
npx hardhat deploy-zksync --script transferETH.ts
```

```bash [yarn]
yarn hardhat deploy-zksync --script transferETH.ts
```

::

You should see an error message with the following content so we know it failed because the amount exceeded the limit.

```shell
Expand Down
4 changes: 4 additions & 0 deletions tests/configs/config.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { steps as erc20PaymasterSteps } from './erc20-paymaster';
import { steps as howToTestContractsSteps } from './how-to-test-contracts';
import { steps as dailySpendLimitSteps } from './daily-spend-limit';

export function getConfig(tutorialName: string) {
let steps;
Expand All @@ -10,6 +11,9 @@ export function getConfig(tutorialName: string) {
case 'how-to-test-contracts':
steps = howToTestContractsSteps;
break;
case 'daily-spend-limit':
steps = dailySpendLimitSteps;
break;
default:
break;
}
Expand Down
Loading
Loading