Skip to main content

Solana (SOL)

Sign Solana transactions and messages. The most reliable input is a base58-serialized transaction; plain-JSON and several data encodings are also accepted.

FieldValue
FamilySolana
coinType501
keyPathm/44'/501'/<accountIdx>'
chainIdsolana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp/slip44:501

Supported Methods

MethodSupported
getAddress
signTransaction
signMessage
signTypedData

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.

MethodDCENT Biometric WalletDCENT X
getAddress2.16.5 or higher1.0.0 or higher
signTransaction2.16.5 or higher1.0.0 or higher
signMessage2.31.0 or higher1.0.0 or higher
info

Firmware versions below are for the DCENT Biometric Wallet line — DCENT X supports them from 1.0.0. SPL token support was added in firmware 2.17.1.

getAddress — account address

Retrieves the Solana account address for a chainId + keyPath. A Solana address is the base58-encoded ed25519 public key (32 bytes); there are no address variants, so addressFormat does not apply.

Parameters

FieldTypeRequiredSourceNotes
chainIdstringRequiredAppFull CAIP-19 — solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp/slip44:501
keyPathstringRequiredAppBIP-44, default m/44'/501'/0'

Request

await dcent.getAddress({
chainId: 'solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp/slip44:501',
keyPath: "m/44'/501'/0'"
})

Response

FieldTypeNotes
parameter.addressstringBase58 ed25519 account address — this is the Solana address
parameter.pubkeystring (hex, optional)Raw 32-byte ed25519 public key; same key material as the address
header.statusstring"success" on success
{
"header": {
"version": "1.0",
"status": "success"
},
"body": {
"command": "getAddress",
"parameter": {
"address": "7Eq…",
"pubkey": "ab12…"
}
}
}

signTransaction

payload.transaction:

"4uQeVj5tqViQh7yWWGStvkEG1Zmhx6u…" // bs58.encode(tx.serialize({ requireAllSignatures:false }))

Variant — plain JSON

payload.transaction:

{
"version": 0,
"feePayer": "<pubkey>",
"instructions": [
{
"programId": "11111111111111111111111111111111",
"keys": [
{
"pubkey": "<from>",
"isSigner": true,
"isWritable": true
},
{
"pubkey": "<to>",
"isSigner": false,
"isWritable": true
}
],
"data": {
"instruction": 2,
"lamports": 1000000
}
}
],
"recentBlockhash": "<blockhash>"
}
FieldTypeRequiredSourceNotes
feePayerpubkeyRequired-RealWalletUsually the signer
instructions[].keysmeta[]Required-RealAppReal account metas / ATAs
recentBlockhashstringRequired-RealAppReal, current blockhash — the app must supply it (form-E); not auto-filled
info

form-E — completed serialized message. The device can only show a friendly label if it recognizes the token locally — use the form-D descriptor below to guarantee a labeled display for any token. SPL token transfer: programId = Tokenkeg…, data = 0x0c + amount (u64 LE) + decimals (u8), keys = [source ATA, mint, dest ATA, owner] — all four are Required-Real, plus a real feePayer + recentBlockhash (form-E).

info

form-D — structured SPL token transfer. Instead of instructions, send transaction.token = { contract (mint), to (the recipient's owner wallet, not an ATA), amount (base units), decimals, symbol }. This is the only shape in which the device can show an SPL token's symbol and amount — a form-E serialized message is signed as opaque bytes. Because the bridge signs with no network access, a Solana form-D transfer must also carry a sender (the fee-paying wallet — without it the call fails with param_error) and these completed fields: recentBlockhash (base58 32-byte, no surrounding whitespace), preparedFee.fee (positive integer lamports — this is what the device displays as the fee), and extra.isAssociated (boolean — whether the recipient's associated token account already exists; false makes the bridge add an ATA-create instruction). Missing any of the three gives -32602. Do not send the recipient ATA — the bridge derives it offline from owner + mint, so what the device shows cannot be redirected by the app.

Response

FieldTypeNotes
parameter.signaturestring (base58)The complete, fully-signed Solana transaction, serialized and base58-encoded — broadcast-ready via sendRawTransaction / sendTransaction. This is the whole signed transaction, not a bare 64-byte signature.
header.statusstring"success" on success
{
"header": {
"version": "1.0",
"status": "success"
},
"body": {
"command": "signTransaction",
"parameter": {
"signature": "4uQe…"
}
}
} // base58 fully-signed serialized tx

signMessage

await dcent.sign({
method: 'signMessage',
chainId: 'solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp/slip44:501',
payload: {
keyPath: "m/44'/501'/0'",
message: '<bytes>',
meta: {
kind: 'raw'
}
}
})

Response

FieldTypeNotes
parameter.signaturestringed25519 signature (64 bytes) over the message bytes
header.statusstring"success" on success
{
"header": {
"version": "1.0",
"status": "success"
},
"body": {
"command": "signMessage",
"parameter": {
"signature": "…"
}
}
} // ed25519 signature over the message

Common Mistakes

danger

Expired blockhash — fetch recentBlockhash immediately before signing. Unsigned VersionedTransaction — serialize with requireAllSignatures:false. Placeholder ATAs — source/dest ATAs must be the real on-chain accounts.