Filecoin (FIL)
Sign Filecoin Lotus Messages. The app builds a complete message (nonce, gas, value in attoFIL) and the device signs it with its secp256k1 key by keyPath.
| Field | Value |
|---|---|
| Family | Filecoin |
| coinType | 461 |
| keyPath | m/44'/461'/0'/0/<accountIdx> |
| amount unit | attoFIL (1 FIL = 1e18) |
| chainId | fil:f/slip44:461 |
Supported Methods
| Method | Supported |
|---|---|
| getAddress | ✓ |
| signTransaction | ✓ |
| signMessage | ✗ |
| signTypedData | ✗ |
| signData | ✗ |
Requirements
Minimum firmware for each method. The two models are on different version lines, so DCENT Biometric Wallet and DCENT X are listed separately (the numbers are not comparable across models). Below this the request returns the firmware-update error (5005) and the bridge prompts to update.
| Method | DCENT Biometric Wallet | DCENT X |
|---|---|---|
getAddress | 2.33.0 or higher | 1.0.0 or higher |
signTransaction | 2.33.0 or higher | 1.0.0 or higher |
getAddress — account address
Retrieves the Filecoin account address for a chainId + keyPath. Returns an f1 (secp256k1) address derived at the keyPath. Call this before building a message so from matches the device account.
| Field | Type | Required | Source | Notes |
|---|---|---|---|---|
chainId | string | Required | App | fil:f/slip44:461 (mainnet); the Calibration testnet is fil:t/slip44:461 (t1 addresses) |
keyPath | string | Required | App | BIP-44 path; default m/44'/461'/0'/0/0 |
Request
await dcent.getAddress({
chainId: 'fil:f/slip44:461',
keyPath: "m/44'/461'/0'/0/0"
})
Response
| Field | Type | Notes |
|---|---|---|
body.parameter.address | string | Filecoin address — f1 (secp256k1), derived at keyPath |
body.command | string | "getAddress" |
header.status | string | "success" on completion |
{
"header": {
"version": "1.0",
"status": "success",
"response_from": "getAddress"
},
"body": {
"command": "getAddress",
"parameter": {
"address": "f1…"
}
}
}
signTransaction — Lotus Message
payload.transaction:
{
"to": "f1aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaahaui6xa",
"from": "f1aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaahaui6xa",
"nonce": 0,
"value": "1000000000000000000",
"gasLimit": 500000,
"gasFeeCap": "100000",
"gasPremium": "100000",
"method": 0,
"params": ""
}
| Field | Type | Required | Source | Notes |
|---|---|---|---|---|
to | string | Required-Real | App | Recipient: f1…, f410f…, or a 0x… EVM address (signed as its f410f form; on testnet the t1… / t410f… forms). f3 (BLS) and f0 (ID) recipients fail with -32603 |
from | string | Required-Real | Wallet | Your device account. It must be present, but it is not checked and not signed — the signed message's From is always your account's address derived from keyPath (f1… on mainnet) |
nonce | number | Required-Real | App | Real, current account nonce — the app must supply it; not auto-filled |
value | string | Required | App | attoFIL; "1000000000000000000" = 1 FIL |
gasLimit | number | Required | RPC | From GasEstimateMessageGas |
gasFeeCap | string | Required | RPC | attoFIL per gas unit (max) |
gasPremium | string | Required | RPC | attoFIL tip per gas unit |
method | number | Optional | App | 0 = plain transfer (also the default when omitted or null). Only 0 (Transfer) can be signed — any other non-negative safe integer → -32601; a negative or non-integer value → -32602 |
params | string | Optional | App | Must be empty (""), null or omitted — non-empty base64 actor params → -32601; a non-string or non-base64 value → -32602 |
Request
await dcent.sign({
method: 'signTransaction',
chainId: 'fil:f/slip44:461',
payload: {
keyPath: "m/44'/461'/0'/0/0",
transaction: {
to: 'f1aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaahaui6xa',
from: 'f1aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaahaui6xa',
nonce: 0,
value: '1000000000000000000',
gasLimit: 500000,
gasFeeCap: '100000',
gasPremium: '100000',
method: 0,
params: ''
}
}
})
Response
| Field | Type | Notes |
|---|---|---|
body.parameter.signature | string | The device's secp256k1 signature over the message, as hex — not a signed message. On DCENT X it is 65 bytes (r‖s‖recovery id). To broadcast, build the Lotus Message yourself and call MpoolPush with { Message, Signature: { Type: 1, Data: <signature as base64> } }. The Message must match what was signed: From = the getAddress result for the keyPath, To in its f410f form (t410f on testnet) if you passed a 0x address, Method 0, Params "", Version 0, and the same nonce, value and gas values. |
body.command | string | "signTransaction" |
header.status | string | "success" on completion |
{
"header": {
"version": "1.0",
"status": "success",
"response_from": "signTransaction"
},
"body": {
"command": "signTransaction",
"parameter": {
"signature": "<secp256k1 signature hex>"
}
}
}
The device signs the CBOR-serialized message body. The signed From is always your secp256k1 account's address derived at keyPath (f1… on mainnet) — the from you send is not used. BLS (f3) keys are not supported.
Common Mistakes
Amounts not in attoFIL — value/gasFeeCap/gasPremium are attoFIL strings; 1 FIL = 1e18. BLS (f3) from — only secp256k1 (f1) accounts are supported; the signed From is always your account's address derived at keyPath. Stale nonce / underestimated gas — refresh nonce and the gas* fields from a live node right before signing. Non-empty params with method: 0 — plain transfers must use method 0 and params "".