The Filecoin wallet service owns Filecoin / Filecoin Pay key derivation, Synapse session setup, IPFS DAG export, and CAR upload for the filecoin-mediator. The mediator calls this service instead of holding any wallet material itself.
The wallet derives an FEVM-compatible f410 address from the Keymaster
mnemonic and uses it as the Filecoin Pay payer for Synapse uploads. The
default derivation path is m/44'/461'/0'/0/0 (BIP-44 coin type 461 =
Filecoin).
The canonical implementation is services/mediators/filecoin-wallet/.
Related specs. The filecoin-wallet is invoked exclusively by the filecoin-mediator. It pulls its mnemonic from the Keymaster and reads CAR data from the local IPFS HTTP API (Kubo-compatible).
A single synchronous pin endpoint plus a small status surface. There is
no background loop, no chain scanner, and no /wallet/send /
/wallet/anchor routes — Filecoin Pay handles deposits implicitly
during upload and there is no concept of an Archon “anchor” on Filecoin.
POST /api/v1/wallet/pin)For each request:
POST ${ARCHON_IPFS_API_URL}/dag/export?arg=<cid> — fetch the CAR
bytes for the requested CID from the local IPFS node. (Kubo’s HTTP
RPC uses POST for all endpoints, even read-only ones.)os.tmpdir().initializeSynapse) with the
derived private key and the configured chain (mainnet or
calibration).synapse.storage.prepare({ dataSize }) — if Filecoin Pay needs a
deposit or approval to cover the upload, execute that transaction
first and record the deposit tx hash.checkUploadReadiness({ synapse, fileSize }) — fail fast with
Filecoin payment not ready: <reason> if the balance still does not
cover the upload after the deposit step.executeUpload(synapse, carStream, rootCid, { pieceMetadata }) —
stream the CAR file to a Filecoin storage provider via Synapse,
attaching archonCid, archonFingerprint, and archonRegistry
piece metadata.The Synapse client is cached at module scope after first use; it is only torn down implicitly when the process restarts or when a new mnemonic is configured.
At startup the service polls GET ${ARCHON_KEYMASTER_URL}/api/v1/wallet/mnemonic
(with X-Archon-Admin-Key) up to 12 times with a 10 s backoff. If all
attempts fail, the service starts anyway with wallet_setup_status = 0
and every pin request will return 500 until Keymaster recovers and
the process is restarted.
All /api/v1 routes are mounted at /api/v1 and require X-Archon-Admin-Key
matching ARCHON_ADMIN_API_KEY. The admin key is mandatory:
ARCHON_ADMIN_API_KEY must be set or every /api/v1/* request is
rejected with 403 { "error": "Admin API key not configured" }. With
the key set, a missing header returns 401 { "error": "Admin API key
required" } and a mismatched header returns
401 { "error": "Invalid admin API key" } (constant-time compared).
GET /api/v1/wallet/version{
"version": "0.4.0",
"commit": "abcd123",
"network": "calibration",
"address": "0x…", // null if wallet setup failed
"derivationPath": "m/44'/461'/0'/0/0",
"ipfsApiUrl": "http://ipfs:5001/api/v0"
}
GET /api/v1/wallet/balanceReturns the full Filecoin Pay payment status from
filecoin-pin/core/payments.getPaymentStatus, with all BigInts
serialised as decimal strings:
{
"address": "0x…",
"filBalance": "<atto-FIL string>",
"usdfcBalance": "<USDFC string>",
"paymentsApproved": true,
"depositedUsdfc": "<string>",
// …additional fields from filecoin-pin's PaymentStatus
"derivationPath": "m/44'/461'/0'/0/0"
}
This is the canonical place for the operator to see how much FIL /
USDFC the wallet has. The filecoin-mediator does not call this
endpoint preemptively — it only calls wallet/version (for the
funding address) after a pin failure that mentions insufficient funds.
POST /api/v1/wallet/pinRequest:
{
"cid": "bafy…", // required, the IPFS CID to pin
"fingerprint": "<sha256 hex>", // optional, echoed back and into piece metadata
"registry": "BTC:mainnet" // optional, original Archon registry
}
Response (WalletPinResult):
{
"requestid": "<uuid v4>",
"status": "pinned",
"cid": "bafy…",
"fingerprint": "<echo>",
"registry": "<echo>",
"filecoin": {
"pieceCid": "baga…",
"network": "calibration",
"ipniValidated": true,
"depositTx": "0x…" // present only if Filecoin Pay deposit was made this call
}
}
Errors:
| Status | Body | Cause |
|---|---|---|
400 |
{ "error": "Missing or invalid \"cid\"" } |
cid missing or not a string. |
400 |
{ "error": "Invalid \"fingerprint\"" } / Invalid "registry" |
Provided fields not strings. |
500 |
{ "error": "Filecoin payment not ready: …" } |
Filecoin Pay balance insufficient after attempted top-up. The mediator detects Insufficient FIL / USDFC in this message and logs the funding address. |
500 |
{ "error": "<other>" } |
IPFS export failure, Synapse error, storage provider rejection, etc. |
The endpoint is synchronous and may take minutes for large payloads (CAR export + Synapse upload + provider acknowledgement). The mediator sends each pin request with a 300 s timeout.
Separate Express app on ARCHON_FIL_WALLET_METRICS_PORT (default
4272):
| Method | Path | Body |
|---|---|---|
GET |
/health |
{ ok: true } |
GET |
/metrics |
Prometheus |
The wallet treats Filecoin as an EVM-flavoured chain (FEVM) for signing:
bip39.mnemonicToSeedSync(mnemonic) — BIP-39 seed.HDKey.fromMasterSeed(seed).derive(ARCHON_WALLET_FIL_DERIVATION_PATH)
— BIP-32 derivation. Default path m/44'/461'/0'/0/0.privateKey as 0x-prefixed hex.keccak_256(secp256k1.getPublicKey(privKey, uncompressed).slice(1)).slice(-20)
— standard EVM derivation, returned as 0x… (this is the f410
funding address for Filecoin Pay).A given mnemonic + path therefore yields a stable address across restarts and across host services that share the same Keymaster.
| Variable | Default | Meaning |
|---|---|---|
ARCHON_FIL_WALLET_PORT |
4270 |
Main HTTP API port. |
ARCHON_FIL_WALLET_METRICS_PORT |
4272 |
Metrics HTTP port. |
ARCHON_KEYMASTER_URL |
http://localhost:4226 |
Source of the wallet mnemonic. |
ARCHON_ADMIN_API_KEY |
unset | Required on every /api/v1/* request; also sent to Keymaster when fetching the mnemonic. |
ARCHON_WALLET_FIL_DERIVATION_PATH |
m/44'/461'/0'/0/0 |
BIP-32 path. |
ARCHON_FIL_NETWORK |
calibration |
mainnet or calibration. Any other value crashes at startup. |
ARCHON_FIL_RPC_URL |
unset | Optional explicit Filecoin JSON-RPC URL passed to Synapse. When unset, Synapse uses its built-in default for the selected network. |
ARCHON_IPFS_API_URL |
http://localhost:5001/api/v0 |
Kubo HTTP API. ARCHON_IPFS_URL accepted as alias. The wallet normalises trailing slashes and appends /api/v0 if missing. |
GIT_COMMIT |
unknown |
Embedded in /version and wallet_version_info. |
The wallet does not read any of the ARCHON_WALLET_BTC_*,
ARCHON_WALLET_ETH_*, or ARCHON_WALLET_ZEC_* variables; coin-type
461 isolation is intentional.
ARCHON_FIL_NETWORK value crashes here)./api/v1 admin-key guard.wallet_setup_status = 1.wallet_setup_status = 0, and start anyway so /health and
/metrics still serve.0.There is no /wallet/setup endpoint. To rotate the mnemonic, change
the Keymaster wallet and restart the filecoin-wallet container; the
Synapse client cache is cleared on configureWallet.
| Metric | Type | Notes |
|---|---|---|
filecoin_wallet_http_requests_total{method,route,status} |
Counter | Per-route HTTP request counts. |
filecoin_wallet_http_request_duration_seconds{method,route} |
Histogram | Buckets [0.001, 0.005, 0.01, 0.05, 0.1, 0.5, 1, 2, 5, 30, 120]. |
filecoin_wallet_pins_total{status="pinned"\|"failed"} |
Counter | Outcomes of POST /wallet/pin. |
wallet_setup_status |
Gauge | 1 if the mnemonic loaded and address derived, else 0. |
wallet_version_info{version,commit} |
Gauge | Always 1. |
Plus standard prom-client default process / nodejs metrics.
ghcr.io/archetech/filecoin-walletNo dedicated conformance tests. Validation is manual: stand up
filecoin-wallet against Filecoin calibration, pin a small CID (e.g. a
hello-world JSON pinned to local IPFS first via gatekeeper.addJSON),
verify wallet/balance shows the deposit, then re-pin and confirm the
second call skips the deposit transaction.
A conformant third implementation MUST:
{ cid, fingerprint?, registry? } at
POST /api/v1/wallet/pin and return the WalletPinResult shape in
§2.3, including a stable requestid per call.ARCHON_ADMIN_API_KEY and reject every
/api/v1/* request that does not present a matching
X-Archon-Admin-Key (403 when unconfigured, 401 when missing or
mismatched). The wallet has no anonymous mode.