Skip to content

Commit

Permalink
docs: add test for multisig
Browse files Browse the repository at this point in the history
  • Loading branch information
sarahschwartz committed Sep 16, 2024
1 parent a832ee0 commit 5075cf1
Show file tree
Hide file tree
Showing 7 changed files with 287 additions and 16 deletions.
1 change: 1 addition & 0 deletions .github/workflows/playwright.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ jobs:
- "tests/erc20-paymaster.spec.ts"
- "tests/how-to-test-contracts.spec.ts"
- "tests/daily-spend-limit.spec.ts"
- "tests/native-aa-multisig.spec.ts"

steps:
- uses: actions/checkout@v4
Expand Down
118 changes: 107 additions & 11 deletions content/tutorials/native-aa-multisig/10.index.md
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,8 @@ Atlas is a smart contract IDE that lets you write, deploy, and interact with con

1. Initiate a new project by running the command:

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

```sh
npx zksync-cli create custom-aa-tutorial --template hardhat_solidity
```
Expand All @@ -41,31 +43,48 @@ Atlas is a smart contract IDE that lets you write, deploy, and interact with con

1. Navigate into the project directory:

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

```sh
cd custom-aa-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-templates"}
```sh
rm -rf ./contracts/*
rm -rf ./deploy/*
```
1. Add the ZKsync and OpenZeppelin contract libraries:
```sh
yarn add -D @matterlabs/zksync-contracts @openzeppelin/[email protected]
:test-action{actionId="install-deps"}
::code-group
```shell [npm]
npm install -D @matterlabs/zksync-contracts @openzeppelin/[email protected] @matterlabs/[email protected]
```
```shell [yarn]
yarn add -D @matterlabs/zksync-contracts @openzeppelin/[email protected] @matterlabs/[email protected]
```
1. Include the `isSystem: true` setting in the `zksolc` section of the `hardhat.config.ts` configuration file to allow interaction with system contracts:
::
1. Include the `enableEraVMExtensions: true` setting in the `zksolc` section of the `hardhat.config.ts` configuration file
to allow interaction with system contracts:
::callout{icon="i-heroicons-light-bulb"}
This project does not use the latest version available of `@openzeppelin/contracts`.
Make sure you install the specific version mentioned above.
::
:test-action{actionId="hardhat-config"}
```ts
import { HardhatUserConfig } from "hardhat/config";
import "@matterlabs/hardhat-zksync-deploy";
Expand All @@ -77,7 +96,7 @@ Atlas is a smart contract IDE that lets you write, deploy, and interact with con
zksolc: {
version: "latest", // Uses latest available in https://github.com/matter-labs/zksolc-bin/
settings: {
isSystem: true, // ⚠️ Make sure to include this line
enableEraVMExtensions: true, // ⚠️ Make sure to include this line
},
},
defaultNetwork: "zkSyncTestnet",
Expand All @@ -97,6 +116,10 @@ Atlas is a smart contract IDE that lets you write, deploy, and interact with con
export default config;
```
:test-action{actionId="add-local-node"}
:test-action{actionId="use-local-node"}
:test-action{actionId="start-local-node"}
## Account Abstraction
Each account must implement the [IAccount](https://docs.zksync.io/build/developer-reference/account-abstraction/design#iaccount-interface) interface.
Expand Down Expand Up @@ -538,6 +561,14 @@ Therefore, it is highly recommended to put `require(success)` for the transactio
1. Create a file `TwoUserMultisig.sol` in the `contracts` folder and copy/paste the code below into it.
:test-action{actionId="make-multisig-contract"}
```shell
touch contracts/TwoUserMultisig.sol
```
:test-action{actionId="multisig-contract-code"}
```solidity [TwoUserMultisig.sol]
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.17;
Expand Down Expand Up @@ -797,6 +828,12 @@ contract TwoUserMultisig is IAccount, IERC1271 {
1. Create a new Solidity file in the `contracts` folder called `AAFactory.sol`.
:test-action{actionId="make-factory-contract"}
```shell
touch contracts/AAFactory.sol
```
The contract is a factory that deploys the accounts.
::callout{icon="i-heroicons-exclamation-triangle"}
Expand All @@ -809,6 +846,8 @@ contract TwoUserMultisig is IAccount, IERC1271 {
1. Copy/paste the following code into the file.
:test-action{actionId="factory-contract-code"}
```solidity [AAFactory.sol]
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.17;
Expand Down Expand Up @@ -863,6 +902,14 @@ Make sure you deposit funds on ZKsync Era using [one of the available bridges](h
1. In the `deploy` folder, create the file `deploy-factory.ts` and copy/paste the following code, replacing `<WALLET_PRIVATE_KET>` with your private key.
:test-action{actionId="make-deploy-script"}
```shell
touch deploy/deploy-factory.ts
```
:test-action{actionId="deploy-script-code"}
```ts [deploy-factory.ts]
import { utils, Wallet } from "zksync-ethers";
import * as ethers from "ethers";
Expand Down Expand Up @@ -891,13 +938,26 @@ Make sure you deposit funds on ZKsync Era using [one of the available bridges](h
}
```
:test-action{actionId="deploy-script-pk"}
1. From the project root, compile and deploy the contracts.
```sh
:test-action{actionId="compile-and-deploy-factory"}
::code-group
```shell [npx]
npx hardhat compile
npx hardhat deploy-zksync --script deploy-factory.ts
```
```sh [yarn]
yarn hardhat compile
yarn hardhat deploy-zksync --script deploy-factory.ts
```
::
The output should look like this:
```txt
Expand All @@ -919,15 +979,23 @@ This section assumes you have an EOA account with sufficient funds on ZKsync Era
In the `deploy` folder, create a file called `deploy-multisig.ts`.
:test-action{actionId="create-deploy-multisig"}
```shell
touch deploy/deploy-multisig.ts
```
The call to the `deployAccount` function deploys the AA.
:test-action{actionId="deploy-multisig-code"}
```ts [deploy-multisig.ts]
import { utils, Wallet, Provider, EIP712Signer, types } from "zksync-ethers";
import * as ethers from "ethers";
import { HardhatRuntimeEnvironment } from "hardhat/types";
// Put the address of your AA factory
const AA_FACTORY_ADDRESS = "<FACTORY-ADDRESS>";
const AA_FACTORY_ADDRESS = "<FACTORY-ADDRESS>"; //sepolia
export default async function (hre: HardhatRuntimeEnvironment) {
const provider = new Provider("https://sepolia.era.zksync.dev");
Expand All @@ -952,6 +1020,7 @@ export default async function (hre: HardhatRuntimeEnvironment) {
// Getting the address of the deployed contract account
// Always use the JS utility methods
const abiCoder = new ethers.AbiCoder();
const multisigAddress = utils.create2Address(
AA_FACTORY_ADDRESS,
await aaFactory.aaBytecodeHash(),
Expand All @@ -974,9 +1043,10 @@ Read the documentation for more information on [address derivation differences b
Before the deployed account can submit transactions, we need to deposit some ETH to it for the transaction fees.
:test-action{actionId="deposit-funds"}
```ts
console.log("Sending funds to multisig account");
// Send funds to the multisig account we just deployed
await(
await wallet.sendTransaction({
Expand All @@ -994,6 +1064,8 @@ console.log(`Multisig account balance is ${multisigBalance.toString()}`);
Now we can try to deploy a new multisig; the initiator of the transaction will be our deployed account from the previous part.
:test-action{actionId="create-deploy-tx"}
```ts
// Transaction to deploy a new account using the multisig we just deployed
let aaTx = await aaFactory.deployAccount.populateTransaction(
Expand All @@ -1006,6 +1078,8 @@ let aaTx = await aaFactory.deployAccount.populateTransaction(
Then, we need to fill all the transaction fields:
:test-action{actionId="modify-deploy-tx"}
```ts
const gasLimit = await provider.estimateGas({ ...aaTx, from: wallet.address });
const gasPrice = await provider.getGasPrice();
Expand All @@ -1029,13 +1103,15 @@ aaTx = {
::callout{icon="i-heroicons-light-bulb"}
Currently, we expect the `l2gasLimit` to cover both the verification and the execution steps.
The gas returned by `estimateGas` is `execution_gas + 20000`, where `20000` is roughly equal to the overhead
needed for the defaultAA to have both fee charged and the signature verified.
needed for the default AA to have both the fee charged and the signature verified.
</br>
In the case that your AA has an expensive verification step, you should add some constant to the `l2gasLimit`.
::
Then, we need to sign the transaction and provide the `aaParamas` in the customData of the transaction.
:test-action{actionId="sign-deploy-tx"}
```ts
const signedTxHash = EIP712Signer.getSignedDigest(aaTx);
Expand All @@ -1050,6 +1126,8 @@ aaTx.customData = {
Finally, we are ready to send the transaction:
:test-action{actionId="send-deploy-tx"}
```ts
console.log(`The multisig's nonce before the first tx is ${await provider.getTransactionCount(multisigAddress)}`);
Expand All @@ -1070,6 +1148,8 @@ console.log(`Multisig account balance is now ${multisigBalance.toString()}`);
1. Copy/paste the following code into the deployment file, replacing the `<FACTORY-ADDRESS>`
and private key `<WALLET-PRIVATE-KEY>` placeholders with the relevant data.
:test-action{actionId="final-deploy-script"}
```ts
import { utils, Wallet, Provider, EIP712Signer, types } from "zksync-ethers";
import * as ethers from "ethers";
Expand Down Expand Up @@ -1112,7 +1192,7 @@ and private key `<WALLET-PRIVATE-KEY>` placeholders with the relevant data.
console.log("Sending funds to multisig account");
// Send funds to the multisig account we just deployed
await (
await(
await wallet.sendTransaction({
to: multisigAddress,
// You can increase the amount of ETH sent to the multisig
Expand Down Expand Up @@ -1165,7 +1245,6 @@ and private key `<WALLET-PRIVATE-KEY>` placeholders with the relevant data.
const sentTx = await provider.broadcastTransaction(types.Transaction.from(aaTx).serialized);
console.log(`Transaction sent from multisig with hash ${sentTx.hash}`);
await sentTx.wait();
// Checking that the nonce for the account has increased
Expand All @@ -1177,12 +1256,29 @@ and private key `<WALLET-PRIVATE-KEY>` placeholders with the relevant data.
}
```
:test-action{actionId="get-deployed-account-address"}
:test-action{actionId="deploy-multisig-account"}
:test-action{actionId="deploy-multisig-provider"}
:test-action{actionId="deploy-multisig-pk"}
:test-action{actionId="import-dotenv"}
1. Run the script from the `deploy` folder.
```sh
:test-action{actionId="run-deploy-multisig"}
::code-group
```shell [npx]
npx hardhat deploy-zksync --script deploy-multisig.ts
```
```sh [yarn]
yarn hardhat deploy-zksync --script deploy-multisig.ts
```
::
The output should look something like this:
```txt
Expand Down
4 changes: 4 additions & 0 deletions tests/configs/config.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { steps as erc20PaymasterSteps } from './erc20-paymaster';
import { steps as howToTestContractsSteps } from './how-to-test-contracts';
import { steps as dailySpendLimitSteps } from './daily-spend-limit';
import { steps as multisigSteps } from './native-aa-multisig';

export function getConfig(tutorialName: string) {
let steps;
Expand All @@ -14,6 +15,9 @@ export function getConfig(tutorialName: string) {
case 'daily-spend-limit':
steps = dailySpendLimitSteps;
break;
case 'native-aa-multisig':
steps = multisigSteps;
break;
default:
break;
}
Expand Down
Loading

0 comments on commit 5075cf1

Please sign in to comment.