Skip to main content

Core Concepts

Four ideas you reuse on every call: chainId, keyPath, the V1Response envelope, and the field-semantics legend used throughout the Chain Reference.

chainId — CAIP-2 / CAIP-19

Every request targets a network by its chainId string. The authoritative list ships in the connector's playground/chains.json (150 entries — the matrix and its family lists cover mainnets and EVM testnets; 21 non-EVM testnets, Kaia Kairos, and Cardano mainnet live only in that file). Examples:

NetworkchainId
Ethereumeip155:1/slip44:60
Bitcoinbip122:000000000019d6689c085ae165831e93/slip44:0
Solanasolana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp/slip44:501
Cosmoscosmos:cosmoshub-4/slip44:118
info

The connector treats chainId as an opaque whitelisted string (charset A-Z a-z 0-9 _ : / . + -). It never branches on chain. The chainId must match the listed value exactly — including the /slip44:NN suffix (e.g. eip155:1/slip44:60). Copy it from playground/chains.json verbatim. Three of its entries cannot be reached in this release — the two Cardano networks and Horizen are rejected with unsupported_method.

keyPath — BIP-44

Derivation path m/44'/{coinType}'/{account}'/{change}/{index}. DCENT keeps purpose 44' consistently. keyPath is required on every sign() call.

The <accountIdx> slot (the {account} segment above) is the account index — increment it to derive additional accounts. Most chains vary it at the account-hardened position m/44'/{coinType}'/<accountIdx>'/0/0; a few differ — Conflux, Solana, Stellar, Hedera and NEAR are 3-level m/44'/{coinType}'/<accountIdx>', Tezos is 4-level m/44'/1729'/<accountIdx>'/0', and EVM Vendor Lock-In variants move it to the address slot m/44'/60'/0'/0/<accountIdx>. BTC-family multi-address chains additionally expose <isChange> (receive 0 / change 1) and <addressIdx>.

V1Response envelope

Every call resolves to the same shape:

{
header: {
version: string,
status: 'success' | 'failure',
request_from?: string,
response_from?: string
},
body: {
command?: string, // 'transaction' | 'getAddress' | …
parameter?: {

}, // success payload (per method)
error?: {
code: string,
message: string
} // failure
}
}

Success → header.status === 'success' + body.parameter. Failure → body.error. Full per-method table on the V1Response page.

Field-semantics legend

Parameter tables in the Chain Reference annotate every field so you know what you must supply versus what the bridge fills in:

AnnotationMeaning
Required-RealMust be the device's real address / account / UTXO. A placeholder fails or risks funds. Source: Wallet
Auto-filledGenerated by the bridge locally (e.g. a timestamp) — you do not supply it. The bridge performs no RPC — the single exception is Polkadot, which reads runtime metadata for display safety — so consensus-fresh values (nonce, sequence, blockhash, fee) are never fetched for you: those are Required-Real and must come from your app, or the call fails with param_error.
Optional / FixedOptional field, or a fixed-format constant.
UnitAmount unit — wei, satoshi, drops, lamports, uatom, …
Utildcent.unitConverter(val, decimals){ num, bignum } — converts a decimal amount string to base units (e.g. wei/satoshi). Use .num for a payload amount/value field: unitConverter('1.5', 18).num'1500000000000000000'.

Token descriptors — sending token metadata

Token metadata — symbol and decimals — is what lets the device show a human-readable amount instead of raw base units. The DCENT Web Bridge never looks token metadata up on-chain for you. Always supply it yourself, for every token transfer, via a form-D descriptor: put the token under transaction.token with its symbol and decimals, and the bridge uses that decimals directly so the device shows the correct token name and amount. There is nothing to check beforehand — send the descriptor and it works the same way for any token.

payload.transaction:

{
"token": {
"contract": "…", // token id: contract address / denom / assetIndex
"to": "…", // recipient
"amount": "1000", // base units — already ×10^decimals, no rescaling
"decimals": 6, // lets the device show the human amount
"symbol": "TKN" // label shown on the device screen
},
"from": "…" // your device account (sender; read-only)
}
FieldTypeRequiredNotes
contractstringRequiredToken identifier — contract address, denom, or asset-id (per family)
tostringRequiredRecipient address
amountstringRequiredBase units — already ×10^decimals; do not rescale
decimalsnumberRequiredToken decimals — lets the device show the human amount
symbolstringOptionalDisplay symbol shown on the device screen — display metadata only, not used for resolution

These five fields are the token object. The sender sits alongside it, not inside — from, or owner_address on TRON.

The descriptor lives under transaction.token = { contract, to, amount, decimals, symbol }. The sender is read from the family's usual field (from, or owner_address on TRON). amount is in base units — do not rescale it by decimals. Available on the nine families listed in the table below — Stellar, Hedera and Tezos do not accept a descriptor at all (third row).

info

