# Deposits

Create and list deposit addresses with DepositAddressService, then follow each deposit from source-chain confirmations to a settled Funding or Trading balance.

A deposit brings a supported Asset from an external Network into a Polyester account. You create a deposit address for the receiving account and Network, send the Asset to it from any wallet or exchange, and follow the resulting deposit flow until the balance is settled.

Each address belongs to one account (the Main Account or one Subaccount) and one Network. It does not rotate, so creating it again returns the same address.

> **Send only to the address Polyester returns**
>
> Send the Asset on the Network the address was created for. Do not send deposits to the account's smart-account address or to the wallet that signs in; neither credits the account.

## Deposit addresses

Two methods manage addresses, and both accept a session or an API key:

- [`CreateDepositAddress`](https://testnet.polyester.com/docs/api-docs/connect/chain.deposit.v1.DepositAddressService/CreateDepositAddress) ([`POST /v1/chain/deposit-addresses`](https://testnet.polyester.com/docs/api-docs/rest/POST/v1/chain/deposit-addresses)) creates the address, or returns the existing one.
- [`ListDepositAddresses`](https://testnet.polyester.com/docs/api-docs/connect/chain.deposit.v1.DepositAddressService/ListDepositAddresses) ([`GET /v1/chain/deposit-addresses`](https://testnet.polyester.com/docs/api-docs/rest/GET/v1/chain/deposit-addresses)) lists the account's addresses.

Both take an optional `subaccountId`. Omit it to target the Main Account, or the bound Subaccount for a Subaccount-scoped API key. `chainId` is the Polyester-registered Network id from the deposit and withdraw configuration, not the Network's native chain id. `ListDepositAddresses` without `chainId` returns the account's addresses on every Network that currently accepts deposits, ordered by `chainId`.

```json
{
	"chainId": 1
}
```

Add `subaccountId` to target a Subaccount. The response wraps the address and its `chainId` in `depositAddress`.

### Who may create and list

Deposit addresses are outside policy scope: no policy action controls them, and an attached Subaccount or API key policy never blocks them. Access depends on the caller:

| Caller                    | Create                                                        | List                         |
| ------------------------- | ------------------------------------------------------------- | ---------------------------- |
| Session on a Subaccount   | `OWNER`, `ADMIN`, `TREASURY`, `TRADER`, or `LEVERAGED_TRADER` | Any role, including `VIEWER` |
| Main Account API key      | The Main Account and every Subaccount it owns                 | Same                         |
| Subaccount-scoped API key | Its bound Subaccount only                                     | Same                         |

Creating an address requires the acting Main Account to have accepted the current terms, including when it uses an API key or a shared Subaccount. Listing and using existing addresses do not. No MFA step-up is required.

### Network availability

Addresses are offered only for Networks that currently accept deposits. When deposits on a Network are suspended, creating an address for it, or listing with that `chainId`, fails with ConnectRPC `FailedPrecondition` (REST `400`, code `failed_precondition`). A `chainId` Polyester does not support for deposits fails with `InvalidArgument`. See [Funds transfer overview](https://testnet.polyester.com/docs/developer-docs/funds-transfers/overview).

## Before you send

Read [`GetDepositWithdrawConfig`](https://testnet.polyester.com/docs/api-docs/connect/chain.zipper.v1.ZipperService/GetDepositWithdrawConfig) ([`GET /v1/chain/deposit-withdraw/config`](https://testnet.polyester.com/docs/api-docs/rest/GET/v1/chain/deposit-withdraw/config)). It is public and lists every supported Network and Asset route:

- `requiredConfirmations` and `confirmationTimeSeconds` per Network, when known
- `depositMinAmount` per Asset route, in Asset units
- `networkFee`, `sourceDecimals`, and the source token contract per route

## Deposit lifecycle

Sending the Asset starts a deposit flow (`KIND_DEPOSIT`). Polyester detects the source transfer, so no API call is needed after you send. A deposit moves through these steps:

1. FLOW_STEP_SOURCE

   Polyester observes the source transaction and counts confirmations. Progress reports `currentConfirmations` and `requiredConfirmations`. The live requirement can differ from the configured default, so follow the flow rather than a fixed count.

2. FLOW_STEP_REQUEST

   Zipper verifies the source transaction against the route and opens a deposit request.

3. FLOW_STEP_VALIDATION

   Independent Zipper validators approve or reject the request. Progress reports approval and rejection counts against the required quorum.

4. FLOW_STEP_TRANSFER

   The route's Zipped Asset is minted on Polyester Chain and credited to the account.

5. FLOW_STEP_SETTLEMENT

   The ledger settlement is confirmed and the balance is usable.

The credit lands in Funding or in Trading according to the receiving account's Default Deposit Destination, an on-chain account setting. The flow's `destinationDomain` and its `ACTIVITY_FUNDING` or `ACTIVITY_TRADING` activity show where it landed. If routing to Trading fails, the credit stays in Funding. See [Deposit Funds](https://testnet.polyester.com/docs/user-docs/funds/deposit-assets).

### Statuses

| `FlowState`                     | Meaning                         |
| ------------------------------- | ------------------------------- |
| `STATE_PENDING_SOURCE`          | Waiting on the source Network.  |
| `STATE_PENDING_POLYESTER_CHAIN` | Progressing on Polyester Chain. |
| `STATE_PENDING_LEDGER`          | Waiting for ledger settlement.  |
| `STATE_COMPLETED`               | Credited and settled.           |
| `STATE_FAILED`                  | Failed; no longer progressing.  |
| `STATE_DROPPED`                 | Dropped before completion.      |
| `STATE_REFUNDED`                | Ended in a refund or reversal.  |

`isTerminal: true` means processing ended, not that it succeeded. Confirm success from `STATE_COMPLETED` and the settlement step, and read `lifecycleReason` for any other outcome. For example, `DEPOSIT_SOURCE_NOT_CONFIRMED` means the source transaction did not confirm in time; the deposit resumes and completes if it confirms later.

An open flow carries `estimatedCompletionUnixMs`. When `isDelayed` is true there is no reliable estimate; the flow still completes once progress resumes.

## Track deposits

| Need                           | Method                                                                                                                                                                   |
| ------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| Deposits for an account        | [`ListFlows`](https://testnet.polyester.com/docs/api-docs/connect/chain.lifecycle.v1.LifecycleReadService/ListFlows) with `flowKind` deposit and an account selector     |
| Flows for a source transaction | [`ListFlowsByTx`](https://testnet.polyester.com/docs/api-docs/connect/chain.lifecycle.v1.LifecycleReadService/ListFlowsByTx) with the source transaction hash            |
| One flow in detail             | [`GetFlowById`](https://testnet.polyester.com/docs/api-docs/connect/chain.lifecycle.v1.LifecycleReadService/GetFlowById)                                                 |
| Credited ledger legs           | [`ListTransfers`](https://testnet.polyester.com/docs/api-docs/connect/ledger.read.v1.LedgerReadService/ListTransfers), rows with `transferCode` `DEPOSIT` and a `flowId` |

The REST routes are [`GET /v1/chain/flows`](https://testnet.polyester.com/docs/api-docs/rest/GET/v1/chain/flows), [`GET /v1/chain/flows/by-tx/{txHash}/matches`](https://testnet.polyester.com/docs/api-docs/rest/GET/v1/chain/flows/by-tx/tx_hash/matches), [`GET /v1/chain/flows/{flowId}`](https://testnet.polyester.com/docs/api-docs/rest/GET/v1/chain/flows/flow_id), and [`GET /v1/transfers`](https://testnet.polyester.com/docs/api-docs/rest/GET/v1/transfers).

One source transaction can create several flows, one per deposit leg. Every transfer to the same address is its own flow, so follow each one to completion. Credited ledger legs also arrive on the [Ledger transfers](https://testnet.polyester.com/docs/api-docs/streams/private-ledger-transfers) stream, and flow changes on the [account lifecycle flow summaries](https://testnet.polyester.com/docs/api-docs/streams/private-chain-lifecycle-flows) stream, over [WebSocket JSON](https://testnet.polyester.com/docs/developer-docs/rest/websocket-json) or [WebSocket Protobuf](https://testnet.polyester.com/docs/developer-docs/connectrpc/websocket-protobuf). See [Track funding flows](https://testnet.polyester.com/docs/developer-docs/funds-transfers/track-funding-flows) for reading progress and outcomes.

Field schemas are in the [API reference](https://testnet.polyester.com/docs/api-docs).
