# Basic Nightfall workflow

*NB: This workflow describes the Deposit, Transfer and Withdraw transactions.  In practice however one should never simply Deposit, Transfer and Withdraw.  Doing so will make your private transactions easily discoverable.  See the section on security and Privacy for more information.*

This section describes a typical Nightfall workflow, with some detail of the internal processes that Nightfall is carrying out.  Reading this section will help you understand how Nightfall works. It briefly describes some of Nightfall's APIs but the API section has more detail.

### Allow listing

Before a User, Proposer or Challenger can interact with Nightfall, they need to get their Ethereum address allowlisted. Nightfall's `X509.sol` contract is used for this, and the `Nf3` class provides a node API for interacting with it.

Firstly, the User, Proposer or Challenger must obtain an x509 certificate that `X509.sol` will accept.  Suitable certificates for currently deployed Nightfall contracts are Entrust Code Signing Extended Validation (EV) or Document Signing EV certificates , Digicert Code Signing EV certificates or EY issued certificates. This is an out-of-band process; obtaining the certificate is nothing to do with Nightfall. The certificate must be in DER encoded format (if you have PEM, convert it with openssl or a similar utility)

Next, the User, Proposer or Challenger must sign their Ethereum address with the private key corresponding to their x509 certificate. This proves that they are the owner of the Ethereum address by tying it back to the x509 certificate. It's a standard RSA signature with PKCS#1 padding.  Normally this would be done in a hardware security module but for test purposes there is a utility called `sign-address.mjs` that can achieve the same thing:

```sh
node test/unit/utils/sign-address.mjs path/to/private-key my-ethereum-address
```

Where the private-key should be stored unencrypted in a DER encoded file.&#x20;

Once the certificate and signed Ethereum address is available, they should be given to `X509.sol` which will validate the certificate and verify the signature.  This is best done by using a method of the `Nf3` class:

```javascript
await nf3.validateCertificate(
    certificate,
    ethereumAddressSignature,
    isEndUser,
    checkOnly,
    oidGroup,
    address,
  )
```

Where:

