Skip to content

Commit 2a6fe0d

Browse files
docs: refactor and update AA reference (#236)
- closes #190 - reorders the pages in the AA developer reference to improve information flow - adds new details about using P256Verify & using smart accounts
1 parent 89b8073 commit 2a6fe0d

File tree

5 files changed

+184
-93
lines changed

5 files changed

+184
-93
lines changed

content/00.build/65.developer-reference/40.account-abstraction/40.building-smart-accounts.md

Lines changed: 76 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -28,14 +28,40 @@ For this purpose, use the `createAccount` or `create2Account` methods of the dep
2828
system contract, rather than the general `create` or `create2` methods, which are
2929
used for contracts not intended to act as accounts.
3030

31-
#### Example Using `zksync-ethers` SDK (v5)
31+
#### Example Using `zksync-ethers` SDK (v6)
32+
33+
You can use the [`ECDSASmartAccount`](https://sdk.zksync.io/js/ethers/api/v6/accounts/smartaccount-factories#ecdsasmartaccount) or
34+
[`MultisigECDSASmartAccount`](https://sdk.zksync.io/js/ethers/api/v6/accounts/smartaccount-factories#multisigecdsasmartaccount)
35+
to create a standard smart account or multisig smart account.
3236

3337
```ts
34-
import { ContractFactory } from "zksync-ethers";
38+
import { types, ECDSASmartAccount, MultisigECDSASmartAccount, } from "zksync-ethers";
39+
40+
const account = ECDSASmartAccount.create(ADDRESS, PRIVATE_KEY, provider);
41+
const multisigAccount = MultisigECDSASmartAccount.create(multisigAddress, [PRIVATE_KEY1, PRIVATE_KEY2], provider);
42+
```
43+
44+
You can also deploy with custom factory and account contracts using the example below.
3545

36-
const contractFactory = new ContractFactory(abi, bytecode, initiator, "createAccount");
37-
const aa = await contractFactory.deploy(...args);
38-
await aa.deployed();
46+
```ts
47+
async function deployAAFactory(hre: HardhatRuntimeEnvironment) {
48+
const deployer = hre.deployer;
49+
// the factory contract
50+
const factoryArtifact = await deployer.loadArtifact('AAFactory');
51+
// the account contract
52+
const aaArtifact = await deployer.loadArtifact('Account');
53+
54+
const factory = await deployer.deploy(
55+
factoryArtifact,
56+
[utils.hashBytecode(aaArtifact.bytecode)],
57+
undefined,
58+
undefined,
59+
[aaArtifact.bytecode]
60+
);
61+
const factoryAddress = await factory.getAddress();
62+
console.log(`AA factory address: ${factoryAddress}`);
63+
return factory;
64+
}
3965
```
4066

4167
### Verification Step Limitations
@@ -65,19 +91,57 @@ Currently, only EIP712 formatted transactions are supported for sending from cus
6591
accounts. Transactions must specify the `from` field as the account's address and
6692
include a `customSignature` in the `customData`.
6793

68-
#### Example Transaction Submission
94+
#### Example Transaction Submission With a Private Key
95+
96+
To send a transaction using the private key of a deployed smart account, you can use the
97+
[`SmartAccount`](https://sdk.zksync.io/js/ethers/api/v6/accounts/smartaccount#sendtransaction) class from `zksync-ethers`:
98+
99+
```ts
100+
import { SmartAccount, Provider, types } from "zksync-ethers";
101+
import { parseEther } from "ethers";
102+
103+
const provider = Provider.getDefaultProvider(types.Network.Sepolia);
104+
const account = new SmartAccount({ address: ADDRESS, secret: PRIVATE_KEY }, provider);
105+
106+
const signedTx = await account.sendTransaction({
107+
to: recipientAddress,
108+
value: parseEther(amount),
109+
});
110+
```
111+
112+
#### Example Transaction Submission Without a Private Key
113+
114+
You can also manually add a custom signature to a transaction,
115+
like in the example below.
69116

70117
```ts
71-
import { utils } from "zksync-ethers";
118+
import { types, Provider } from "zksync-ethers";
119+
import { parseEther, AbiCoder } from "ethers";
120+
121+
const provider = new Provider(rpcUrl);
122+
let tx: types.TransactionLike = {
123+
to: recipientAddress,
124+
value: parseEther(amount),
125+
gasPrice: await provider.getGasPrice(),
126+
gasLimit: BigInt(20000000),
127+
chainId: (await provider.getNetwork()).chainId,
128+
nonce: await provider.getTransactionCount(aaAddress),
129+
};
130+
131+
const abiCoder = new AbiCoder();
132+
const aaSignature = abiCoder.encode(
133+
['string', 'string'],
134+
['hello', 'world']
135+
);
72136

73-
// Here, `tx` is a `TransactionRequest` object from `zksync-ethers` SDK.
74-
// `zksyncProvider` is the `Provider` object from `zksync-ethers` SDK connected to the ZKSync network.
75137
tx.from = aaAddress;
138+
tx.type = 113;
76139
tx.customData = {
77140
...tx.customData,
78141
customSignature: aaSignature,
79142
};
80-
const serializedTx = utils.serialize({ ...tx });
81-
82-
const sentTx = await zksyncProvider.sendTransaction(serializedTx);
143+
const sentTx = await provider.broadcastTransaction(
144+
types.Transaction.from(tx).serialized
145+
);
146+
await sentTx.wait();
83147
```
Lines changed: 108 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,108 @@
1+
---
2+
title: Signature Validation
3+
description: Recommended approaches to signature validation.
4+
---
5+
6+
One of the most notable differences between various types of accounts to be built
7+
is different signature schemes. We expect accounts to support the [EIP-1271](https://eips.ethereum.org/EIPS/eip-1271) standard.
8+
9+
## OpenZeppelin Libraries
10+
11+
The
12+
[`@openzeppelin/contracts/utils/cryptography/SignatureChecker.sol`](https://github.com/OpenZeppelin/openzeppelin-contracts/blob/5ed5a86d1d22f387ce69ab4e0ace405de8bc888d/contracts/utils/cryptography/SignatureChecker.sol#L22)
13+
library provides a way to verify signatures for different
14+
account implementations. We strongly encourage you to use this library whenever you need to check that a signature of an account is correct.
15+
16+
### Adding the library to your project
17+
18+
::code-group
19+
20+
```bash [npm]
21+
npm add @openzeppelin/contracts
22+
```
23+
24+
```bash [yarn]
25+
yarn add @openzeppelin/contracts
26+
```
27+
28+
```bash [pnpm]
29+
pnpm add @openzeppelin/contracts
30+
```
31+
32+
```bash [bun]
33+
bun add @openzeppelin/contracts
34+
```
35+
36+
::
37+
38+
### Example of using the library
39+
40+
```solidity
41+
pragma solidity ^0.8.0;
42+
43+
import { SignatureChecker } from "@openzeppelin/contracts/utils/cryptography/SignatureChecker.sol";
44+
45+
contract TestSignatureChecker {
46+
using SignatureChecker for address;
47+
48+
function isValidSignature(
49+
address _address,
50+
bytes32 _hash,
51+
bytes memory _signature
52+
) public pure returns (bool) {
53+
return _address.isValidSignatureNow(_hash, _signature);
54+
}
55+
}
56+
```
57+
58+
## Verifying AA signatures
59+
60+
Our SDK provides two methods within `utils` to verify the signature of an account:
61+
[`isMessageSignatureCorrect`](https://sdk.zksync.io/js/ethers/api/v6/utilities#ismessagesignaturecorrect) and [`isTypedDataSignatureCorrect`](https://sdk.zksync.io/js/ethers/api/v6/utilities#istypeddatasignaturecorrect).
62+
63+
```ts
64+
import { utils, EIP712Signer } from "zksync-ethers";
65+
66+
const isValidMessageSignature = await utils.isMessageSignatureCorrect(provider, ADDRESS, message, messageSignature);
67+
68+
const isValidTypesSignature = await utils.isTypedDataSignatureCorrect(provider, ADDRESS, await eip712Signer.getDomain(), utils.EIP712_TYPES, EIP712Signer.getSignInput(tx), typedSignature);
69+
```
70+
71+
Currently these methods only support verifying ECDSA signatures, but very soon they will support EIP1271 signature verification as well.
72+
73+
Both of these methods return `true` or `false` depending on whether the message signature is correct.
74+
75+
It is **not recommended** to use the `ethers.js` library to verify user signatures.
76+
77+
## Validating Secp256r1 Signatures
78+
79+
The [`P256Verify` precompile](https://docs.zksync.io/build/developer-reference/era-contracts/elliptic-curve-precompiles#p256)
80+
is available to validate secp256r1 signatures.
81+
82+
```solidity
83+
address constant P256 = 0x0000000000000000000000000000000000000100;
84+
85+
/**
86+
* input[ 0: 32] = signed data hash
87+
* input[ 32: 64] = signature r
88+
* input[ 64: 96] = signature s
89+
* input[ 96:128] = public key x
90+
* input[128:160] = public key y
91+
*/
92+
bytes memory input = abi.encodePacked(
93+
hash,
94+
rs[0],
95+
rs[1],
96+
pubKey[0],
97+
pubKey[1]
98+
);
99+
100+
(bool __, bytes memory output) = P256.staticcall(input);
101+
// if signature is valid:
102+
// output = 0x0000000000000000000000000000000000000000000000000000000000000001
103+
// if signature is NOT valid:
104+
// output.length == 0
105+
```
106+
107+
You can find a more in-depth example showing how
108+
it can be used in the ["Signing Transactions with WebAuthn"](https://code.zksync.io/tutorials/signing-transactions-with-webauthn) tutorial.

content/00.build/65.developer-reference/40.account-abstraction/60.signature-validation.md

Lines changed: 0 additions & 81 deletions
This file was deleted.

0 commit comments

Comments
 (0)