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

# Sending withdrawals

> Validating addresses, signing legacy transactions offline, pricing fees with eth_estimateSmartFee, managing nonces, and replacing stuck withdrawals.

A withdrawal is an ordinary transaction from one of your hot wallet
addresses. The parts that need care are the ones the protocol leaves to
you: which transaction type to sign, what fee to pay, keeping nonces in
order, and what to do when a transaction does not confirm.

## Where keys live

Keep signing keys off your nodes. A node that serves JSON-RPC and also
holds unlocked keys turns any RPC exposure into a loss of funds.

* **Hot wallet:** sign in your own signing service, HSM or key management
  system, and hand the node only the signed transaction. Parallax signatures
  are standard secp256k1 with EIP-155, so any signer that supports Ethereum
  legacy transactions works with chain ID `2110`.
* **Cold storage:** sign on an offline machine with `parallax-wallet signtx`,
  which never talks to a node, and carry the signed transaction across. See
  [parallax-wallet](/v2.1.x/parallax-client/tools/parallax-wallet#cold-sign-a-transaction-on-an-air-gapped-machine).
* **Clef** is also available as an external signer with rule-based
  approval; see [Clef](/v2.1.x/parallax-client/tools/clef/introduction).

Keep in the hot wallet only what a day or so of withdrawals needs, and
refill it from cold storage.

## Validate the destination

* An address is `0x` followed by 40 hexadecimal characters. Reject
  anything else.
* If the address is mixed case, it carries an
  [EIP-55](https://eips.ethereum.org/EIPS/eip-55) checksum: verify it and
  reject the address if it fails. That catches most typing mistakes. An
  all-lowercase or all-uppercase address has no checksum to verify.
* Parallax uses the same address format as Ethereum and other EVM chains,
  so an address can be valid on several chains at once. Make clear in your
  interface that the withdrawal is on Parallax, so users do not send it to
  an address only they control on another chain.

## Build and sign

Sign a **legacy (type 0) transaction** with an explicit `gasPrice` and chain
ID `2110`:

| Field | Value |
| - | - |
| `type` | `0`. Type 1 (access list) is also accepted; type 2 (EIP-1559) is rejected |
| `chainId` | `2110`. Transactions without EIP-155 replay protection are rejected |
| `nonce` | The next nonce for the sending address, from your own records (see [Nonces](#nonces)) |
| `gasPrice` | From [`eth_estimateSmartFee`](#fees) |
| `gas` | `21000` for a plain transfer to an ordinary address. For a contract recipient, `eth_estimateGas` plus a margin |
| `to`, `value` | Destination and amount in wei |

Ethereum libraries work unchanged as long as they produce legacy
transactions. Most choose legacy on their own when blocks have no
`baseFeePerGas`, which Parallax blocks never have, but setting the type and
gas price explicitly avoids surprises after a library upgrade. For example,
with ethers v6:

```js theme={null}
const tx = await wallet.signTransaction({
  type: 0,
  chainId: 2110,
  nonce,
  to,
  value,
  gasLimit: 21000n,
  gasPrice,
});
```

Or offline, with `parallax-wallet`:

```bash theme={null}
parallax-wallet signtx \
  --chainid 2110 --nonce 42 \
  --gas 21000 --gasprice 2000000000 \
  --to 0x… --value 1000000000000000000 \
  /secure/keystore/UTC--…
```

## Fees

Parallax has no base fee. A transaction pays `gas used × gasPrice`, all of
it to the miner, and miners include the best-paying transactions first. A
plain transfer always uses 21,000 gas.

Price withdrawals with **`eth_estimateSmartFee`**, a port of Bitcoin Core's
fee estimator. Give it how many blocks you are willing to wait:

```json theme={null}
{"jsonrpc":"2.0","id":1,"method":"eth_estimateSmartFee","params":[3]}
```

```json theme={null}
{"jsonrpc":"2.0","id":1,"result":{
  "gasPrice":"0x77359400","confTarget":3,"successRate":0.92,"legacyFallback":false}}
```

| Field | Meaning |
| - | - |
| `gasPrice` | Suggested price per gas, in wei, as hex |
| `confTarget` | The target you asked for. Targets below 2 are treated as 2, and the longest is 1,008 blocks (a week) |
| `successRate` | How often transactions at this price have historically confirmed within the target |
| `legacyFallback` | `true` when the estimator has too little data and fell back to a percentile of recent blocks' prices |

While recent blocks are less than half full, the estimate is the floor that
miners accept by default, **1 gwei**. Transactions priced below that are
generally not mined. `eth_gasPrice` (or `parallax-cli gasprice`) returns the
estimate for a 2-block target.

A target of 2 to 6 blocks (20 minutes to an hour) suits most withdrawals.
Set an upper limit of your own, too. The node also refuses to broadcast any
transaction whose total fee exceeds `--rpc.txfeecap`, 1 LAX by default.

## Nonces

Each address's transactions must use consecutive nonces, starting from 0.
A transaction cannot be mined until every lower nonce from the same address
has been, so one stuck transaction holds up every withdrawal behind it.

* Send withdrawals from a small number of hot addresses, each used by one
  signing process at a time.
* Assign nonces from your own database, inside the same transaction that
  reserves the withdrawal. Do not ask the node for the next nonce for each
  withdrawal: with several in flight it will hand out the same one twice.
* On startup and after any doubt, reconcile your next nonce against
  `eth_getTransactionCount(address, "latest")`, which counts mined
  transactions, and `"pending"`, which also counts those in the node's pool.

## Broadcast

Submit with `eth_sendRawTransaction`, or `parallax-cli sendraw <hex>`, to
more than one of your nodes. Each relays it to its peers. Submitting the
same transaction twice is harmless: the second node already knows it.

Errors you may see:

| Error | Cause |
| - | - |
| `transaction type not supported` | A type 2 transaction. Sign it as legacy |
| `only replay-protected (EIP-155) transactions allowed over RPC` | Signed without a chain ID |
| `invalid sender` | Signed for a different chain ID, or malformed |
| `nonce too low` | That nonce is already used by a mined transaction. Check whether it was this withdrawal |
| `already known` | The node already has this exact transaction. Not a failure |
| `replacement transaction underpriced` | Another transaction with the same nonce is pending, and this one does not pay at least 10% more |
| `insufficient funds for gas * price + value` | The hot address cannot cover the amount plus the fee |
| `tx fee (…) exceeds the configured cap (…)` | Fee above `--rpc.txfeecap` |

Your own node accepts a transaction you submit even if it pays less than
the network's usual minimum, and keeps it across restarts. Miners do not:
by default a mining node refuses transactions below 1 gwei, so an
underpriced withdrawal can sit in pools indefinitely without being mined.
Do not price below the `eth_estimateSmartFee` result.

## After broadcast

Track each withdrawal until it is buried, the same way you track deposits:

1. Poll `eth_getTransactionReceipt` with the transaction hash. When it
   returns a receipt, the transaction is in a block. Check `status` is
   `0x1`. A failed withdrawal still uses its nonce and pays its fee.
2. Record the block number and hash, and count confirmations as for
   [deposits](./deposits#tracking-confirmations).
3. If a reorganization removes the block, the transaction normally goes
   back into nodes' pools and is mined again. If it has not reappeared after
   a few blocks, **rebroadcast the same signed transaction**. It has the
   same nonce and hash, so it can never be paid twice.

Show users the transaction hash and an
[explorer](https://explorer.parallaxprotocol.org) link as soon as you
broadcast, and set expectations in minutes, not seconds: the first
confirmation takes 10 minutes on average and sometimes much longer.

### Stuck withdrawals

Pending transactions are not dropped after a timeout, so an underpriced
withdrawal can wait in the pool for a long time. To speed it up, sign a
**replacement**: the same nonce, the same destination and amount, and a
`gasPrice` at least **10% higher** than the one it replaces. Nodes swap the
old transaction for the new one. Use a fresh `eth_estimateSmartFee` with a
short target, and stay at least 10% above the original.

Whichever version is mined, the other becomes invalid, because they share
a nonce. Watch for **both** hashes until one confirms, and update the hash
you show the user.

To cancel a withdrawal that has not been mined, replace it with a
transaction of the same nonce that sends 0 LAX to your own address, at least
10% more expensive. If the original is mined first, the cancellation fails
with `nonce too low`, and the withdrawal stands.

### Batching

Parallax has no native batch payment. Each withdrawal is one transaction
and one nonce. If you send many small withdrawals, a batch-payment contract
can pay many recipients in one transaction. Compile it with
`evmVersion: "berlin"`, and audit it as you would any contract that holds
customer funds.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.