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

# Fund a test account

> Testnet tokens for integration development

> [!NOTE]
>
> **What you'll be able to do**
>
> * Fund a test account with the required test token.
> * Verify the amount received using the account's token balance and transaction receipt.

Faucet tokens are used to fund onchain testing and have no monetary value. RPC credit in
the Metal console pays for endpoint requests separately.

## Before you start

* Obtain the public address of a test account you control from the signing
  system or wallet. A browser wallet is optional, and the faucet never needs
  the private key.
* Select the token required by the test. `*USDZ` pays gas for standard Ethereum
  transactions. Funding an account with another token does not replace that
  requirement. See [Fees](https://docs.metalntwx.com/build/prepare/estimate-and-record-fees.md) for selecting a different gas
  token in a Metal transaction.

## Read the starting balance

Read the balance of `ACCOUNT_ADDRESS`, the account to fund, in the default gas
token, `*USDZ`. For another token, substitute its verified address from
[Contract addresses](https://docs.metalntwx.com/reference/contract-addresses.md).

```typescript theme={null}
import { erc20Abi, formatUnits, getAddress } from "viem";

const accountInput = process.env.ACCOUNT_ADDRESS;
if (!accountInput) throw new Error("Set ACCOUNT_ADDRESS.");
const account = getAddress(accountInput);
const token = getAddress("0x000000000000000000000000000000000000b5d5");
const blockNumber = await client.getBlockNumber({ cacheTime: 0 });
const balanceBefore = await client.readContract({
  address: token, abi: erc20Abi, functionName: "balanceOf",
  args: [account], blockNumber,
});
const decimals = await client.readContract({
  address: token, abi: erc20Abi, functionName: "decimals", blockNumber,
});
const displayBalance = formatUnits(balanceBefore, decimals);
```

Keep `balanceBefore` in integer base units to compare it with the amount
received after funding. For the 18-decimal `*USDZ` token,
`1000000000000000000` base units represents one token. Reading this balance
requires no signature or transaction fee.

## Request funds

Open the [faucet](https://faucet.metalntwx.com), paste `ACCOUNT_ADDRESS`, select
`*USDZ`, and choose **Request funds**. Wait for **Funded**, then follow
**View transaction** to inspect the transaction receipt.

For automated test accounts, request funds over HTTP.
The public endpoint accepts JSON with `address` and `symbol`. The API symbol
is `USDZ`, without the leading asterisk shown in the UI. No sign-in or
transaction signature is required.

```bash theme={null}
curl --fail-with-body --silent --show-error \
  https://faucet.metalntwx.com/api/fund \
  -H "content-type: application/json" \
  --data "{\"address\":\"$ACCOUNT_ADDRESS\",\"symbol\":\"USDZ\"}" \
  --output funding-response.json
```

On success, `funding-response.json` contains:

| Field | Meaning |
| - | - |
| `address` | Funded account |
| `symbol` | Requested token symbol, such as `USDZ` |
| `amount` | Base units transferred, encoded as a decimal string |
| `txHash` | Hash of the successfully executed funding transaction |

The faucet tops up the selected token to its grant target. For `*USDZ`, that
target is 100 tokens. An account holding 25 receives 75 while an account holding
100 or more receives an `already_funded` response. Other tokens may have
a larger target to cover gas. The response's `amount` is the amount sent,
which can differ from the account's resulting balance.

## Verify funding

After the funding transaction succeeds, read `balanceOf(account)` at a fresh
block number. Check that the account and token match the funding request, then
compare the new balance with `balanceBefore`. If the account had no other activity,
the increase must equal the response's `amount`. Compare these values as
integers in base units.

Look up `txHash` in the [testnet explorer](https://testnet.metalntwx.com) at
`/tx/<txHash>`. Confirm a successful receipt and a transfer of the expected
token and amount to the test account. Read the receipt programmatically
with viem's `getTransactionReceipt({ hash })`. Funding is complete when the
successful transaction and the account's token balance agree.

## Handle refusals and uncertain results

Faucet application errors return a non-success HTTP status and a JSON object
with top-level `code` and `message` fields. Keep the response for diagnosis and
use the code to choose the next step from the table below.

An upstream service may return a non-JSON error, including a `429` for rapid
requests. Check the HTTP status and handle parsing failures. Back off before
retrying a rate-limited request.

| Result | Next step |
| - | - |
| `invalid_address` (400) | Supply a complete, nonzero EVM account address |
| `unknown_currency` (400) | Use a symbol offered by the faucet, without `*` |
| `already_funded` (409) | Read the selected token balance. The account already holds a full grant |
| `client_rate_limited` (429) | Wait the returned `retryAfter` seconds before retrying |
| `client_daily_limit_reached` or `daily_limit_reached` (429) | Retry after the next UTC day begins |
| `rpc_error` (502) | Retry. The faucet could not read the balance and sent nothing |
| `state_unavailable` (503) | Retry shortly. The faucet could not reserve the request and sent nothing |
| `missing_client_ip` (400) | Send the request to the faucet's public hostname, `https://faucet.metalntwx.com` |
| `funding_failed` (502), timeout, or connection loss | Check the account's balance and explorer history before retrying |

The faucet limits grants by client IP and across the service, so developers
on the same network may share a limit. Check
[faucet status](https://faucet.metalntwx.com/healthz) for the offered symbols and
the `limits.clientCooldownSeconds`, `limits.clientDailyGrants`, and
`limits.dailyGrants` values. Use those limits to space requests and reuse
funded test accounts.


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