# Gas Station

Keep your wallets able to pay their network fees: per chain and asset, a threshold, a target, caps and a maximum gas price, paid from a funding wallet whose key never leaves Aurea's hardware security modules.

## Overview

- **A policy** says, for one chain and one asset — the chain's native coin or a token —, when a covered wallet is topped up (its balance below `threshold`), up to what (`target`), how much at most (`capPerTopUp` each time, `capPerWalletDay` in any 24 hours), and never while the network's gas price is above `maxGasPriceWei`.
- **A funding wallet** pays: one per chain, its key made in Aurea's hardware security modules and never exported. You fund its address.
- **Aurea runs the station.** Each pass reads the covered wallets' balances and tops up those below their threshold — or records why it did not (a skip). Every top-up and skip is in [List Top-Ups](https://docs.aureahub.com/docs/gas-station-top-ups.md); what needs your attention, in [List Alarms](https://docs.aureahub.com/docs/gas-station-alarms.md).
- **The routes** are under **Gas Station** in the API Reference — [Settings](https://docs.aureahub.com/docs/gas-station-settings.md), [List](https://docs.aureahub.com/docs/gas-station-policies.md), [Create](https://docs.aureahub.com/docs/gas-station-policy-create.md) and [Change](https://docs.aureahub.com/docs/gas-station-policy-update.md) a policy, [List](https://docs.aureahub.com/docs/gas-station-funding-wallets.md) and [Create](https://docs.aureahub.com/docs/gas-station-funding-wallet-create.md) a funding wallet, top-ups and alarms —, on the caller's own tenant, with an access token (Who Calls the Routes, below).
- **Amounts** are whole numbers of the asset's smallest unit, as decimal text ([Amount Units](https://docs.aureahub.com/docs/amounts.md)): wei for a native coin of 18 decimals, a token's own unit for a token. A gas price is in wei.

```json
{
  "chain": "base",
  "asset": "native",
  "threshold": "200000000000000",
  "target": "1000000000000000",
  "capPerTopUp": "1000000000000000",
  "capPerWalletDay": "2000000000000000",
  "maxGasPriceWei": "5000000000"
}
```

On Base, a custodial wallet below 0.0002 ETH is topped up to 0.001 ETH, at most 0.001 ETH a time and 0.002 ETH in any 24 hours, never while the gas price is above 5 gwei.

## Gas Modes

[Coming soon, upon request](https://docs.aureahub.com/docs/feature-availability.md) Top-ups need your tenant in the `station` mode, set with Aurea. Your tenant's gas mode, which [Gas Station Settings](https://docs.aureahub.com/docs/gas-station-settings.md) answers as `gasMode`:

| gasMode | How your wallets get gas |
| --- | --- |
| airdrop | **The default.** where your tenant has the registration gas airdrop, a client-side wallet registered on its network receives a small amount of the native coin for fees ([Register Client Wallet](https://docs.aureahub.com/docs/wallets-client-register.md)). The Gas Station tops nothing up, whatever your policies say. |
| station | The Gas Station covers your wallets with your policies — and with Aurea's default policies where you have none for a chain and asset (below) —, and no registration airdrop is sent. |

- **Your tenant's gas mode is set with Aurea**, on request. No route of yours changes it.
- `stationRunning`: whether Aurea runs the Gas Station now. A wallet is topped up only while your tenant is active, in `station`, and `stationRunning` is `true`.
- The routes answer in both modes: write your policies and make your funding wallets before your tenant moves.

## Policies

- **One per chain, network and asset**: `chain`, an EVM chain's slug (Chains, below), with `isTestnet` (default `false`) — the chain's id follows, as `chainId` —, and `asset`: `native`, or a token's contract address (all lower or all upper case, or EIP-55 — a mixed case with a wrong checksum is refused —, never the zero address; answered in EIP-55). A second policy for the same chain, network and asset answers `409` `GAS_STATION_POLICY_EXISTS`: change the one you have.
- **`decimals`**: the native coin's, from Aurea's chain registry (18 where it gives none); a token's, read on chain when the policy is created — an address with no contract, or a contract with no `decimals()`, answers `422` `GAS_STATION_ASSET_NOT_A_TOKEN`. A policy's chain and asset never change.

| Field | Meaning and rule |
| --- | --- |
| threshold | A covered wallet whose balance of the asset is below it is topped up. 0 or more. |
| target | The balance it is topped up to. Above `threshold`. |
| capPerTopUp | At most this much in one top-up. Above 0. |
| capPerWalletDay | At most this much to one wallet, of this asset, in any 24 hours — rolling, not a calendar day. At least `capPerTopUp`. |
| maxGasPriceWei | No top-up while the network's gas price is above it, and a top-up never pays more per gas. Above 0. |
| coverage | `custodial` (default), `account` with `accountId`, or `tag` with `tag` — Which Wallets a Policy Covers, below. `accountId` is given with `account` only, `tag` with `tag` only. |
| includeNonCustodial | `false` (default): only the keys the platform holds for your tenant. `true`: client-side and MPC wallets too. |
| enabled | `true` (default). `false`: the policy tops nothing up — and still stands in place of Aurea's default for its chain and asset. |

- Each amount up to 2256 − 1, written as text: `"1000000000000000"`, never `"0.001"` or a number.
- [Change a Policy](https://docs.aureahub.com/docs/gas-station-policy-update.md) changes its limits, coverage or switch; the result keeps the same rules.

## Which Wallets a Policy Covers

Your tenant's wallets stored on the policy's chain and network — the `chain` and `isTestnet` a wallet's reads answer —, not deactivated, with no top-up of theirs on its way:

| coverage | Wallets |
| --- | --- |
| custodial | Every such wallet whose key the platform holds for your tenant and that is not watch-only: a `keyManagementScheme` other than `client_side`, `client_side_pending` and `mpc_tss`. A custodial Solana wallet is on no chain the Gas Station serves today. |
| account | The custodial ones among the wallets held in the [account](https://docs.aureahub.com/docs/guide-accounts.md) `accountId` names. It must be an account of your tenant: `404` `GAS_STATION_ACCOUNT_NOT_FOUND` otherwise. |
| tag | The custodial ones among the wallets held in the accounts whose tags include `tag`, exactly as written: 1 to 50 of `A–Z a–z 0–9 _ . : -`, starting with a letter or a digit. |

- **`includeNonCustodial` `true`** adds, within the same coverage, the client-side (`client_side`) and MPC (`mpc_tss`) wallets: your opt-in, on your own policies only.
- **Never covered**: a wallet whose key is on its way to the user's device (`client_side_pending`), a watch-only wallet, a deactivated one.
- **A wallet stored on chain `evm`** — an account's one EVM key, one address on every EVM chain ([Accounts](https://docs.aureahub.com/docs/guide-accounts.md)) — is covered by a policy of any EVM chain, on the policy's network, when its key is Aurea's: custodial only, whatever `includeNonCustodial` says. Its top-ups and skips are the policy's chain's (`chain`, `chainId`), and its day cap counts on each chain apart. An address your tenant also holds as a wallet of the policy's chain is topped up once, as that wallet. One top-up at a time per wallet: a key due on two chains gets the second at a later pass.
- A wallet held in no account (in its user's default account) is covered only by a policy whose `coverage` is `custodial`.

## Aurea's Default Policies

- Aurea may provide default policies: [List Policies](https://docs.aureahub.com/docs/gas-station-policies.md) answers them in `platformDefaults`, with `scope` `platform`. They cover custodial wallets only, and only the tenants in `station`. You read them; you do not change them.
- **Yours comes first.** For each chain, network and asset, your own policy — enabled or not, whatever it covers — stands in place of Aurea's default. Where you have none, Aurea's default applies, when it is enabled. To have neither, keep a policy of yours with `enabled` `false`.
- **Who pays: the policy's owner.** A top-up under your policy comes from your funding wallet on that chain; a top-up under Aurea's default is paid by Aurea's funding wallet on that chain, never yours.

## Funding Wallets

- **One per chain and network** (`409` `GAS_STATION_FUNDING_WALLET_EXISTS` for a second), made with [Create a Funding Wallet](https://docs.aureahub.com/docs/gas-station-funding-wallet-create.md). Its key is its own, made for it in Aurea's hardware security modules and never exported: Aurea keeps its address and a reference to the key, never the key. It is not one of your users' wallets.
- `custodyTier`: `institutional` where your tenant's custody tier is institutional, else `premium` — a hardware security module either way.
- **Fund it**: send the chain's native coin to its `address` — it pays every top-up's network fee and, on a native policy, the top-up itself — and, for a token policy, the token. [List Funding Wallets](https://docs.aureahub.com/docs/gas-station-funding-wallets.md) reads each one's native balance now (`nativeBalance`).
- **Your tenant's quorum.** Making one is a covered action of [your tenant's quorum](https://docs.aureahub.com/docs/guide-tenant-quorum.md) — `gas_station.funding_wallet.create_own` on `POST /v1/gas-station/funding-wallets`, `gas_station.funding_wallet.create` on `POST /v1/admin/tenants/{id}/gas-station/funding-wallets`: where your tenant's quorum holds administrators' actions [Coming soon, upon request](https://docs.aureahub.com/docs/feature-availability.md), it answers `202` and waits for another administrator's approval. A call it would refuse — a chain the station does not serve, a funding wallet that exists — is answered at once, never held.
- **The key store**: `503` `WALLET_KEY_STORE_NOT_CONFIGURED` or `WALLET_KEY_STORE_UNAVAILABLE`, and nothing is made.
- No route removes or replaces a funding wallet: to stop its top-ups, switch the policies off.

## Top-Ups

Each pass, for your tenant in `station`: per chain, the network's gas price, once; per policy, its covered wallets — those the station never recorded first, then those whose last top-up or skip is the oldest, up to a number Aurea sets per pass — and each one's balance of the asset. At or above the threshold, nothing happens and nothing is recorded. Below it, in this order:

1. **The day cap.** What the station sent that wallet of that asset on that chain in the last 24 hours — its top-ups signed, sent or confirmed — is taken off `capPerWalletDay`. Nothing left: skipped, `day_cap_reached`.
2. **The amount**: the smallest of `target` − the balance, `capPerTopUp`, and what the day cap leaves.
3. **The price.** The network's gas price above `maxGasPriceWei`: skipped, `gas_price_above_max`.
4. **Who pays.** The policy's owner has no funding wallet on the chain: `no_funding_wallet`. Its balances could not be read: `funding_unreadable`. It cannot pay the amount and the most the fee can cost: `funding_insufficient`. On a token policy, the funding wallet's token pays the amount and its native coin the fee.

- **The fee.** A top-up carries the network's own fee cap per gas, never above `maxGasPriceWei`: it never pays more per gas than its policy allows. A native top-up is a plain transfer (21 000 gas); a token top-up a token transfer, its gas as the node estimates it plus a fifth (100 000 when the node cannot estimate it).
- **One at a time per wallet**: a wallet with a top-up `planned`, `signed` or `sent` gets no other until it ends.
- **A failed top-up** delivers nothing, and is not counted by the day cap: the next pass tries again, as a new top-up, while the wallet stays below its threshold.
- A wallet whose balance cannot be read, or a chain whose gas price cannot be read, waits for the next pass: nothing is recorded. Every read and send goes through Aurea's own node of the chain, never your tenant's blockchain configuration.

## A Top-Up's Statuses

```text
planned ──► signed ──► sent ──► confirmed
   └──────────┴──────────┴──► failed     (failureCode)
skipped: below the threshold, not topped up    (skipReason, occurrences)
```

| status | Meaning |
| --- | --- |
| planned | Recorded, about to be signed. Never signed within two minutes: `failed` `NOT_SIGNED`, and nothing went out. |
| signed | Signed by the funding wallet's key, its hash (`txHash`) kept before the node is handed it. After a restart the same signed transaction is handed over again — never a second top-up. |
| sent | The node took it (`sentAt`). |
| confirmed | Mined and successful (`finishedAt`). |
| failed | Ended without delivering its amount; `failureCode` says why: `REVERTED` (mined, and reverted), `NONCE_TAKEN` (another transaction of the funding wallet took its place), `NOT_SIGNED`, the node's refusal (for example `INSUFFICIENT_FUNDS`), or a refusal before anything was signed — your tenant frozen (`TENANT_FROZEN`, [Freezes & Quarantines](https://docs.aureahub.com/docs/guide-freezes.md)), your institutional tenant's policy ([Policy Sets](https://docs.aureahub.com/docs/guide-policy-sets.md)), the key store (`WALLET_KEY_STORE_UNAVAILABLE`). |
| skipped | A wallet below its threshold that was not topped up, with `skipReason`. One row per episode: the same reason again on the wallet's last row of that asset counts in `occurrences` and `lastSeenAt`; anything else starts a new row. |

## Operations and the Audit Trail

- **Where your tenant has operation records** [Coming soon, upon request](https://docs.aureahub.com/docs/feature-availability.md) ([Operations & Fees](https://docs.aureahub.com/docs/guide-operations.md)), each top-up signed is an operation of your tenant of type `GAS_TOPUP`, `origin` `gas_station.topup`: recorded at `SIGNED` `signed_by_hub`, then `BROADCASTING` `sending` and `CONFIRMING` `awaiting_confirmation`, and ended `COMPLETED` `confirmed`, `FAILED` `reverted`, or `FAILED` `submission_failed` — the node refused it, or another transaction took its nonce —, with the top-up's `failureCode` as `failureReason`.
- It has no `userId` and no `walletId` (the funding wallet is not one of your wallets): `destination` is the covered wallet's address, `asset` and `amount` the top-up's, `providerRef` `gas_topup:` and the top-up's id. The top-up's `operationId` names it. The roles that read every operation of your tenant read it, and its `operation.*` events reach the endpoints that name them ([Webhooks & Events](https://docs.aureahub.com/docs/guide-events.md)). The Gas Station has no event type of its own.
- **Your [audit trail](https://docs.aureahub.com/docs/audit-events.md)** [Coming soon, upon request](https://docs.aureahub.com/docs/feature-availability.md), records `gas_station.policy.created` and `gas_station.policy.changed` and Aurea moving your tenant between the gas modes (`gas_station.mode.changed`), category `settings`; `gas_station.funding_wallet.created`, category `keys`; and each top-up of your wallets signed, `gas_station.topup.signed`, category `money`, by the station — whoever pays. Ids, chains, assets, amounts and limits: never an address.

## Alarms

[List Alarms](https://docs.aureahub.com/docs/gas-station-alarms.md) answers the Gas Station's open alarms about your tenant. One alarm per subject while it is open: raised again, it counts `occurrences` and moves `lastSeenAt`, its `detail` the latest.

| kind | Raised when | Resolved when | detail |
| --- | --- | --- | --- |
| gas_funding_low | One of your funding wallets could not pay a top-up (a skip `funding_insufficient`). | A pass where it pays a top-up and is short of none. | `fundingWalletId`, `chainId`, `asset`, `balance` (what it held of the asset), `needed` (the amount it could not pay) |
| gas_price_above_max | A pass reads the network's gas price above the `maxGasPriceWei` of one of your enabled policies — whether or not a wallet waits. | A pass reads it at or under the maximum. | `policyId`, `chainId`, `asset`, `gasPriceWei`, `maxGasPriceWei` |
| gas_topup_failed | A top-up of one of your wallets failed: refused before or at signing, refused by the node, reverted, or its nonce taken. | A later top-up of that wallet is confirmed. | `walletId`, `topUpId`, `chainId`, `asset`, `code` |

- Aurea's funding wallets and Aurea's default policies raise their alarms to Aurea; a top-up of your wallet that fails under a default is yours (`gas_topup_failed`).
- An alarm leaves the list once it is resolved, or once Aurea acknowledges it. Its detail never holds an address.

## Chains

The Gas Station serves the EVM chains the Hub supports, each on its mainnet or its testnet (`isTestnet`). Solana is not served.

| chain | chainId | chainId, isTestnet true |
| --- | --- | --- |
| ethereum | 1 | 11155111 |
| polygon | 137 | 80002 |
| gnosis | 100 | 10200 |
| bsc | 56 | 97 |
| arbitrum | 42161 | 421614 |
| optimism | 10 | 11155420 |
| base | 8453 | 84532 |
| avalanche | 43114 | 43113 |
| celo | 42220 | 11142220 |
| flowevm | 747 | 545 |

- Send the slug, in any case, with `isTestnet`. Any other value — `solana`, `evm`, a testnet's registry id such as `polygon-amoy` — answers `400` `GAS_STATION_CHAIN_NOT_SUPPORTED`.
- Where Aurea has no node of a chain, its policies wait, a token policy on it cannot be created (`503` `GAS_STATION_CHAIN_UNAVAILABLE`), and its funding wallet's `nativeBalance` is `null`.

## Who Calls the Routes

- **With an access token** (`Authorization: Bearer`), on `/v1/gas-station/…`, for the caller's own tenant.
- **Each route also under `/v1/admin/tenants/{id}/gas-station/…`**, with your tenant's id: the same roles, the same answers. Another tenant's id answers `403` (`Admin access required or you can only access your own tenant.`).
- **Read** — settings, policies, funding wallets, top-ups, alarms: `owner`, `tenantadmin`, `non_signing_admin`, `signer`, `approver`, `editor`, `viewer`, `auditor`. **Write the policies and make the funding wallets**: `owner`, `tenantadmin`, `non_signing_admin` ([Roles](https://docs.aureahub.com/docs/authentication.md)). Any other role: `403` — on `/v1/gas-station/…` `Tenant admin access required. Your role does not have permission to perform this action.`, by tenant id `Admin access required or you can only access your own tenant.`

## Refusals

The usual envelope, the code in `details.code`. Nothing is written.

| Status | details.code | message |
| --- | --- | --- |
| 400 | GAS_STATION_INVALID | `Invalid request`, with each problem in `details.errors` — for example `threshold: must be a whole number of the smallest unit, as text` —; or a rule broken, with `details.field`: `target must be above threshold`, `capPerTopUp must be above 0`, `capPerWalletDay must be at least capPerTopUp`, `maxGasPriceWei must be above 0`, `accountId is given with coverage account, and only then`, `tag is given with coverage tag, and only then` |
| 400 | GAS_STATION_CHAIN_NOT_SUPPORTED | `The Gas Station serves the EVM chains the Hub supports; "solana" is not one of them`, with `details.field` `chain` |
| 404 | GAS_STATION_POLICY_NOT_FOUND | `Gas Station policy not found` — also another tenant's, or one of Aurea's defaults |
| 404 | GAS_STATION_ACCOUNT_NOT_FOUND | `Account not found` |
| 404 | GAS_STATION_TENANT_NOT_FOUND | `Tenant not found` — the `/v1/admin/tenants/{id}` routes |
| 409 | GAS_STATION_POLICY_EXISTS | `A Gas Station policy for this chain and asset exists already: change it` |
| 409 | GAS_STATION_FUNDING_WALLET_EXISTS | `This tenant has a Gas Station funding wallet on this chain already` |
| 422 | GAS_STATION_ASSET_NOT_A_TOKEN | `This address holds no token contract on this chain (no code, or no decimals())` |
| 503 | GAS_STATION_CHAIN_UNAVAILABLE | `The platform has no node for this chain: the Gas Station cannot read it`, or `The platform's node of this chain did not answer: the token was not read` (with `details.reason`) — a token policy |
| 503 | WALLET_KEY_STORE_NOT_CONFIGURED | `The key store of this wallet's custody tier is not configured, so the wallet was not created.` — a funding wallet |
| 503 | WALLET_KEY_STORE_UNAVAILABLE | `The key store did not answer, so the wallet was not created. Try again later.` — a funding wallet |

- On List Top-Ups, `400` `GAS_STATION_INVALID` also for a `cursor` the route did not give (`cursor: is not a cursor this route gave`) and for `tenantId`, which is not one of its filters (`tenantId: is not a filter of this route`).
- A funding wallet held by your tenant's quorum answers `202` `{ "state": "awaiting_quorum", "requestId" }` ([Your Tenant's Quorum](https://docs.aureahub.com/docs/guide-tenant-quorum.md)).

---

Web version: https://docs.aureahub.com/#guide-gas-station