A descriptor only supplies display metadata — it never bypasses signing. The device still signs the exact transfer bytes, so the amount and recipient shown on screen must match what you send.

form-D vs form-E — two ways a token transfer reaches the device

The same transfer can arrive in one of several shapes; which one you send decides whether an unregistered token can be signed at all:

FormFamiliesUnregistered token
form-D + decimals
structured transaction.token
EVM · Kaia · TRON · Cosmos · Algorand · Havah · Stacks · Solana · VeChain · NEAR · Hedera · Constellation · Stellar (issued assets only) · Tezos (FA1.2/FA2 — the only path, form-E deprecated 2026-07-21) (14)descriptor supported → the supplied decimals are used as-is, so it displays + signs
form-E
native encoded tx; no descriptor
EVM · Kaia · TRON · Cosmos · Algorand · Havah · Stacks · Solana · VeChain · NEAR (10 — not Stellar/Tezos/Hedera/Constellation, see below)EVM · Kaia: still signs, but as a plain contract call — the device shows no token symbol/amount (graceful fallback). Everything else: rejected — -32602. The bridge signs with no network access, so it cannot look decimals up for you
native asset — no registry at all
token is a first-class field in the chain's own tx format
XRP / Xahau (issued currency — {currency, issuer, value}) (2)Not applicable — there is no DCENT registry step to pass or fail. Any issuer the app supplies signs; the IOU value is a decimal string in the transaction itself, so there is no separate decimals field to gate
blob passthrough
pre-built signing bytes
Stellar ({xdr} envelope — native XLM payments and Soroban invocations only) · Tezos (unsignedTx, pre-forged — fallback for operations outside the structured/form-D paths) · Hedera (unsignedTx — fallback for HTS operations beyond a plain transfer, e.g. mint/associate) · Polkadot ({extra.scaleHex} SCALE-encoded extrinsic — the app must encode assets.transfer itself; the native structured path is registry-gated the same way as Conflux) (4)For Stellar / Tezos / Hedera: not the deciding factor — these already have a form-D path for plain token transfers, blob passthrough is only for what form-D does not cover. For Polkadot: this is the only way to move an unregistered token — the app must build the fully-encoded bytes itself (blind-sign, no device symbol/amount display)

Constellation sits outside the family list above in spirit but is included in the form-D row — see its own note on the Constellation page for the metagraph-specific caveats (trust model differs between registered and unregistered metagraphs even though both sign).

Conflux has no form-D path — its token transfers go through a synthesized TokenAccount that requires the token to already be in DCENT's currency registry (currency.currencyUnits[0] supplies decimals/symbol). An unregistered CRC-20 token still signs on Conflux — the plain native-transfer data field is never interpreted or gated, so a hand-built transfer(address,uint256) calldata passes through byte-for-byte (same graceful pass-through family as EVM/Kaia's form-E, verified on real hardware 2026-07-26). The catch: the device confirmation screen shows only the outer native-transfer fields (to = the token contract, amount = 0 CFX) — it never surfaces the real recipient or token amount buried in data. This is a display-only gap, not a signing-safety issue: the signed bytes are exactly what you sent. Polkadot's native assets.transfer path has the identical registry gate (account.currency.contractAddress, same TokenAccount pattern) — but unlike Conflux, Polkadot has a SCALE-hex blob passthrough (see row above) that lets an app blind-sign an assets.transfer extrinsic for an unregistered asset.

The Bitcoin-family coins (Bitcoin, Bitcoin Cash, Litecoin, Dogecoin, Dash, eCash, Zcash, Bitcoin Gold, DigiByte, Ravencoin) and Filecoin have no token-transfer concept in the wire protocol at all (native-asset-only families) — this table does not apply to them.

form-E (encoded) is the chain's native transaction passed through as-is — EVM/Kaia raw calldata (0xa9059cbb…), TRON raw_data, Solana VersionedTransaction, NEAR ft_transfer FunctionCall, VeChain clause { to, data, value }. Rule of thumb: send form-D + decimals whenever the token might not be on DCENT's supported list — that is the shape that signs an unregistered token on most families, and on Stellar / Tezos / Hedera / Constellation it is the only shape that does. XRP/Xahau skip this question entirely — their tokens were never gated by a DCENT registry. Polkadot is registry-gated on its native/structured path, but has a blind-sign blob-passthrough escape hatch (see table above) — so an unregistered token can still move, just without a device-displayed symbol/amount. Conflux is the one family with no unregistered-token path at all, blob passthrough included. form-E stays valid for a registered token on the families that support it, and remains how you express anything that is not a plain transfer.

warning

Source decimals from the chain, not a guess. The device renders the on-screen amount by scaling with decimals — a wrong value shows the user a wrong amount, exactly the mis-display that signing only known tokens used to prevent. Read decimals from the token contract's decimals() or a chain RPC. Sourcing it from the chain is what keeps unregistered-token signing as safe as a registered token.