# Private Transactions

As discussed previously, we need to craft a `ZTransaction` struct that represents a shielded transaction. This is so that we can invoke the `transact` method on-chain and execute the private transaction.

```solidity
function transact(ZTransaction memory ztx) external;
```

We also saw previously how to initialize an instance (variable `zkfi` ) of SDK.&#x20;

### Creating Transactions

The SDK exposes easy API for developers to specify what transaction they want to send. We will create a transaction using `TransactionRequest` and `TransactionOptions` object and pass it to `createTransaction(...)`  method of our SDK instance `zkfi`.

```typescript
type TransactionRequest = {
  type: TransactionType;
  assetIds: number[];
  values: bigint[];
  feeAssetId: number;
  to: string;
  payload?: string;
};

export type TransactionOptions = {
  revokerId: number;
  paymaster?: Hex;
  viaBundler?: boolean;
};
```

Since, initially we have no funds in our shielded account, we'd like to deposit some assets into it. Let's say, we'd like to deposit 2 `WETH` .  To achieve this, we create a request with the following parameters:

```typescript
import { parseEther } from 'viem';
import { TransactionRequest, TransactionOptions, TransactionType } from '@zkfi-tech/shared-types';

const req: TransactionRequest = {
  type: TransactionType.DEPOSIT,
  assetIds: [65537],
  values: [parseEther('2')],
  feeAssetId: 0,
  to: 'bob.eth',
}

const options: TransactionOptions = {
  revokerId: 0
}
```

So what did we do? Let's break it down:

1. `TransactionRequest`

* We set `type` to `TransactionType.DEPOSIT` since we want to do a deposit from our public wallet to shielded account.
* We set `assetIds` to include only one asset of id `65537` (`0x010001` in hex) which is the asset id for `WETH` in Labyrinth. We only want to deposit one asset i.e `WETH`. You can get a list of all supported assets from `contractService::getAssets()`.&#x20;
* Let `values` to include only one value which is `2 ether` . Since it is at the same index as `WETH` in `assetIds`, it is the value of `WETH` we want to deposit.
* We set `feeAssetId` to `0`. `0` is a dummy/placeholder asset id and does not represent any token or asset in reality. We set it to `0` because in a `DEPOSIT` transaction, we are not going to pay any fee, from any of the assets mentioned in `assetIds`. This is because we will be paying gas fees ourselves from our wallets.
* We set `to` to the address, shielded address, or ENS of the target. In this case, it is the recipient of the deposit i.e. `bob.eth`. We assume that the address associated with `bob.eth` is already registered with Labyrinth protocol so that it can be ultimately resolved to a shielded address where the funds will be sent.&#x20;

2. `TransactionOptions`:\
   \- `revokerId`: The id of the revoker chosen to keep this transaction compliant.

Now we create the `Transaction`:

```typescript
import { Transaction } from '@zkfi-tech/transaction';
import { TransactionRequest, TransactionOptions, TransactionType } from '@zkfi-tech/shared-types';

const req: TransactionRequest = {...};
const options: TransactionOptions = {...};

const tx: Transaction = await zkfi.createTransaction(req, options);
```

Now to authorize this transaction if it needs to be signed. For this, we pass the created transaction instance `tx` to `zkfi.signTransaction(...)` the method.

```typescript
const signedTx: Transaction = await zkfi.signTransaction(tx);
```

We've created the transaction finally! But wait. it is not yet ready to be sent on-chain! Remember we need a shielded transaction `ZTransaction` for this. To create a shielded transaction we need to hide sensitive values and prove our signed transaction.

Again, `zkfi`instance provides a simple `proveTransaction(...)`method to generate a ZK-SNARK proof proving the validity of the transaction `tx` and yield an instance of the `ZTransaction` class.

```typescript
import { ZTransaction } from '@zkfi-tech/zk-prover';

const ztx: ZTransaction = await zkfi.proveTransaction(tx);
```

Finally, we have a private and fully compliant transaction represented by the `ZTransaction` instance - `ztx` . If you want to send this transaction on-chain, you can simply convert it to proper input to the contract's `transact` by calling `ztx.toSolidityInput()`.&#x20;

Congrats!

### Creating a private asset transfer

Now that we have some funds in our shielded account, let's use it! Let's transfer 1 `WETH` privately to the `alice.eth` (again, assuming that the public address associated with `alice.eth` is already registered).&#x20;

First, we create a `TRANSFER` request.

```typescript
import { parseEther } from 'viem';
import { TransactionRequest, TransactionOptions, TransactionType } from '@zkfi-tech/shared-types';

const req: TransactionRequest = {
  type: TransactionType.TRANSFER,
  assetIds: [65537],
  values: [parseEther('1')],
  feeAssetId: 65537,
  to: 'alice.eth',
}

const options: TransactionOptions = {
  revokerId: 0,
  paymaster?: '0xE45c40643af3aa4146E1B1C95051c23f7439ed75',
  viaBundler?: true
}
```

We specify the same kind of fields in our request, except this time we specify a `feeAssetId` of `WETH` . We specify that we want to pay transaction fees with the `WETH` asset from our shielded account.&#x20;

`TransactionOptions`:\
\- `revokerId`: The id of the revoker chosen.\
\- We set the `paymaster` to the address of the paymaster contract (ERC-4337), which will sponsor this transaction and will be paid in return for it.\
\- We finally set the`viaBundler` option to true, as we want this transaction to be relayed through the bundler thus keeping our privacy intact.

#### But why and where are we paying fees?

Unlike the `DEPOSIT`, we don't want to send this transaction with our public wallet. This will expose our wallet's public address on block explorers and privacy will be harmed because anyone can inspect and match the previous deposit transaction and this transfer transaction. Hence, linking them. To resolve this issue, we will send the transaction through a third party, in exchange for some fee. One possible third party is the [bundler node from EIP 4337.](https://www.erc4337.io/docs/understanding-ERC-4337/architecture) This fee, paid in `WETH`, is sent to the bundler ultimately. Note that we don't input the fee value, it is determined using SDK automatically as of now - you can see the value after transaction creation using the `tx.feeValue` property.

The rest of the steps remain the same - creating, signing and proving the transaction to get the `ZTransaction`.

```typescript
const tx: Transaction = await zkfi.createTransaction(req);

const signedTx: Transaction = await zkfi.signTransaction(tx);

const ztx: ZTransaction = await zkfi.proveTransaction(signedTx);
```

Now, you can make calling `transact(...)` method with `ztx.toSolidityInput()` an [EIP-4337 UserOperation](https://www.erc4337.io/docs/understanding-ERC-4337/user-operation) and relay it via bundler.

{% hint style="info" %}
We are currently working on a module to convert `ZTransaction` to a EIP-4337 `UserOperation`and send the transaction via bundler with a single call.
{% endhint %}

### Withdraw from a shielded account

In case for any reason you want to withdraw assets from your shielded account to any public address you can follow the same steps as the above transfer transaction, but with `type` set to `TransactionType.WITHDRAW`.

```typescript
import { parseEther } from 'viem';
import { TransactionRequest, TransactionType } from '@zkfi-tech/shared-types';

const req: TransactionRequest = {
  type: TransactionType.WITHDRAW,
  assetIds: [65537],
  values: [parseEther('1')],
  feeAssetId: 65537,
  to: 'carl.eth',
}
```

In this case what you specify as `to` is a public address or ENS (it is not resolved to a shielded address) where funds will be sent.

```typescript
const tx: Transaction = await zkfi.createTransaction(req);

const signedTx: Transaction = await zkfi.signTransaction(tx);

const ztx: ZTransaction = await zkfi.proveTransaction(signedTx);
```

