Conflux (CFX)
Sign Conflux Core Space transactions. The fields are EVM-style, but addresses use the CIP-37 base32 format (cfx:…) — the device firmware expects base32, not hex.
| Field | Value |
|---|---|
| Family | Conflux (Core Space) |
| coinType | 503 in the chainId (slip44:503); keys are derived on the EVM path m/44'/60' |
| keyPath | m/44'/60'/<accountIdx>' |
| amount unit | Drip |
| chainId | conflux:cfx/slip44:503 |
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.18.3 or higher | 1.0.0 or higher |
signTransaction | 2.18.3 or higher | 1.0.0 or higher |
Conflux derives keys on the EVM path m/44'/60'/0' even though the chainId's slip44 segment is 503. The path and the coinType are intentionally different.
getAddress — account address
Retrieves the Conflux Core Space account address. On DCENT X it returns a CIP-37 base32 address (cfx:…), not a hex address.
| Field | Type | Required | Source | Notes |
|---|---|---|---|---|
chainId | string | Required | App | Full CAIP-19 — conflux:cfx/slip44:503 |
keyPath | string | Required | App | BIP-44 EVM path — m/44'/60'/0' |
Request
await dcent.getAddress({
chainId: 'conflux:cfx/slip44:503',
keyPath: "m/44'/60'/0'"
})
Response
| Field | Type | Description |
|---|---|---|
header.status | string | success on completion |
body.command | string | getAddress |
body.parameter.address | cfx address | Account address in CIP-37 base32 (cfx:…) on DCENT X; mainnet prefix is cfx: |
{
"header": {
"version": "1.0",
"status": "success",
"response_from": "getAddress"
},
"body": {
"command": "getAddress",
"parameter": {
"address": "cfx:…"
}
}
}
signTransaction — Core Space transaction
payload.transaction:
{
"from": "cfx:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa0sfbnjm2",
"to": "cfx:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa0sfbnjm2",
"value": "0x10",
"gas": "0x5208",
"gasPrice": "0x3b9aca00",
"nonce": "0x0",
"chainId": "0x405",
"epochHeight": "0x0",
"storageLimit": "0x0",
"data": "0x"
}
| Field | Type | Required | Source | Description |
|---|---|---|---|---|
from | cfx address | Optional | Wallet | Device CFX account in CIP-37 base32 (cfx:…). Not used for signing and not checked — the signer is always the keyPath account |
to | cfx address | Required-Real | App | Recipient in CIP-37 base32 (cfx:…) |
value | hex | Optional | App | Amount in Drip — 0x10 = 16 Drip (1 CFX = 1e18 Drip). Omitted → 0 |
gas | hex | Required | App | 0x5208 = 21000 (plain transfer) |
gasPrice | hex | Required | App | Price per gas in Drip — 0x3b9aca00 = 1e9 |
nonce | hex | Required-Real | App | Real, current sender transaction count — the app must supply it; not auto-filled |
chainId | hex | Optional | App | Ignored — the bridge always signs with chain id 1029 (Conflux mainnet) |
epochHeight | hex | Required-Real | App | Real, current Conflux epoch height — the app must supply it; not auto-filled |
storageLimit | hex | Required | App | Collateral storage cap; 0x0 for plain transfer |
data | hex | Optional | App | 0x for a plain transfer; contract calldata otherwise |
Request
await dcent.sign({ method: 'signTransaction',
chainId: 'conflux:cfx/slip44:503',
payload: { keyPath: "m/44'/60'/0'",
transaction: {
"from": "cfx:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa0sfbnjm2",
"to": "cfx:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa0sfbnjm2",
"value": "0x10", "gas": "0x5208", "gasPrice": "0x3b9aca00",
"nonce": "0x0", "chainId": "0x405", "epochHeight": "0x0",
"storageLimit": "0x0", "data": "0x" } } })
Response
| Field | Type | Description |
|---|---|---|
header.status | string | success on completion |
body.command | string | signTransaction |
body.parameter.signature | hex | The RLP-encoded signed Core Space transaction (not a bare signature). A native CFX transfer returns it as bare hex (no 0x); a CRC-20 transfer returns it 0x-prefixed — add 0x if it is missing before cfx_sendRawTransaction |
{
"header": {
"version": "1.0",
"status": "success",
"response_from": "signTransaction"
},
"body": {
"command": "signTransaction",
"parameter": {
"signature": "<signed tx hex>"
}
}
}
Variant — CRC-20 token transfer (raw calldata)
Only for a token on DCENT's supported list. The bridge recognizes the transfer(address,uint256) calldata and signs it as a token transfer of that registered CRC-20 token. For a token that is not on the list, this shape is rejected with param_error (-32602) — send the form-D descriptor below with decimals instead.
payload.transaction:
{
"from": "cfx:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa0sfbnjm2",
"to": "cfx:achc8nxj7r451c223m18w2dwjnmhkd6rxawrvkvsy2",
"value": "0x0",
"gas": "0x186a0",
"gasPrice": "0x3b9aca00",
"nonce": "0x0",
"chainId": "0x405",
"epochHeight": "0x6a1b2c",
"storageLimit": "0x0",
"data": "0xa9059cbb0000000000000000000000001cad0b19bb29d4674531d6f115237e16afce377c0000000000000000000000000000000000000000000000000de0b6b3a7640000"
} // to = FansCoin (FC) contract, a registered token (CIP-37 base32); data = transfer(address,uint256) selector + recipient + amount (1 FC)
| Field | Type | Required | Source | Description |
|---|---|---|---|---|
to | cfx address | Required-Real | App | The token contract, in CIP-37 base32 (cfx:…) — must be a token on DCENT's supported list |
value | hex | Optional | App | 0x0 (or omit) for a token call |
data | hex | Required | App | ABI-encoded transfer(address,uint256) — 0xa9059cbb + 32-byte recipient + 32-byte base-unit amount |
Variant — CRC-20 token transfer, unregistered token (form-D)
For a CRC-20 token that is not on DCENT's supported list, put the token under transaction.token with its decimals (see form-D vs form-E). The bridge builds the transfer(address,uint256) call itself. Do not send a non-zero data or a non-zero value alongside token — either is rejected with param_error (-32602).
payload.transaction:
{
"from": "cfx:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa0sfbnjm2",
"gas": "0x186a0",
"gasPrice": "0x3b9aca00",
"nonce": "0x0",
"chainId": "0x405",
"epochHeight": "0x6a1b2c",
"storageLimit": "0x0",
"token": {
"contract": "cfx:acg158kvr8zanb1bs048ryb6rtrhr283ma70vz70tx",
"to": "0x1cad0b19bb29d4674531d6f115237e16afce377c",
"amount": "1000000000000000000",
"decimals": 18,
"symbol": "WCFX"
}
} // token.contract = WCFX (not on the supported list); amount in base units (1 WCFX)
Common Mistakes
Hex (0x…) addresses instead of CIP-37 base32 — Conflux Core Space addresses are cfx:…. A hex address (to, or token.to) is converted to cfx: base32 by the bridge before it reaches the device, so either form works; base32 matches the format the device shows. Using a testnet address — only Conflux mainnet is supported (chain id 1029, cfx: addresses). A cfxtest: address is rejected for a token transfer (-32602); don't use one for a native transfer either. Confusing coinType with keyPath — coinType is 503 but derivation uses the EVM path m/44'/60'/0'. Stale epochHeight — it bounds transaction validity; refresh it near the current epoch or the network rejects the tx.