HAVAH (HVH)
Sign HAVAH transactions. HAVAH is an ICON-family chain, so transactions use the ICON-native wire shape (from/to/value/stepLimit/nid/nonce). The bridge converts this wire into a HavahTransaction before the device signs.
| Field | Value |
|---|---|
| coinType | 858 |
| keyPath | m/44'/858'/<accountIdx>'/0/0 |
| amount unit | loop |
| chainId | havah:mainnet/slip44:858 |
Supported Methods
| Method | Supported |
|---|---|
| getAddress | ✓ |
| signTransaction | ✓ |
| signMessage | ✗ |
| signTypedData | ✗ |
| signAuthEntry | ✗ |
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.26.0 or higher | 1.0.0 or higher |
signTransaction | 2.26.0 or higher | 1.0.0 or higher |
getAddress — account address
Retrieves the HAVAH account address for a chainId + keyPath. HAVAH uses the ICON-family hx… address format (there are no address variants). Call this before building a transaction so from matches the device account.
| Field | Type | Required | Source | Description |
|---|---|---|---|---|
chainId | string | Required | App | Full CAIP-19 id — havah:mainnet/slip44:858 |
keyPath | string | Required | App | BIP-44 derivation path — default m/44'/858'/0'/0/0 |
Request
await dcent.getAddress({
chainId: 'havah:mainnet/slip44:858',
keyPath: "m/44'/858'/0'/0/0"
})
Response
| Field | Type | Description |
|---|---|---|
header.status | string | success on a completed request |
body.command | string | Echoes the method — getAddress |
body.parameter.address | string | HAVAH account address in ICON-family hx… format |
{
"header": {
"version": "1.0",
"status": "success"
},
"body": {
"command": "getAddress",
"parameter": {
"address": "hx…"
}
}
}
signTransaction — ICON-native wire
Variant — native HVH transfer
payload.transaction:
{
"from": "hx0000000000000000000000000000000000000000",
"to": "hx0000000000000000000000000000000000000000",
"value": "0xDE0B6B3A7640001",
"stepLimit": "0x186a0",
"stepPrice": "0x2e90edd000",
"timestamp": "0x0",
"nid": "0x100",
"nonce": "0x1",
"version": "0x3"
}
| Field | Type | Required | Source | Description |
|---|---|---|---|---|
from | string | Required-Real | Wallet | Device HAVAH account (hx…) |
to | string | Required-Real | App | Recipient (hx… for native send) |
value | hex | Required | App | Amount in loop, 0x-prefixed hex (1 HVH = 1e18 loop). Keep as hex — values exceed MAX_SAFE_INTEGER |
stepLimit | hex | Required | App | Step (gas) limit, hex. When provided together with stepPrice the bridge builds a self-contained preparedFee |
stepPrice | hex | Required-Real | App | Real, current step price, hex — the app must supply it; a stale/zero value is rejected |
timestamp | hex | Required-Real | App | ICON microsecond epoch. The wallet never fills this in — the value you send is the one that is signed. Omitting it fails with -32602 |
nid | hex | Required | App | Network id — 0x100 for mainnet |
nonce | hex | Optional | App | Transaction nonce, hex |
version | hex | Required | App | ICON tx version — 0x3 |
js — Request:
await dcent.sign({
method: 'signTransaction',
chainId: 'havah:mainnet/slip44:858',
payload: {
keyPath: "m/44'/858'/0'/0/0",
transaction: {
from: "hx0000000000000000000000000000000000000000",
to: "hx0000000000000000000000000000000000000000",
value: "0xDE0B6B3A7640001",
stepLimit: "0x186a0",
stepPrice: "0x2e90edd000",
timestamp: "0x0",
nid: "0x100",
nonce: "0x1",
version: "0x3"
}
}
}) // → body.parameter.signature
Response
| Field | Type | Description |
|---|---|---|
header.status | string | success on a completed signature |
body.command | string | Signing command echo — signTransaction |
body.parameter.signature | string | Broadcast-ready serialized signed HAVAH (ICON) transaction, not a bare r/s/v signature. Submit it as-is to a HAVAH node |
{
"header": {
"status": "success"
},
"body": {
"command": "signTransaction",
"parameter": {
"signature": "0x…"
}
}
}
Variant — HSP-20 token transfer
Token model: form-D descriptor. Always send the token's symbol and decimals under transaction.token — the bridge signs with no network access and uses the decimals you supply directly, so the device shows the correct token name and amount. See Core Concepts → Token descriptors.
HSP-20 (IRC-2-like) tokens use the ICON call data shape. to is the token contract (cx…), the real recipient is data.params._to, and native value stays 0x0 (no native HVH moves).
payload.transaction:
{
"dataType": "call",
"from": "hx0000000000000000000000000000000000000000",
"to": "cxd7fed2ae1d9b2314087520efe1870c33e5c5baa4",
"value": "0x0",
"stepLimit": "0x186a0",
"stepPrice": "0x2e90edd000",
"timestamp": "0x0",
"nid": "0x100",
"nonce": "0x1",
"version": "0x3",
"data": {
"method": "transfer",
"params": {
"_to": "hx0000000000000000000000000000000000000000",
"_value": "0xDE0B6B3A7640001"
}
}
}
| Field | Type | Required | Source | Description |
|---|---|---|---|---|
dataType | enum | Required | App | Must be call for a contract call |
to | string | Required-Real | App | Token contract address (cx…), not the recipient |
value | hex | Required | App | Native HVH amount — keep 0x0 for a token-only transfer |
data.method | string | Required | App | Contract method — transfer |
data.params._to | string | Required-Real | App | Real token recipient (hx…) |
data.params._value | hex | Required | App | Token amount in base units, 0x-prefixed hex (PER has 18 decimals; 0xF4240 = 1e6 for a 6-decimal token) |
timestamp | hex | Required-Real | App | ICON microsecond epoch — the wire path never fills it in; omitting it fails with -32602 |
js — Request:
await dcent.sign({
method: 'signTransaction',
chainId: 'havah:mainnet/slip44:858',
payload: {
keyPath: "m/44'/858'/0'/0/0",
transaction: {
dataType: "call",
from: "hx0000000000000000000000000000000000000000",
to: "cxd7fed2ae1d9b2314087520efe1870c33e5c5baa4",
value: "0x0",
stepLimit: "0x186a0",
stepPrice: "0x2e90edd000",
timestamp: "0x0",
nid: "0x100",
nonce: "0x1",
version: "0x3",
data: { method: "transfer",
params: { _to: "hx0000000000000000000000000000000000000000",
_value: "0xDE0B6B3A7640001" } }
}
}
}) // → body.parameter.signature
Response
| Field | Type | Description |
|---|---|---|
header.status | string | success on a completed signature |
body.command | string | Signing command echo — signTransaction |
body.parameter.signature | string | Broadcast-ready serialized signed HAVAH (ICON) transaction carrying the HSP-20 call data, not a bare r/s/v signature. Submit it as-is to a HAVAH node |
{
"header": {
"status": "success"
},
"body": {
"command": "signTransaction",
"parameter": {
"signature": "0x…"
}
}
}
HSP-20 tokens are signed under parent HAVAH on mainnet (slip44:858). A wrong chain is rejected (-32602); any HSP-20 contract signs — supply a form-D descriptor (see Core Concepts → Token descriptors) to prevent a silent native HVH transfer.
Variant — HSP-20 form-D descriptor
Send a compact token descriptor instead of a full ICON dataType:"call" envelope. The bridge builds the transfer(_to,_value) SCORE call from { contract, to, amount }, rewrites to to the contract address, and sets value to 0x0. Envelope fields you send (from, stepLimit, stepPrice, nid, nonce, version) are preserved. amount is a base-unit string (not rescaled by decimals).
payload.transaction:
{
"token": {
"contract": "cxd8303731bf989a1597a6d38505d7a9483c4d9a38",
"to": "hx0000000000000000000000000000000000000000",
"amount": "1000000",
"decimals": 6,
"symbol": "GODH"
},
"from": "hx0000000000000000000000000000000000000000",
"stepLimit": "0x186a0",
"stepPrice": "0x2e90edd000",
"timestamp": "0x0",
"nid": "0x100",
"nonce": "0x1",
"version": "0x3"
}
| Field | Type | Required | Notes |
|---|---|---|---|
token.contract | string | Required | SCORE address; must match cx + 40 hex chars. Unregistered tokens allowed. |
token.to | string | Required | Recipient (hx…). Becomes data.params._to. |
token.amount | string | Required | Base-unit integer string; not rescaled by decimals. 0 is allowed. |
token.decimals | number | Required | Base-unit exponent; enables descriptor resolution on the device. |
token.symbol | string | Optional | Display metadata only. |
from | string | Required-Real | Device HAVAH account that signs (hx…). Omitting it fails with -32602. |
stepLimit / stepPrice | string | Required | Map to the fee gate (gasLimit / fee). Zero or missing fails the gate. |
nid / nonce / version | string | Optional | ICON envelope fields; passed through unchanged. |
timestamp | hex | Required-Real | ICON microsecond epoch — the wire path never fills it in; omitting it fails with -32602 |
Verified on device (2026-07-20): this descriptor displays as GODH 1.0 — amount "1000000" at decimals 6. Replace token.to / from with your own device HAVAH account (hx…).
Common Mistakes
Decimal amounts — value / _value must be 0x-prefixed hex loop, not a decimal string. Keep them as hex because values exceed MAX_SAFE_INTEGER. Token to vs recipient — for HSP-20, to is the contract (cx…) and the recipient is data.params._to (hx…). Putting the recipient in to moves native HVH instead. Non-zero value on a token transfer — leave value as 0x0 for HSP-20; a non-zero value sends native HVH alongside the token. Missing stepLimit — without it the bridge cannot build preparedFee. Missing stepPrice — the app must supply a real, current step price; it is not auto-filled.