Skip to main content

Constellation (DAG)

Sign Constellation (DAG / Hypergraph) transfers. The device signs a wire transaction built from a source / destination / amount shape. Addresses are not checksum-validated by the bridge, so a placeholder address is signed as-is and only fails at broadcast.

FieldValue
FamilyConstellation
coinType1137
keyPathm/44'/1137'/0'/0/<accountIdx>
amount unitDATUM (1 DAG = 1e8)
chainIdconstellation:mainnet/slip44:1137
chainId · Testnetconstellation:testnet/slip44:1137 (no metagraph tokens)

Supported Methods​

MethodSupported
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.

MethodDCENT Biometric WalletDCENT X
getAddress2.34.0 or higher1.0.0 or higher
signTransaction2.34.0 or higher1.0.0 or higher

getAddress — account address​

Retrieves the Constellation account address for a chainId + keyPath. Call before building a transfer so source can be substituted with the device account. Returns a checksummed DAG address.

FieldTypeRequiredSourceNotes
chainIdstringRequiredAppFull CAIP-19 — constellation:mainnet/slip44:1137
keyPathstringRequiredAppBIP-44 — default m/44'/1137'/0'/0/0

Request

await dcent.getAddress({
chainId: 'constellation:mainnet/slip44:1137',
keyPath: "m/44'/1137'/0'/0/0"
})

Response

FieldTypeDescription
header.statusstringsuccess on completion
body.commandstringgetAddress
body.parameter.addressstringChecksummed DAG address in Constellation (Hypergraph) format — e.g. DAG…
{
"header": {
"version": "1.0",
"status": "success",
"response_from": "getAddress"
},
"body": {
"command": "getAddress",
"parameter": {
"address": "DAG…"
}
}
}

signTransaction — transfer​

payload.transaction:

{
"type": "transfer",
"source": "DAG…",
"destination": "DAG0000000000000000000000000000000000001",
"amount": "100000000",
"fee": "0",
"salt": "0",
"lastRef": {
"ordinal": 1024,
"hash": "58ba6390b751a9e04edea64ada97024798e91519983a94f5992d6a3fd72953b1"
}
}
FieldTypeRequiredSourceDescription
typeenumOptionalAppTransaction kind — transfer (omitting it signs the same transfer; any other value fails with -32602)
sourcestringRequired-RealWalletSender DAG address — use the device account from getAddress. It is not checked against the keyPath account
destinationstringRequired-RealAppRecipient DAG address (not checksum-validated — use a real address)
amountstringRequiredAppDATUM as a decimal string — 1 DAG = 1e8 (here 1 DAG). Must be greater than 0, otherwise -32602
feestringOptionalAppDATUM; "0" is valid on Constellation
lastRef{ ordinal, hash }Required-RealAppLast transaction reference — ordinal (number) and hash (prev tx hash) from the DAG address’s current state; the app must supply real values
saltstring | numberRequired-RealAppNon-negative safe integer. dag4 generates a random salt when it is absent, and the salt is inside the signed hash — so the app must pin it to be able to rebuild the transaction for broadcast. Omitting it fails with -32602

Request

await dcent.sign({
method: 'signTransaction',
chainId: 'constellation:mainnet/slip44:1137',
payload: {
keyPath: "m/44'/1137'/0'/0/0",
transaction: {
type: 'transfer',
source: 'DAG…',
destination: 'DAG0000000000000000000000000000000000001',
amount: '100000000',
fee: '0',
salt: '0',
lastRef: {
ordinal: 1024,
hash: '58ba6390b751a9e04edea64ada97024798e91519983a94f5992d6a3fd72953b1'
}
}
}
})

Response

FieldTypeDescription
header.statusstringsuccess on completion
body.commandstringsignTransaction
body.parameter.signaturestringThe signature itself (on DCENT X, DER-encoded secp256k1 ECDSA, hex) over the transaction — not a postable transaction. To broadcast, rebuild the transaction from the same fields (including salt and lastRef) and attach this signature as its proof, together with your public key as the proof id (the response does not carry the public key)
{
"header": {
"version": "1.0",
"status": "success",
"response_from": "signTransaction"
},
"body": {
"command": "signTransaction",
"parameter": {
"signature": "<DER signature hex>"
}
}
}
info

