zkSync Goerli Testnet will be shutdown on March 31st. Please use zkSync Sepolia Testnet instead. For more information see this announcement.
`,
copyright: false,
diff --git a/docs/build/developer-reference/contract-deployment.md b/docs/build/developer-reference/contract-deployment.md
index 65be85b290..1fca7a92d2 100644
--- a/docs/build/developer-reference/contract-deployment.md
+++ b/docs/build/developer-reference/contract-deployment.md
@@ -31,7 +31,7 @@ Here's a [step-by-step guide on how to use it](../tooling/hardhat/getting-starte
You might wonder how validators obtain the preimage of the bytecode hashes necessary to execute the code. This is where the concept of factory dependencies, or factory_deps for short, comes into play. Factory dependencies refer to a list of bytecode hashes whose corresponding preimages were previously revealed on the L1 (where data is always available).
-Under the hood, zkSync does not store bytecodes of contracts, but [specially formatted hashes of the bytecodes](#contract-size-limit-and-format-of-bytecode-hash). You can see that the [ContractDeployer](./system-contracts.md#contractdeployer) system contract accepts the bytecode hash of the deployed contract and not its bytecode. However, for contract deployment to succeed, the operator needs to know the bytecode. The `factory_deps` field of the transaction is used for this reason: it contains the bytecodes that should be known to the operator for this transaction to succeed. Once the transaction succeeds, these bytecodes are published on L1 and are considered "known" to the operator forever.
+Under the hood, zkSync does not store bytecodes of contracts in its state tree, but [specially formatted hashes of the bytecodes](#contract-size-limit-and-format-of-bytecode-hash). You can see that the [ContractDeployer](./system-contracts.md#contractdeployer) system contract accepts the bytecode hash of the deployed contract and not its bytecode. However, for contract deployment to succeed, the operator needs to know the bytecode. The `factory_deps` field of the transaction is used for this reason: it contains the bytecodes that should be known to the operator for this transaction to succeed. Once the transaction succeeds, these bytecodes are published on L1 and are considered "known" to the operator forever.
Some examples of usage are:
@@ -50,7 +50,9 @@ Each zkEVM bytecode must adhere to the following format:
- Its length must be divisible by 32.
- Its length in words (32-byte chunks) should be odd. In other words, `bytecodeLength % 64 == 32`.
-- It can not be longer than `2^16` 32-byte words, i.e. `2^21` bytes.
+- There is a VM limit, the bytecode can not be more than `2^16` 32-byte words, i.e. `2^21` bytes.
+- The bootloader has a memory limit for supplying pubdata of 450999 bytes, therefore limiting the contract size to it as well. This limit is valid for Validium hyperchains, that don’t have to publish the bytecode to the base layer.
+- For rollups that must publish the deployed bytecode to the base layer (e.g. Ethereum), there is an additional pubdata limit, which is normally smaller. By default, for each batch, this limit is set to 100000 bytes for hyperchains using calldata DA, or 120000\*number_of_blobs, for hyperchains using EIP-4844 blobs.
The 32-byte hash of the bytecode of a zkSync contract is calculated in the following way:
@@ -70,6 +72,7 @@ The process of auditing a smart contract should be carried out by experts who ha
For detailed information on smart contract vulnerabilities and security best practices, refer to the following resources:
+- [Cyfrin Updraft Security & Auditing Curriculum](https://updraft.cyfrin.io/courses/security).
- [Consensys smart contract best practices](https://consensys.github.io/smart-contract-best-practices/).
- [Solidity docs security considerations](https://docs.soliditylang.org/en/latest/security-considerations.html).
- [Security considerations and best practices on zkSync](../quick-start/best-practices.md)
diff --git a/docs/build/quick-start/add-zksync-to-metamask.md b/docs/build/quick-start/add-zksync-to-metamask.md
index 9cb6ddcc61..3584a9a93b 100644
--- a/docs/build/quick-start/add-zksync-to-metamask.md
+++ b/docs/build/quick-start/add-zksync-to-metamask.md
@@ -18,6 +18,12 @@ Fill in the following details for the zkSync network:
## Mainnet network info
+Add zkSync Era Mainnet automatically using the button below:
+
+
+
+**Network details:**
+
- Network Name: `zkSync Era Mainnet`
- RPC URL: `https://mainnet.era.zksync.io`
- Chain ID: `324`
@@ -27,6 +33,12 @@ Fill in the following details for the zkSync network:
## Sepolia testnet network info
+Add zkSync Era testnet automatically using the button below:
+
+
+
+**Network details:**
+
- Network Name: `zkSync Era Sepolia Testnet`
- RPC URL: `https://sepolia.era.zksync.dev`
- Chain ID: `300`
diff --git a/docs/build/sdks/js/accounts-l1-l2.md b/docs/build/sdks/js/accounts-l1-l2.md
index 14689a8acb..5529d911c4 100644
--- a/docs/build/sdks/js/accounts-l1-l2.md
+++ b/docs/build/sdks/js/accounts-l1-l2.md
@@ -39,6 +39,6 @@ method specification [`getBaseCost`](accounts.md#getbasecost).
## Withdrawal
-`Wallet` and `Signer` objects provide a withdrawal workflow. For more information, please refer to the method specification [`Deposit`](accounts.md#deposit).
+`Wallet` and `Signer` objects provide a withdrawal workflow. For more information, please refer to the method specification [`Withdraw`](accounts.md#withdraw).
For a complete example of how to execute the deposit workflow, take a look at the following: [Withdraw ETH and ERC20 token](https://github.com/zksync-sdk/zksync2-examples/blob/main/js/src/03_withdraw.ts).
diff --git a/docs/build/sdks/js/accounts.md b/docs/build/sdks/js/accounts.md
index 174bb4999f..3858c7cb96 100644
--- a/docs/build/sdks/js/accounts.md
+++ b/docs/build/sdks/js/accounts.md
@@ -14,6 +14,11 @@ head:
- `Wallet` class is an extension of the `ethers.Wallet` with additional zkSync features.
- `EIP712Signer` class that is used to sign `EIP712`_-typed_ zkSync transactions.
- `Signer` and `L1Signer` classes, which should be used for browser integration.
+- `VoidSigner` and `L1VoidSigner` classes, which should be used for designed to allow an address to
+ be used in any API which accepts a `Signer`, but for which there are no credentials available to perform any actual signing.
+- `SmartAccount` which provides better support for account abstraction. There are following factory classes:
+ - `ECDSASmartAccount`: uses a single ECDSA key for signing payload.
+ - `MultisigECDSASmartAccount`: uses multiple ECDSA keys for signing payloads.
## `Wallet`
@@ -786,7 +791,7 @@ use the [`allowanceL1`](#getallowancel1) method.
| Parameter | Type | Description |
| -------------------------------- | ------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `transaction.token` | `Address` | The address of the token to deposit. `ETH` by default. |
-| `transaction.amount` | `BigNumberish` | The amount of the token to withdraw. |
+| `transaction.amount` | `BigNumberish` | The amount of the token to deposit. |
| `transaction.to?` | `Address` | The address that will receive the deposited tokens on L2 (optional). |
| `transaction.operatorTip?` | `BigNumberish` | (_currently is not used_) If the ETH value passed with the transaction is not explicitly stated in the overrides, this field will be equal to the tip the operator will receive on top of the base cost of the transaction (optional). |
| `transaction.bridgeAddress?` | `Address` | The address of the bridge contract to be used. Defaults to the default zkSync bridge (either `L1EthBridge` or `L1Erc20Bridge`) (optional). |
@@ -857,7 +862,7 @@ Returns populated deposit transaction.
| Parameter | Type | Description |
| -------------------------------- | ------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `transaction.token` | `Address` | The address of the token to deposit. `ETH` by default. |
-| `transaction.amount` | `BigNumberish` | The amount of the token to withdraw. |
+| `transaction.amount` | `BigNumberish` | The amount of the token to deposit. |
| `transaction.to?` | `Address` | The address that will receive the deposited tokens on L2 (optional). |
| `transaction.operatorTip?` | `BigNumberish` | (_currently is not used_) If the ETH value passed with the transaction is not explicitly stated in the overrides, this field will be equal to the tip the operator will receive on top of the base cost of the transaction (optional). |
| `transaction.bridgeAddress?` | `Address` | The address of the bridge contract to be used. Defaults to the default zkSync bridge (either `L1EthBridge` or `L1Erc20Bridge`) (optional). |
@@ -910,7 +915,7 @@ Estimates the amount of gas required for a deposit transaction on L1 network. Ga
| Parameter | Type | Description |
| -------------------------------- | ------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `transaction.token` | `Address` | The address of the token to deposit. `ETH` by default. |
-| `transaction.amount` | `BigNumberish` | The amount of the token to withdraw. |
+| `transaction.amount` | `BigNumberish` | The amount of the token to deposit. |
| `transaction.to?` | `Address` | The address that will receive the deposited tokens on L2 (optional). |
| `transaction.operatorTip?` | `BigNumberish` | (_currently is not used_) If the ETH value passed with the transaction is not explicitly stated in the overrides, this field will be equal to the tip the operator will receive on top of the base cost of the transaction (optional). |
| `transaction.bridgeAddress?` | `Address` | The address of the bridge contract to be used. Defaults to the default zkSync bridge (either `L1EthBridge` or `L1Erc20Bridge`) (optional). |
@@ -1520,10 +1525,10 @@ async getDomain(): Promise
This class is to be used in a browser environment. The easiest way to construct it is to use the `getSigner` method of the `Web3Provider`. This structure extends `ethers.providers.JsonRpcSigner` and so supports all the methods available for it.
```typescript
-import { Web3Provider } from "zksync-ethers";
+import { Web3Provider, Provider, types } from "zksync-ethers";
-const provider = new Web3Provider(window.ethereum);
-const signer = provider.getSigner();
+const browserProvider = new Web3Provider(window.ethereum);
+const signer = Signer.from(browserProvider.getSigner(), Provider.getDefaultProvider(types.Network.Sepolia));
```
### `getBalance`
@@ -1543,19 +1548,85 @@ async getBalance(token?: Address, blockTag: BlockTag = 'committed'): Promise
+```
+
+#### Example
+
+```ts
+import { Web3Provider, Provider, types } from "zksync-ethers";
+
+const browserProvider = new Web3Provider(window.ethereum);
+const signer = Signer.from(browserProvider.getSigner(), Provider.getDefaultProvider(types.Network.Sepolia));
+
+const allBalances = await signer.getAllBalances();
+```
+
+### `getDeploymentNonce`
+
+Returns the deployment nonce of the account.
+
+```ts
+async getDeploymentNonce(): Promise
+```
-// Getting ETH balance
-console.log(await signer.getBalance());
+#### Example
+
+```ts
+import { Web3Provider, Provider, types } from "zksync-ethers";
+
+const browserProvider = new Web3Provider(window.ethereum);
+const signer = Signer.from(browserProvider.getSigner(), Provider.getDefaultProvider(types.Network.Sepolia));
+
+console.log(`Nonce: ${await signer.getDeploymentNonce()}`);
+```
+
+### `getL2BridgeContracts`
+
+Returns L2 bridge contracts.
+
+```ts
+async getDeploymentNonce(): Promise
+```
+
+#### Example
+
+```ts
+import { Web3Provider, Provider, types } from "zksync-ethers";
+
+const browserProvider = new Web3Provider(window.ethereum);
+const signer = Signer.from(browserProvider.getSigner(), Provider.getDefaultProvider(types.Network.Sepolia));
+
+const l2BridgeContracts = await signer.getL2BridgeContracts();
```
### `getNonce`
@@ -1575,12 +1646,12 @@ async getNonce(blockTag?: BlockTag): Promise
#### Example
```ts
-import { Web3Provider } from "zksync-ethers";
+import { Web3Provider, Provider, types } from "zksync-ethers";
-const provider = new Web3Provider(window.ethereum);
-const signer = provider.getSigner();
+const browserProvider = new Web3Provider(window.ethereum);
+const signer = Signer.from(browserProvider.getSigner(), Provider.getDefaultProvider(types.Network.Sepolia));
-console.log(await signer.getNonce());
+const nonce = await signer.getNonce();
```
### `transfer`
@@ -1615,34 +1686,36 @@ async transfer(transaction: {
Transfer ETH.
```ts
-import { Wallet, Web3Provider } from "zksync-ethers";
-
-const provider = new Web3Provider(window.ethereum);
-const signer = provider.getSigner();
+import { Web3Provider, Provider, Wallet, types } from "zksync-ethers";
+import { ethers } from "ethers";
-const recipient = Wallet.createRandom();
+const browserProvider = new Web3Provider(window.ethereum);
+const signer = Signer.from(browserProvider.getSigner(), Provider.getDefaultProvider(types.Network.Sepolia));
-const transferHandle = signer.transfer({
- to: recipient.address,
+const tx = signer.transfer({
+ to: Wallet.createRandom().address,
amount: ethers.utils.parseEther("0.01"),
});
+
+const receipt = await tx.wait();
+
+console.log(`The sum of ${receipt.value} ETH was transferred to ${receipt.to}`);
```
Transfer ETH using paymaster to facilitate fee payment with an ERC20 token.
```ts
-import { Wallet, Web3Provider } from "zksync-ethers";
+import { Web3Provider, Provider, Wallet, types } from "zksync-ethers";
+import { ethers } from "ethers";
const token = "0x927488F48ffbc32112F1fF721759649A89721F8F"; // Crown token which can be minted for free
const paymaster = "0x13D0D8550769f59aa241a41897D4859c87f7Dd46"; // Paymaster for Crown token
-const provider = new Web3Provider(window.ethereum);
-const signer = provider.getSigner();
-
-const recipient = Wallet.createRandom();
+const browserProvider = new Web3Provider(window.ethereum);
+const signer = Signer.from(browserProvider.getSigner(), Provider.getDefaultProvider(types.Network.Sepolia));
-const transferHandle = signer.transfer({
- to: recipient.address,
+const tx = signer.transfer({
+ to: Wallet.createRandom().address,
amount: ethers.utils.parseEther("0.01"),
paymasterParams: utils.getPaymasterParams(paymaster, {
type: "ApprovalBased",
@@ -1651,6 +1724,10 @@ const transferHandle = signer.transfer({
innerInput: new Uint8Array(),
}),
});
+
+const receipt = await tx.wait();
+
+console.log(`The sum of ${receipt.value} ETH was transferred to ${receipt.to}`);
```
### `withdraw`
@@ -1685,13 +1762,13 @@ async withdraw(transaction: {
Withdraw ETH.
```ts
-import { Web3Provider } from "zksync-ethers";
+import { Web3Provider, Provider, types } from "zksync-ethers";
-const provider = new Web3Provider(window.ethereum);
-const signer = provider.getSigner();
+const browserProvider = new Web3Provider(window.ethereum);
+const signer = Signer.from(browserProvider.getSigner(), Provider.getDefaultProvider(types.Network.Sepolia));
const tokenL2 = "0x6a4Fb925583F7D4dF82de62d98107468aE846FD1";
-const tokenWithdrawHandle = await signer.withdraw({
+await signer.withdraw({
token: tokenL2,
amount: 10_000_000,
});
@@ -1700,16 +1777,16 @@ const tokenWithdrawHandle = await signer.withdraw({
Withdraw ETH using paymaster to facilitate fee payment with an ERC20 token.
```ts
-import { Web3Provider } from "zksync-ethers";
+import { Web3Provider, Provider, types } from "zksync-ethers";
const token = "0x927488F48ffbc32112F1fF721759649A89721F8F"; // Crown token which can be minted for free
const paymaster = "0x13D0D8550769f59aa241a41897D4859c87f7Dd46"; // Paymaster for Crown token
-const provider = new Web3Provider(window.ethereum);
-const signer = provider.getSigner();
+const browserProvider = new Web3Provider(window.ethereum);
+const signer = Signer.from(browserProvider.getSigner(), Provider.getDefaultProvider(types.Network.Sepolia));
const tokenL2 = "0x6a4Fb925583F7D4dF82de62d98107468aE846FD1";
-const tokenWithdrawHandle = await signer.withdraw({
+await wallet.withdraw({
token: tokenL2,
amount: 10_000_000,
paymasterParams: utils.getPaymasterParams(paymaster, {
@@ -1750,9 +1827,8 @@ async getMainContract(): Promise
import { Provider, L1Signer, types } from "zksync-ethers";
import { ethers } from "ethers";
-const provider = new ethers.providers.Web3Provider(window.ethereum);
-const zksyncProvider = Provider.getDefaultProvider(types.Network.Sepolia);
-const signer = L1Signer.from(provider.getSigner(), zksyncProvider);
+const browserProvider = new ethers.providers.Web3Provider(window.ethereum);
+const signer = L1Signer.from(browserProvider.getSigner(), Provider.getDefaultProvider(types.Network.Sepolia));
const mainContract = await signer.getMainContract();
console.log(mainContract.address);
@@ -1778,9 +1854,8 @@ there is no separate Ether bridge contract, [Main contract](./accounts.md#getmai
import { Provider, L1Signer, types } from "zksync-ethers";
import { ethers } from "ethers";
-const provider = new ethers.providers.Web3Provider(window.ethereum);
-const zksyncProvider = Provider.getDefaultProvider(types.Network.Sepolia);
-const signer = L1Signer.from(provider.getSigner(), zksyncProvider);
+const browserProvider = new ethers.providers.Web3Provider(window.ethereum);
+const signer = L1Signer.from(browserProvider.getSigner(), Provider.getDefaultProvider(types.Network.Sepolia));
const l1BridgeContracts = await signer.getL1BridgeContracts();
```
@@ -1802,21 +1877,29 @@ async getBalanceL1(token?: Address, blockTag?: BlockTag): Promise
#### Example
+Get ETH balance.
+
```ts
import { Provider, L1Signer, types } from "zksync-ethers";
import { ethers } from "ethers";
-const provider = new ethers.providers.Web3Provider(window.ethereum);
-const zksyncProvider = Provider.getDefaultProvider(types.Network.Sepolia);
-const signer = L1Signer.from(provider.getSigner(), zksyncProvider);
+const browserProvider = new ethers.providers.Web3Provider(window.ethereum);
+const signer = L1Signer.from(browserProvider.getSigner(), Provider.getDefaultProvider(types.Network.Sepolia));
-const tokenL1 = "0x56E69Fa1BB0d1402c89E3A4E3417882DeA6B14Be";
+console.log(await signer.getBalanceL1());
+```
-// Getting token balance
-console.log(await signer.getBalanceL1(tokenL1));
+Get token balance.
-// Getting ETH balance
-console.log(await signer.getBalanceL1());
+```ts
+import { Provider, L1Signer, types } from "zksync-ethers";
+import { ethers } from "ethers";
+
+const browserProvider = new ethers.providers.Web3Provider(window.ethereum);
+const signer = L1Signer.from(browserProvider.getSigner(), Provider.getDefaultProvider(types.Network.Sepolia));
+
+const tokenL1 = "0x56E69Fa1BB0d1402c89E3A4E3417882DeA6B14Be";
+console.log(await signer.getBalanceL1(tokenL1));
```
### `l2TokenAddress`
@@ -1843,9 +1926,8 @@ async l2TokenAddress(token: Address): Promise
import { Provider, L1Signer, types } from "zksync-ethers";
import { ethers } from "ethers";
-const provider = new ethers.providers.Web3Provider(window.ethereum);
-const zksyncProvider = Provider.getDefaultProvider(types.Network.Sepolia);
-const signer = L1Signer.from(provider.getSigner(), zksyncProvider);
+const browserProvider = new ethers.providers.Web3Provider(window.ethereum);
+const signer = L1Signer.from(browserProvider.getSigner(), Provider.getDefaultProvider(types.Network.Sepolia));
const tokenL1 = "0x5C221E77624690fff6dd741493D735a17716c26B";
@@ -1878,9 +1960,8 @@ async getAllowanceL1(
import { Provider, L1Signer, types } from "zksync-ethers";
import { ethers } from "ethers";
-const provider = new ethers.providers.Web3Provider(window.ethereum);
-const zksyncProvider = Provider.getDefaultProvider(types.Network.Sepolia);
-const signer = L1Signer.from(provider.getSigner(), zksyncProvider);
+const browserProvider = new ethers.providers.Web3Provider(window.ethereum);
+const signer = L1Signer.from(browserProvider.getSigner(), Provider.getDefaultProvider(types.Network.Sepolia));
const tokenL1 = "0x5C221E77624690fff6dd741493D735a17716c26B";
console.log(`Token allowance: ${await signer.getAllowanceL1(tokenL1)}`);
@@ -1912,14 +1993,11 @@ async approveERC20(
import { Provider, L1Signer, types } from "zksync-ethers";
import { ethers } from "ethers";
-const provider = new ethers.providers.Web3Provider(window.ethereum);
-const zksyncProvider = Provider.getDefaultProvider(types.Network.Sepolia);
-const signer = L1Signer.from(provider.getSigner(), zksyncProvider);
-
-const tokenL1 = "0x56E69Fa1BB0d1402c89E3A4E3417882DeA6B14Be";
-const txHandle = await signer.approveERC20(tokenL1, "10000000");
+const browserProvider = new ethers.providers.Web3Provider(window.ethereum);
+const signer = L1Signer.from(browserProvider.getSigner(), Provider.getDefaultProvider(types.Network.Sepolia));
-await txHandle.wait();
+const tokenL1 = "0x5C221E77624690fff6dd741493D735a17716c26B";
+await signer.approveERC20(tokenL1, 5);
```
### `getBaseCost`
@@ -1948,9 +2026,8 @@ async getBaseCost(params: {
import { Provider, L1Signer, types } from "zksync-ethers";
import { ethers } from "ethers";
-const provider = new ethers.providers.Web3Provider(window.ethereum);
-const zksyncProvider = Provider.getDefaultProvider(types.Network.Sepolia);
-const signer = L1Signer.from(provider.getSigner(), zksyncProvider);
+const browserProvider = new ethers.providers.Web3Provider(window.ethereum);
+const signer = L1Signer.from(browserProvider.getSigner(), Provider.getDefaultProvider(types.Network.Sepolia));
console.log(`Base cost: ${await signer.getBaseCost({ gasLimit: 100_000 })}`);
```
@@ -1968,7 +2045,7 @@ use the [`allowanceL1`](#getallowancel1) method.
| Parameter | Type | Description |
| -------------------------------- | ------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `transaction.token` | `Address` | The address of the token to deposit. `ETH` by default. |
-| `transaction.amount` | `BigNumberish` | The amount of the token to withdraw. |
+| `transaction.amount` | `BigNumberish` | The amount of the token to deposit. |
| `transaction.to?` | `Address` | The address that will receive the deposited tokens on L2 (optional). |
| `transaction.operatorTip?` | `BigNumberish` | (_currently is not used_) If the ETH value passed with the transaction is not explicitly stated in the overrides, this field will be equal to the tip the operator will receive on top of the base cost of the transaction (optional). |
| `transaction.bridgeAddress?` | `Address` | The address of the bridge contract to be used. Defaults to the default zkSync bridge (either `L1EthBridge` or `L1Erc20Bridge`) (optional). |
@@ -1999,33 +2076,36 @@ async deposit(transaction: {
#### Example
+Deposit ETH.
+
```ts
import { Provider, L1Signer, types } from "zksync-ethers";
import { ethers } from "ethers";
-const provider = new ethers.providers.Web3Provider(window.ethereum);
-const zksyncProvider = Provider.getDefaultProvider(types.Network.Sepolia);
-const signer = L1Signer.from(provider.getSigner(), zksyncProvider);
+const browserProvider = new ethers.providers.Web3Provider(window.ethereum);
+const signer = L1Signer.from(browserProvider.getSigner(), Provider.getDefaultProvider(types.Network.Sepolia));
+
+await signer.deposit({
+ token: utils.ETH_ADDRESS,
+ amount: 10_000_000,
+});
+```
+
+Deposit token.
+
+```ts
+import { Provider, L1Signer, types } from "zksync-ethers";
+import { ethers } from "ethers";
+
+const browserProvider = new ethers.providers.Web3Provider(window.ethereum);
+const signer = L1Signer.from(browserProvider.getSigner(), Provider.getDefaultProvider(types.Network.Sepolia));
const tokenL1 = "0x56E69Fa1BB0d1402c89E3A4E3417882DeA6B14Be";
-const tokenDepositHandle = await signer.deposit({
+await signer.deposit({
token: tokenL1,
- amount: "10000000",
+ amount: 10_000_000,
approveERC20: true,
});
-// Note that we wait not only for the L1 transaction to complete but also for it to be
-// processed by zkSync. If we want to wait only for the transaction to be processed on L1,
-// we can use `await tokenDepositHandle.waitL1Commit()`
-await tokenDepositHandle.wait();
-
-const ethDepositHandle = await signer.deposit({
- token: utils.ETH_ADDRESS,
- amount: "10000000",
-});
-// Note that we wait not only for the L1 transaction to complete but also for it to be
-// processed by zkSync. If we want to wait only for the transaction to be processed on L1,
-// we can use `await ethDepositHandle.waitL1Commit()`
-await ethDepositHandle.wait();
```
### `getDepositTx`
@@ -2037,7 +2117,7 @@ Returns populated deposit transaction.
| Parameter | Type | Description |
| -------------------------------- | ------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `transaction.token` | `Address` | The address of the token to deposit. `ETH` by default. |
-| `transaction.amount` | `BigNumberish` | The amount of the token to withdraw. |
+| `transaction.amount` | `BigNumberish` | The amount of the token to deposit. |
| `transaction.to?` | `Address` | The address that will receive the deposited tokens on L2 (optional). |
| `transaction.operatorTip?` | `BigNumberish` | (_currently is not used_) If the ETH value passed with the transaction is not explicitly stated in the overrides, this field will be equal to the tip the operator will receive on top of the base cost of the transaction (optional). |
| `transaction.bridgeAddress?` | `Address` | The address of the bridge contract to be used. Defaults to the default zkSync bridge (either `L1EthBridge` or `L1Erc20Bridge`) (optional). |
@@ -2068,14 +2148,13 @@ async getDepositTx(transaction: {
import { Provider, L1Signer, types } from "zksync-ethers";
import { ethers } from "ethers";
-const provider = new ethers.providers.Web3Provider(window.ethereum);
-const zksyncProvider = Provider.getDefaultProvider(types.Network.Sepolia);
-const signer = L1Signer.from(provider.getSigner(), zksyncProvider);
+const browserProvider = new ethers.providers.Web3Provider(window.ethereum);
+const signer = L1Signer.from(browserProvider.getSigner(), Provider.getDefaultProvider(types.Network.Sepolia));
const tokenL1 = "0x56E69Fa1BB0d1402c89E3A4E3417882DeA6B14Be";
const tx = await signer.getDepositTx({
token: tokenL1,
- amount: "10000000",
+ amount: 10_000_000,
});
```
@@ -2088,7 +2167,7 @@ Estimates the amount of gas required for a deposit transaction on L1 network. Ga
| Parameter | Type | Description |
| -------------------------------- | ------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `transaction.token` | `Address` | The address of the token to deposit. `ETH` by default. |
-| `transaction.amount` | `BigNumberish` | The amount of the token to withdraw. |
+| `transaction.amount` | `BigNumberish` | The amount of the token to deposit. |
| `transaction.to?` | `Address` | The address that will receive the deposited tokens on L2 (optional). |
| `transaction.operatorTip?` | `BigNumberish` | (_currently is not used_) If the ETH value passed with the transaction is not explicitly stated in the overrides, this field will be equal to the tip the operator will receive on top of the base cost of the transaction (optional). |
| `transaction.bridgeAddress?` | `Address` | The address of the bridge contract to be used. Defaults to the default zkSync bridge (either `L1EthBridge` or `L1Erc20Bridge`) (optional). |
@@ -2119,14 +2198,13 @@ async estimateGasDeposit(transaction:
import { Provider, L1Signer, types } from "zksync-ethers";
import { ethers } from "ethers";
-const provider = new ethers.providers.Web3Provider(window.ethereum);
-const zksyncProvider = Provider.getDefaultProvider(types.Network.Sepolia);
-const signer = L1Signer.from(provider.getSigner(), zksyncProvider);
+const browserProvider = new ethers.providers.Web3Provider(window.ethereum);
+const signer = L1Signer.from(browserProvider.getSigner(), Provider.getDefaultProvider(types.Network.Sepolia));
const tokenL1 = "0x5C221E77624690fff6dd741493D735a17716c26B";
const gas = await signer.estimateGasDeposit({
token: tokenL1,
- amount: "10000000",
+ amount: 10_000_000,
});
console.log(`Gas: ${gas}`);
```
@@ -2160,17 +2238,16 @@ async getFullRequiredDepositFee(transaction: {
#### Example
```ts
-import { Provider, L1Signer, types } from "zksync-ethers";
+import { Provider, L1Signer, Wallet, types } from "zksync-ethers";
import { ethers } from "ethers";
-const provider = new ethers.providers.Web3Provider(window.ethereum);
-const zksyncProvider = Provider.getDefaultProvider(types.Network.Sepolia);
-const signer = L1Signer.from(provider.getSigner(), zksyncProvider);
+const browserProvider = new ethers.providers.Web3Provider(window.ethereum);
+const signer = L1Signer.from(browserProvider.getSigner(), Provider.getDefaultProvider(types.Network.Sepolia));
const tokenL1 = "0x56E69Fa1BB0d1402c89E3A4E3417882DeA6B14Be";
const fee = await signer.getFullRequiredDepositFee({
token: tokenL1,
- to: await wallet.getAddress(),
+ to: Wallet.createRandom().address,
});
console.log(`Fee: ${fee}`);
```
@@ -2197,9 +2274,8 @@ async claimFailedDeposit(depositHash: BytesLike): Promise
+```
+
+#### Example
+
+```ts
+import { SmartAccount, Provider, types } from "zksync-ethers";
+
+const ADDRESS = "";
+const PRIVATE_KEY = "";
+
+const provider = Provider.getDefaultProvider(types.Network.Sepolia);
+const account = new SmartAccount({ address: ADDRESS, secret: PRIVATE_KEY }, provider);
+
+const address = await account.getAddress();
+```
+
+### `getBalance`
+
+Returns the balance of the account.
+
+#### Inputs
+
+| Parameter | Type | Description |
+| ---------- | ---------- | -------------------------------------------------------------------------------- |
+| `token` | `Address` | The token address to query balance for. Defaults to the native token (optional). |
+| `blockTag` | `BlockTag` | The block tag to get the balance at. Defaults to `committed`. |
+
+```ts
+async getBalance(token?: Address, blockTag: BlockTag = 'committed'): Promise
+```
+
+#### Example
+
+```ts
+import { SmartAccount, Provider, types } from "zksync-ethers";
+
+const ADDRESS = "";
+const PRIVATE_KEY = "";
+
+const provider = Provider.getDefaultProvider(types.Network.Sepolia);
+const account = new SmartAccount({ address: ADDRESS, secret: PRIVATE_KEY }, provider);
+
+const balance = await account.getBalance();
+```
+
+### `getAllBalances`
+
+Returns all token balances of the account.
+
+```ts
+async getAllBalances(): Promise
+```
+
+#### Example
+
+```ts
+import { SmartAccount, Provider, types } from "zksync-ethers";
+
+const ADDRESS = "";
+const PRIVATE_KEY = "";
+
+const provider = Provider.getDefaultProvider(types.Network.Sepolia);
+const account = new SmartAccount({ address: ADDRESS, secret: PRIVATE_KEY }, provider);
+
+const balances = await account.getAllBalances();
+```
+
+### `getDeploymentNonce`
+
+Returns the deployment nonce of the account.
+
+```ts
+async getDeploymentNonce(): Promise
+```
+
+#### Example
+
+```ts
+import { SmartAccount, Provider, types } from "zksync-ethers";
+
+const ADDRESS = "";
+const PRIVATE_KEY = "";
+
+const provider = Provider.getDefaultProvider(types.Network.Sepolia);
+const account = new SmartAccount({ address: ADDRESS, secret: PRIVATE_KEY }, provider);
+
+const nonce = await account.getDeploymentNonce();
+```
+
+### `getNonce`
+
+Get the number of transactions ever sent for account, which is used as the `nonce` when sending a transaction.
+
+#### Inputs
+
+| Parameter | Type | Description |
+| ----------- | ---------- | ----------------------------------------------- |
+| `blockTag?` | `BlockTag` | The block tag to get the balance at (optional). |
+
+```ts
+async getNonce(blockTag?: BlockTag): Promise
+```
+
+#### Example
+
+```ts
+import { SmartAccount, Provider, types } from "zksync-ethers";
+import { ethers } from "ethers";
+
+const ADDRESS = "";
+const PRIVATE_KEY = "";
+
+const provider = Provider.getDefaultProvider(types.Network.Sepolia);
+const account = new SmartAccount({ address: ADDRESS, secret: PRIVATE_KEY }, provider);
+
+const nonce = await account.getNonce();
+```
+
+### `populateTransaction`
+
+Populates the transaction `tx` using the provided [`TransactionBuilder`](./types.md#transactionbuilder) function.
+If `tx.from` is not set, it sets the value from the `getAddress` method which can
+be utilized in the [`TransactionBuilder`](./types.md#transactionbuilder) function.
+
+#### Inputs
+
+| Parameter | Type | Description |
+| --------- | ----------------------------------------------------- | ------------------------------------------- |
+| `tx` | [`TransactionRequest`](./types.md#transactionrequest) | The transaction that needs to be populated. |
+
+```ts
+async populateTransaction(tx: TransactionRequest): Promise
+```
+
+#### Example
+
+```ts
+import { SmartAccount, Provider, types, utils } from "zksync-ethers";
+
+const ADDRESS = "";
+const PRIVATE_KEY = "";
+
+const provider = Provider.getDefaultProvider(types.Network.Sepolia);
+const account = new SmartAccount({ address: ADDRESS, secret: PRIVATE_KEY }, provider);
+
+const populatedTx = await account.populateTransaction({
+ type: utils.EIP712_TX_TYPE,
+ to: "",
+ value: 7_000_000_000,
});
+```
-console.log(`Executing the transaction will cost ${ethers.utils.formatEther(txCostPrice)} ETH`);
+### `signTransaction`
-const executeTx = await signer.getRequestExecuteTx({
- contractAddress: CONTRACT_ADDRESS,
- calldata,
- l2Value: 1,
- l2GasLimit,
- overrides: {
- gasPrice,
- value: txCostPrice,
+Signs the transaction `tx` using the provided [`PayloadSigner`](./types.md#payloadsigner) function,
+returning the fully signed transaction. The `populateTransaction` method
+is called first to ensure that all necessary properties for the transaction to be valid
+have been populated.
+
+#### Inputs
+
+| Parameter | Type | Description |
+| --------- | ----------------------------------------------------- | ---------------------------------------- |
+| `tx` | [`TransactionRequest`](./types.md#transactionrequest) | The transaction that needs to be signed. |
+
+```ts
+async signTransaction(tx: TransactionRequest): Promise
+```
+
+#### Example
+
+```ts
+import { SmartAccount, Provider, types } from "zksync-ethers";
+import { ethers } from "ethers";
+
+const ADDRESS = "";
+const PRIVATE_KEY = "";
+
+const provider = Provider.getDefaultProvider(types.Network.Sepolia);
+const account = new SmartAccount({ address: ADDRESS, secret: PRIVATE_KEY }, provider);
+
+const signedTx = await account.signTransaction({
+ to: "",
+ value: ethers.utils.parseEther("1"),
+});
+```
+
+### `sendTransaction`
+
+Sends `tx` to the Network. The `signTransaction`
+is called first to ensure transaction is properly signed.
+
+#### Inputs
+
+| Parameter | Type | Description |
+| --------- | ----------------------------------------------------- | -------------------------------------- |
+| `tx` | [`TransactionRequest`](./types.md#transactionrequest) | The transaction that needs to be sent. |
+
+```ts
+async sendTransaction(tx: TransactionRequest): Promise
+```
+
+#### Example
+
+```ts
+import { SmartAccount, Provider, types } from "zksync-ethers";
+import { ethers } from "ethers";
+
+const ADDRESS = "";
+const PRIVATE_KEY = "";
+
+const provider = Provider.getDefaultProvider(types.Network.Sepolia);
+const account = new SmartAccount({ address: ADDRESS, secret: PRIVATE_KEY }, provider);
+
+const signedTx = await account.sendTransaction({
+ to: "",
+ value: ethers.utils.parseEther("1"),
+});
+```
+
+### `signMessage`
+
+Signs a `message` using the provided [`PayloadSigner`](./types.md#payloadsigner) function.
+
+#### Inputs
+
+| Parameter | Type | Description |
+| --------- | ------------------------ | ------------------------------------ |
+| `message` | `string` or `Uint8Array` | The message that needs to be signed. |
+
+```ts
+signMessage(message: string | Uint8Array): Promise
+```
+
+#### Example
+
+```ts
+import { SmartAccount, Provider, types } from "zksync-ethers";
+import { ethers } from "ethers";
+
+const ADDRESS = "";
+const PRIVATE_KEY = "";
+
+const provider = Provider.getDefaultProvider(types.Network.Sepolia);
+const account = new SmartAccount({ address: ADDRESS, secret: PRIVATE_KEY }, provider);
+
+const signedMessage = await account.signMessage("Hello World!");
+```
+
+### `_signTypedData`
+
+Signs a typed data using the provided [`PayloadSigner`](./types.md#payloadsigner) function.
+
+#### Inputs
+
+| Parameter | Type | Description |
+| --------- | ----------------------------------------- | -------------------------------------------------------- |
+| `domain` | `ethers.TypedDataDomain` | The domain data. |
+| `types` | `Record` | A map of records pointing from field name to field type. |
+| `value` | `Record` | A single record value. |
+
+```ts
+async signTypedData(
+ domain: ethers.TypedDataDomain,
+ types: Record,
+ value: Record
+): Promise
+```
+
+#### Example
+
+```ts
+import { SmartAccount, Provider, types } from "zksync-ethers";
+import { ethers } from "ethers";
+
+const ADDRESS = "";
+const PRIVATE_KEY = "";
+
+const provider = Provider.getDefaultProvider(types.Network.Sepolia);
+const account = new SmartAccount({ address: ADDRESS, secret: PRIVATE_KEY }, provider);
+
+const signedTypedData = await account._signTypedData(
+ { name: "Example", version: "1", chainId: 270 },
+ {
+ Person: [
+ { name: "name", type: "string" },
+ { name: "age", type: "uint8" },
+ ],
},
+ { name: "John", age: 30 }
+);
+```
+
+### `withdraw`
+
+Initiates the withdrawal process which withdraws ETH or any ERC20 token from the associated account on L2 network to the target account on
+L1 network.
+
+#### Inputs
+
+| Parameter | Type | Description |
+| ------------------------------ | ----------------------------------------------- | ----------------------------------------------------------------------------------------------------- |
+| `transaction.token` | `Address` | The address of the token. `ETH` by default. |
+| `transaction.amount` | `BigNumberish` | The amount of the token to withdraw. |
+| `transaction.to?` | `Address` | The address of the recipient on L1 (optional). |
+| `transaction.bridgeAddress?` | `Address` | The address of the bridge contract to be used (optional). |
+| `transaction.paymasterParams?` | [`PaymasterParams`](./types.md#paymasterparams) | Paymaster parameters (optional). |
+| `transaction.overrides?` | `ethers.CallOverrides` | Transaction's overrides which may be used to pass L2 `gasLimit`, `gasPrice`, `value`, etc (optional). |
+
+```ts
+async withdraw(transaction: {
+ token: Address;
+ amount: BigNumberish;
+ to?: Address;
+ bridgeAddress?: Address;
+ paymasterParams?: PaymasterParams;
+ overrides?: ethers.CallOverrides;
+}): Promise
+```
+
+#### Examples
+
+Withdraw ETH.
+
+```ts
+import { SmartAccount, Provider, types, utils } from "zksync-ethers";
+
+const ADDRESS = "";
+const PRIVATE_KEY = "";
+
+const provider = Provider.getDefaultProvider(types.Network.Sepolia);
+const account = new SmartAccount({ address: ADDRESS, secret: PRIVATE_KEY }, provider);
+
+const tokenWithdrawHandle = await account.withdraw({
+ token: utils.ETH_ADDRESS,
+ amount: 10_000_000,
+});
+```
+
+Withdraw ETH using paymaster to facilitate fee payment with an ERC20 token.
+
+```ts
+import { SmartAccount, Provider, types, utils } from "zksync-ethers";
+
+const ADDRESS = "";
+const PRIVATE_KEY = "";
+
+const token = "0x927488F48ffbc32112F1fF721759649A89721F8F"; // Crown token which can be minted for free
+const paymaster = "0x13D0D8550769f59aa241a41897D4859c87f7Dd46"; // Paymaster for Crown token
+
+const provider = Provider.getDefaultProvider(types.Network.Sepolia);
+const account = new SmartAccount({ address: ADDRESS, secret: PRIVATE_KEY }, provider);
+
+const tokenWithdrawHandle = await account.withdraw({
+ token: utils.ETH_ADDRESS,
+ amount: 10_000_000,
+ paymasterParams: utils.getPaymasterParams(paymaster, {
+ type: "ApprovalBased",
+ token: token,
+ minimalAllowance: 1,
+ innerInput: new Uint8Array(),
+ }),
});
```
+
+### `transfer`
+
+Transfer ETH or any ERC20 token within the same interface.
+
+| Parameter | Type | Description |
+| ------------------------------ | ----------------------------------------------- | ----------------------------------------------------------------------------------------------------- |
+| `transaction.to` | `Address` | The address of the recipient. |
+| `transaction.amount` | `BigNumberish` | The amount of the token to transfer. |
+| `transaction.token?` | `Address` | The address of the token. `ETH` by default (optional). |
+| `transaction.paymasterParams?` | [`PaymasterParams`](./types.md#paymasterparams) | Paymaster parameters (optional). |
+| `transaction.overrides?` | `ethers.CallOverrides` | Transaction's overrides which may be used to pass L2 `gasLimit`, `gasPrice`, `value`, etc (optional). |
+
+```ts
+async transfer(transaction: {
+ to: Address;
+ amount: BigNumberish;
+ token?: Address;
+ overrides?: ethers.CallOverrides;
+}): Promise
+```
+
+#### Examples
+
+Transfer ETH.
+
+```ts
+import { SmartAccount, Wallet, Provider, types } from "zksync-ethers";
+import { ethers } from "ethers";
+
+const ADDRESS = "";
+const PRIVATE_KEY = "";
+
+const provider = Provider.getDefaultProvider(types.Network.Sepolia);
+const account = new SmartAccount({ address: ADDRESS, secret: PRIVATE_KEY }, provider);
+
+const transferHandle = await account.transfer({
+ token: utils.ETH_ADDRESS,
+ to: Wallet.createRandom().address,
+ amount: ethers.parseEther("0.01"),
+});
+
+const tx = await transferHandle.wait();
+
+console.log(`The sum of ${tx.value} ETH was transferred to ${tx.to}`);
+```
+
+Transfer ETH using paymaster to facilitate fee payment with an ERC20 token.
+
+```ts
+import { SmartAccount, Wallet, Provider, utils } from "zksync-ethers";
+import { ethers } from "ethers";
+
+const ADDRESS = "";
+const PRIVATE_KEY = "";
+
+const token = "0x927488F48ffbc32112F1fF721759649A89721F8F"; // Crown token which can be minted for free
+const paymaster = "0x13D0D8550769f59aa241a41897D4859c87f7Dd46"; // Paymaster for Crown token
+
+const provider = Provider.getDefaultProvider(types.Network.Sepolia);
+const account = new SmartAccount({ address: ADDRESS, secret: PRIVATE_KEY }, provider);
+
+const transferHandle = await account.transfer({
+ to: Wallet.createRandom().address,
+ amount: ethers.parseEther("0.01"),
+ paymasterParams: utils.getPaymasterParams(paymaster, {
+ type: "ApprovalBased",
+ token: token,
+ minimalAllowance: 1,
+ innerInput: new Uint8Array(),
+ }),
+});
+
+const tx = await transferHandle.wait();
+
+console.log(`The sum of ${tx.value} ETH was transferred to ${tx.to}`);
+```
+
+## `ECDSASmartAccount`
+
+A `ECDSASmartAccount` is a factory which creates a `SmartAccount` instance
+that uses single ECDSA key for signing payload.
+
+### `create`
+
+Creates a `SmartAccount` instance that uses a single ECDSA key for signing payload.
+
+#### Inputs
+
+| Parameter | Type | Description |
+| ---------- | ------------------------------------- | --------------------------- |
+| `address` | `string` | The account address. |
+| `secret` | `string` or `ethers.utils.SigningKey` | The ECDSA private key. |
+| `provider` | [`Provider`](./providers.md#provider) | The provider to connect to. |
+
+```ts
+static create(address: string, secret: string | utils.SigningKey, provider: Provider): SmartAccount
+```
+
+#### Example
+
+```ts
+import { ECDSASmartAccount, Provider, types } from "zksync-ethers";
+
+const ADDRESS = "";
+const PRIVATE_KEY = "";
+
+const provider = Provider.getDefaultProvider(types.Network.Sepolia);
+const account = ECDSASmartAccount.create(ADDRESS, PRIVATE_KEY, provider);
+```
+
+## `MultisigECDSASmartAccount`
+
+A `MultisigECDSASmartAccount` is a factory which creates a `SmartAccount` instance
+that uses multiple ECDSA keys for signing payloads.
+The signature is generated by concatenating signatures created by signing with each key individually.
+
+### `create`
+
+Creates a `SmartAccount` instance that uses multiple ECDSA keys for signing payloads.
+
+#### Inputs
+
+| Parameter | Type | Description |
+| ---------- | ------------------------------------------ | ----------------------------------- |
+| `address` | `string` | The account address. |
+| `secret` | `string[]` or `ethers.utils.SigningKeyp[]` | The list of the ECDSA private keys. |
+| `provider` | [`Provider`](./providers.md#provider) | The provider to connect to. |
+
+```ts
+static create(address: string, secret: string[] | utils.SigningKey[], provider: Provider): SmartAccount
+```
+
+#### Example
+
+```ts
+import { MultisigECDSASmartAccount, Provider, types } from "zksync-ethers";
+
+const ADDRESS = "";
+const PRIVATE_KEY1 = "";
+const PRIVATE_KEY2 = "";
+
+const provider = Provider.getDefaultProvider(types.Network.Sepolia);
+
+const account = MultisigECDSASmartAccount.create(multisigAddress, [PRIVATE_KEY1, PRIVATE_KEY2], provider);
+```
diff --git a/docs/build/sdks/js/paymaster-utils.md b/docs/build/sdks/js/paymaster-utils.md
index 992df50fee..0c7c20d3f9 100644
--- a/docs/build/sdks/js/paymaster-utils.md
+++ b/docs/build/sdks/js/paymaster-utils.md
@@ -14,7 +14,7 @@ The [paymaster utilities library](https://github.com/zksync-sdk/zksync-ethers/bl
Constant ABI definition for
the [Paymaster Flow Interface](https://github.com/matter-labs/era-contracts/blob/583cb674a2b942dda34e9f46edb5a9f5b696b90a/l2-contracts/contracts/interfaces/IPaymasterFlow.sol).
-```typescript
+```ts
export const PAYMASTER_FLOW_ABI = new ethers.Interface(require("../abi/IPaymasterFlow.json"));
```
@@ -59,7 +59,7 @@ Returns a correctly-formed `paymasterParams` object for common [paymaster flows]
| `paymasterAddress` | `Address` | The non-zero `paymaster` address. |
| `paymasterInput` | [`PaymasterInput`](./types.md#paymasterinput) | The input data to the paymaster. |
-```typescript
+```ts
export function getPaymasterParams(paymasterAddress: Address, paymasterInput: PaymasterInput): PaymasterParams;
```
diff --git a/docs/build/sdks/js/smart-account-utils.md b/docs/build/sdks/js/smart-account-utils.md
new file mode 100644
index 0000000000..a381d7955e
--- /dev/null
+++ b/docs/build/sdks/js/smart-account-utils.md
@@ -0,0 +1,239 @@
+---
+head:
+ - - meta
+ - name: "twitter:title"
+ content: JS SDK Smart Account Utilities | zkSync Docs
+---
+
+# Smart Account Utilities
+
+## Functions
+
+### `signPayloadWithECDSA`
+
+Signs the `payload` using an ECDSA private key.
+
+#### Inputs
+
+| Parameter | Type | Description |
+| --------- | ------------------------------------- | ------------------------------------ |
+| `payload` | `BytesLike` | The payload that needs to be signed. |
+| `secret` | `string` or `ethers.utils.SigningKey` | The ECDSA private key. |
+
+```ts
+export const signPayloadWithECDSA: PayloadSigner = async (payload, secret: string | utils.SigningKey)
+```
+
+#### Examples
+
+Sign EIP712 transaction hash.
+
+```ts
+import { EIP712Signer, types, utils } from "zksync-ethers";
+
+const PRIVATE_KEY = "";
+
+const tx: types.TransactionRequest = {
+ chainId: 270,
+ from: ADDRESS,
+ to: "",
+ value: 7_000_000_000,
+};
+
+const txHash = EIP712Signer.getSignedDigest(tx);
+const signature = await utils.signPayloadWithECDSA(txHash, PRIVATE_KEY);
+```
+
+Sign message hash.
+
+```ts
+import { utils } from "zksync-ethers";
+import { ethers } from "ethers";
+
+const PRIVATE_KEY = "";
+
+const message = "Hello World!";
+const messageHash = ethers.utils.hashMessage(message);
+
+const signature = await utils.signPayloadWithECDSA(messageHash, PRIVATE_KEY);
+```
+
+Sign typed data hash.
+
+```ts
+import { utils } from "zksync-ethers";
+import { ethers } from "ethers";
+
+const PRIVATE_KEY = "";
+
+const typedDataHash = ethers.utils._TypedDataEncoder.hash(
+ { name: "Example", version: "1", chainId: 270 },
+ {
+ Person: [
+ { name: "name", type: "string" },
+ { name: "age", type: "uint8" },
+ ],
+ },
+ { name: "John", age: 30 }
+);
+const signature = await utils.signPayloadWithECDSA(typedDataHash, PRIVATE_KEY);
+```
+
+### `signPayloadWithMultipleECDSA`
+
+Signs the `payload` using multiple ECDSA private keys.
+The signature is generated by concatenating signatures created by signing with each key individually.
+The length of the resulting signature should be `secrets.length * 65 + 2`.
+
+#### Inputs
+
+| Parameter | Type | Description |
+| --------- | ----------------------------------------- | ------------------------------------ |
+| `payload` | `BytesLike` | The payload that needs to be signed. |
+| `secret` | `string[]` or `ethers.utils.SigningKey[]` | The list of the ECDSA private keys. |
+
+```ts
+const signPayloadWithMultipleECDSA: PayloadSigner = async (payload, secret: string[] | utils.SigningKey[])
+```
+
+#### Examples
+
+Sign EIP712 transaction hash.
+
+```ts
+import { EIP712Signer, types, utils } from "zksync-ethers";
+
+const PRIVATE_KEY1 = "";
+const PRIVATE_KEY2 = "";
+
+const tx: types.TransactionRequest = {
+ chainId: 270,
+ from: ADDRESS,
+ to: "",
+ value: 7_000_000_000,
+};
+
+const txHash = EIP712Signer.getSignedDigest(tx);
+const signature = await utils.signPayloadWithMultipleECDSA(txHash, [PRIVATE_KEY1, PRIVATE_KEY2]);
+```
+
+Sign message hash.
+
+```ts
+import { utils } from "zksync-ethers";
+import { ethers } from "ethers";
+
+const PRIVATE_KEY1 = "";
+const PRIVATE_KEY2 = "";
+
+const message = "Hello World!";
+const messageHash = ethers.utils.hashMessage(message);
+
+const signature = await utils.signPayloadWithMultipleECDSA(messageHash, [PRIVATE_KEY1, PRIVATE_KEY2]);
+```
+
+Sign typed data hash.
+
+```ts
+import { utils } from "zksync-ethers";
+import { ethers } from "ethers";
+
+const PRIVATE_KEY1 = "";
+const PRIVATE_KEY2 = "";
+
+const typedDataHash = ethers.utils._TypedDataEncoder.hash(
+ { name: "Example", version: "1", chainId: 270 },
+ {
+ Person: [
+ { name: "name", type: "string" },
+ { name: "age", type: "uint8" },
+ ],
+ },
+ { name: "John", age: 30 }
+);
+const signature = await utils.signPayloadWithMultipleECDSA(typedDataHash, [PRIVATE_KEY1, PRIVATE_KEY2]);
+```
+
+## `populateTransactionECDSA`
+
+Populates missing properties meant for signing using an ECDSA private key:
+
+- Populates `from` using the address derived from the ECDSA private key.
+- Populates `nonce` via `provider.getTransactionCount(tx.from, "pending")`.
+- Populates `gasLimit` via `provider.estimateGas(tx)`. If `tx.from` is not EOA, the estimation is done with address
+ derived from the ECDSA private key.
+- Populates `chainId` via `provider.getNetwork()`.
+- Populates `type` with `utils.EIP712_TX_TYPE`.
+- Populates `value` by converting to `bigint` if set, otherwise to `0n`.
+- Populates `data` with `0x`.
+- Populates `customData` with `{factoryDeps=[], gasPerPubdata=utils.DEFAULT_GAS_PER_PUBDATA_LIMIT}`.
+
+#### Inputs
+
+| Parameter | Type | Description |
+| ---------- | ------------------------------------- | ---------------------------------------------------------------------------------- |
+| `tx` | `BytesLike` | The transaction that needs to be populated. |
+| `secret` | `string` or `ethers.utils.SigningKey` | The ECDSA private key. |
+| `provider` | [`Provider`](./providers.md#provider) | The provider is used to fetch data from the network if it is required for signing. |
+
+```ts
+const populateTransactionECDSA: TransactionBuilder = async (tx, secret: string | utils.SigningKey, provider)
+```
+
+#### Example
+
+```ts
+import { Provider, types, utils } from "zksync-ethers";
+
+const PRIVATE_KEY = "";
+
+const provider = Provider.getDefaultProvider(types.Network.Sepolia);
+
+const populatedTx = await utils.populateTransactionECDSA(
+ {
+ chainId: 270,
+ to: "",
+ value: 7_000_000_000,
+ },
+ PRIVATE_KEY,
+ provider
+);
+```
+
+## `populateTransactionMultisigECDSA`
+
+Populates missing properties meant for signing using multiple ECDSA private keys.
+It uses [`populateTransactionECDSA`](#populatetransactionecdsa), where the address of the first ECDSA key is set as the `secret` argument.
+
+#### Inputs
+
+| Parameter | Type | Description |
+| ---------- | ----------------------------------------- | ---------------------------------------------------------------------------------- |
+| `tx` | `BytesLike` | The transaction that needs to be populated. |
+| `secret` | `string[]` or `ethers.utils.SigningKey[]` | The list of the ECDSA private keys used for populating the transaction. |
+| `provider` | [`Provider`](./providers.md#provider) | The provider is used to fetch data from the network if it is required for signing. |
+
+```ts
+const populateTransactionMultisigECDSA: TransactionBuilder = async (tx, secret: string[] | SigningKey[], provider)
+```
+
+#### Example
+
+```ts
+import { Provider, types, utils } from "zksync-ethers";
+
+const PRIVATE_KEY1 = "";
+const PRIVATE_KEY2 = "";
+
+const provider = Provider.getDefaultProvider(types.Network.Sepolia);
+
+const populatedTx = await utils.populateTransactionMultisigECDSA(
+ {
+ chainId: 270,
+ to: "",
+ value: 7_000_000_000,
+ },
+ [PRIVATE_KEY1, PRIVATE_KEY2],
+ provider
+);
+```
diff --git a/docs/build/sdks/js/types.md b/docs/build/sdks/js/types.md
index 93ba1c75d9..cb751cfdfb 100644
--- a/docs/build/sdks/js/types.md
+++ b/docs/build/sdks/js/types.md
@@ -86,15 +86,15 @@ Interface representation of block information containing various optional and ma
## `BlockTag`
-Pipe-delimited list of block labels that includes block number in denary and hex plus block statuses.
+Pipe-delimited list of block labels that includes block number in binary and hex plus block statuses.
- `number`
- `string` // hex representation of block number
-- "committed"
-- "finalized"
-- "latest"
-- "earliest"
-- "pending"
+- `committed`
+- `finalized`
+- `latest`
+- `earliest`
+- `pending`
## `BlockWithTransaction`
@@ -244,6 +244,14 @@ Type defining a paymaster by address and the bytestream input.
- `paymaster`: `Address`;
- `paymasterInput`: `BytesLike`;
+## `PayloadSigner`
+
+Signs various types of payloads, optionally using a some kind of secret.
+
+- `payload`: `BytesLike`;
+- `secret`: `any`;
+- `provider` `null | Provider`;
+
## `PriorityOpResponse`
Interface representation of priority op response that extends [`TransactionResponse`](#transactionresponse) and adds a function that waits to commit a layer 1 transaction, including when given on optional confirmation number.
@@ -283,9 +291,18 @@ Interface representation of raw block with transactions
0x-prefixed, hex-encoded, ECDSA signature as string.
+## `SmartAccountSigner`
+
+Encapsulates the required input parameters for creating a signer for [`SmartAccount`](./accounts.md#smartaccount).
+
+- `address`: `string`;
+- `secret`: `any`;
+- `payloadSigner`: `PayloadSigner`;
+- `transactionBuilder`: `TransactionBuilder`;
+
## `StorageProof`
-Interace representation of Merkle proofs for storage values.
+Interface representation of Merkle proofs for storage values.
- `address`: `string`;
- `storageProof` (Array):
@@ -305,6 +322,14 @@ Interface representation of token containing various fields.
- `symbol`: `string`;
- `decimals`: `number`;
+## `TransactionBuilder`
+
+Populates missing fields in a transaction with default values.
+
+- `transaction`: `TransactionRequest`;
+- `secret`: `any`;
+- `provider`: `null | Provider`;
+
## `TransactionDetails`
Interface representation of transaction details containing various mandatory and optional fields.
@@ -351,5 +376,5 @@ Non-enumerated enum list of transaction statuses.
- Finalized = `finalized`
:::tip More info
-Find the code definition of the types above on the [zkSync Era Github repo.](https://github.com/zksync-sdk/zksync-ethers/blob/ethers-v5/src/utils.ts)
+Find the code definition of the types above on the [zkSync Era GitHub repo.](https://github.com/zksync-sdk/zksync-ethers/blob/ethers-v5/src/utils.ts)
:::
diff --git a/docs/build/sdks/js/zksync-ethers/accounts-l1-l2.md b/docs/build/sdks/js/zksync-ethers/accounts-l1-l2.md
index 5c9c9b7229..220d5f916b 100644
--- a/docs/build/sdks/js/zksync-ethers/accounts-l1-l2.md
+++ b/docs/build/sdks/js/zksync-ethers/accounts-l1-l2.md
@@ -41,6 +41,6 @@ method specification [`getBaseCost`](accounts.md#getbasecost).
## Withdrawal
-`Wallet` and `Signer` objects provide a withdrawal workflow. For more information, please refer to the method specification [`Deposit`](accounts.md#deposit).
+`Wallet` and `Signer` objects provide a withdrawal workflow. For more information, please refer to the method specification [`Withdraw`](accounts.md#withdraw).
For a complete example of how to execute the deposit workflow, take a look at the following: [Withdraw ETH and ERC20 token](https://github.com/zksync-sdk/zksync2-examples/blob/main/js/src/03_withdraw.ts).
diff --git a/docs/build/sdks/js/zksync-ethers/accounts.md b/docs/build/sdks/js/zksync-ethers/accounts.md
index dbf6dbece4..7134e0f5c4 100644
--- a/docs/build/sdks/js/zksync-ethers/accounts.md
+++ b/docs/build/sdks/js/zksync-ethers/accounts.md
@@ -14,6 +14,11 @@ head:
- `Wallet` class is an extension of the `ethers.Wallet` with additional zkSync features.
- `EIP712Signer` class that is used to sign `EIP712`_-typed_ zkSync transactions.
- `Signer` and `L1Signer` classes, which should be used for browser integration.
+- `VoidSigner` and `L1VoidSigner` classes, which should be used for designed to allow an address to
+ be used in any API which accepts a `Signer`, but for which there are no credentials available to perform any actual signing.
+- `SmartAccount` which provides better support for account abstraction. There are following factory classes:
+ - `ECDSASmartAccount`: uses a single ECDSA key for signing payload.
+ - `MultisigECDSASmartAccount`: uses multiple ECDSA keys for signing payloads.
## `Wallet`
@@ -786,7 +791,7 @@ use the [`allowanceL1`](#getallowancel1) method.
| Parameter | Type | Description |
| -------------------------------- | ------------------------------------------------------------------------ | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `transaction.token` | `Address` | The address of the token to deposit. `ETH` by default. |
-| `transaction.amount` | `BigNumberish` | The amount of the token to withdraw. |
+| `transaction.amount` | `BigNumberish` | The amount of the token to deposit. |
| `transaction.to?` | `Address` | The address that will receive the deposited tokens on L2 (optional). |
| `transaction.operatorTip?` | `BigNumberish` | (_currently is not used_) If the ETH value passed with the transaction is not explicitly stated in the overrides, this field will be equal to the tip the operator will receive on top of the base cost of the transaction (optional). |
| `transaction.bridgeAddress?` | `Address` | The address of the bridge contract to be used. Defaults to the default zkSync bridge (either `L1EthBridge` or `L1Erc20Bridge`) (optional). |
@@ -857,7 +862,7 @@ Returns populated deposit transaction.
| Parameter | Type | Description |
| -------------------------------- | ------------------------------------------------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `transaction.token` | `Address` | The address of the token to deposit. `ETH` by default. |
-| `transaction.amount` | `BigNumberish` | The amount of the token to withdraw. |
+| `transaction.amount` | `BigNumberish` | The amount of the token to deposit. |
| `transaction.to?` | `Address` | The address that will receive the deposited tokens on L2 (optional). |
| `transaction.operatorTip?` | `BigNumberish` | (_currently is not used_) If the ETH value passed with the transaction is not explicitly stated in the overrides, this field will be equal to the tip the operator will receive on top of the base cost of the transaction (optional). |
| `transaction.bridgeAddress?` | `Address` | The address of the bridge contract to be used. Defaults to the default zkSync bridge (either `L1EthBridge` or `L1Erc20Bridge`) (optional). |
@@ -910,7 +915,7 @@ Estimates the amount of gas required for a deposit transaction on L1 network. Ga
| Parameter | Type | Description |
| -------------------------------- | ------------------------------------------------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `transaction.token` | `Address` | The address of the token to deposit. `ETH` by default. |
-| `transaction.amount` | `BigNumberish` | The amount of the token to withdraw. |
+| `transaction.amount` | `BigNumberish` | The amount of the token to deposit. |
| `transaction.to?` | `Address` | The address that will receive the deposited tokens on L2 (optional). |
| `transaction.operatorTip?` | `BigNumberish` | (_currently is not used_) If the ETH value passed with the transaction is not explicitly stated in the overrides, this field will be equal to the tip the operator will receive on top of the base cost of the transaction (optional). |
| `transaction.bridgeAddress?` | `Address` | The address of the bridge contract to be used. Defaults to the default zkSync bridge (either `L1EthBridge` or `L1Erc20Bridge`) (optional). |
@@ -1522,10 +1527,10 @@ This class is to be used in a browser environment. The easiest way to construct
extends `ethers.JsonRpcSigner` and so supports all the methods available for it.
```ts
-import { BrowserProvider } from "zksync-ethers";
+import { BrowserProvider, Provider, types } from "zksync-ethers";
-const provider = new BrowserProvider(window.ethereum);
-const signer = provider.getSigner();
+const browserProvider = new BrowserProvider(window.ethereum);
+const signer = Signer.from(await browserProvider.getSigner(), Number((await browserProvider.getNetwork()).chainId), Provider.getDefaultProvider(types.Network.Sepolia));
```
### `getBalance`
@@ -1545,18 +1550,85 @@ async getBalance(token?: Address, blockTag: BlockTag = 'committed'): Promise
+```
+
+#### Example
+
+```ts
+import { BrowserProvider, Provider, types } from "zksync-ethers";
+
+const browserProvider = new BrowserProvider(window.ethereum);
+const signer = Signer.from(await browserProvider.getSigner(), Number((await browserProvider.getNetwork()).chainId), Provider.getDefaultProvider(types.Network.Sepolia));
+
+const allBalances = await signer.getAllBalances();
+```
+
+### `getDeploymentNonce`
+
+Returns the deployment nonce of the account.
+
+```ts
+async getDeploymentNonce(): Promise
+```
+
+#### Example
-// Getting ETH balance
-console.log(await signer.getBalance());
+```ts
+import { BrowserProvider, Provider, types } from "zksync-ethers";
+
+const browserProvider = new BrowserProvider(window.ethereum);
+const signer = Signer.from(await browserProvider.getSigner(), Number((await browserProvider.getNetwork()).chainId), Provider.getDefaultProvider(types.Network.Sepolia));
+
+console.log(`Nonce: ${await signer.getDeploymentNonce()}`);
+```
+
+### `getL2BridgeContracts`
+
+Returns L2 bridge contracts.
+
+```ts
+async getDeploymentNonce(): Promise
+```
+
+#### Example
+
+```ts
+import { BrowserProvider, Provider, types } from "zksync-ethers";
+
+const browserProvider = new BrowserProvider(window.ethereum);
+const signer = Signer.from(await browserProvider.getSigner(), Number((await browserProvider.getNetwork()).chainId), Provider.getDefaultProvider(types.Network.Sepolia));
+
+const l2BridgeContracts = await signer.getL2BridgeContracts();
```
### `getNonce`
@@ -1576,12 +1648,12 @@ async getNonce(blockTag?: BlockTag): Promise
#### Example
```ts
-import { BrowserProvider } from "zksync-ethers";
+import { BrowserProvider, Provider, types } from "zksync-ethers";
-const provider = new BrowserProvider(window.ethereum);
-const signer = provider.getSigner();
+const browserProvider = new BrowserProvider(window.ethereum);
+const signer = Signer.from(await browserProvider.getSigner(), Number((await browserProvider.getNetwork()).chainId), Provider.getDefaultProvider(types.Network.Sepolia));
-console.log(await signer.getNonce());
+const nonce = await signer.getNonce();
```
### `transfer`
@@ -1616,36 +1688,36 @@ async transfer(transaction: {
Transfer ETH.
```ts
-import { BrowserProvider } from "zksync-ethers";
+import { BrowserProvider, Provider, Wallet, types } from "zksync-ethers";
import { ethers } from "ethers";
-const provider = new BrowserProvider(window.ethereum);
-const signer = provider.getSigner();
-
-const recipient = Wallet.createRandom();
+const browserProvider = new BrowserProvider(window.ethereum);
+const signer = Signer.from(await browserProvider.getSigner(), Number((await browserProvider.getNetwork()).chainId), Provider.getDefaultProvider(types.Network.Sepolia));
-const transferHandle = signer.transfer({
- to: recipient.address,
+const tx = signer.transfer({
+ to: Wallet.createRandom().address,
amount: ethers.parseEther("0.01"),
});
+
+const receipt = await tx.wait();
+
+console.log(`The sum of ${receipt.value} ETH was transferred to ${receipt.to}`);
```
Transfer ETH using paymaster to facilitate fee payment with an ERC20 token.
```ts
-import { BrowserProvider } from "zksync-ethers";
+import { BrowserProvider, Provider, Wallet, types } from "zksync-ethers";
import { ethers } from "ethers";
const token = "0x927488F48ffbc32112F1fF721759649A89721F8F"; // Crown token which can be minted for free
const paymaster = "0x13D0D8550769f59aa241a41897D4859c87f7Dd46"; // Paymaster for Crown token
-const provider = new BrowserProvider(window.ethereum);
-const signer = provider.getSigner();
-
-const recipient = Wallet.createRandom();
+const browserProvider = new BrowserProvider(window.ethereum);
+const signer = Signer.from(await browserProvider.getSigner(), Number((await browserProvider.getNetwork()).chainId), Provider.getDefaultProvider(types.Network.Sepolia));
-const transferHandle = signer.transfer({
- to: recipient.address,
+const tx = signer.transfer({
+ to: Wallet.createRandom().address,
amount: ethers.parseEther("0.01"),
paymasterParams: utils.getPaymasterParams(paymaster, {
type: "ApprovalBased",
@@ -1654,6 +1726,10 @@ const transferHandle = signer.transfer({
innerInput: new Uint8Array(),
}),
});
+
+const receipt = await tx.wait();
+
+console.log(`The sum of ${receipt.value} ETH was transferred to ${receipt.to}`);
```
### `withdraw`
@@ -1688,14 +1764,14 @@ async withdraw(transaction: {
Withdraw ETH.
```ts
-import { BrowserProvider } from "zksync-ethers";
+import { BrowserProvider, Provider, types } from "zksync-ethers";
import { ethers } from "ethers";
-const provider = new BrowserProvider(window.ethereum);
-const signer = provider.getSigner();
+const browserProvider = new BrowserProvider(window.ethereum);
+const signer = Signer.from(await browserProvider.getSigner(), Number((await browserProvider.getNetwork()).chainId), Provider.getDefaultProvider(types.Network.Sepolia));
const tokenL2 = "0x6a4Fb925583F7D4dF82de62d98107468aE846FD1";
-const tokenWithdrawHandle = await signer.withdraw({
+const tx = await signer.withdraw({
token: tokenL2,
amount: 10_000_000,
});
@@ -1704,19 +1780,18 @@ const tokenWithdrawHandle = await signer.withdraw({
Withdraw ETH using paymaster to facilitate fee payment with an ERC20 token.
```ts
-import { BrowserProvider } from "zksync-ethers";
-import { ethers } from "ethers";
+import { BrowserProvider, Provider, types } from "zksync-ethers";
const token = "0x927488F48ffbc32112F1fF721759649A89721F8F"; // Crown token which can be minted for free
const paymaster = "0x13D0D8550769f59aa241a41897D4859c87f7Dd46"; // Paymaster for Crown token
-const provider = new BrowserProvider(window.ethereum);
-const signer = provider.getSigner();
+const browserProvider = new BrowserProvider(window.ethereum);
+const signer = Signer.from(await browserProvider.getSigner(), Number((await browserProvider.getNetwork()).chainId), Provider.getDefaultProvider(types.Network.Sepolia));
const tokenL2 = "0x6a4Fb925583F7D4dF82de62d98107468aE846FD1";
-const tokenWithdrawHandle = await signer.withdraw({
+const tx = await wallet.withdraw({
token: tokenL2,
- amount: 10_000_000,
+ amount: 10_000_000n,
paymasterParams: utils.getPaymasterParams(paymaster, {
type: "ApprovalBased",
token: token,
@@ -1756,9 +1831,8 @@ async getMainContract(): Promise
import { Provider, L1Signer, types } from "zksync-ethers";
import { ethers } from "ethers";
-const provider = new ethers.BrowserProvider(window.ethereum);
-const zksyncProvider = Provider.getDefaultProvider(types.Network.Sepolia);
-const signer = L1Signer.from(provider.getSigner(), zksyncProvider);
+const browserProvider = new ethers.BrowserProvider(window.ethereum);
+const signer = L1Signer.from(await browserProvider.getSigner(), Provider.getDefaultProvider(types.Network.Sepolia));
const mainContract = await signer.getMainContract();
console.log(mainContract.address);
@@ -1784,9 +1858,8 @@ there is no separate Ether bridge contract, [Main contract](./accounts.md#getmai
import { Provider, L1Signer, types } from "zksync-ethers";
import { ethers } from "ethers";
-const provider = new ethers.BrowserProvider(window.ethereum);
-const zksyncProvider = Provider.getDefaultProvider(types.Network.Sepolia);
-const signer = L1Signer.from(provider.getSigner(), zksyncProvider);
+const browserProvider = new ethers.BrowserProvider(window.ethereum);
+const signer = L1Signer.from(await browserProvider.getSigner(), Provider.getDefaultProvider(types.Network.Sepolia));
const l1BridgeContracts = await signer.getL1BridgeContracts();
```
@@ -1808,21 +1881,30 @@ async getBalanceL1(token?: Address, blockTag?: BlockTag): Promise
#### Example
+Get ETH balance.
+
```ts
import { Provider, L1Signer, types } from "zksync-ethers";
import { ethers } from "ethers";
-const provider = new ethers.BrowserProvider(window.ethereum);
-const zksyncProvider = Provider.getDefaultProvider(types.Network.Sepolia);
-const signer = L1Signer.from(provider.getSigner(), zksyncProvider);
+const browserProvider = new ethers.BrowserProvider(window.ethereum);
+const signer = L1Signer.from(await browserProvider.getSigner(), Provider.getDefaultProvider(types.Network.Sepolia));
+
+console.log(await signer.getBalanceL1());
+```
+
+Get token balance.
+
+```ts
+import { Provider, L1Signer, types } from "zksync-ethers";
+import { ethers } from "ethers";
+
+const browserProvider = new ethers.BrowserProvider(window.ethereum);
+const signer = L1Signer.from(await browserProvider.getSigner(), Provider.getDefaultProvider(types.Network.Sepolia));
const tokenL1 = "0x56E69Fa1BB0d1402c89E3A4E3417882DeA6B14Be";
-// Getting token balance
console.log(await signer.getBalanceL1(tokenL1));
-
-// Getting ETH balance
-console.log(await signer.getBalanceL1());
```
### `l2TokenAddress`
@@ -1849,9 +1931,8 @@ async l2TokenAddress(token: Address): Promise
import { Provider, L1Signer, types } from "zksync-ethers";
import { ethers } from "ethers";
-const provider = new ethers.BrowserProvider(window.ethereum);
-const zksyncProvider = Provider.getDefaultProvider(types.Network.Sepolia);
-const signer = L1Signer.from(provider.getSigner(), zksyncProvider);
+const browserProvider = new ethers.BrowserProvider(window.ethereum);
+const signer = L1Signer.from(await browserProvider.getSigner(), Provider.getDefaultProvider(types.Network.Sepolia));
const tokenL1 = "0x5C221E77624690fff6dd741493D735a17716c26B";
@@ -1884,9 +1965,8 @@ async getAllowanceL1(
import { Provider, L1Signer, types } from "zksync-ethers";
import { ethers } from "ethers";
-const provider = new ethers.BrowserProvider(window.ethereum);
-const zksyncProvider = Provider.getDefaultProvider(types.Network.Sepolia);
-const signer = L1Signer.from(provider.getSigner(), zksyncProvider);
+const browserProvider = new ethers.BrowserProvider(window.ethereum);
+const signer = L1Signer.from(await browserProvider.getSigner(), Provider.getDefaultProvider(types.Network.Sepolia));
const tokenL1 = "0x5C221E77624690fff6dd741493D735a17716c26B";
console.log(`Token allowance: ${await signer.getAllowanceL1(tokenL1)}`);
@@ -1918,14 +1998,11 @@ async approveERC20(
import { Provider, L1Signer, types } from "zksync-ethers";
import { ethers } from "ethers";
-const provider = new ethers.BrowserProvider(window.ethereum);
-const zksyncProvider = Provider.getDefaultProvider(types.Network.Sepolia);
-const signer = L1Signer.from(provider.getSigner(), zksyncProvider);
-
-const tokenL1 = "0x56E69Fa1BB0d1402c89E3A4E3417882DeA6B14Be";
-const txHandle = await signer.approveERC20(tokenL1, "10000000");
+const browserProvider = new ethers.BrowserProvider(window.ethereum);
+const signer = L1Signer.from(await browserProvider.getSigner(), Provider.getDefaultProvider(types.Network.Sepolia));
-await txHandle.wait();
+const tokenL1 = "0x5C221E77624690fff6dd741493D735a17716c26B";
+await signer.approveERC20(tokenL1, 5);
```
### `getBaseCost`
@@ -1954,9 +2031,8 @@ async getBaseCost(params: {
import { Provider, L1Signer, types } from "zksync-ethers";
import { ethers } from "ethers";
-const provider = new ethers.BrowserProvider(window.ethereum);
-const zksyncProvider = Provider.getDefaultProvider(types.Network.Sepolia);
-const signer = L1Signer.from(provider.getSigner(), zksyncProvider);
+const browserProvider = new ethers.BrowserProvider(window.ethereum);
+const signer = L1Signer.from(await browserProvider.getSigner(), Provider.getDefaultProvider(types.Network.Sepolia));
console.log(`Base cost: ${await signer.getBaseCost({ gasLimit: 100_000 })}`);
```
@@ -1974,7 +2050,7 @@ use the [`allowanceL1`](#getallowancel1) method.
| Parameter | Type | Description |
| -------------------------------- | ------------------------------------------------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `transaction.token` | `Address` | The address of the token to deposit. `ETH` by default. |
-| `transaction.amount` | `BigNumberish` | The amount of the token to withdraw. |
+| `transaction.amount` | `BigNumberish` | The amount of the token to deposit. |
| `transaction.to?` | `Address` | The address that will receive the deposited tokens on L2 (optional). |
| `transaction.operatorTip?` | `BigNumberish` | (_currently is not used_) If the ETH value passed with the transaction is not explicitly stated in the overrides, this field will be equal to the tip the operator will receive on top of the base cost of the transaction (optional). |
| `transaction.bridgeAddress?` | `Address` | The address of the bridge contract to be used. Defaults to the default zkSync bridge (either `L1EthBridge` or `L1Erc20Bridge`) (optional). |
@@ -2005,33 +2081,36 @@ async deposit(transaction: {
#### Example
+Deposit ETH.
+
```ts
import { Provider, L1Signer, types } from "zksync-ethers";
import { ethers } from "ethers";
-const provider = new ethers.BrowserProvider(window.ethereum);
-const zksyncProvider = Provider.getDefaultProvider(types.Network.Sepolia);
-const signer = L1Signer.from(provider.getSigner(), zksyncProvider);
+const browserProvider = new ethers.BrowserProvider(window.ethereum);
+const signer = L1Signer.from(await browserProvider.getSigner(), Provider.getDefaultProvider(types.Network.Sepolia));
+
+await signer.deposit({
+ token: utils.ETH_ADDRESS,
+ amount: 10_000_000n,
+});
+```
+
+Deposit token.
+
+```ts
+import { Provider, L1Signer, types } from "zksync-ethers";
+import { ethers } from "ethers";
+
+const browserProvider = new ethers.BrowserProvider(window.ethereum);
+const signer = L1Signer.from(await browserProvider.getSigner(), Provider.getDefaultProvider(types.Network.Sepolia));
const tokenL1 = "0x56E69Fa1BB0d1402c89E3A4E3417882DeA6B14Be";
-const tokenDepositHandle = await signer.deposit({
+await signer.deposit({
token: tokenL1,
- amount: "10000000",
+ amount: 10_000_000n,
approveERC20: true,
});
-// Note that we wait not only for the L1 transaction to complete but also for it to be
-// processed by zkSync. If we want to wait only for the transaction to be processed on L1,
-// we can use `await tokenDepositHandle.waitL1Commit()`
-await tokenDepositHandle.wait();
-
-const ethDepositHandle = await signer.deposit({
- token: utils.ETH_ADDRESS,
- amount: "10000000",
-});
-// Note that we wait not only for the L1 transaction to complete but also for it to be
-// processed by zkSync. If we want to wait only for the transaction to be processed on L1,
-// we can use `await ethDepositHandle.waitL1Commit()`
-await ethDepositHandle.wait();
```
### `getDepositTx`
@@ -2043,7 +2122,7 @@ Returns populated deposit transaction.
| Parameter | Type | Description |
| -------------------------------- | ------------------------------------------------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `transaction.token` | `Address` | The address of the token to deposit. `ETH` by default. |
-| `transaction.amount` | `BigNumberish` | The amount of the token to withdraw. |
+| `transaction.amount` | `BigNumberish` | The amount of the token to deposit. |
| `transaction.to?` | `Address` | The address that will receive the deposited tokens on L2 (optional). |
| `transaction.operatorTip?` | `BigNumberish` | (_currently is not used_) If the ETH value passed with the transaction is not explicitly stated in the overrides, this field will be equal to the tip the operator will receive on top of the base cost of the transaction (optional). |
| `transaction.bridgeAddress?` | `Address` | The address of the bridge contract to be used. Defaults to the default zkSync bridge (either `L1EthBridge` or `L1Erc20Bridge`) (optional). |
@@ -2074,14 +2153,13 @@ async getDepositTx(transaction: {
import { Provider, L1Signer, types } from "zksync-ethers";
import { ethers } from "ethers";
-const provider = new ethers.BrowserProvider(window.ethereum);
-const zksyncProvider = Provider.getDefaultProvider(types.Network.Sepolia);
-const signer = L1Signer.from(provider.getSigner(), zksyncProvider);
+const browserProvider = new ethers.BrowserProvider(window.ethereum);
+const signer = L1Signer.from(await browserProvider.getSigner(), Provider.getDefaultProvider(types.Network.Sepolia));
const tokenL1 = "0x56E69Fa1BB0d1402c89E3A4E3417882DeA6B14Be";
const tx = await signer.getDepositTx({
token: tokenL1,
- amount: "10000000",
+ amount: 10_000_000n,
});
```
@@ -2094,7 +2172,7 @@ Estimates the amount of gas required for a deposit transaction on L1 network. Ga
| Parameter | Type | Description |
| -------------------------------- | ------------------------------------------------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `transaction.token` | `Address` | The address of the token to deposit. `ETH` by default. |
-| `transaction.amount` | `BigNumberish` | The amount of the token to withdraw. |
+| `transaction.amount` | `BigNumberish` | The amount of the token to deposit. |
| `transaction.to?` | `Address` | The address that will receive the deposited tokens on L2 (optional). |
| `transaction.operatorTip?` | `BigNumberish` | (_currently is not used_) If the ETH value passed with the transaction is not explicitly stated in the overrides, this field will be equal to the tip the operator will receive on top of the base cost of the transaction (optional). |
| `transaction.bridgeAddress?` | `Address` | The address of the bridge contract to be used. Defaults to the default zkSync bridge (either `L1EthBridge` or `L1Erc20Bridge`) (optional). |
@@ -2125,14 +2203,13 @@ async estimateGasDeposit(transaction:
import { Provider, L1Signer, types } from "zksync-ethers";
import { ethers } from "ethers";
-const provider = new ethers.BrowserProvider(window.ethereum);
-const zksyncProvider = Provider.getDefaultProvider(types.Network.Sepolia);
-const signer = L1Signer.from(provider.getSigner(), zksyncProvider);
+const browserProvider = new ethers.BrowserProvider(window.ethereum);
+const signer = L1Signer.from(await browserProvider.getSigner(), Provider.getDefaultProvider(types.Network.Sepolia));
const tokenL1 = "0x5C221E77624690fff6dd741493D735a17716c26B";
const gas = await signer.estimateGasDeposit({
token: tokenL1,
- amount: "10000000",
+ amount: 10_000_000n,
});
console.log(`Gas: ${gas}`);
```
@@ -2166,17 +2243,16 @@ async getFullRequiredDepositFee(transaction: {
#### Example
```ts
-import { Provider, L1Signer, types } from "zksync-ethers";
+import { Provider, L1Signer, Wallet, types } from "zksync-ethers";
import { ethers } from "ethers";
-const provider = new ethers.BrowserProvider(window.ethereum);
-const zksyncProvider = Provider.getDefaultProvider(types.Network.Sepolia);
-const signer = L1Signer.from(provider.getSigner(), zksyncProvider);
+const browserProvider = new ethers.BrowserProvider(window.ethereum);
+const signer = L1Signer.from(await browserProvider.getSigner(), Provider.getDefaultProvider(types.Network.Sepolia));
const tokenL1 = "0x56E69Fa1BB0d1402c89E3A4E3417882DeA6B14Be";
const fee = await signer.getFullRequiredDepositFee({
token: tokenL1,
- to: await wallet.getAddress(),
+ to: Wallet.createRandom().address,
});
console.log(`Fee: ${fee}`);
```
@@ -2203,9 +2279,8 @@ async claimFailedDeposit(depositHash: BytesLike): Promise
+```
+
+#### Example
+
+```ts
+import { SmartAccount, Provider, types } from "zksync-ethers";
+
+const ADDRESS = "";
+const PRIVATE_KEY = "";
+
+const provider = Provider.getDefaultProvider(types.Network.Sepolia);
+const account = new SmartAccount({ address: ADDRESS, secret: PRIVATE_KEY }, provider);
+
+const address = await account.getAddress();
+```
+
+### `getBalance`
+
+Returns the balance of the account.
+
+#### Inputs
+
+| Parameter | Type | Description |
+| ---------- | ---------- | -------------------------------------------------------------------------------- |
+| `token?` | `Address` | The token address to query balance for. Defaults to the native token (optional). |
+| `blockTag` | `BlockTag` | The block tag to get the balance at. Defaults to `committed`. |
+
+```ts
+async getBalance(token?: Address, blockTag: BlockTag = 'committed'): Promise
+```
+
+#### Example
+
+```ts
+import { SmartAccount, Provider, types } from "zksync-ethers";
+
+const ADDRESS = "";
+const PRIVATE_KEY = "";
+
+const provider = Provider.getDefaultProvider(types.Network.Sepolia);
+const account = new SmartAccount({ address: ADDRESS, secret: PRIVATE_KEY }, provider);
+
+const balance = await account.getBalance();
+```
+
+### `getAllBalances`
+
+Returns all token balances of the account.
+
+```ts
+async getAllBalances(): Promise
+```
+
+#### Example
+
+```ts
+import { SmartAccount, Provider, types } from "zksync-ethers";
+
+const ADDRESS = "";
+const PRIVATE_KEY = "";
+
+const provider = Provider.getDefaultProvider(types.Network.Sepolia);
+const account = new SmartAccount({ address: ADDRESS, secret: PRIVATE_KEY }, provider);
+
+const balances = await account.getAllBalances();
+```
+
+### `getDeploymentNonce`
+
+Returns the deployment nonce of the account.
+
+```ts
+async getDeploymentNonce(): Promise
+```
+
+#### Example
+
+```ts
+import { SmartAccount, Provider, types } from "zksync-ethers";
+
+const ADDRESS = "";
+const PRIVATE_KEY = "";
+
+const provider = Provider.getDefaultProvider(types.Network.Sepolia);
+const account = new SmartAccount({ address: ADDRESS, secret: PRIVATE_KEY }, provider);
+
+const nonce = await account.getDeploymentNonce();
+```
+
+### `populateTransaction`
+
+Populates the transaction `tx` using the provided [`TransactionBuilder`](./types.md#transactionbuilder) function.
+If `tx.from` is not set, it sets the value from the `getAddress` method which can
+be utilized in the [`TransactionBuilder`](./types.md#transactionbuilder) function.
+
+#### Inputs
+
+| Parameter | Type | Description |
+| --------- | ----------------------------------------------------- | ------------------------------------------- |
+| `tx` | [`TransactionRequest`](./types.md#transactionrequest) | The transaction that needs to be populated. |
+
+```ts
+async populateTransaction(tx: TransactionRequest): Promise
+```
+
+#### Example
+
+```ts
+import { SmartAccount, Provider, types, utils } from "zksync-ethers";
+
+const ADDRESS = "";
+const PRIVATE_KEY = "";
+
+const provider = Provider.getDefaultProvider(types.Network.Sepolia);
+const account = new SmartAccount({ address: ADDRESS, secret: PRIVATE_KEY }, provider);
+
+const populatedTx = await account.populateTransaction({
+ type: utils.EIP712_TX_TYPE,
+ to: "",
+ value: 7_000_000_000,
+});
+```
+
+### `signTransaction`
+
+Signs the transaction `tx` using the provided [`PayloadSigner`](./types.md#payloadsigner) function,
+returning the fully signed transaction. The `populateTransaction` method
+is called first to ensure that all necessary properties for the transaction to be valid
+have been populated.
+
+#### Inputs
+
+| Parameter | Type | Description |
+| --------- | ----------------------------------------------------- | ---------------------------------------- |
+| `tx` | [`TransactionRequest`](./types.md#transactionrequest) | The transaction that needs to be signed. |
+
+```ts
+async signTransaction(tx: TransactionRequest): Promise
+```
+
+#### Example
+
+```ts
+import { SmartAccount, Provider, types } from "zksync-ethers";
+import { ethers } from "ethers";
+
+const ADDRESS = "";
+const PRIVATE_KEY = "";
+
+const provider = Provider.getDefaultProvider(types.Network.Sepolia);
+const account = new SmartAccount({ address: ADDRESS, secret: PRIVATE_KEY }, provider);
+
+const signedTx = await account.signTransaction({
+ to: "",
+ value: ethers.parseEther("1"),
+});
+```
+
+### `sendTransaction`
+
+Sends `tx` to the Network. The `signTransaction`
+is called first to ensure transaction is properly signed.
+
+#### Inputs
+
+| Parameter | Type | Description |
+| --------- | ----------------------------------------------------- | -------------------------------------- |
+| `tx` | [`TransactionRequest`](./types.md#transactionrequest) | The transaction that needs to be sent. |
+
+```ts
+async sendTransaction(tx: TransactionRequest): Promise
+```
+
+#### Example
+
+```ts
+import { SmartAccount, Provider, types } from "zksync-ethers";
+import { ethers } from "ethers";
+
+const ADDRESS = "";
+const PRIVATE_KEY = "";
+
+const provider = Provider.getDefaultProvider(types.Network.Sepolia);
+const account = new SmartAccount({ address: ADDRESS, secret: PRIVATE_KEY }, provider);
+
+const signedTx = await account.sendTransaction({
+ to: "",
+ value: ethers.parseEther("1"),
+});
+```
+
+### `signMessage`
+
+Signs a `message` using the provided [`PayloadSigner`](./types.md#payloadsigner) function.
+
+#### Inputs
+
+| Parameter | Type | Description |
+| --------- | ------------------------ | ------------------------------------ |
+| `message` | `string` or `Uint8Array` | The message that needs to be signed. |
+
+```ts
+signMessage(message: string | Uint8Array): Promise
+```
+
+#### Example
+
+```ts
+import { SmartAccount, Provider, types } from "zksync-ethers";
+import { ethers } from "ethers";
+
+const ADDRESS = "";
+const PRIVATE_KEY = "";
+
+const provider = Provider.getDefaultProvider(types.Network.Sepolia);
+const account = new SmartAccount({ address: ADDRESS, secret: PRIVATE_KEY }, provider);
+
+const signedMessage = await account.signMessage("Hello World!");
+```
+
+### `signTypedData`
+
+Signs a typed data using the provided [`PayloadSigner`](./types.md#payloadsigner) function.
+
+#### Inputs
+
+| Parameter | Type | Description |
+| --------- | ----------------------------------------- | -------------------------------------------------------- |
+| `domain` | `ethers.TypedDataDomain` | The domain data. |
+| `types` | `Record` | A map of records pointing from field name to field type. |
+| `value` | `Record` | A single record value. |
+
+```ts
+async signTypedData(
+ domain: ethers.TypedDataDomain,
+ types: Record,
+ value: Record
+): Promise
+```
+
+#### Example
+
+```ts
+import { SmartAccount, Provider, types } from "zksync-ethers";
+import { ethers } from "ethers";
+
+const ADDRESS = "";
+const PRIVATE_KEY = "";
+
+const provider = Provider.getDefaultProvider(types.Network.Sepolia);
+const account = new SmartAccount({ address: ADDRESS, secret: PRIVATE_KEY }, provider);
+
+const signedTypedData = await account.signTypedData(
+ { name: "Example", version: "1", chainId: 270 },
+ {
+ Person: [
+ { name: "name", type: "string" },
+ { name: "age", type: "uint8" },
+ ],
},
+ { name: "John", age: 30 }
+);
+```
+
+### `withdraw`
+
+Initiates the withdrawal process which withdraws ETH or any ERC20 token from the associated account on L2 network to the target account on
+L1 network.
+
+#### Inputs
+
+| Parameter | Type | Description |
+| ------------------------------ | ------------------------------------------------------------------------ | ----------------------------------------------------------------------------------------------------- |
+| `transaction.token` | `Address` | The address of the token. `ETH` by default. |
+| `transaction.amount` | `BigNumberish` | The amount of the token to withdraw. |
+| `transaction.to?` | `Address` | The address of the recipient on L1 (optional). |
+| `transaction.bridgeAddress?` | `Address` | The address of the bridge contract to be used (optional). |
+| `transaction.paymasterParams?` | [`PaymasterParams`](./types.md#paymasterparams) | Paymaster parameters (optional). |
+| `transaction.overrides?` | [`ethers.Overrides`](https://docs.ethers.org/v6/api/contract/#Overrides) | Transaction's overrides which may be used to pass l2 `gasLimit`, `gasPrice`, `value`, etc (optional). |
+
+```ts
+async withdraw(transaction: {
+ token: Address;
+ amount: BigNumberish;
+ to?: Address;
+ bridgeAddress?: Address;
+ paymasterParams?: PaymasterParams;
+ overrides?: ethers.Overrides;
+}): Promise
+```
+
+#### Examples
+
+Withdraw ETH.
+
+```ts
+import { SmartAccount, Provider, types, utils } from "zksync-ethers";
+
+const ADDRESS = "";
+const PRIVATE_KEY = "";
+
+const provider = Provider.getDefaultProvider(types.Network.Sepolia);
+const account = new SmartAccount({ address: ADDRESS, secret: PRIVATE_KEY }, provider);
+
+const tokenWithdrawHandle = await account.withdraw({
+ token: utils.ETH_ADDRESS,
+ amount: 10_000_000,
+});
+```
+
+Withdraw ETH using paymaster to facilitate fee payment with an ERC20 token.
+
+```ts
+import { SmartAccount, Provider, types, utils } from "zksync-ethers";
+
+const ADDRESS = "";
+const PRIVATE_KEY = "";
+
+const token = "0x927488F48ffbc32112F1fF721759649A89721F8F"; // Crown token which can be minted for free
+const paymaster = "0x13D0D8550769f59aa241a41897D4859c87f7Dd46"; // Paymaster for Crown token
+
+const provider = Provider.getDefaultProvider(types.Network.Sepolia);
+const account = new SmartAccount({ address: ADDRESS, secret: PRIVATE_KEY }, provider);
+
+const tokenWithdrawHandle = await account.withdraw({
+ token: utils.ETH_ADDRESS,
+ amount: 10_000_000,
+ paymasterParams: utils.getPaymasterParams(paymaster, {
+ type: "ApprovalBased",
+ token: token,
+ minimalAllowance: 1,
+ innerInput: new Uint8Array(),
+ }),
+});
+```
+
+### `transfer`
+
+Transfer ETH or any ERC20 token within the same interface.
+
+#### Inputs
+
+| Parameter | Type | Description |
+| ------------------------------ | ------------------------------------------------------------------------ | ---------------------------------------------------------------------------------------------------------- |
+| `transaction.to` | `Address` | The address of the recipient. |
+| `transaction.amount` | `BigNumberish` | The amount of the token to transfer. |
+| `transaction.token?` | `Address` | The address of the token. `ETH` by default. |
+| `transaction.paymasterParams?` | [`PaymasterParams`](./types.md#paymasterparams) | Paymaster parameters (optional). |
+| `transaction.overrides?` | [`ethers.Overrides`](https://docs.ethers.org/v6/api/contract/#Overrides) | Transaction's overrides which may be used to pass l2 `gasLimit`, `gasPrice`, `value`, etc (optional). |
+
+```ts
+async transfer(transaction: {
+ to: Address;
+ amount: BigNumberish;
+ token ? : Address;
+ paymasterParams?: PaymasterParams;
+ overrides ? : ethers.Overrides;
+}): Promise
+```
+
+#### Examples
+
+Transfer ETH.
+
+```ts
+import { SmartAccount, Wallet, Provider, types } from "zksync-ethers";
+import { ethers } from "ethers";
+
+const ADDRESS = "";
+const PRIVATE_KEY = "";
+
+const provider = Provider.getDefaultProvider(types.Network.Sepolia);
+const account = new SmartAccount({ address: ADDRESS, secret: PRIVATE_KEY }, provider);
+
+const transferHandle = await account.transfer({
+ token: utils.ETH_ADDRESS,
+ to: Wallet.createRandom().address,
+ amount: ethers.parseEther("0.01"),
+});
+
+const tx = await transferHandle.wait();
+
+console.log(`The sum of ${tx.value} ETH was transferred to ${tx.to}`);
+```
+
+Transfer ETH using paymaster to facilitate fee payment with an ERC20 token.
+
+```ts
+import { SmartAccount, Wallet, Provider, utils } from "zksync-ethers";
+import { ethers } from "ethers";
+
+const ADDRESS = "";
+const PRIVATE_KEY = "";
+
+const token = "0x927488F48ffbc32112F1fF721759649A89721F8F"; // Crown token which can be minted for free
+const paymaster = "0x13D0D8550769f59aa241a41897D4859c87f7Dd46"; // Paymaster for Crown token
+
+const provider = Provider.getDefaultProvider(types.Network.Sepolia);
+const account = new SmartAccount({ address: ADDRESS, secret: PRIVATE_KEY }, provider);
+
+const transferHandle = await account.transfer({
+ to: Wallet.createRandom().address,
+ amount: ethers.parseEther("0.01"),
+ paymasterParams: utils.getPaymasterParams(paymaster, {
+ type: "ApprovalBased",
+ token: token,
+ minimalAllowance: 1,
+ innerInput: new Uint8Array(),
+ }),
});
+
+const tx = await transferHandle.wait();
+
+console.log(`The sum of ${tx.value} ETH was transferred to ${tx.to}`);
+```
+
+## `ECDSASmartAccount`
+
+A `ECDSASmartAccount` is a factory which creates a `SmartAccount` instance
+that uses single ECDSA key for signing payload.
+
+### `create`
+
+Creates a `SmartAccount` instance that uses a single ECDSA key for signing payload.
+
+#### Inputs
+
+| Parameter | Type | Description |
+| ---------- | ------------------------------------------------------------------------------------ | --------------------------- |
+| `address` | `string` | The account address. |
+| `secret` | `string` or [`ethers.SigningKey`](https://docs.ethers.org/v6/api/crypto/#SigningKey) | The ECDSA private key. |
+| `provider` | [`Provider`](./providers.md#provider) | The provider to connect to. |
+
+```ts
+static create(address: string, secret: string | SigningKey, provider: Provider): SmartAccount
+```
+
+#### Example
+
+```ts
+import { ECDSASmartAccount, Provider, types } from "zksync-ethers";
+
+const ADDRESS = "";
+const PRIVATE_KEY = "";
+
+const provider = Provider.getDefaultProvider(types.Network.Sepolia);
+const account = ECDSASmartAccount.create(ADDRESS, PRIVATE_KEY, provider);
+```
+
+## `MultisigECDSASmartAccount`
+
+A `MultisigECDSASmartAccount` is a factory which creates a `SmartAccount` instance
+that uses multiple ECDSA keys for signing payloads.
+The signature is generated by concatenating signatures created by signing with each key individually.
+
+### `create`
+
+Creates a `SmartAccount` instance that uses multiple ECDSA keys for signing payloads.
+
+#### Inputs
+
+| Parameter | Type | Description |
+| ---------- | ----------------------------------------------------------------------------------------- | ----------------------------------- |
+| `address` | `string` | The account address. |
+| `secret` | `string[]` or [`ethers.SigningKeyp[]`](https://docs.ethers.org/v6/api/crypto/#SigningKey) | The list of the ECDSA private keys. |
+| `provider` | [`Provider`](./providers.md#provider) | The provider to connect to. |
+
+```ts
+static create(address: string, secret: string[] | SigningKey[], provider: Provider): SmartAccount
+```
+
+#### Example
+
+```ts
+import { MultisigECDSASmartAccount, Provider, types } from "zksync-ethers";
+
+const ADDRESS = "";
+const PRIVATE_KEY1 = "";
+const PRIVATE_KEY2 = "";
+
+const provider = Provider.getDefaultProvider(types.Network.Sepolia);
+
+const account = MultisigECDSASmartAccount.create(multisigAddress, [PRIVATE_KEY1, PRIVATE_KEY2], provider);
```
diff --git a/docs/build/sdks/js/zksync-ethers/paymaster-utils.md b/docs/build/sdks/js/zksync-ethers/paymaster-utils.md
index 3ed0ff44e3..dc74628578 100644
--- a/docs/build/sdks/js/zksync-ethers/paymaster-utils.md
+++ b/docs/build/sdks/js/zksync-ethers/paymaster-utils.md
@@ -14,7 +14,7 @@ The [paymaster utilities library](https://github.com/zksync-sdk/zksync-ethers/bl
Constant ABI definition for
the [Paymaster Flow Interface](https://github.com/matter-labs/era-contracts/blob/583cb674a2b942dda34e9f46edb5a9f5b696b90a/l2-contracts/contracts/interfaces/IPaymasterFlow.sol).
-```typescript
+```ts
export const PAYMASTER_FLOW_ABI = new ethers.Interface(require("../abi/IPaymasterFlow.json"));
```
@@ -59,7 +59,7 @@ Returns a correctly-formed `paymasterParams` object for common [paymaster flows]
| `paymasterAddress` | `Address` | The non-zero `paymaster` address. |
| `paymasterInput` | [`PaymasterInput`](./types.md#paymasterinput) | The input data to the paymaster. |
-```typescript
+```ts
export function getPaymasterParams(paymasterAddress: Address, paymasterInput: PaymasterInput): PaymasterParams;
```
diff --git a/docs/build/sdks/js/zksync-ethers/smart-account-utils.md b/docs/build/sdks/js/zksync-ethers/smart-account-utils.md
new file mode 100644
index 0000000000..672d156fdb
--- /dev/null
+++ b/docs/build/sdks/js/zksync-ethers/smart-account-utils.md
@@ -0,0 +1,239 @@
+---
+head:
+ - - meta
+ - name: "twitter:title"
+ content: JS SDK Smart Account Utilities | zkSync Docs
+---
+
+# Smart Account Utilities
+
+## Functions
+
+### `signPayloadWithECDSA`
+
+Signs the `payload` using an ECDSA private key.
+
+#### Inputs
+
+| Parameter | Type | Description |
+| --------- | ------------------------------------------------------------------------------------ | ------------------------------------ |
+| `payload` | `BytesLike` | The payload that needs to be signed. |
+| `secret` | `string` or [`ethers.SigningKey`](https://docs.ethers.org/v6/api/crypto/#SigningKey) | The ECDSA private key. |
+
+```ts
+const signPayloadWithECDSA: PayloadSigner = async (payload, secret: string | SigningKey);
+```
+
+#### Examples
+
+Sign EIP712 transaction hash.
+
+```ts
+import { EIP712Signer, types, utils } from "zksync-ethers";
+
+const PRIVATE_KEY = "";
+
+const tx: types.TransactionRequest = {
+ chainId: 270,
+ from: ADDRESS,
+ to: "",
+ value: 7_000_000_000,
+};
+
+const txHash = EIP712Signer.getSignedDigest(tx);
+const result = await utils.signPayloadWithECDSA(txHash, PRIVATE_KEY);
+```
+
+Sign message hash.
+
+```ts
+import { utils } from "zksync-ethers";
+import { hashMessage } from "ethers";
+
+const PRIVATE_KEY = "";
+
+const message = "Hello World!";
+const messageHash = hashMessage(message);
+
+const result = await utils.signPayloadWithECDSA(messageHash, PRIVATE_KEY);
+```
+
+Sign typed data hash.
+
+```ts
+import { utils } from "zksync-ethers";
+import { TypedDataEncoder } from "ethers";
+
+const PRIVATE_KEY = "";
+
+const typedDataHash = TypedDataEncoder.hash(
+ { name: "Example", version: "1", chainId: 270 },
+ {
+ Person: [
+ { name: "name", type: "string" },
+ { name: "age", type: "uint8" },
+ ],
+ },
+ { name: "John", age: 30 }
+);
+const result = await utils.signPayloadWithECDSA(typedDataHash, PRIVATE_KEY);
+```
+
+### `signPayloadWithMultipleECDSA`
+
+Signs the `payload` using multiple ECDSA private keys.
+The signature is generated by concatenating signatures created by signing with each key individually.
+The length of the resulting signature should be `secrets.length * 65 + 2`.
+
+#### Inputs
+
+| Parameter | Type | Description |
+| --------- | ---------------------------------------------------------------------------------------- | ------------------------------------ |
+| `payload` | `BytesLike` | The payload that needs to be signed. |
+| `secret` | `string[]` or [`ethers.SigningKey[]`](https://docs.ethers.org/v6/api/crypto/#SigningKey) | The list of the ECDSA private keys. |
+
+```ts
+const signPayloadWithMultipleECDSA: PayloadSigner = async (payload, secret: string[] | SigningKey[])
+```
+
+#### Examples
+
+Sign EIP712 transaction hash.
+
+```ts
+import { EIP712Signer, types, utils } from "zksync-ethers";
+
+const PRIVATE_KEY1 = "";
+const PRIVATE_KEY2 = "";
+
+const tx: types.TransactionRequest = {
+ chainId: 270,
+ from: ADDRESS,
+ to: "",
+ value: 7_000_000_000,
+};
+
+const txHash = EIP712Signer.getSignedDigest(tx);
+const result = await utils.signPayloadWithMultipleECDSA(typedDataHash, [PRIVATE_KEY1, PRIVATE_KEY2]);
+```
+
+Sign message hash.
+
+```ts
+import { utils } from "zksync-ethers";
+import { hashMessage } from "ethers";
+
+const PRIVATE_KEY1 = "";
+const PRIVATE_KEY2 = "";
+
+const message = "Hello World!";
+const messageHash = hashMessage(message);
+
+const result = await utils.signPayloadWithMultipleECDSA(typedDataHash, [PRIVATE_KEY1, PRIVATE_KEY2]);
+```
+
+Sign typed data hash.
+
+```ts
+import { utils } from "zksync-ethers";
+import { TypedDataEncoder } from "ethers";
+
+const PRIVATE_KEY1 = "";
+const PRIVATE_KEY2 = "";
+
+const typedDataHash = TypedDataEncoder.hash(
+ { name: "Example", version: "1", chainId: 270 },
+ {
+ Person: [
+ { name: "name", type: "string" },
+ { name: "age", type: "uint8" },
+ ],
+ },
+ { name: "John", age: 30 }
+);
+const result = await utils.signPayloadWithMultipleECDSA(typedDataHash, [PRIVATE_KEY1, PRIVATE_KEY2]);
+```
+
+## `populateTransactionECDSA`
+
+Populates missing properties meant for signing using an ECDSA private key:
+
+- Populates `from` using the address derived from the ECDSA private key.
+- Populates `nonce` via `provider.getTransactionCount(tx.from, "pending")`.
+- Populates `gasLimit` via `provider.estimateGas(tx)`. If `tx.from` is not EOA, the estimation is done with address
+ derived from the ECDSA private key.
+- Populates `chainId` via `provider.getNetwork()`.
+- Populates `type` with `utils.EIP712_TX_TYPE`.
+- Populates `value` by converting to `bigint` if set, otherwise to `0n`.
+- Populates `data` with `0x`.
+- Populates `customData` with `{factoryDeps=[], gasPerPubdata=utils.DEFAULT_GAS_PER_PUBDATA_LIMIT}`.
+
+#### Inputs
+
+| Parameter | Type | Description |
+| ---------- | ------------------------------------------------------------------------------------ | ---------------------------------------------------------------------------------- |
+| `tx` | `BytesLike` | The transaction that needs to be populated. |
+| `secret` | `string` or [`ethers.SigningKey`](https://docs.ethers.org/v6/api/crypto/#SigningKey) | The ECDSA private key. |
+| `provider` | [`Provider`](./providers.md#provider) | The provider is used to fetch data from the network if it is required for signing. |
+
+```ts
+const populateTransactionECDSA: TransactionBuilder = async (tx, secret: string | SigningKey, provider)
+```
+
+#### Example
+
+```ts
+import { Provider, types, utils } from "zksync-ethers";
+
+const PRIVATE_KEY = "";
+
+const provider = Provider.getDefaultProvider(types.Network.Sepolia);
+
+const populatedTx = await utils.populateTransactionECDSA(
+ {
+ chainId: 270,
+ to: "",
+ value: 7_000_000_000,
+ },
+ PRIVATE_KEY,
+ provider
+);
+```
+
+## `populateTransactionMultisigECDSA`
+
+Populates missing properties meant for signing using multiple ECDSA private keys.
+It uses [`populateTransactionECDSA`](#populatetransactionecdsa), where the address of the first ECDSA key is set as the `secret` argument.
+
+#### Inputs
+
+| Parameter | Type | Description |
+| ---------- | ---------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------- |
+| `tx` | `BytesLike` | The transaction that needs to be populated. |
+| `secret` | `string[]` or [`ethers.SigningKey[]`](https://docs.ethers.org/v6/api/crypto/#SigningKey) | The list of the ECDSA private keys used for populating the transaction. |
+| `provider` | [`Provider`](./providers.md#provider) | The provider is used to fetch data from the network if it is required for signing. |
+
+```ts
+const populateTransactionMultisigECDSA: TransactionBuilder = async (tx, secret: string[] | SigningKey[], provider)
+```
+
+#### Example
+
+```ts
+import { Provider, types, utils } from "zksync-ethers";
+
+const PRIVATE_KEY1 = "";
+const PRIVATE_KEY2 = "";
+
+const provider = Provider.getDefaultProvider(types.Network.Sepolia);
+
+const populatedTx = await utils.populateTransactionMultisigECDSA(
+ {
+ chainId: 270,
+ to: "",
+ value: 7_000_000_000,
+ },
+ [PRIVATE_KEY1, PRIVATE_KEY2],
+ provider
+);
+```
diff --git a/docs/build/sdks/js/zksync-ethers/types.md b/docs/build/sdks/js/zksync-ethers/types.md
index def921e359..3428350c54 100644
--- a/docs/build/sdks/js/zksync-ethers/types.md
+++ b/docs/build/sdks/js/zksync-ethers/types.md
@@ -86,7 +86,7 @@ Interface representation of block information containing various optional and ma
## `BlockTag`
-Pipe-delimited list of block labels that includes block number in denary and hex plus block statuses.
+Pipe-delimited list of block labels that includes block number in binary and hex plus block statuses.
- `BigNumberish`
- `string` // block hash
@@ -226,6 +226,14 @@ Type defining a paymaster by address and the bytestream input.
- `paymaster`: `Address`;
- `paymasterInput`: `BytesLike`;
+## `PayloadSigner`
+
+Signs various types of payloads, optionally using a some kind of secret.
+
+- `payload`: `BytesLike`;
+- `secret`: `any`;
+- `provider` `null | Provider`;
+
## `PriorityOpResponse`
Interface representation of priority op response that extends [`TransactionResponse`](#transactionresponse) and adds a function that waits to commit a layer 1 transaction, including when given on optional confirmation number.
@@ -265,9 +273,18 @@ Interface representation of raw block with transactions
0x-prefixed, hex-encoded, ECDSA signature as string.
+## `SmartAccountSigner`
+
+Encapsulates the required input parameters for creating a signer for [`SmartAccount`](./accounts.md#smartaccount).
+
+- `address`: `string`;
+- `secret`: `any`;
+- `payloadSigner`: `PayloadSigner`;
+- `transactionBuilder`: `TransactionBuilder`;
+
## `StorageProof`
-Interace representation of Merkle proofs for storage values.
+Interface representation of Merkle proofs for storage values.
- `address`: `string`;
- `storageProof` (Array):
@@ -286,6 +303,14 @@ Interface representation of token containing various fields.
- `symbol`: `string`;
- `decimals`: `number`;
+## `TransactionBuilder`
+
+Populates missing fields in a transaction with default values.
+
+- `transaction`: `TransactionRequest`;
+- `secret`: `any`;
+- `provider`: `null | Provider`;
+
## `TransactionDetails`
Interface representation of transaction details containing various mandatory and optional fields.
@@ -332,5 +357,5 @@ Non-enumerated enum list of transaction statuses.
- Finalized = `finalized`
:::tip More info
-Find the code definition of the types above on the [zkSync Era Github repo.](https://github.com/zksync-sdk/zksync-ethers/blob/main/src/types.ts)
+Find the code definition of the types above on the [zkSync Era GitHub repo.](https://github.com/zksync-sdk/zksync-ethers/blob/main/src/types.ts)
:::
diff --git a/docs/build/test-and-debug/era-test-node.md b/docs/build/test-and-debug/era-test-node.md
index 1876f2e90a..78f968e456 100644
--- a/docs/build/test-and-debug/era-test-node.md
+++ b/docs/build/test-and-debug/era-test-node.md
@@ -240,10 +240,10 @@ Here's an example of what you should expect to see:
{"jsonrpc":"2.0","result":"0x0000000000000000000000000000000000000000000000000000000000000012","id":1}
```
-Or, if you prefer, use [`foundry-zksync`](https://github.com/matter-labs/foundry-zksync). Make sure to install and configure `foundry-zksync` before proceeding (for installation instructions, please see this [link](https://github.com/matter-labs/foundry-zksync/tree/main#foundry-with-zksync-era-v01)):
+Or, if you prefer, use [`foundry-zksync`](https://github.com/matter-labs/foundry-zksync). Make sure to install and configure `foundry-zksync` before proceeding (for installation instructions, please see this [link](https://github.com/matter-labs/foundry-zksync?tab=readme-ov-file#-prerequisites)):
```bash
-zkcast call 0xe1134444211593Cfda9fc9eCc7B43208615556E2 "name()(string)" --rpc-url http://localhost:8011
+cast call 0xe1134444211593Cfda9fc9eCc7B43208615556E2 "name()(string)" --rpc-url http://localhost:8011
```
Here's an example of what you should expect to see:
@@ -255,7 +255,7 @@ Uniswap
Retrieve the balance of a particular contract:
```bash
-zkcast call 0x40609141Db628BeEE3BfAB8034Fc2D8278D0Cc78 "balanceOf(address)(uint256)" 0x40609141Db628BeEE3BfAB8034Fc2D8278D0Cc78 --rpc-url http://localhost:8011
+cast call 0x40609141Db628BeEE3BfAB8034Fc2D8278D0Cc78 "balanceOf(address)(uint256)" 0x40609141Db628BeEE3BfAB8034Fc2D8278D0Cc78 --rpc-url http://localhost:8011
```
Here's an example of what you should expect to see:
@@ -266,25 +266,12 @@ Here's an example of what you should expect to see:
### Deploying contracts
-For the deployment of your contracts, you have the flexibility to choose between two preferred methods: either by using Hardhat with the `hardhat-zksync-deploy` and `hardhat-zksync-solc` plugins, or via `foundry-zksync`. The following example will detail the process using `foundry-zksync`.
+For the deployment of your contracts, you have the flexibility to choose between two preferred methods: either by using Hardhat with the `@matter-labs/hardhat-zksync`, or via `foundry-zksync`. The following example will detail the process using `foundry-zksync`.
-Before proceeding, ensure that you've compiled your contracts using `zkforge zk-build`. For instructions on how to do this, please refer to this [link](https://github.com/matter-labs/foundry-zksync#compile-with-zkforge-zk-build).
+Before proceeding, ensure that you've compiled your contracts using `forge build --zksync`.
```bash
-zkforge zkc contracts/Greeter.sol:Greeter --constructor-args "ZkSync and Foundry" --private-key 7726827caac94a7f9e1b160f7ea819f172f7b6f9d2a97f992c38edeab82d4110 --rpc-url http://localhost:8011 --chain 260
-```
-
-Here's an example of what you should expect to see:
-
-```bash
-Deploying contract...
-+-------------------------------------------------+
-Contract successfully deployed to address: 0x0a40ecde17dc16c4001bf0e4f5d5ff1818219b3b
-Transaction Hash: 0x9d59bea38ca6f3cef365c23f339547bcc8ce28abb8344999ffffa5fa62c9ff8e
-Gas used: 2570407
-Effective gas price: 500
-Block Number: 8072361
-+-------------------------------------------------+
+forge create contracts/Greeter.sol:Greeter --constructor-args "ZkSync and Foundry" --private-key 7726827caac94a7f9e1b160f7ea819f172f7b6f9d2a97f992c38edeab82d4110 --rpc-url http://localhost:8011 --chain 260 --zksync
```
## Testing bootloader and system contracts
@@ -366,8 +353,7 @@ Ensure era-test-node is running in another process before executing yarn test.
:::
```typescript
-import "@matterlabs/hardhat-zksync-deploy";
-import "@matterlabs/hardhat-zksync-solc";
+import "@matterlabs/hardhat-zksync";
module.exports = {
zksolc: {
@@ -399,7 +385,7 @@ module.exports = {
import { expect } from "chai";
import { Wallet, Provider, Contract } from "zksync-ethers";
import * as hre from "hardhat";
-import { Deployer } from "@matterlabs/hardhat-zksync-deploy";
+import { Deployer } from "@matterlabs/hardhat-zksync";
const RICH_WALLET_PK = "0x7726827caac94a7f9e1b160f7ea819f172f7b6f9d2a97f992c38edeab82d4110";
diff --git a/docs/build/test-and-debug/foundry.md b/docs/build/test-and-debug/foundry.md
index 2399902249..9dc3e07003 100644
--- a/docs/build/test-and-debug/foundry.md
+++ b/docs/build/test-and-debug/foundry.md
@@ -11,7 +11,7 @@ For instructions on how to install `foundry-zksync` please refer to the [Getting
## Overview
-`foundry-zksync`, a fork of Foundry, provides developers with a tailored testing framework designed specifically for zkSync environments. Utilizing `zkforge test`, you can execute your smart contract tests efficiently. Tests are written in Solidity, and the framework is designed to recognize any contract function prefixed with `test` as a test case. By convention, tests are typically stored within the `test/` directory and have a `.t.sol` extension.
+`foundry-zksync`, a fork of Foundry, provides developers with a tailored testing framework designed specifically for zkSync environments. Utilizing `forge test --zksync`, you can execute your smart contract tests efficiently. Tests are written in Solidity, and the framework is designed to recognize any contract function prefixed with `test` as a test case. By convention, tests are typically stored within the `test/` directory and have a `.t.sol` extension.
:::info
For more detailed documentation related to Foundry testing please refer to the official upstream Foundry documentation [here](https://book.getfoundry.sh/forge/tests).
@@ -19,10 +19,10 @@ For more detailed documentation related to Foundry testing please refer to the o
## Running Tests
-To initiate your tests, use the `zkforge test` command. This command automatically locates and executes tests across your source directory. Here's an example of executing tests in a standard project setup:
+To initiate your tests, use the `forge test --zksync` command with the `--zksync` flag, or incorporate `vm.zkVm(true)` within your tests. This command automatically locates and executes tests across your source directory. Here's an example of executing tests in a standard project setup:
```bash
-zkforge test
+forge test --zksync
Running 2 tests for test/Counter.t.sol:CounterTest
[PASS] testFuzz_SetNumber(uint256) (runs: 256, μ: 27553, ~: 28409)
@@ -35,7 +35,7 @@ Test result: ok. 2 passed; 0 failed; 0 skipped; finished in 96.80ms
You can run specific tests by filtering based on the contract or test names:
```bash
-zkforge test --match-contract CounterTest --match-test test_Increment
+forge test --match-contract CounterTest --match-test test_Increment --zksync
```
This command will execute only the tests within `CounterTest` that include `test_Increment` in their name.
@@ -43,14 +43,14 @@ This command will execute only the tests within `CounterTest` that include `test
Similarly, you can use `--match-path` to run tests in files that match a specific glob pattern:
```bash
-zkforge test --match-path Counter.t.sol
+forge test --match-path test/Counter.t.sol --zksync
```
Inverse filters are available through `--no-match-contract`, `--no-match-test`, and `--no-match-path` flags.
## Watch Mode
-To automatically re-run tests upon any file changes, use the `zkforge test --watch --run-all` command.
+To automatically re-run tests upon any file changes, use the `forge test --watch --run-all --zksync` command.
## Writing Tests
diff --git a/docs/build/test-and-debug/hardhat.md b/docs/build/test-and-debug/hardhat.md
index b31565b979..04d5ae4507 100644
--- a/docs/build/test-and-debug/hardhat.md
+++ b/docs/build/test-and-debug/hardhat.md
@@ -36,16 +36,16 @@ yarn install
Add the following additional dependencies:
```bash
-yarn add -D @matterlabs/hardhat-zksync-chai-matchers @nomicfoundation/hardhat-chai-matchers @nomiclabs/hardhat-ethers
+yarn add -D @nomicfoundation/hardhat-chai-matchers @nomiclabs/hardhat-ethers
```
-Import `@matterlabs/hardhat-zksync-chai-matchers` into the `hardhat.config.ts` file:
+Import `@nomicfoundation/hardhat-chai-matchers` into the `hardhat.config.ts` file:
```typescript
-import "@matterlabs/hardhat-zksync-chai-matchers";
+import "@nomicfoundation/hardhat-chai-matchers";
```
-The `@matterlabs/hardhat-zksync-chai-matchers` plugin adds zkSync specific capabilities to the [Chai](https://www.chaijs.com/) assertion library for testing smart contracts. It extends all the functionalities supported by the [hardhat-chai-matchers](https://hardhat.org/hardhat-chai-matchers/docs/overview) plugin, with the idea to preserve the same behaviour and interface.
+The `@nomicfoundation/hardhat-chai-matchers` plugin adds Ethereum specific capabilities to the [Chai](https://www.chaijs.com/) assertion library for testing smart contracts.
Before running tests, a local zkSync Era node is required. If you are unfamiliar with `era_test_node` refer to the documentation [here](era-test-node/). Start `era_test_node`:
@@ -294,7 +294,7 @@ Here, we've declared our main test suite. Each test or nested suite inside provi
it("Should emit an event when the greeting is changed", async function () { ... });
```
- We test the emission of an event when the greeting changes in the contract making use of the `hardhat-zksync-chai-matchers`.
+ We test the emission of an event when the greeting changes in the contract making use of the `hardhat-chai-matchers`.
### Conclusion
diff --git a/docs/build/tooling/data-indexers.md b/docs/build/tooling/data-indexers.md
index 5b41a39b25..e2bb7bb60a 100644
--- a/docs/build/tooling/data-indexers.md
+++ b/docs/build/tooling/data-indexers.md
@@ -11,27 +11,35 @@ head:
Welcome to the Analytics page, a comprehensive hub dedicated to interacting with data services, analytic tooling on zkSync Era. Each guide includes hands-on examples, ensuring that both newcomers and experienced developers can seamlessly harness the power of the analytical tooling within the zkSync Era.
-### The Graph Network
-
-[The Graph](https://thegraph.com/) is a decentralized protocol for indexing and querying blockchain data. The Graph makes it possible to query data that is difficult to query directly. Use The Graph network today to index protocol data on zkSync!
-
-### SubQuery Network
-
-[SubQuery](https://subquery.network/) is a fast, flexible, and reliable open-source data indexer that provides you with custom APIs for your web3 project across all of our supported chains.
-
### Covalent
[Covalent](https://www.covalenthq.com/docs/networks/zksync-era/) provides the industry-leading Unified API bringing visibility to billions of Web3 data points. Developers use Covalent to build exciting multi-chain applications like crypto wallets, NFT galleries, and investor dashboard tools utilizing data.
+### DipDup
+
+[DipDup](https://dipdup.io/) is a Python framework for building smart contract indexers. It helps developers focus on business logic instead of writing a boilerplate to store and serve data. DipDup-based indexers are selective, which means only required data is requested. This approach allows to achieve faster indexing times and decreased load on underlying APIs.
+
### Flair
[Flair](https://docs.flair.dev/) offers reusable **indexing primitives** (such as fault-tolerant RPC ingestors, custom processors, re-org aware database integrations) to make it easy to receive, transform, store and access your on-chain data.
+### Graph Network
+
+[The Graph](https://thegraph.com/) is a decentralized protocol for indexing and querying blockchain data. The Graph makes it possible to query data that is difficult to query directly. Use The Graph network today to index protocol data on zkSync!
+
+### Space & Time
+
+[Space and Time](https://www.spaceandtime.io/) is the verifiable compute layer that scales zero-knowledge proofs on a decentralized data warehouse to deliver trustless data processing to smart contracts, LLMs, and enterprises. Space and Time joins indexed blockchain data from major chains with offchain datasets.
+
+### SubQuery Network
+
+[SubQuery](https://subquery.network/) is a fast, flexible, and reliable open-source data indexer that provides you with custom APIs for your web3 project across all of our supported chains.
+
### Usage guides
- [the-graph](../tutorials/tooling-guides/the-graph.md)
- [subquery](../tutorials/tooling-guides/subquery.md)
-### **Contribute**
+### Contribute
The world of decentralized analytics is expansive, and there's always room for fresh perspectives. If you have carved your path through the data forest and gleaned invaluable insights or have fresh tutorials to share, we wholeheartedly welcome your contributions. Enlighten the community with your analytical prowess.
diff --git a/docs/build/tooling/foundry/getting-started.md b/docs/build/tooling/foundry/getting-started.md
index 83887ec3f0..833c413591 100644
--- a/docs/build/tooling/foundry/getting-started.md
+++ b/docs/build/tooling/foundry/getting-started.md
@@ -17,37 +17,51 @@ To integrate `foundry-zksync` into your projects, you have the flexibility to in
1. Clone the repository:
- ```bash
- git clone git@github.com:matter-labs/foundry-zksync.git
- ```
+```bash
+git clone git@github.com:matter-labs/foundry-zksync.git
+```
-2. Navigate to the project directory and switch to the main branch:
+2. Navigate to the project directory:
- ```bash
- cd foundry-zksync && git checkout main
- ```
+```bash
+cd foundry-zksync
+```
-For component-specific installations:
+3. Prepare the Installation Script: Ensure the script is executable
-- **zkForge**: To install, execute:
+```bash
+chmod +x ./install-foundry-zksync
+```
- ```bash
- cargo install --path ./crates/zkforge --profile local --force --locked
- ```
+4. Run the Installer: Execute the script to install the foundry-zksync binaries forge and cast
-- **zkCast**: To install, run:
+```bash
+./install-foundry-zksync
+```
- ```bash
- cargo install --path ./crates/zkcast --profile local --force --locked
- ```
+Once the `forge` and `cast` binaries are installed, you can start using `foundry-zksync`. Source your preferred profile or refresh your terminal window to activate the changes. You are now ready to begin working with `foundry-zksync`!
+
+For component-specific installations from source:
+
+- **Forge**: To install, execute:
+
+```bash
+cargo install --path ./crates/forge --profile local --force --locked
+```
+
+- **Cast**: To install, run:
+
+```bash
+cargo install --path ./crates/cast --profile local --force --locked
+```
For the entire suite:
- Execute the following command for a comprehensive installation:
- ```bash
- cargo build --release
- ```
+```bash
+cargo build --release
+```
Choose the installation that best fits your development needs.
@@ -55,7 +69,7 @@ Choose the installation that best fits your development needs.
### Initial Setup
-After installation, initialize a new project with `zkforge init `, which sets up the basic structure of a new Foundry project.
+After installation, initialize a new project with `forge init `, which sets up the basic structure of a new Foundry project.
### Project Configuration using `foundry.toml`
@@ -65,11 +79,11 @@ Configuration can be arbitrarily namespaced by profiles. The default profile is
You can select another profile using the `FOUNDRY_PROFILE` environment variable. You can also override parts of your configuration using `FOUNDRY_` or `DAPP_` prefixed environment variables, like `FOUNDRY_SRC`.
-`zkforge init` creates a basic, extendable `foundry.toml` file.
+`forge init` creates a basic, extendable `foundry.toml` file.
-To see your current configuration, run `zkforge config`. To see only basic options (as set with `zkforge init`), run `zkforge config --basic`. This can be used to create a new `foundry.toml` file with `zkforge config --basic > foundry.toml`.
+To see your current configuration, run `forge config`. To see only basic options (as set with `forge init`), run `forge config --basic`. This can be used to create a new `foundry.toml` file with `forge config --basic > foundry.toml`.
-By default `zkforge config` shows the currently selected foundry profile and its values. It also accepts the same arguments as `zkforge build`. An example `foundry.toml` for zkSync with zksolc configurations may look like:
+By default `forge config` shows the currently selected foundry profile and its values. It also accepts the same arguments as `forge build`. An example `foundry.toml` for zkSync with zksolc configurations may look like:
```
[profile.default]
@@ -81,7 +95,7 @@ libs = ['lib']
src = 'src'
libs = ['lib']
fallback_oz = true
-is_system = true
+is_system = false
mode = "3"
```
@@ -89,18 +103,18 @@ mode = "3"
### Running Tests
-Use `zkforge test` to run tests written for your smart contracts. For an overview of how to write tests using `Foundry-zksync` please refer to Foundry testing [here](../../test-and-debug/foundry.md).
+Use `forge test --zksync` to run tests written for your smart contracts. For an overview of how to write tests using `foundry-zksync` please refer to Foundry testing [here](../../test-and-debug/foundry.md).
-## Deploying Smart Contracts with `zkforge`
+## Deploying Smart Contracts with `forge`
-### Compilation with `zkforge zk-build`
+### Compilation with `forge build --zksync`
-`zkforge zkbuild` (also accessible via aliases like `zkforge zk-build`, `zkforge zk-compile`, `zkforge zkb`) is used for compiling smart contracts into zkEVM bytecode. The compiled files are stored in a structured directory at `/zkout/`.
+`forge build --zksync` is used for compiling smart contracts into zkEVM bytecode. The compiled files are stored in a structured directory at `/zkout/`.
**Usage:**
```sh
-zkforge zkbuild [OPTIONS]
+forge build [OPTIONS] --zksync
```
**Key Compiler Options:**
@@ -117,20 +131,17 @@ zkforge zkbuild [OPTIONS]
Compile with default settings or specify `zksolc` version:
```sh
-zkforge zkbuild
-
-# specifying zksolc version
-zkforge zkbuild --use-zksolc v1.3.19
+forge build --zksync
```
-### Deployment with `zkforge zk-create`
+### Deployment with `forge create --zksync`
-`zkforge zkcreate` (and its aliases `zkforge zk-create`, `zkforge zk-deploy`, `zkforge zkc`) deploys smart contracts to zkSync.
+`forge create --zksync` deploys smart contracts to zkSync.
**Usage:**
```sh
-zkforge zkcreate [OPTIONS] --rpc-url --chain --private-key
+forge create [OPTIONS] --rpc-url --chain --private-key --zksync
```
**Options:**
@@ -170,7 +181,7 @@ contract Greeter {
```bash
-zkforge zkcreate src/Greeter.sol:Greeter --constructor-args "Hello zkSync" --private-key --rpc-url https://sepolia.era.zksync.dev --chain 300
+forge create src/Greeter.sol:Greeter --constructor-args "Hello zkSync" --private-key --rpc-url https://sepolia.era.zksync.dev --chain 300 --zksync
```
### Deploying Factory Contracts
@@ -209,25 +220,25 @@ contract Factory {
**Compile `GreeterFactory.sol`:**
```bash
-zkforge zkbuild --is-system=true
+forge build --is-system=true --zksync
```
**Deploy `GreeterFactory.sol`:**
```sh
-zkforge zkcreate src/GreeterFactory.sol:Factory --factory-deps src/Greeter.sol:Greeter --private-key --rpc-url https://sepolia.era.zksync.dev --chain 300
+forge create src/GreeterFactory.sol:Factory --factory-deps src/Greeter.sol:Greeter --private-key --rpc-url https://sepolia.era.zksync.dev --chain 300 --zksync
```
**Deploy `Greeter.sol` via `GreeterFactory.sol`:**
```sh
-zkcast zk-send "CreateNewGreeter(string)" "zkSync Rules" --private-key --rpc-url https://sepolia.era.zksync.dev --chain 300
+cast send "CreateNewGreeter(string)" "zkSync Rules" --private-key --rpc-url https://sepolia.era.zksync.dev --chain 300
```
**Interact with `Greeter.sol`**
```sh
-zkcast call "greet()(string)" --rpc-url https://sepolia.era.zksync.dev --chain 300
+cast call "greet()(string)" --rpc-url https://sepolia.era.zksync.dev --chain 300
```
**Output:**
@@ -239,7 +250,7 @@ zkcast call "greet()(string)" --rpc-url https://sepolia.era.z
**To decode the output to a readable string:**
```sh
-zkcast to-ascii 0x0000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000c7a6b53796e632052756c65730000000000000000000000000000000000000000
+cast to-ascii 0x0000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000c7a6b53796e632052756c65730000000000000000000000000000000000000000
```
**Output:**
@@ -248,11 +259,11 @@ zkcast to-ascii 0x0000000000000000000000000000000000000000000000000000000000000
zkSync Rules
```
-## Basic zkSync Chain Interactions with `zkcast`
+## Basic zkSync Chain Interactions with `cast`
### Introduction
-This guide introduces you to fundamental interactions within the zkSync chain using `zkcast`, a component of the `foundry-zksync` toolkit. Learn how to query chain IDs, retrieve client versions, check L2 ETH balances, obtain gas prices, and more.
+This guide introduces you to fundamental interactions within the zkSync chain using `cast`, a component of the `foundry-zksync` toolkit. Learn how to query chain IDs, retrieve client versions, check L2 ETH balances, obtain gas prices, and more.
### Chain ID Retrieval
@@ -261,7 +272,7 @@ This guide introduces you to fundamental interactions within the zkSync chain us
Retrieve the Chain ID for a local zkSync node with:
```sh
- zkcast chain-id --rpc-url http://localhost:3050
+ cast chain-id --rpc-url http://localhost:3050
```
Expected Output: `270`, indicating the Chain ID of your local zkSync node.
@@ -271,7 +282,7 @@ This guide introduces you to fundamental interactions within the zkSync chain us
For the zkSync Sepolia Testnet, use:
```sh
- zkcast chain-id --rpc-url https://sepolia.era.zksync.dev
+ cast chain-id --rpc-url https://sepolia.era.zksync.dev
```
Expected Output: `300`, the Chain ID for the zkSync Sepolia Testnet.
@@ -281,7 +292,7 @@ This guide introduces you to fundamental interactions within the zkSync chain us
Knowing the client version is vital for compatibility checks and debugging:
```sh
-zkcast client --rpc-url https://sepolia.era.zksync.dev
+cast client --rpc-url https://sepolia.era.zksync.dev
```
Expected Output: `zkSync/v2.0`, denoting the client version.
@@ -291,7 +302,7 @@ Expected Output: `zkSync/v2.0`, denoting the client version.
Verify the Layer 2 (L2) balance of an account:
```sh
-zkcast balance 0x8b1d48a69ACEbC6eb201e2F4d162A002203Bfe8E --rpc-url https://sepolia.era.zksync.dev
+cast balance 0x8b1d48a69ACEbC6eb201e2F4d162A002203Bfe8E --rpc-url https://sepolia.era.zksync.dev
```
Expected Output: A numerical value, e.g., `774909739323110932`, representing the account's L2 balance.
@@ -301,7 +312,7 @@ Expected Output: A numerical value, e.g., `774909739323110932`, representing the
Fetch the current gas price on the network for transaction cost estimations:
```sh
-zkcast gas-price --rpc-url https://sepolia.era.zksync.dev
+cast gas-price --rpc-url https://sepolia.era.zksync.dev
```
Expected Output: A value such as `100000000`, indicating the current gas price.
@@ -311,57 +322,23 @@ Expected Output: A value such as `100000000`, indicating the current gas price.
Gain insights into the latest block on the zkSync chain:
```sh
-zkcast block latest --rpc-url https://sepolia.era.zksync.dev
+cast block latest --rpc-url https://sepolia.era.zksync.dev
```
Expected Output: Detailed information about the latest block, including base fee per gas, gas limit, block hash, and more.
### Sending Transactions
-Initiate transactions, such as contract function calls, using `zkcast`:
+Initiate transactions, such as contract function calls, using `cast`:
```sh
-zkcast zk-send --rpc-url --private-key --chain
+cast send --rpc-url --private-key --chain
```
Example:
```sh
-zkcast zk-send 0x97b985951fd3e0c1d996421cc783d46c12d00082 "setGreeting(string)" "Hello, zkSync!" --rpc-url http://localhost:3050 --private-key --chain 270
+cast send 0xe34E488C1B0Fb372Cc4a5d39219261A5a6fc7996 "setGreeting(string)" "Hello, zkSync!" --rpc-url https://sepolia.era.zksync.dev --private-key --chain 300
```
This command calls the `setGreeting` function of a contract, updating the greeting to "Hello, zkSync!". Replace `` with your actual private key.
-
-### Bridging Assets Between L1 and L2
-
-#### L1 to L2 Deposits
-
-Deposit assets from Layer 1 (Ethereum) to Layer 2 (zkSync):
-
-```sh
-zkcast zk-deposit --l1-rpc-url --l2-url --chain --private-key
-```
-
-Note: For ETH deposits, leave the `` parameter empty.
-
-Example (Depositing ETH):
-
-```sh
-zkcast zk-deposit 0x36615Cf349d7F6344891B1e7CA7C72883F5dc049 1 ether --l1-rpc-url http://localhost:8545 --l2-url http://localhost:3050 --private-key --chain 270
-```
-
-#### L2 to L1 Withdrawals
-
-Withdraw assets from Layer 2 back to Layer 1:
-
-```sh
-zkcast zk-send --withdraw --amount --rpc-url --private-key --chain
-```
-
-Example (Withdrawing ETH):
-
-```sh
-zkcast zk-send --withdraw 0x36615Cf349d7F6344891B1e7CA7C728
-
-83F5dc049 --amount 1 ether --rpc-url http://localhost:3050 --private-key --chain 270
-```
diff --git a/docs/build/tooling/foundry/overview.md b/docs/build/tooling/foundry/overview.md
index 01fa85279c..8f4946eee7 100644
--- a/docs/build/tooling/foundry/overview.md
+++ b/docs/build/tooling/foundry/overview.md
@@ -9,7 +9,7 @@ head:
## Overview
-`foundry-zksync` is a specialized fork of [Foundry](https://github.com/foundry-rs/foundry), tailored for zkSync. It extends Foundry's capabilities for Ethereum app development to support zkSync, allowing for the compilation, deployment, testing, and interaction with smart contracts on zkSync. `foundry-zksync` introduces `zkforge` and `zkcast` extensions of Foundry's existing `forge` and `cast` tools but tailored for zkSync usage.
+`foundry-zksync` is a specialized fork of [Foundry](https://github.com/foundry-rs/foundry), tailored for zkSync. It extends Foundry's capabilities for Ethereum app development to support zkSync, allowing for the compilation, deployment, testing, and interaction with smart contracts on zkSync. `foundry-zksync` introduces `--zksync` flag, or the use of `vm.zkVm(true)` to target the zkSync VM.
### Status and Contribution
@@ -36,7 +36,6 @@ head:
While `foundry-zksync` is **alpha stage**, there are some limitations to be aware of, but not limited to:
-- **Cheat Codes Support**: Not all cheat codes are fully supported. [View the list of supported cheat codes](https://github.com/matter-labs/foundry-zksync/blob/main/SUPPORTED_CHEATCODES.md).
- **Compile Time**: Some users may experience slow compiling.
- **Specific Foundry Features**: Currently features such as `coverage`, `--gas-report` or `--verify` may not work as intended. We are actively working on providing support for these feature types.
- **Compiling Libraries**: Compiling non-inlinable libraries requires deployment and adding to configuration. For more information please refer to [official docs](https://era.zksync.io/docs/tools/hardhat/compiling-libraries.html).
diff --git a/docs/build/tooling/hardhat/getting-started.md b/docs/build/tooling/hardhat/getting-started.md
index e3721dc446..f357e37038 100644
--- a/docs/build/tooling/hardhat/getting-started.md
+++ b/docs/build/tooling/hardhat/getting-started.md
@@ -20,12 +20,12 @@ zkSync Era has the following official plugins for Hardhat:
- [@matterlabs/hardhat-zksync-solc](./hardhat-zksync-solc.md) - used to compile contracts written in Solidity.
- [@matterlabs/hardhat-zksync-vyper](./hardhat-zksync-vyper.md) - used to compile contracts written in Vyper.
- [@matterlabs/hardhat-zksync-deploy](./hardhat-zksync-deploy.md) - used to deploy smart contracts.
-- [@matterlabs/hardhat-zksync-chai-matchers](./hardhat-zksync-chai-matchers.md) - adds zkSync-specific capabilities to the [Chai](https://www.chaijs.com/) assertion library for testing smart contracts.
- [@matterlabs/hardhat-zksync-verify](./hardhat-zksync-verify.md) - used to verify smart contracts.
- [@matterlabs/hardhat-zksync-verify-vyper](./hardhat-zksync-verify-vyper.md) - used to verify vyper smart contracts.
- [@matterlabs/hardhat-zksync-upgradable](./hardhat-zksync-upgradable.md) - used to deploy, update, and verify proxy smart contracts.
- [@matterlabs/hardhat-zksync-ethers](./hardhat-zksync-ethers.md) - wrapper around zksync-ethers with some extra Hardhat-specific functionality.
- [@matterlabs/hardhat-zksync-node](./hardhat-zksync-node.md) - used to run the zkSync era-test-node locally.
+- [@matterlabs/hardhat-zksync](./hardhat-zksync.md) - used to access to all of the supported plugins and to use them as needed in your project.
::: tip Additional plugins
Learn more about [other plugins from the community](./other-plugins.md) that you can use with zkSync Era.
diff --git a/docs/build/tooling/hardhat/hardhat-zksync-chai-matchers.md b/docs/build/tooling/hardhat/hardhat-zksync-chai-matchers.md
deleted file mode 100644
index 32956983e9..0000000000
--- a/docs/build/tooling/hardhat/hardhat-zksync-chai-matchers.md
+++ /dev/null
@@ -1,155 +0,0 @@
----
-head:
- - - meta
- - name: "twitter:title"
- content: hardhat-zksync-chai-matchers | zkSync Docs
----
-
-# `hardhat-zksync-chai-matchers`
-
-This plugin adds zkSync-specific capabilities to the [Chai](https://www.chaijs.com/) assertion library for testing smart contracts. It extends all the functionalities supported by the [hardhat-chai-matchers](https://hardhat.org/hardhat-chai-matchers/docs/overview) plugin, with the idea to preserve the same behavior and interface.
-Currently, it is used in combination with [local testing environment](../../test-and-debug/getting-started.md).
-
-[Changelog](https://github.com/matter-labs/hardhat-zksync/blob/main/packages/hardhat-zksync-chai-matchers/CHANGELOG.md)
-
-::: info
-
-- Since responses from transactions that revert are highly dependent on the RPC implementation, all [Hardhat](https://hardhat.org/hardhat-chai-matchers/docs/overview) chai matchers that start with `revert` have been affected (without any changes to the chai matchers interface).
-- In addition, the `options` argument from `changeEtherBalance`/`changeEtherBalances` now includes the `overrides` field in order to support `zksync-ethers` transfer methods with overrides.
- :::
-
-::: warning Version Compatibility Warning
-Ensure you are using the correct version of the plugin with ethers:
-
-- For plugin version **<1.0.0**:
-
- - Compatible with ethers **v5**.
-
-- For plugin version **≥1.0.0**:
- - Compatible with ethers **v6** (⭐ Recommended)
-
-Examples are adopted for plugin version **>=1.0.0**
-:::
-
-## Installation
-
-Add the latest version of this plugin to your project with the following command:
-
-::: code-tabs
-
-@tab:active yarn
-
-```bash
-yarn add -D @matterlabs/hardhat-zksync-chai-matchers @nomicfoundation/hardhat-chai-matchers chai @nomiclabs/hardhat-ethers ethers
-```
-
-@tab npm
-
-```bash
-npm i -D @matterlabs/hardhat-zksync-chai-matchers
-```
-
-:::
-
-### Usage
-
-After installing it, add the plugin to your Hardhat config:
-
-```javascript
-import "@matterlabs/hardhat-zksync-chai-matchers";
-```
-
-Then you'll be able to use the matchers in your tests.
-
-#### changeEtherBalance
-
-Assert that the ether balance of an address changed by a specific amount:
-
-```javascript
-await expect(() =>
- sender.transfer({
- to: receiver.address,
- amount: 2000,
- })
-).to.changeEtherBalance(sender.address, -2000);
-
-await expect(() =>
- sender.sendTransaction({
- to: receiver.address,
- value: 1000,
- })
-).to.changeEtherBalance(sender.address, "-1000");
-```
-
-This matchers include additional options argument with functionalities for including fee and overriding transaction:
-
-```javascript
-overrides = {
- type: 2,
- maxFeePerGas: 1 * gasPrice,
- maxPriorityFeePerGas: 1 * gasPrice,
-};
-
-await expect(() =>
- sender.transfer({
- to: receiver.address,
- amount: 500,
- overrides,
- })
-).to.changeEtherBalance(sender, -(txGasFees + 500), {
- balanceChangeOptions: {
- includeFee: true,
- },
- overrides,
-});
-```
-
-#### changeTokenBalance
-
-Assert that an ERC20 token balance of an address changed by a specific amount:
-
-```javascript
-await expect(sender.transfer({ to: receiver.address, amount: 5, token: token.address })).to.changeTokenBalance(token, sender, -5);
-
-await expect(token.transfer(receiver.address, 5)).to.not.changeTokenBalance(token, sender, 0);
-```
-
-#### reverted
-
-Assert that a transaction reverted for any reason:
-
-```javascript
-await expect(contract.setAmount(100)).to.be.reverted;
-```
-
-#### revertedWithCustomError
-
-Assert that a transaction reverted with a specific custom error:
-
-```javascript
-await expect(contract.setAmount(100)).to.be.revertedWithCustomError(contract, "InvalidAmount");
-```
-
-
-
-And you can also use regular chai matchers like:
-
-#### emit
-
-```javascript
-await expect(contract.setAmount(100)).to.emit(contract, "AmountUpdated");
-```
-
-#### properAddress
-
-```javascript
-expect("0x36615Cf349d7F6344891B1e7CA7C72883F5dc049").to.be.properAddress;
-```
-
-#### Comparisons of numbers
-
-```javascript
-expect(await contract.getAmount()).to.equal(100);
-```
-
-Checkout the advantages of using chai matchers [here](https://hardhat.org/hardhat-chai-matchers/docs/overview#why-would-i-want-to-use-it?). Since the list of all supported chai matchers is same as with [hardhat-chai-matchers](https://hardhat.org/hardhat-chai-matchers/docs/overview) plugin, check the [reference documentation](https://hardhat.org/hardhat-chai-matchers/docs/reference).
diff --git a/docs/build/tooling/hardhat/hardhat-zksync-deploy.md b/docs/build/tooling/hardhat/hardhat-zksync-deploy.md
index 558d405c84..27c9dd4c54 100644
--- a/docs/build/tooling/hardhat/hardhat-zksync-deploy.md
+++ b/docs/build/tooling/hardhat/hardhat-zksync-deploy.md
@@ -545,6 +545,31 @@ If network argument `--network` or `defaultNetwork` configuration are not specif
For more details about a dockerized local setup, check out [Local testing](../../test-and-debug/getting-started.md).
:::
+`yarn hardhat deploy-zksync:contract --contract-name `
+
+Provides an easy and fast way to deploy the given contract on the specified network. If the provided command for deploying a single contract is insufficient and you require additional flexibility, such as incorporating additional dependencies or overrides, it would be advisable to utilize a script-based approach.
+
+- `--contract-name ` - contract name or FQN, required argument in all tasks, e.g. `hardhat deploy-zksync:proxy --contract-name SomeContract`.
+- `` - list of constructor arguments, e.g. `hardhat deploy-zksync:proxy --contract-name Greeter 'Hello'`.
+- `--constructor-args ` - name of javascript module containing complex constructor arguments. Works only if `` are not provided e.g. `hardhat deploy-zksync:contract --contract-name ComplexContract --constructor-args args.js`. Example of `args.js` :
+
+```typescript
+module.exports = [
+ "a string argument",
+ "0xabcdef",
+ "42",
+ {
+ property1: "one",
+ property2: 2,
+ },
+];
+```
+
+- `--no-compile`- skip the compilation process, e.g. `hardhat deploy-zksync:beacon --contract-name Contract --no-compile`.
+- `--deployment-type` - specify which deployer smart contract function will be called. Permissible values for this parameter include `create`, `create2`, `createAccount`, and `create2Account`. If this parameter is omitted, the default value will be `create`, e.g. `hardhat deploy-zksync:beacon --contract-name Greeter 'Hello' --deployment-type create2`.
+
+The account used for deployment will be the one specified by the `deployerAccount` configuration within the `hardhat.config.ts` file. If no such configuration is present, the account with index `0` will be used.
+
`yarn hardhat deploy-zksync:libraries` -- runs compilation and deployment of missing libraries (the list of all missing libraries is provided by the output of `@matterlabs/hardhat-zksync-solc` plugin).
The account used for deployment will be the one specified by the `deployerAccount` configuration within the `hardhat.config.ts` file. If no such configuration is present, the account with index `0` will be used.
diff --git a/docs/build/tooling/hardhat/hardhat-zksync-toolbox.md b/docs/build/tooling/hardhat/hardhat-zksync-toolbox.md
deleted file mode 100644
index 9af251e434..0000000000
--- a/docs/build/tooling/hardhat/hardhat-zksync-toolbox.md
+++ /dev/null
@@ -1,61 +0,0 @@
----
-head:
- - - meta
- - name: "twitter:title"
- content: zkSync Hardhat Plugins | zkSync Docs
----
-
-# `hardhat-zksync-toolbox`
-
-The hardhat-zksync-toolbox plugin provides a convenient method for bundling and accessing a range of zkSync-related Hardhat plugins. This approach simplifies the process of utilizing these plugins and promotes ease of use.
-
-List of contained plugins:
-
-- [hardhat-zksync-solc](./hardhat-zksync-solc.md)
-- [hardhat-zksync-deploy](./hardhat-zksync-deploy.md)
-- [hardhat-zksync-chai-matchers](./hardhat-zksync-chai-matchers.md)
-- [hardhat-zksync-verify](./hardhat-zksync-verify.md)
-
-::: tip Popular Hardhat plugins
-
-You can find a list of all official plugins [here](./getting-started.md). Also, zkSync supports some other [popular plugins](./other-plugins.md) that can be used.
-
-:::
-
-### Installation
-
-Add the latest version of this plugin to your project with the following command:
-
-::: code-tabs
-
-@tab:active yarn
-
-```bash
-yarn add -D @matterlabs/hardhat-zksync-toolbox @matterlabs/hardhat-zksync-solc @matterlabs/hardhat-zksync-chai-matchers @matterlabs/hardhat-zksync-deploy @matterlabs/hardhat-zksync-verify @nomicfoundation/hardhat-verify @nomiclabs/hardhat-ethers ethers chai zksync-ethers
-```
-
-@tab npm
-
-```bash
-npm i -D @matterlabs/hardhat-zksync-toolbox
-```
-
-:::
-
-::: note
-For `npm`, version 7 or later is recommended.
-:::
-
-### Usage
-
-After installing it, add the plugin to your Hardhat config:
-
-```javascript
-import "@matterlabs/hardhat-zksync-toolbox";
-```
-
-With the hardhat-zksync-toolbox plugin installed and imported, you will have access to all of the supported plugins and will be able to use them as needed in your project.
-
-::: note
-To learn more about using any of the plugins that are supported by the hardhat-zksync-toolbox plugin, you can refer to their documentation above.
-:::
diff --git a/docs/build/tooling/hardhat/hardhat-zksync-upgradable.md b/docs/build/tooling/hardhat/hardhat-zksync-upgradable.md
index 171d3ff07b..f7aa065765 100644
--- a/docs/build/tooling/hardhat/hardhat-zksync-upgradable.md
+++ b/docs/build/tooling/hardhat/hardhat-zksync-upgradable.md
@@ -737,3 +737,108 @@ Each of these methods totals the fee for every contract in their respective pipe
```typescript
const totalGasEstimation = await hre.zkUpgrades.estimation.estimateGasProxy(this.deployer, contract, [], { kind: "uups" }, true);
```
+
+# Commands
+
+Please consider that while the provided commands enable contract deployment and upgrading, not all arguments may be available. If these commands lack the required functionality, it may be necessary to utilize scripting for a more comprehensive approach.
+
+## Configuration
+
+To extend the configuration to support commands, we need to add an accounts field to the specific network configuration in the networks section of the `hardhat.config.ts` file. This accounts field can support an array of private keys or a mnemonic object and represents accounts that will be used as wallet automatically.
+
+```typescript
+const config: HardhatUserConfig = {
+ networks: {
+ sepolia: {
+ url: "https://sepolia.infura.io/v3/", // The Ethereum Web3 RPC URL (optional).
+ },
+ zkSyncSepoliaTestnet: {
+ url: "https://sepolia.era.zksync.dev", // The testnet RPC URL of zkSync Era network.
+ ethNetwork: "sepolia", // The Ethereum Web3 RPC URL, or the identifier of the network (e.g. `mainnet` or `sepolia`)
+ zksync: true,
+ // ADDITION
+ // The private keys for the accounts used in the deployment or in the upgrade process.
+ accounts: ["0xac1e735be8536c6534bb4f17f06f6afc73b2b5ba84ac2cfb12f7461b20c0bbe3", "0x28a574ab2de8a00364d5dd4b07c4f2f574ef7fcc2a86a197f65abaec836d1959"],
+ // Mnemonic used in the deployment or in the upgrade process
+ // accounts: {
+ // mnemonic: 'stuff slice staff easily soup parent arm payment cotton trade scatter struggle'
+ // }
+ },
+ },
+};
+```
+
+- accounts represents a list of the private keys or mnemonic object for the account used in the deployment or in the upgrade process.
+
+ accounts object will automatically be populated with rich accounts if used network is zkSync Era Test Node or zksync-cli Local Node
+ To establish a default index per network, which is by default `0`, you can include a `deployerAccounts` section in your `hardhat.config.ts` file.
+
+```typescript
+const config: HardhatUserConfig = {
+ // ADDITION
+ deployerAccounts: {
+ zkTestnet: 1, // The default index of the account for the specified network.
+ //default: 0 // The default value for not specified networks. Automatically set by plugin to the index 0.
+ },
+ networks: {
+ sepolia: {
+ url: "https://sepolia.infura.io/v3/", // The Ethereum Web3 RPC URL (optional).
+ },
+ zkSyncSepoliaTestnet: {
+ url: "https://sepolia.era.zksync.dev", // The testnet RPC URL of zkSync Era network.
+ ethNetwork: "sepolia", // The Ethereum Web3 RPC URL, or the identifier of the network (e.g. `mainnet` or `sepolia`)
+ zksync: true,
+ // The private keys for the accounts used in the deployment process.
+ accounts: ["0xac1e735be8536c6534bb4f17f06f6afc73b2b5ba84ac2cfb12f7461b20c0bbe3", "0x28a574ab2de8a00364d5dd4b07c4f2f574ef7fcc2a86a197f65abaec836d1959"],
+ // Mnemonic used in the deployment process
+ // accounts: {
+ // mnemonic: 'stuff slice staff easily soup parent arm payment cotton trade scatter struggle'
+ // }
+ },
+ },
+};
+```
+
+- `deployerAccounts` represents an object where the default index of the accounts is provided and automatically used in the upgradable commands described below. If the network name is not specified inside the object, the default index of the account will be `0`. We can change and deafult index for not specified networks if we override `default` name with index that we want.
+
+## Command list
+
+`yarn hardhat deploy-zksync:proxy --contract-name [] [--constructor-args ] [--deployment-type ] [--initializer ] [--no-compile]`
+
+Automatically determine whether the deployment requires a Transparent or UUPS proxy, and deploy all necessary contracts accordingly. If the Transparent proxy is chosen, the deployment will include the implementation, admin, and proxy. Alternatively, selecting the UUPS proxy will result in deploying the implementation and proxy.
+
+`yarn hardhat upgrade-zksync:proxy --contract-name --proxy-address [--deployment-type ] [--no-compile]`
+
+Upgrade UUPS or Transparent implementation on the specified network.
+
+`yarn hardhat deploy-zksync:beacon --contract-name [] [--constructor-args ] [--deployment-type ] [--initializer ] [--no-compile]`
+
+Initiates the deployment of the specified implementation, beacon, and proxy on the specified network.
+
+`yarn hardhat upgrade-zksync:beacon --contract-name --beacon-address [--deployment-type ] [--no-compile]`
+
+Upgrade beacon implementation on the specified network.
+
+- `--contract-name ` - contract name or FQN, required argument in all tasks, e.g. `hardhat deploy-zksync:proxy --contract-name SomeContract`.
+- `` - list of constructor arguments, e.g. `hardhat deploy-zksync:proxy --contract-name Greeter 'Hello'`.
+- `--constructor-args ` - name of javascript module containing complex constructor arguments. Works only if `` are not provided, e.g. `hardhat deploy-zksync:contract --contract-name ComplexContract --constructor-args args.js`. Example of `args.js` :
+
+```typescript
+module.exports = [
+ "a string argument",
+ "0xabcdef",
+ "42",
+ {
+ property1: "one",
+ property2: 2,
+ },
+];
+```
+
+- `--beacon-address ` - deployed beacon contract address, e.g. `yarn hardhat upgrade-zksync:beacon --contract-name BoxV2 --beacon-address 0x4bbeEB066eD09B7AEd07bF39EEe0460DFa261520`.
+- `--proxy-address ` - deployed proxy contract address, e.g. `yarn hardhat upgrade-zksync:proxy --contract-name BoxV2 --proxy-address 0x4bbeEB066eD09B7AEd07bF39EEe0460DFa261520`.
+- `--initializer ` - initializer method name present in the contract, e.g. `hardhat deploy-zksync:proxy --contract-name Contract --initializer store`. If this parameter is omitted, the default value will be `initialize`.
+- `--no-compile`- skip the compilation process, e.g. `hardhat deploy-zksync:beacon --contract-name Contract --no-compile`.
+- `--deployment-type` - specify which deployer smart contract function will be called. Permissible values for this parameter include `create`, `create2`, `createAccount`, and `create2Account`. If this parameter is omitted, the default value will be `create`, e.g. `hardhat deploy-zksync:beacon --contract-name Greeter 'Hello' --deployment-type create2`.
+
+The account used for deployment will be the one specified by the `deployerAccount` configuration within the `hardhat.config.ts` file. If no such configuration is present, the account with index `0` will be used.
diff --git a/docs/build/tooling/hardhat/hardhat-zksync.md b/docs/build/tooling/hardhat/hardhat-zksync.md
new file mode 100644
index 0000000000..84f65992b3
--- /dev/null
+++ b/docs/build/tooling/hardhat/hardhat-zksync.md
@@ -0,0 +1,74 @@
+---
+head:
+ - - meta
+ - name: "twitter:title"
+ content: zkSync Hardhat Plugins | zkSync Docs
+---
+
+# `hardhat-zksync`
+
+The hardhat-zksync plugin provides a convenient method for bundling and accessing a range of zkSync-related Hardhat plugins. This approach simplifies the process of utilizing these plugins and promotes ease of use.
+
+List of contained plugins:
+
+- [hardhat-zksync-solc](./hardhat-zksync-solc.md)
+- [hardhat-zksync-deploy](./hardhat-zksync-deploy.md)
+- [hardhat-zksync-upgradable](./hardhat-zksync-upgradable.md)
+- [hardhat-zksync-verify](./hardhat-zksync-verify.md)
+- [hardhat-zksync-node](./hardhat-zksync-node.md)
+- [hardhat-zksync-ethers](./hardhat-zksync-ethers.md)
+
+::: tip Popular Hardhat plugins
+
+You can find a list of all official plugins [here](./getting-started.md). Also, zkSync supports some other [popular plugins](./other-plugins.md) that can be used.
+
+:::
+
+### Installation
+
+Add the latest version of this plugin to your project with the following command:
+
+::: code-tabs
+
+@tab:active yarn
+
+```bash
+yarn add -D @matterlabs/hardhat-zksync
+```
+
+@tab npm
+
+```bash
+npm i -D @matterlabs/hardhat-zksync
+```
+
+:::
+
+### Usage
+
+After installing it, add the plugin to your Hardhat config:
+
+```javascript
+import "@matterlabs/hardhat-zksync";
+```
+
+With the `hardhat-zksync` plugin installed and imported, you will have access to all of the supported plugins and will be able to use them as needed in your project.
+This plugin enables access to all commands available for each specific plugin, making them readily accessible with just the usage of this plugin.
+
+::: note
+To learn more about using any of the plugins that are supported by the hardhat-zksync plugin, you can refer to their documentation above.
+:::
+
+For certain tasks present in the plugins encompassed by this plugin, it overrides them with new features and parameters. These tasks streamline common functionalities into a simplified workflow.
+
+Here is a list of overriden tasks where this plugin adds new optional parameter `--verify`:
+
+- `deploy-zksync:contract`
+- `deploy-zksync:proxy`
+- `upgrade-zksync:proxy`
+- `deploy-zksync:beacon`
+- `upgrade-zksync:beacon`
+
+The `--verify` parameter allow the task to immediately verify all deployed and upgraded contracts when task is called.
+
+To check other parameters present in these tasks, please check the documentation pages for [hardhat-zksync-deploy](./hardhat-zksync-deploy.md) and [hardhat-zksync-upgradable](./hardhat-zksync-upgradable.md).
diff --git a/docs/build/tooling/hardhat/other-plugins.md b/docs/build/tooling/hardhat/other-plugins.md
index cc3b091304..93330bd455 100644
--- a/docs/build/tooling/hardhat/other-plugins.md
+++ b/docs/build/tooling/hardhat/other-plugins.md
@@ -35,9 +35,13 @@ Automatically generate TypeScript bindings for smart contracts.
Plugin used to deploy and update upgradable smart contracts (proxies). Use the [hardhat-zksync-upgradable plugin](./hardhat-zksync-upgradable.md) which provides an easy-to-use interface for interacting with the OpenZeppelin Upgrades Plugins within a Hardhat environment on zkSync.
-### hardhat-contract-sizer
+### hardhat-chai-matchers
+
+Adds capabilities to make your smart contract tests easy to write and read.
-Generates a report of the bytecode size of the contracts in your project.
+[More information](https://www.npmjs.com/package/@nomicfoundation/hardhat-chai-matchers)
+
+### hardhat-contract-sizer
[More information](https://www.npmjs.com/package/hardhat-contract-sizer)
diff --git a/docs/build/tooling/network-faucets.md b/docs/build/tooling/network-faucets.md
index 3c8874703b..1b15db4d95 100644
--- a/docs/build/tooling/network-faucets.md
+++ b/docs/build/tooling/network-faucets.md
@@ -27,3 +27,7 @@ Use any of the following faucets to claim SepoliaETH, which you can bridge to zk
- [Proof of Work Sepolia faucet](https://sepolia-faucet.pk910.de/)
- [Infura Sepolia faucet](https://www.infura.io/faucet/sepolia/)
- [Ethereum Ecosystem Sepolia faucet](https://www.ethereum-ecosystem.com/faucets/ethereum-sepolia)
+
+## Sepolia USDC faucet
+
+You can use [Circle's Testnet Faucet](https://faucet.circle.com/) to claim testnet USDC on zkSync Sepolia or Ethereum Sepolia Testnet.
diff --git a/docs/build/tooling/nft-marketplaces.md b/docs/build/tooling/nft-marketplaces.md
index 83be9740c7..ee03860fbb 100644
--- a/docs/build/tooling/nft-marketplaces.md
+++ b/docs/build/tooling/nft-marketplaces.md
@@ -29,6 +29,11 @@ The following NFT marketplaces are specialized in facilitating the trade, creati
[Tevaera](https://market.tevaera.com/) is the first paymasters and ONFT powered marketplace on the zkSync Era. It offers the lowest transaction fees while being fully secured by the Ethereum consensus.\
**Specialty**: zkSync Era, Low Fees, Paymasters and ONFT
+### zkMarkets
+
+[zkMarkets](https://www.zkmarkets.com/zksync-era) is a native NFT marketplace on zkSync, supporting paymasters and Smart Wallets like Clave. It features a Launchpad, rarity tools, and aggregated listings.
+**Specialty**: Aggregated Marketplace, Paymasters, Smart Accounts, Rarity tools
+
### Zonic
[Zonic](https://zonic.app/) supports the Ethereum Layer-2 ecosystem by providing a platform where individuals can construct their own NFT projects and exchange them through an intuitive user interface.\
diff --git a/docs/build/tooling/node-providers.md b/docs/build/tooling/node-providers.md
index 89ca7559c5..bb96fa9224 100644
--- a/docs/build/tooling/node-providers.md
+++ b/docs/build/tooling/node-providers.md
@@ -7,6 +7,10 @@ head:
# RPC Providers
+### Alchemy
+
+[Alchemy](https://www.alchemy.com/zksync) is a leading developer platform with powerful APIs, SDKs, and tools to build truly scalable onchain apps. Deploy on zkSync Mainnet and zkSync Sepolia Testnet using Alchemy's free and [paid plans](https://www.alchemy.com/pricing).
+
### Ankr
[Ankr](https://www.ankr.com/rpc/zksync_era/) provides private and public RPC endpoints for zkSync, powered by a globally distributed and decentralized network of nodes. They offer free and [paid plans](https://www.ankr.com/rpc/pricing/) with increased request limits.
@@ -27,6 +31,10 @@ head:
[DRPC](https://drpc.org/public-endpoints/zksync) offers access to distributed network of independent third-party partners and public nodes for zkSync. They provide a free tier that allows for an unlimited amount of requests over public nodes, or a paid tier which provides access to all providers, as well as other additional features.
+### GetBlock
+
+[GetBlock](https://getblock.io/nodes/zksync/) provides access to zkSync API endpoint for your project. With GetBlock you don’t need to know how to run zkSync nodes as they are already are available for mainnet and testnets.
+
### Quicknode
[QuickNode](https://www.quicknode.com/chains/zkSync) offers access to hosted zkSync nodes as part of their free Discover Plan. You can configure add-ons, like "Trace Mode" and "Archive Mode" for an additional cost by upgrading to one of their paid plans.
@@ -37,9 +45,10 @@ head:
### Public RPCs
-| Mainnet | Testnet |
-| ---------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------- |
-| [https://mainnet.era.zksync.io](https://mainnet.era.zksync.io) | [https://sepolia.era.zksync.dev](https://sepolia.era.zksync.dev) |
-| [https://zksync.drpc.org](https://zksync.drpc.org) | [https://zksync-era-sepolia.blockpi.network/v1/rpc/public](https://zksync-era-sepolia.blockpi.network/v1/rpc/public) |
-| [https://zksync.meowrpc.com](https://zksync.meowrpc.com) | |
-| [https://zksync-era.blockpi.network/v1/rpc/public](https://zksync-era.blockpi.network/v1/rpc/public) | |
+| Mainnet | Testnet |
+| ------------------------------------------------------------------------------------------------------------------ | -------------------------------------------------------------------------------------------------------------------- |
+| [https://mainnet.era.zksync.io](https://mainnet.era.zksync.io) | [https://sepolia.era.zksync.dev](https://sepolia.era.zksync.dev) |
+| [https://zksync.drpc.org](https://zksync.drpc.org) | [https://zksync-era-sepolia.blockpi.network/v1/rpc/public](https://zksync-era-sepolia.blockpi.network/v1/rpc/public) |
+| [https://zksync.meowrpc.com](https://zksync.meowrpc.com) | |
+| [https://zksync-era.blockpi.network/v1/rpc/public](https://zksync-era.blockpi.network/v1/rpc/public) | |
+| [https://go.getblock.io/f76c09905def4618a34946bf71851542](https://go.getblock.io/f76c09905def4618a34946bf71851542) | |
diff --git a/docs/build/tooling/oracles.md b/docs/build/tooling/oracles.md
index 312c2ea8a5..01082aa4a5 100644
--- a/docs/build/tooling/oracles.md
+++ b/docs/build/tooling/oracles.md
@@ -11,6 +11,10 @@ head:
Welcome to the Oracles page, a comprehensive hub dedicated to interacting with oracle services on zkSync Era. As the demand for decentralized applications continues, the need for reliable and efficient oracle services becomes paramount. Within these sections, you'll unearth specialized usage guides and tangible examples designed to facilitate seamless interactions with a variety of different oracle services.
+### Chainlink
+
+[Chainlink](https://docs.chain.link/data-feeds/price-feeds/addresses?network=zksync&page=1) private feeds provide secure, reliable, and tamper-proof price data for your smart contracts.
+
### DIA
[DIA](https://docs.diadata.org/products/token-price-feeds) token price feeds provide smart contract real-time price information of 3,000+ cryptocurrencies, transparently sourced from 80+ trusted, high-volume DEXs and CEXs. Check out the usage guide below to get started today!
@@ -21,7 +25,11 @@ Welcome to the Oracles page, a comprehensive hub dedicated to interacting with o
### Pyth
-[Pythnet](https://docs.pyth.network/documentation/pythnet-price-feeds) price feeds use a "pull" price update model, where users are responsible for posting price updates on-chain when needed. Checkout the usage guide to get started today!
+[Pythnet](https://docs.pyth.network/price-feeds) price feeds use a "pull" price update model, where users are responsible for posting price updates on-chain when needed. Checkout the usage guide to get started today!
+
+### Gelato
+
+[Gelato](https://docs.gelato.network/web3-services/vrf/understanding-vrf) provides access to Verifiable Random Functions (VRF) on zkSync. VRFs are cryptographic primitives that generate pseudorandom numbers in a way that is provably secure and verifiable. A VRF allows a holder of a private key to produce a random number along with a proof that the number was generated legitimately (making it publically verifable). More information, including how to use VRFs in your dApp, can be found in the Gelato docs.
### Usage guides
diff --git a/docs/build/tutorials/how-to/test-contracts.md b/docs/build/tutorials/how-to/test-contracts.md
index 7a4fe9371d..eeda629b8d 100644
--- a/docs/build/tutorials/how-to/test-contracts.md
+++ b/docs/build/tutorials/how-to/test-contracts.md
@@ -7,7 +7,7 @@ head:
# Test smart contracts with Hardhat plugins
-This tutorial provides a step-by-step guide on testing smart contracts using the **hardhat-zksync-chai-matchers** plugin in conjunction with the **zkSync Era Test Node** on your local machine. To facilitate this process of running tests on the **zkSync Era Test Node**, you'll also utilize the **hardhat-zksync-node** plugin.
+This tutorial provides a step-by-step guide on testing smart contracts using the **hardhat-chai-matchers** plugin in conjunction with the **zkSync Era Test Node** on your local machine. To facilitate this process of running tests on the **zkSync Era Test Node**, you'll also utilize the **hardhat-zksync-node** plugin.
# Prerequisites
@@ -83,9 +83,9 @@ Since we've confirmed that the **zkSync Era Test Node** is functioning properly
Read more about **hardhat-zksync-node** [here.](../../tooling/hardhat/hardhat-zksync-node.md)
-## Integration with hardhat-zksync-chai-matchers plugin
+## Integration with hardhat-chai-matchers plugin
-To leverage zkSync-specific capabilities within the [Chai](https://www.chaijs.com/) assertion library for testing smart contracts, it's necessary to use the **hardhat-zksync-chai-matchers** plugin.
+To leverage zkSync-specific capabilities within the [Chai](https://www.chaijs.com/) assertion library for testing smart contracts, it's necessary to use the **hardhat-chai-matchers** plugin.
### Installation
@@ -96,13 +96,13 @@ In the root directory of your project, execute this command:
@tab:active yarn
```bash
-yarn add -D @matterlabs/hardhat-zksync-chai-matchers @nomicfoundation/hardhat-chai-matchers chai @nomiclabs/hardhat-ethers ethers
+yarn add -D @nomicfoundation/hardhat-chai-matchers chai@4.3.6 @nomiclabs/hardhat-ethers
```
@tab npm
```bash
-npm i -D @matterlabs/hardhat-zksync-chai-matchers
+npm i -D @nomicfoundation/hardhat-chai-matchers
```
:::
@@ -111,17 +111,8 @@ After installing it, add the plugin at the top of your **hardhat.config.ts** fil
```bash
import "@nomicfoundation/hardhat-chai-matchers"
-import "@matterlabs/hardhat-zksync-chai-matchers";
```
-::: note Import order matters
-
-To enable the **@matterlabs/hardhat-zksync-chai-matchers** plugin to override **@nomicfoundation/hardhat-chai-matchers**, you must import the latter first, ensuring that all zkSync-specific matchers take override the original ones.
-
-:::
-
-Read more about **hardhat-zksync-chai-matchers** [here.](../../tooling/hardhat/hardhat-zksync-chai-matchers.md)
-
### Smart Contract creation
To set up the environment for using chai matchers and writing tests, you'll need to create some contracts. Follow these steps:
@@ -189,7 +180,7 @@ You can find more details about available configuration options in the [official
### Deploy configuration
-We'll use provided example contract for testing with help of **hardhat-zksync-chai-matchers** plugin and deploying it on **zkSync Era Test Node**. Since deployment is involved, we'll also require the **hardhat-zksync-deploy** plugin for assistance. In the same directory, execute the command to install **hardhat-zksync-deploy** plugin:
+We'll use provided example contract for testing with help of **hardhat-chai-matchers** plugin and deploying it on **zkSync Era Test Node**. Since deployment is involved, we'll also require the **hardhat-zksync-deploy** plugin for assistance. In the same directory, execute the command to install **hardhat-zksync-deploy** plugin:
::: code-tabs
@@ -226,7 +217,6 @@ import "@matterlabs/hardhat-zksync-solc";
import "@matterlabs/hardhat-zksync-deploy";
import "@matterlabs/hardhat-zksync-node";
import "@nomicfoundation/hardhat-chai-matchers";
-import "@matterlabs/hardhat-zksync-chai-matchers";
const config: HardhatUserConfig = {
zksolc: {
@@ -242,13 +232,13 @@ const config: HardhatUserConfig = {
export default config;
```
-Here are the steps to create test cases with the **hardhat-zksync-chai-matchers** plugin:
+Here are the steps to create test cases with the **hardhat-chai-matchers** plugin:
1. Navigate to your project's root directory.
2. Create a new folder named **test**.
3. Inside the **test** folder, create a file named **test.ts**.
-Once you've completed these steps, you'll be ready to write your tests using the **hardhat-zksync-chai-matchers** plugin.
+Once you've completed these steps, you'll be ready to write your tests using the **hardhat-chai-matchers** plugin.
Here's a brief example showcasing the functionalities of our contract:
@@ -258,7 +248,6 @@ import { expect } from "chai";
import { Wallet, Provider, Contract } from "zksync-ethers";
import { Deployer } from "@matterlabs/hardhat-zksync-deploy";
import { ZkSyncArtifact } from "@matterlabs/hardhat-zksync-deploy/src/types";
-import { ZkSyncProviderAdapter } from "@matterlabs/hardhat-zksync-node";
import "@matterlabs/hardhat-zksync-node/dist/type-extensions";
const RICH_PRIVATE_KEY = "0x7726827caac94a7f9e1b160f7ea819f172f7b6f9d2a97f992c38edeab82d4110";
diff --git a/docs/build/tutorials/smart-contract-development/account-abstraction/custom-aa-tutorial.md b/docs/build/tutorials/smart-contract-development/account-abstraction/custom-aa-tutorial.md
index 2cd48c6fbc..0fe12c58db 100644
--- a/docs/build/tutorials/smart-contract-development/account-abstraction/custom-aa-tutorial.md
+++ b/docs/build/tutorials/smart-contract-development/account-abstraction/custom-aa-tutorial.md
@@ -66,7 +66,7 @@ yarn add -D @matterlabs/zksync-contracts @openzeppelin/contracts@4.9.5
::: warning
-This project does not use the latest version available of `@openzeppelin/contracts`. Mae sure you install the specific version mentioned above.
+This project does not use the latest version available of `@openzeppelin/contracts`. Make sure you install the specific version mentioned above.
:::
@@ -165,7 +165,9 @@ contract TwoUserMultisig is IAccount, IERC1271 {
external
payable
{
- _validateTransaction(bytes32(0), _transaction);
+ bytes4 magic = _validateTransaction(bytes32(0), _transaction);
+ require(magic == ACCOUNT_VALIDATION_SUCCESS_MAGIC, "NOT VALIDATED");
+
_executeTransaction(_transaction);
}
@@ -636,7 +638,8 @@ contract TwoUserMultisig is IAccount, IERC1271 {
external
payable
{
- _validateTransaction(bytes32(0), _transaction);
+ bytes4 magic = _validateTransaction(bytes32(0), _transaction);
+ require(magic == ACCOUNT_VALIDATION_SUCCESS_MAGIC, "NOT VALIDATED");
_executeTransaction(_transaction);
}
diff --git a/docs/build/tutorials/smart-contract-development/account-abstraction/daily-spend-limit.md b/docs/build/tutorials/smart-contract-development/account-abstraction/daily-spend-limit.md
index af811599e4..04950b0867 100644
--- a/docs/build/tutorials/smart-contract-development/account-abstraction/daily-spend-limit.md
+++ b/docs/build/tutorials/smart-contract-development/account-abstraction/daily-spend-limit.md
@@ -64,7 +64,7 @@ yarn add -D @matterlabs/zksync-contracts @openzeppelin/contracts@4.9.5
```
::: warning
-This project does not use the latest version available of `@openzeppelin/contracts`. Mae sure you install the specific version mentioned above.
+This project does not use the latest version available of `@openzeppelin/contracts`. Make sure you install the specific version mentioned above.
:::
5. Include the `isSystem: true` setting in the `zksolc` section of the `hardhat.config.ts` configuration file to allow interaction with system contracts:
@@ -600,7 +600,8 @@ contract Account is IAccount, IERC1271, SpendLimit {
function executeTransactionFromOutside(
Transaction calldata _transaction
) external payable {
- _validateTransaction(bytes32(0), _transaction);
+ bytes4 magic = _validateTransaction(bytes32(0), _transaction);
+ require(magic == ACCOUNT_VALIDATION_SUCCESS_MAGIC, "NOT VALIDATED");
_executeTransaction(_transaction);
}
diff --git a/docs/build/tutorials/smart-contract-development/paymasters/erc20fixed.md b/docs/build/tutorials/smart-contract-development/paymasters/erc20fixed.md
index fd4727d2cf..53baea0cf2 100644
--- a/docs/build/tutorials/smart-contract-development/paymasters/erc20fixed.md
+++ b/docs/build/tutorials/smart-contract-development/paymasters/erc20fixed.md
@@ -23,11 +23,11 @@ For detailed explanations of the IPaymaster interface please refer to the docume
### **Step 1 — Understanding the ERC20FixedPaymaster contract**
-The provided `ApprovalPaymaster` contract allows transactions to have the gas covered in a specified ERC-20 token for accounts that hold a balance of a specific ERC20 token. For the purposes of this guide we will make use of the [DAI ERC-20 token](https://sepolia.explorer.zksync.io/address/0x6Ff473f001877D553833B6e312C89b3c8fACa7Ac).
+The paymaster smart contract allows transactions to have the gas covered in exchange for 1 unit of a specified ERC20 token.
**Key components**:
-- `validateAndPayForPaymasterTransaction`: Validates the user's token balance, checks the transaction allowance, calculates the required ETH, and pays the bootloader.
+- `validateAndPayForPaymasterTransaction`: Validates the user's token balance, checks the transaction allowance, transfers the ERC20 token from the user's account to the paymaster, calculates the required ETH, and pays the bootloader.
Each paymaster should implement the `IPaymaster` interface. We will be using `zksync-cli` to bootstrap the boilerplate code for this paymaster.
@@ -59,9 +59,9 @@ Ensure your account has a sufficient balance.
### Step 3 — Updating the Contract
-No modifications are needed for `ERC20FixedPaymaster` since the provided `ApprovalPaymaster` contract is already configured for this purpose.
+The provided `ApprovalPaymaster` contract is already configured for the purpose of this tutorial.
-Reviewing the `validateAndPayForPaymasterTransaction` function reveals its simplicity: it verifies if the token is correct, the user holds the token and has provided enough allowance.
+Reviewing the `validateAndPayForPaymasterTransaction` function reveals its simplicity: it verifies if the token is correct, the user holds the token and has provided enough allowance, transfers the ERC20 and pays the bootloader:
```solidity
(address token, uint256 amount, bytes memory data) = abi.decode(
@@ -85,100 +85,41 @@ require(
providedAllowance >= PRICE_FOR_PAYING_FEES,
"Min allowance too low"
);
-```
-
-### Step 4 — Deploy the Contract
-
-Create a new file under `/deploy`, for example `deploy-erc20FixedPaymaster.ts`. Insert the provided script:
-
-#### deploy-erc20FixedPaymaster.ts
-
-```typescript
-import { Provider, Wallet } from "zksync-ethers";
-import * as ethers from "ethers";
-import { HardhatRuntimeEnvironment } from "hardhat/types";
-import { Deployer } from "@matterlabs/hardhat-zksync-deploy";
-
-// load env file
-import dotenv from "dotenv";
-dotenv.config();
-
-// load wallet private key from env file
-const PRIVATE_KEY = process.env.WALLET_PRIVATE_KEY || "";
-// The address of the DAI token contract
-const TOKEN_ADDRESS = "0x6Ff473f001877D553833B6e312C89b3c8fACa7Ac";
-
-if (!PRIVATE_KEY) throw "⛔️ Private key not detected! Add it to the .env file!";
-
-if (!TOKEN_ADDRESS) throw "⛔️ TOKEN_ADDRESS not detected! Add it to the TOKEN_ADDRESS variable!";
-export default async function (hre: HardhatRuntimeEnvironment) {
- console.log(`Running deploy script for the ApprovalPaymaster contract...`);
- const provider = new Provider("https://sepolia.era.zksync.dev");
- // The wallet that will deploy the token and the paymaster
- // It is assumed that this wallet already has sufficient funds on zkSync
- const wallet = new Wallet(PRIVATE_KEY);
- const deployer = new Deployer(hre, wallet);
-
- // Deploying the paymaster
- const paymasterArtifact = await deployer.loadArtifact("ApprovalPaymaster");
- const deploymentFee = await deployer.estimateDeployFee(paymasterArtifact, [TOKEN_ADDRESS]);
- const parsedFee = ethers.formatEther(deploymentFee.toString());
- console.log(`The deployment is estimated to cost ${parsedFee} ETH`);
- // Deploy the contract
- const paymaster = await deployer.deploy(paymasterArtifact, [TOKEN_ADDRESS]);
- const paymasterAddress = await paymaster.getAddress();
- console.log(`Paymaster address: ${paymasterAddress}`);
-
- console.log("Funding paymaster with ETH");
- // Supplying paymaster with ETH
- await (
- await deployer.zkWallet.sendTransaction({
- to: paymasterAddress,
- value: ethers.parseEther("0.005"),
- })
- ).wait();
-
- let paymasterBalance = await provider.getBalance(paymasterAddress);
- console.log(`Paymaster ETH balance is now ${paymasterBalance.toString()}`);
-
- // Verify contract programmatically
- //
- // Contract MUST be fully qualified name (e.g. path/sourceName:contractName)
- const contractFullyQualifedName = "contracts/paymasters/ApprovalPaymaster.sol:ApprovalPaymaster";
- const verificationId = await hre.run("verify:verify", {
- address: paymasterAddress,
- contract: contractFullyQualifedName,
- constructorArguments: [TOKEN_ADDRESS],
- bytecode: paymasterArtifact.bytecode,
- });
- console.log(`${contractFullyQualifedName} verified! VerificationId: ${verificationId}`);
-
- console.log(`Done!`);
+// Note, that while the minimal amount of ETH needed is tx.gasPrice * tx.gasLimit,
+// neither paymaster nor account are allowed to access this context variable.
+uint256 requiredETH = _transaction.gasLimit *
+ _transaction.maxFeePerGas;
+
+try
+ IERC20(token).transferFrom(userAddress, thisAddress, amount)
+{} catch (bytes memory revertReason) {
+ // If the revert reason is empty or represented by just a function selector,
+ // we replace the error with a more user-friendly message
+ if (revertReason.length <= 4) {
+ revert("Failed to transferFrom from users' account");
+ } else {
+ assembly {
+ revert(add(0x20, revertReason), mload(revertReason))
+ }
+ }
}
-```
-
-:::info
-Update the `TOKEN_ADDRESS` variable to the address of your preferred token.
-:::
-
-Compile the contract:
-
-```bash
-yarn hardhat compile
-```
-
-Deploy the contract:
-```bash
-yarn hardhat deploy-zksync --script deploy-erc20FixedPaymaster.ts
+// The bootloader never returns any data, so it can safely be ignored here.
+(bool success, ) = payable(BOOTLOADER_FORMAL_ADDRESS).call{
+ value: requiredETH
+}("");
+require(
+ success,
+ "Failed to transfer tx fee to the bootloader. Paymaster balance might not be enough."
+);
```
-### Step 5 — Testing the Contract
+### Step 4 — Testing the Contract
-To test the functionality, you can utilize a mock ERC-20 token contract. This will help confirm that the paymaster operates as expected. Inside the `/contracts/` directory, create a file named `ERC20.sol` and insert the following contract:
+To test the functionality, we'll use a mock ERC-20 token contract. This will help confirm that the paymaster operates as expected. Inside the `/contracts/` directory, create a file named `MyERC20.sol` and insert the following code:
-#### ERC20.sol
+#### MyERC20.sol
```solidity
// SPDX-License-Identifier: MIT
@@ -216,6 +157,8 @@ contract MyERC20 is ERC20 {
}
```
+This is the token we'll use to pay the transaction fees with.
+
To further validate the operations of the ERC20FixedPaymaster contract, we've provided a test script. Create a file named `erc20FixedPaymaster.test.ts` within the `/test` directory, then populate it with the subsequent script:.
#### erc20FixedPaymaster.test.ts
@@ -279,8 +222,7 @@ describe.only("ERC20fixedPaymaster", function () {
innerInput: new Uint8Array(),
});
- await greeter.connect(user);
- const setGreetingTx = await greeter.setGreeting("Hola, mundo!", {
+ const setGreetingTx = await greeter.connect(user).setGreeting("Hola, mundo!", {
maxPriorityFeePerGas: BigInt(0),
maxFeePerGas: gasPrice,
// hardcoded for testing
@@ -312,9 +254,9 @@ describe.only("ERC20fixedPaymaster", function () {
const finalPaymasterBalance = await provider.getBalance(paymasterAddress);
expect(await greeter.greet()).to.equal("Hola, mundo!");
- expect(initialPaymasterBalance).to.be.gt(finalPaymasterBalance);
+ expect(initialPaymasterBalance > finalPaymasterBalance).to.be.true;
expect(userInitialETHBalance).to.eql(finalETHBalance);
- expect(userInitialTokenBalance.gt(finalUserTokenBalance)).to.be.true;
+ expect(userInitialTokenBalance > finalUserTokenBalance).to.be.true;
});
it("should allow owner to withdraw all funds", async function () {
@@ -350,7 +292,7 @@ describe.only("ERC20fixedPaymaster", function () {
}
function setupDeployer(url: string, privateKey: string): [Provider, Wallet, Deployer] {
- const provider = new Provider(url);
+ const provider = new Provider(url, undefined, { cacheTimeout: -5 });
const wallet = new Wallet(privateKey, provider);
const deployer = new Deployer(hre, wallet);
return [provider, wallet, deployer];
@@ -366,6 +308,93 @@ To execute test:
yarn hardhat test --network hardhat
```
+### Step 5 — Deploy to zkSync Sepolia testnet
+
+To deploy the paymaster contract to the zkSync Sepolia testnet, create a new file under `/deploy`, for example `deploy-erc20FixedPaymaster.ts`. Insert the provided script:
+
+#### deploy-erc20FixedPaymaster.ts
+
+```typescript
+import { Provider, Wallet } from "zksync-ethers";
+import * as ethers from "ethers";
+import { HardhatRuntimeEnvironment } from "hardhat/types";
+import { Deployer } from "@matterlabs/hardhat-zksync-deploy";
+
+// load env file
+import dotenv from "dotenv";
+dotenv.config();
+
+// load wallet private key from env file
+const PRIVATE_KEY = process.env.WALLET_PRIVATE_KEY || "";
+// The address of the token to be used. TEST token in this example
+const TOKEN_ADDRESS = "0x7E2026D8f35872923F5459BbEDDB809F6aCEfEB3";
+
+if (!PRIVATE_KEY) throw "⛔️ Private key not detected! Add it to the .env file!";
+
+if (!TOKEN_ADDRESS) throw "⛔️ TOKEN_ADDRESS not detected! Add it to the TOKEN_ADDRESS variable!";
+
+export default async function (hre: HardhatRuntimeEnvironment) {
+ console.log(`Running deploy script for the ApprovalPaymaster contract...`);
+ const provider = new Provider("https://sepolia.era.zksync.dev");
+ // The wallet that will deploy the token and the paymaster
+ // It is assumed that this wallet already has sufficient funds on zkSync
+ const wallet = new Wallet(PRIVATE_KEY);
+ const deployer = new Deployer(hre, wallet);
+
+ // Deploying the paymaster
+ const paymasterArtifact = await deployer.loadArtifact("ApprovalPaymaster");
+ const deploymentFee = await deployer.estimateDeployFee(paymasterArtifact, [TOKEN_ADDRESS]);
+ const parsedFee = ethers.formatEther(deploymentFee.toString());
+ console.log(`The deployment is estimated to cost ${parsedFee} ETH`);
+ // Deploy the contract
+ const paymaster = await deployer.deploy(paymasterArtifact, [TOKEN_ADDRESS]);
+ const paymasterAddress = await paymaster.getAddress();
+ console.log(`Paymaster address: ${paymasterAddress}`);
+
+ console.log("Funding paymaster with ETH");
+ // Supplying paymaster with ETH
+ await (
+ await deployer.zkWallet.sendTransaction({
+ to: paymasterAddress,
+ value: ethers.parseEther("0.005"),
+ })
+ ).wait();
+
+ let paymasterBalance = await provider.getBalance(paymasterAddress);
+ console.log(`Paymaster ETH balance is now ${paymasterBalance.toString()}`);
+
+ // Verify contract programmatically
+ //
+ // Contract MUST be fully qualified name (e.g. path/sourceName:contractName)
+ const contractFullyQualifedName = "contracts/paymasters/ApprovalPaymaster.sol:ApprovalPaymaster";
+ const verificationId = await hre.run("verify:verify", {
+ address: paymasterAddress,
+ contract: contractFullyQualifedName,
+ constructorArguments: [TOKEN_ADDRESS],
+ bytecode: paymasterArtifact.bytecode,
+ });
+ console.log(`${contractFullyQualifedName} verified! VerificationId: ${verificationId}`);
+
+ console.log(`Done!`);
+}
+```
+
+:::info
+Update the `TOKEN_ADDRESS` variable to the address of your preferred token. In the example above we're using a [TEST token deployed in zkSync Sepolia testnet](https://sepolia.explorer.zksync.io/address/0x7E2026D8f35872923F5459BbEDDB809F6aCEfEB3).
+:::
+
+Compile the contract:
+
+```bash
+yarn hardhat compile
+```
+
+Deploy the contract:
+
+```bash
+yarn hardhat deploy-zksync --script deploy-erc20FixedPaymaster.ts
+```
+
### Conclusion
The `ERC20FixedPaymaster` contract introduces an efficient mechanism, allowing developers to cover gas fees for users holding a specific ERC20 token with that ERC20 token. This improves UX for dApps, making it easier for users to interact without worrying about gas fees. Further customizations or protocol-specific validations can be added as necessary.
diff --git a/docs/zk-stack/running-a-hyperchain/locally.md b/docs/zk-stack/running-a-hyperchain/locally.md
index 7b5ff43fa4..cd711eee4f 100644
--- a/docs/zk-stack/running-a-hyperchain/locally.md
+++ b/docs/zk-stack/running-a-hyperchain/locally.md
@@ -7,9 +7,9 @@ head:
# Getting Started with ZK Stack
-:::warning
+::: danger Note
-ZK Stack is still under development. We advise you to only use for local and testnet deployments.
+A new and improved ZK Stack CLI is coming very soon. The current version is deprecated and may not function as expected.
:::
## Development dependencies
diff --git a/docs/zk-stack/running-a-hyperchain/production.md b/docs/zk-stack/running-a-hyperchain/production.md
index 591e97ce63..521f06c28a 100644
--- a/docs/zk-stack/running-a-hyperchain/production.md
+++ b/docs/zk-stack/running-a-hyperchain/production.md
@@ -7,9 +7,9 @@ head:
# Deploying to a Non-Local Environment
-:::warning
+::: danger Note
-ZK Stack is still under development. We advise you to only use for local and testnet deployments.
+A new and improved ZK Stack CLI is coming very soon. The current version is deprecated and may not function as expected.
:::
## Deploying to a non-local environment
diff --git a/firebase.json b/firebase.json
index bc4cf779db..67805d3588 100644
--- a/firebase.json
+++ b/firebase.json
@@ -1045,12 +1045,12 @@
},
{
"source": "/docs/tools/hardhat/plugins.html",
- "destination": "/build/tooling/hardhat/hardhat-zksync-toolbox.html",
+ "destination": "/build/tooling/hardhat/hardhat-zksync.html",
"type": "302"
},
{
"source": "/docs/tools/hardhat/plugins.html",
- "destination": "/build/tooling/hardhat/hardhat-zksync-toolbox.html",
+ "destination": "/build/tooling/hardhat/hardhat-zksync.html",
"type": "302"
},
{
@@ -2270,12 +2270,12 @@
},
{
"source": "/docs/tools/hardhat/plugins.html",
- "destination": "/build/tooling/hardhat/hardhat-zksync-toolbox.html",
+ "destination": "/build/tooling/hardhat/hardhat-zksync.html",
"type": "302"
},
{
"source": "/docs/tools/hardhat/plugins.html",
- "destination": "/build/tooling/hardhat/hardhat-zksync-toolbox.html",
+ "destination": "/build/tooling/hardhat/hardhat-zksync.html",
"type": "302"
},
{