Skip to content

Commit

Permalink
feat(java): add SmartAccount (#79)
Browse files Browse the repository at this point in the history
  • Loading branch information
petarTxFusion authored Aug 9, 2024
1 parent 2b98dd2 commit 1501b55
Show file tree
Hide file tree
Showing 3 changed files with 331 additions and 0 deletions.
216 changes: 216 additions & 0 deletions content/sdk/40.java/02.api/01.accounts/03.smartaccount.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,216 @@
---
title: SmartAccount
description: A flexible signer for various payloads using different secrets.
tags: ["web3", "blockchain", "zksync", "smartaccount"]
---

A `SmartAccount` is a signer which can be configured to sign various payloads using a provided secret.
The secret can be in any form, allowing for flexibility when working with different account implementations.
The `SmartAccount` is bound to a specific address and provides the ability to define custom method for populating transactions
and custom signing method used for signing.

### `constructor`

Creates a `SmartAccount` instance with provided `signer` and `provider`.
By default, uses [`sign_payload_with_ecdsa`](smart-account-utils.md#signpayloadwithecdsa) and [`sign_payload_with_multiple_ecdsa`](smart-account-utils.md#signpayloadwithmultipleecdsa).

#### Inputs

| Parameter | Type | Description |
|----------------------|--------------|--------------------------------------------------------------------------------|
| `provider` | ZkSync | The provider to connect to. |
| `address` | String | Address of the smart account. |
| `secret` | List<String> | Secrets to be used for signing transactions. |
| `transactionBuilder` | IPopulateTransaction | Implementation of transaction builder (default is populate_transaction_ecdsa). |
| `payloadSigner` | ISignPayload | Implementation of signing (default is sign_payload_with_ecdsa). |

### `getAddress`

Returns the address of the account.

#### Example

```java
String result = smartAccount.getAddress()
```

### `getBalance`

Returns the amount of the token the `Wallet` has.

```java
BigInteger ethBalance = wallet.getBalance().sendAsync().join();
```

#### Inputs

| Parameter | Type | Description |
| --------- | -------- | ---------------------------------------------------- |
| `token` | `String` | The address of the token. ETH by default (optional). |

#### Example

```java
String L1_DAI = "0x56E69Fa1BB0d1402c89E3A4E3417882DeA6B14Be"
String l2DAI = wallet.l2TokenAddress(L1_DAI);

BigInteger tokenBalance = wallet.getBalance(l2DAI).sendAsync().join();
```

#### Inputs

| Parameter | Type | Description |
| ------------- | ------------- | ---------------------------------------------------------------------------------------------------------------- |
| `address` | `String` | The address of the wallet. |
| `token` | `String` | The address of the token. ETH by default. |
| `blockNumber` | `BlockNumber` | In which block a balance should be checked on. `committed`, i.e. the latest processed one is the default option. |

#### Example

```java
String L1_DAI = "0x56E69Fa1BB0d1402c89E3A4E3417882DeA6B14Be"
String l2DAI = wallet.l2TokenAddress(L1_DAI);

BigInteger tokenBalance = wallet.getBalance(signer.getAddress(), l2DAI, ZkBlockParameterName.COMMITTED).sendAsync().join();
```

### `getAllBalances`

Returns all balances for confirmed tokens given by an account address.

#### Inputs and outputs

| Name | Description |
| ------- | ----------------------------------------------- |
| returns | `ZksAccountBalances` with all account balances. |

#### Example

```java
ZksAccountBalances allBalances = wallet.getAddress().join();
```

### `getDeploymentNonce`

Returns account's deployment nonce number.

#### Inputs and outputs

| Name | Description |
| ------- | ---------------------------- |
| returns | The deployment nonce number. |

#### Example

```java
BigInteger deploymentNonce = wallet.getDeploymentNonce().join()
```

### `populateTransaction`

Populates the transaction `tx` using the provided transaction_builder function.
If `tx.from` is not set, it sets the value from the `getAddress` method which can
be utilized in the transaction builder function.

#### Inputs

| Parameter | Type | Description |
| --------- | --------------------------------------------------- | ------------------------------------------- |
| `tx` | `Transaction` | The transaction that needs to be populated. |

### `signTransaction`

Signs the transaction `tx` using the provided payload_signer 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` | `Transaction` | The transaction that needs to be signed. |

### `sendTransaction`

Sends `tx` to the Network. The `signTransaction`
is called first to ensure transaction is properly signed.

#### Inputs

| Parameter | Type | Description |
| --------- | ----------------------------------------------------- | -------------------------------------- |
| `tx` | `Transaction` | The transaction that needs to be sent. |

### `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

| Name | Description |
| ----------- |------------------------------------------------------------------|
| transaction | [`WithdrawTransaction`](/sdk/java/api/types#withdrawtransaction) |

#### Example

```java
BigInteger amount = new BigInteger("7000000000");
WithdrawTransaction transaction = new WithdrawTransaction(ZkSyncAddresses.ETH_ADDRESS, amount, testWallet.getAddress());

TransactionReceipt result = smartAccount.withdraw(transaction).sendAsync().join();

TransactionReceipt receipt = smartAccount.getTransactionReceiptProcessor().waitForTransactionReceipt(result.getTransactionHash());
```

Withdraw ETH using paymaster to facilitate fee payment with an ERC20 token.

```java
BigInteger amount = new BigInteger("7000000000");
String token = "0x927488F48ffbc32112F1fF721759649A89721F8F"; // Crown token which can be minted for free
String paymaster = "0x13D0D8550769f59aa241a41897D4859c87f7Dd46"; // Paymaster for Crown token

PaymasterParams paymasterParams = new PaymasterParams(paymaster, Numeric.hexStringToByteArray(FunctionEncoder.encode(Paymaster.encodeApprovalBased(token, BigInteger.ONE, new byte[]
{}))));
WithdrawTransaction transaction = new WithdrawTransaction(ZkSyncAddresses.ETH_ADDRESS, amount, paymasterParams);

TransactionReceipt result = smartAccount.withdraw(transaction).sendAsync().join();

TransactionReceipt receipt = smartAccount.getTransactionReceiptProcessor().waitForTransactionReceipt(result.getTransactionHash());
```

### `transfer`

For convenience, the `Wallet` class has `transfer` method, which can transfer `ETH` or any `ERC20`
token within the same interface.

#### Inputs and outputs

| Name | Description |
| ------- |-------------------------------------------------------------------|
| tx | [`TransferTransaction`](/sdk/java/api/types#transfertransaction). |
| returns | A `TransactionReceipt` of transaction. |

#### Example

Transfer ETH.

```java
TransferTransaction transaction = new TransferTransaction("<RECIPIENT_ADDRESS>", BigInteger(7_000_000_000L), signer.getAddress());

TransactionReceipt receipt = smartAccount.transfer(transaction).sendAsync().join();

smartAccount.getTransactionReceiptProcessor().waitForTransactionReceipt(receipt.getTransactionHash());
```

Transfer ETH using paymaster to facilitate fee payment with an ERC20 token.

```java
PaymasterParams paymasterParams = new PaymasterParams(PAYMASTER, Numeric.hexStringToByteArray(FunctionEncoder.encode(Paymaster.encodeApprovalBased(TOKEN, BigInteger.ONE, new byte[] {}))));
TransferTransaction transaction = new TransferTransaction("<RECIPIENT_ADDRESS>", BigInteger(7_000_000_000L), signer.getAddress(), paymasterParams);

TransactionReceipt receipt = smartAccount.transfer(transaction).sendAsync().join();

smartAccount.getTransactionReceiptProcessor().waitForTransactionReceipt(receipt.getTransactionHash());
```
63 changes: 63 additions & 0 deletions content/sdk/40.java/02.api/01.accounts/04.smart-account-utils.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
---
title: Smart Account Utilities
description: Utilities for managing and signing payloads with smart accounts
tags: ["web3", "blockchain", "zksync", "smart accounts"]
---

The Smart Account Utilities in the ZKsync Python SDK provide functions to manage and sign payloads using ECDSA private keys.

### `SignPayloadWithECDSA`

### `sign`
Signs the `payload` using an ECDSA private key.

#### Inputs

| Parameter | Type | Description |
|-----------|------------------|---------------------------------------------------------|
| `payload` | `Transaction712` | The payload that needs to be signed. |
| `secret` | `List<String>` | The ECDSA private key. Uses only first key in the list. |
| `chainId` | `long` | The chain id. |

## `SignPayloadWithMultipleECDSA`

### `sign`

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` | `bytes` | The payload that needs to be signed. |
| `secret` | `[HexStr]` | The list of the ECDSA private keys. |

## `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.zksync.get_transaction_count(Web3.to_checksum_address(tx.from_), EthBlockParams.PENDING.value)`.
- Populates `gas_limit` via `provider.zksync.zks_estimate_fee(tx.to_zk_transaction())`. If `tx.from` is not EOA,
- the estimation is done with address
derived from the ECDSA private key.
- Populates `chain_id` via `provider.eth.chain_id`.
- Populates `type` with `EIP_712_TX_TYPE`.
- Populates `value` if set, otherwise to `0`.
- Populates `data` with `0x`.
- Populates `meta` with `{factoryDeps=[], gasPerPubdata=50_000}`.

#### Inputs

| Parameter | Type | Description |
|------------|------------------------|---------------------------------------------------|
| `tx` | `Transaction` | The transaction that needs to be populated. |
| `secret` | `List<String>` | The ECDSA private keys. |
| `provider` | `ZkSync` | The provider which fetches data from the network. |
| `nonce` | `@Nullable BigInteger` | The nonce to be used in transaction, can be null. |

::callout{icon="i-heroicons-exclamation-triangle" color="amber"}
For development and testing, it is recommended to use burner wallets. Avoid using real private keys to prevent security risks.
::
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
---
title: SmartAccount Factories
description: ECDSASmartAccount and MultisigECDSASmartAccount for SmartAccount.
tags: ["smartaccount", "ecdsa", "multisig", "zksync", "python"]
---

## `ECDSASmartAccount`

A `ECDSASmartAccount` is a class which creates a `SmartAccount` instance
that uses single ECDSA key for signing payload.

### `constructor`

Creates a `SmartAccount` instance that uses a single ECDSA key for signing payload.

#### Inputs

| Parameter | Type | Description |
| ---------- |----------| --------------------------- |
| `provider` | `ZkSync` | The provider to connect to. |
| `address` | `String` | The account address. |
| `secret` | `String` | The ECDSA private key. |

#### Example

```java
ECDSASmartAccount smartAccount = new ECDSASmartAccount(zksync, <ADDRESS>, <PRIVATE_KEY>);
```

## `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.

### `constructor`

Creates a `SmartAccount` instance that uses multiple ECDSA keys for signing payloads.

#### Inputs

| Parameter | Type | Description |
| ---------- |----------------|-----------------------------|
| `provider` | `ZkSync` | The provider to connect to. |
| `address` | `String` | The account address. |
| `secret` | `List<String>` | The ECDSA private key list. |

#### Example

```java
ECDSASmartAccount smartAccount = new ECDSASmartAccount(zksync, <ADDRESS>, Arrays.asList(<PRIVATE_KEY_1>, <PRIVATE_KEY_2>));
```

0 comments on commit 1501b55

Please sign in to comment.