DAG addresses include a checksum. In the playground, clicking 🔑 Resolve sender from device replaces source (always) and destination (only when it is a placeholder) with the connected wallet address. A zero-style placeholder such as DAG0000… is not a valid address — the bridge does not check it and signs it as-is.

signTransaction — metagraph L0 token transfer​

info

Token model: form-D descriptor (same pattern as Havah / Hedera / Stacks / Tezos). Always send a token descriptor ({ contract, decimals, symbol }) and it signs on mainnet (testnet rejects metagraph tokens, see below) — the signed payload is identical to a native DAG transfer (the token field never enters it); the device trusts your declared decimals/symbol for unregistered metagraphs, and shows DCENT's own verified values for registered ones. See Core Concepts → Token descriptors.

Constellation metagraph (L0) tokens are transferred with the same source / destination / amount / fee wire shape as native DAG — the signed payload is identical. The metagraph is identified out-of-band by token.contract (the metagraph id).

metagraph L0 · form-D

payload.transaction — DOR (registered):

{
"type": "transfer",
"source": "DAG…",
"destination": "DAG0000000000000000000000000000000000001",
"amount": "100000000",
"fee": "0",
"token": {
"contract": "DAG0CyySf35ftDQDQBnd1bdQ9aPyUdacMghpnCuM",
"decimals": 8,
"symbol": "DOR"
},
"salt": "0",
"lastRef": {
"ordinal": 1024,
"hash": "58ba6390b751a9e04edea64ada97024798e91519983a94f5992d6a3fd72953b1"
}
}
FieldTypeRequiredSourceDescription
token.contractstringRequired-RealAppMetagraph id (a DAG-format address). On mainnet, registered and unregistered metagraphs are both accepted — see the note below. On constellation:testnet/slip44:1137 a metagraph token is rejected with -32602. Without a non-empty string contract (or, when contract is omitted or null, its assetId / address alias), token is ignored and the request is signed as a native DAG transfer.
token.decimals / token.symbolnumber / stringOptional (token.decimals Required for an unregistered metagraph)AppDisplay metadata (DOR = 8 decimals; amount 100000000 = 1 DOR). An unregistered metagraph without token.decimals is rejected with -32602
source / destination / amount / feestringRequired (fee Optional)Wallet / AppSame wire fields as a native DAG transfer; source should be the device account; the bridge does not check it. An omitted fee is signed as 0
lastRef{ ordinal, hash }Required-RealAppSame as native — last transaction reference (ordinal + hash); the app must supply real values
saltstring | numberRequired-RealAppNon-negative safe integer. dag4 generates a random salt when it is absent, and the salt is inside the signed hash — so the app must pin it to be able to rebuild the transaction for broadcast. Omitting it fails with -32602

Request

await dcent.sign({
method: 'signTransaction',
chainId: 'constellation:mainnet/slip44:1137',
payload: {
keyPath: "m/44'/1137'/0'/0/0",
transaction: {
type: 'transfer',
source: 'DAG…',
destination: 'DAG0000000000000000000000000000000000001',
amount: '100000000',
fee: '0',
salt: '0',
token: {
contract: 'DAG0CyySf35ftDQDQBnd1bdQ9aPyUdacMghpnCuM',
decimals: 8,
symbol: 'DOR'
},
lastRef: {
ordinal: 1024,
hash: '58ba6390b751a9e04edea64ada97024798e91519983a94f5992d6a3fd72953b1'
}
}
}
})
info

An unregistered metagraph — e.g. token: { contract: 'DAG7X5idd4aLfp4XC6WQdG1eDfR3LGPVEwtUUB2W', decimals: 8, symbol: 'UNREG' } — signs the same way as a registered one. The only difference is trust: for a registered metagraph the device shows DCENT's own verified symbol/decimals; for an unregistered one it shows whatever your app declared, with no cryptographic binding to the real token. Because the signed payload is identical to a native DAG transfer, the signature itself does not identify the metagraph — get token.contract right.

Common Mistakes​

danger

Placeholder zero-address — EVM/Solana-style DAG0000… is not rejected by the bridge; it is signed as-is and fails at broadcast. Use a real getAddress result for source / destination. Amount not in DATUM — amount is an integer string in DATUM, not DAG (1 DAG = 1e8 DATUM). source not the device account — source must be the wallet's own DAG address. DCENT X does not check it and signs anyway.