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.
| Field | Value |
|---|---|
| Family | Constellation |
| coinType | 1137 |
| keyPath | m/44'/1137'/0'/0/<accountIdx> |
| amount unit | DATUM (1 DAG = 1e8) |
| chainId | constellation:mainnet/slip44:1137 |
| chainId · Testnet | constellation:testnet/slip44:1137 (no metagraph tokens) |
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.34.0 or higher | 1.0.0 or higher |
signTransaction | 2.34.0 or higher | 1.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.
| Field | Type | Required | Source | Notes |
|---|---|---|---|---|
chainId | string | Required | App | Full CAIP-19 — constellation:mainnet/slip44:1137 |
keyPath | string | Required | App | BIP-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
| Field | Type | Description |
|---|---|---|
header.status | string | success on completion |
body.command | string | getAddress |
body.parameter.address | string | Checksummed 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"
}
}
| Field | Type | Required | Source | Description |
|---|---|---|---|---|
type | enum | Optional | App | Transaction kind — transfer (omitting it signs the same transfer; any other value fails with -32602) |
source | string | Required-Real | Wallet | Sender DAG address — use the device account from getAddress. It is not checked against the keyPath account |
destination | string | Required-Real | App | Recipient DAG address (not checksum-validated — use a real address) |
amount | string | Required | App | DATUM as a decimal string — 1 DAG = 1e8 (here 1 DAG). Must be greater than 0, otherwise -32602 |
fee | string | Optional | App | DATUM; "0" is valid on Constellation |
lastRef | { ordinal, hash } | Required-Real | App | Last transaction reference — ordinal (number) and hash (prev tx hash) from the DAG address’s current state; the app must supply real values |
salt | string | number | Required-Real | App | Non-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
| Field | Type | Description |
|---|---|---|
header.status | string | success on completion |
body.command | string | signTransaction |
body.parameter.signature | string | The 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>"
}
}
}
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
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"
}
}
| Field | Type | Required | Source | Description |
|---|---|---|---|---|
token.contract | string | Required-Real | App | Metagraph 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.symbol | number / string | Optional (token.decimals Required for an unregistered metagraph) | App | Display metadata (DOR = 8 decimals; amount 100000000 = 1 DOR). An unregistered metagraph without token.decimals is rejected with -32602 |
source / destination / amount / fee | string | Required (fee Optional) | Wallet / App | Same 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-Real | App | Same as native — last transaction reference (ordinal + hash); the app must supply real values |
salt | string | number | Required-Real | App | Non-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'
}
}
}
})
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
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.