* `certificate` is a `Buffer` containing the binary DER certificate.
* `ethereumAddressSignature` is a `Buffer` containing the binary DER signature over the Ethereum Address (can be `null` if we're dealing with an intermediate certificate.
* `isEndUser` is a boolean which is true when dealing with an end-user certificate
* `checkOnly` if true, the certificate will be validated but, in the case of an intermediate certificate, it's public key won't be added to the trust store and, in the case of an end-user certificate, the signature over the Ethereum address will not be verified. This is useful for testing.
* &#x20;`oidGroup` is a selector for the OIDs that are checked for presence in the certificate. Its value depends on where the certificate originated from (0=Entrust code signer, 1=Entrust document signer, 2=EY certificate, 3=Digicert code signer).
* `address` is a string containing the Ethereum address that has been signed (prefixed by `0x...`).

If everything checks out, Nightfall will add the Ethereum address to the allowlist. It is possible that one would need to validate a certificate chain, rather than just the end user certificate, if `X509.sol` had not previously encountered the intermediate CA certs.  This is done by sequentially passing in the chain's certificates, most authoritative first, until the end-user cert is reached. For now, we'll just assume the simple case.

It's quite expensive to add an address to the allow list in this way (\~1MGas) but fortunately it only needs doing once for each certificate (it will need to be repeated once the certificate expires).

### The Deposit transaction

Now that the User is allowlisted, Nightfall will allow them to interact with its other smart contracts. However, before Nightfall can be used for transfer, the User must commit some funds to Nightfall's Layer 2 (at least equal to the amount that they wish to transfer). This is made easy by using the `Nf3` classes' `Deposit` method, which interacts with the Client container and the Shield contract to do the right things.

```javascript
await deposit(
    ercAddress,
    tokenType,
    value,
    tokenId,
    fee = this.defaultFeeTokenValue,
    providedCommitmentsFee = [],
    salt = undefined,
  )
```

Where:

* `ercAddress` is a hex string containing the address of the ERC20, 721 or 1155 contract that Nightfall should take funds from to fund the deposit.
* `tokenType` is the type of ERC token we are dealing with.  Valid values are `'ERC20'`, `'ERC721'` or `'ERC1155'.`
* `value` is the quantity of the ERC token (0 in the case of an ERC721 as it has no meaning for this token.
* `tokenId` is the token ID for an ERC721 or ERC1155 token, for an ERC20 it has no meaning and should be set to `'0x00'`.
* `fee` is the amount to be paid to the Proposer for including this deposit transaction in a Layer 2 block.
* `providedCommitmentsFee` Advanced use; this will be covered later.
* `salt` Advanced use; this will be covered later.

Under the hood, this Deposit call is doing quite a lot of work:

1. It will approve the Nightfall `Shield.sol` contract to transfer funds from your ERC20,721 or 1155 balance (an amount equal to that you wish to deposit into the Nightfall Layer 2)
2. It will contact the Client to assemble a Layer 2 transaction struct and embed that into an unsigned Ethereum transaction, which will post the transaction Struct to the Shield contract,
3. It will sign the Ethereum transaction and send it to the blockchain.

The (Layer 2) Transaction struct is worth a look.  Here it is in Solidity, although the Nightfall containers have an equivalent Nodejs object.

```solidity
   struct Transaction {
        uint256 packedInfo;
        uint256[] historicRootBlockNumberL2;
        bytes32 tokenId;
        bytes32 ercAddress;
        bytes32 recipientAddress;
        bytes32[] commitments;
        bytes32[] nullifiers;
        bytes32[2] compressedSecrets;
        uint256[4] proof;
    }
```

A detailed description is out of scope for this section, but a few things are noteworthy:

* Irrespective of the transaction type (e.g. Deposit, Transfer, Withdraw) the transaction struct is the same, although not all of the fields are populated for all transaction types.
* It contains a compressed Groth 16 proof of the correctness of the transaction
* It contains secrets that can be decrypted by a recipient to take ownership of a commitment during a Layer 2 transfer
* The transfer struct is not stored on-chain, except as calldata.

Note that a deposit transaction **is not private**. It can't be because it interacts with a Layer 1 ERC contract. This means that if you deposit tokens into Nightfall *everyone will know you did that, what type they were and how much/many*.

It's also quite expensive to do a deposit, about 130 kGas.  That's mostly because of the ERCx transactions that Nightfall has to do. Fortunately it should not be a transaction that you do often.

### Paying Proposers

Note that each time you create a transaction of any type, you have to pay a Proposer to incorporate it into a block.  Proposers advertise their fees on chain as part of their registration.

The payment is made as a layer 2 transaction and is incorporated into the circuit that is used to enforce the transaction that you are making. This is to preserve privacy; payment to a Proposer on Layer 1 would leak information about what you are doing. The upshot of this is that the Proposer payment transaction is completely transparent to the user, the fees are just taken from your L2 balance.

The is one caveat however; you do need to have sufficient funds in your Layer 2 balance to pay the proposer and these funds must be in the correct currency that the Proposer accepts. For test deployments this is the ERC20Mock token and for Mumbai and Polygon it is WMATIC. If you are doing your own Nightfall deployment, it can be any ERC20 that you like (set by the environment variable&#x20;

```sh
FEE_L2_TOKEN_ID
```

For example `FEE_L2_TOKEN_ID=WMATIC`. Note that the address corresponding to the token name be set in `default/config.js` under the `environment` object; Nightfall has no way to introspect the token name.

If you haven't deposited sufficient balance of this token into Layer 2, Nightfall will complain and will not process your transaction. The only exception to this rule is a Deposit that is made in the Proposer payment currency, in which case a Proposer payment will be taken from the Deposit and the rest credited to your balance (and available for future Proposer payments).

### The transfer transaction

Having deposited some tokens into Nightfall's Layer 2, you are now in a position to transfer tokens to someone else within Nightfall's Layer 2. These transfers do not interact with any ERCx contract and are completely private; unless you are careless, no one will know what tokens you send to whom, or how many/much you sent.

In the case of an fungible token, you can transfer any amount, up to the maximum that you have in your Layer 2 balance (either through a deposit transaction of by someone else sending you the funds). For a non-fungible token, you can only transfer whole tokens, that sort of definitional.

Again, the `Nf3` class is the easiest way to tell a Nightfall node to do a transfer transaction for you.

```javascript
await nf3.transfer(
    offchain = false,
    ercAddress,
    tokenType,
    value,
    tokenId,
    compressedZkpPublicKey,
    fee = this.defaultFeeTokenValue,
    providedCommitments,
    providedCommitmentsFee,
  )
```

Where:

* `offchain` is a boolean. If set to `false`, the transaction will be signed and posted to the blockchain as per a deposit transaction.  However, a transfer does not need to interact with any smart contract, and therefore the only purpose in posting it to the blockchain is for a Proposer to pick up the transaction. Notarising the transaction to the blockchain in this way is therefore an expensive way to send it to a Proposer.  Instead, it can be sent directly to a Proposer (or many Proposers). Proposers have an http\:// endpoint for this purpose. They actually then proxy the transaction to their Optimist instance, so it can also be sent directly there. Proposers publish this URL to the blockchain as a means of Proposer discovery. The direct sending is enabled by setting `offchain` to `true`.
* `compressedZkpPublicKey` is the public key corresponding to the transfer recipient's zkp private key (also known as a viewing key). It's a Babyjubjub curve point in compressed form (y coordinate and a parity bit). It's role is equivalent to an account address in an conventional Ethereum blockchain; it identifies the recipient of the transfer. If someone asks for your 'Nightfall address', you should give them your `compressedZkpPublicKey`.

The other parameters are the same as the deposit transaction. `providedCommitments` and `providedCommitmentsFee` are for advanced use. They can be left `undefined`.

A transfer transaction is very cheap to do. The gas cost is only the cost of posting a Layer 2 block, amortised across all the transactions in that block, plus any fees that the Proposer charges (run your own Proposer if you don't want to pay fees).  Assuming there are enough transactions (\~60) in the block to amortise the overhead of the block header, then the gas cost is about 6500 Gas.

### The Withdraw transaction

Completing the trio of basic Nightfall transactions is the withdraw transaction. This is the inverse of a deposit transaction. It takes tokens out of Layer 2 and returns them to their respective ERCx contract. One slight complication is that, although the tokens are returned to the ERCx contract, they remain as part of Nightfall's balance, and are not returned to the owner until the Layer 2 block which contains the withdraw transaction is finalised.  Being an Optimistic Layer 2, this takes one week, to allow sufficient time for incorrect Layer 2 blocks to be challenged. See the pages on Liquidity Providers for a way around that delay.

The  `Nf3` classes withdraw method is called like this:

```javascript
 await nf3.withdraw(
    offchain = false,
    ercAddress,
    tokenType,
    value,
    tokenId,
    recipientAddress,
    fee = this.defaultFeeTokenValue,
    providedCommitments,
    providedCommitmentsFee,
  )
```

All of these parameters have been covered except for the `recipientAddress` which, as you might guess, is the Ethereum address that will take ownership of the tokens once the withdrawal is finalised.

Once this transaction is completed `Nf3` will have an attribute `nf3.latestWithdrawHash,` which contains the hash of the withdraw transaction and is needed to claim the tokens. After the Layer 2 block which contained the withdraw transaction is finalised, the owner of the tokens can claim them by calling:

```javascript
await nf3.finaliseWithdrawal(withdrawTransactionHash)
```

Where withdrawTransactionHash is the value of nf3.latestWithdrawHash resulting from the withdraw transaction that you are concerned with.

### Tokenise, Transform and Burn transactions

\[ToDo]


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://westlad.gitbook.io/nightfall_3/basic-nightfall-workflow.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
