-
Notifications
You must be signed in to change notification settings - Fork 14
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
a832ee0
commit 5075cf1
Showing
7 changed files
with
287 additions
and
16 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -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 | ||
``` | ||
|
@@ -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"; | ||
|
@@ -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", | ||
|
@@ -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. | ||
|
@@ -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; | ||
|
@@ -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"} | ||
|
@@ -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; | ||
|
@@ -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"; | ||
|
@@ -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 | ||
|
@@ -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"); | ||
|
@@ -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(), | ||
|
@@ -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({ | ||
|
@@ -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( | ||
|
@@ -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(); | ||
|
@@ -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); | ||
|
@@ -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)}`); | ||
|
@@ -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"; | ||
|
@@ -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 | ||
|
@@ -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 | ||
|
@@ -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 | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.