> ## Documentation Index
> Fetch the complete documentation index at: https://docs.ryvo.network/llms.txt
> Use this file to discover all available pages before exploring further.

# Balances and Withdrawals

> How participant balances, pending withdrawals, and channel locks work in Ryvo.

Ryvo keeps user funds in two places:

1. **The protocol vault**, which holds real SPL tokens.
2. **Protocol state**, which tracks who is entitled to what inside that vault.

Balance accounting sits at two layers:

* **Participant balance** - stored in participant buckets
* **Channel lock** - stored in channel-bucket lane state

## Participant balance states

For each allowlisted token, a participant can hold:

| State                                             | Meaning                                                           |
| ------------------------------------------------- | ----------------------------------------------------------------- |
| `available_balance`                               | Spendable inside the protocol right now                           |
| `withdrawing_balance`                             | Amount reserved for a pending withdrawal                          |
| `withdrawal_destination` + `withdrawal_unlock_at` | Where a pending withdrawal will go and when it becomes executable |

The first deposit for a token appears entirely in `available_balance`.

## Channel locks are separate

Channel locks live in `ChannelState.locked_balance`, not in `ParticipantAccount`. A participant can therefore hold:

* shared available balance that may flow across several relationships, plus
* one or more channel-specific locked amounts that are ring-fenced for specific payees.

During settlement, the protocol spends **channel-specific locked balance first** and **shared participant balance second**.

## Deposit flow

Depositing is a normal SPL token transfer from the user's token account into the protocol vault, followed by a credit to protocol balance:

```ts theme={null}
await program.methods
  .deposit(tokenId, new anchor.BN(amount))
  .accounts({
    owner: owner.publicKey,
    participantAccount,
    ownerTokenAccount,
    vaultTokenAccount,
  } as any)
  .signers([owner])
  .rpc();
```

`deposit_for` is the batch version of the same idea. It lets one funder credit up to 16 participants in one transaction.

## Withdrawal flow

Withdrawals are intentionally two-step. This protects the payee from a payer draining shared balance immediately after signing a commitment.

### Step 1 - request

`request_withdrawal` moves funds from `available_balance` to `withdrawing_balance`, records the destination token account, and starts the timelock.

### Step 2 - execute

Once the timelock has expired, `execute_withdrawal_timelocked` transfers the net amount to the destination token account and the withdrawal fee to the protocol fee recipient.

The withdrawal fee is the larger of:

1. the configured basis-point fee, or
2. a minimum fee floor scaled to the token's decimals.

On mainnet the timelock is seven days. On devnet, testnet, and localnet the timelock is short so the flow is practical for testing. See [Deployment](/reference/deployment) for exact values.

## Pending withdrawal is not final

One behavior surprises people at first:

<Warning>
  A pending withdrawal can still be consumed by later settlement before it is executed.
</Warning>

A withdrawal request is not final settlement. Until the execute step succeeds, the funds are still part of the participant's total protocol balance. If later settlement consumes that balance:

* the withdrawal may execute with only the residual amount, or
* it may execute with zero and simply clear the pending state.

This is deliberate. *"Requested for withdrawal"* is not stronger than *"already withdrawn."*

## Cancelling a withdrawal

If the participant changes their mind before execution, `cancel_withdrawal` moves `withdrawing_balance` back to `available_balance` and clears the stored destination and unlock time.

## Channel unlock flow

Channel locks have their own two-step flow:

1. `request_unlock_channel_funds`
2. `execute_unlock_channel_funds`

This is separate from participant withdrawals because channel locks are not the same thing as participant balances.

When a channel unlock executes, the protocol returns `min(pending_unlock_amount, locked_balance)` to the payer's `available_balance`. If later settlement has already used part or all of the locked balance, the unlock releases only what remains.

## Practical rules

If you are building a provider, client, or gateway, these are the balance rules that matter most:

1. Deposits increase `available_balance`.
2. Channel locks reduce shared flexibility but strengthen one specific relationship.
3. Pending withdrawals are not final until executed.
4. Settlement can consume both shared balance and channel-specific locks, locked balance first.
5. Unlock requests and signer rotations are also timelocked.

<Tip>
  If you are considering a yield-bearing settlement asset, prefer a fixed-balance share token over a rebasing one. Ryvo's internal accounting is aligned with tokens whose balances stay constant while redemption value rises over time. See [Yield-bearing assets](/core-concepts/yield-bearing-assets).
</Tip>

## See also

* [Participants](/core-concepts/participants)
* [Payment channels](/core-concepts/payment-channels)
* [Deployment](/reference/deployment)
* [Yield-bearing assets](/core-concepts/yield-bearing-assets)
