@ledgerhq/hw-app-concordium
v0.8.2
Published
Ledger Hardware Wallet Concordium Application API
Readme
GitHub, Ledger Devs Discord, Developer Portal
@ledgerhq/hw-app-concordium
⚠️ DEPRECATED — this package is deprecated and will be removed in a future release.
Ledger Live has migrated to the Device Management Kit (DMK). New integrations should use
@ledgerhq/device-signer-kit-concordiuminstead. The DMK signer provides the same Concordium device operations through the unified DMK transport layer.No further features or fixes will be shipped here. Pin a version if you still depend on it.
Ledger Hardware Wallet Concordium JavaScript bindings.
Low-level device communication library. Depends on @ledgerhq/hw-transport and @ledgerhq/concordium-core (shared Concordium protocol types and serialization).
This package provides direct communication with Concordium Ledger device apps. It uses hw-app-specific types (raw Buffers, primitives) independent of the Concordium SDK.
For Ledger Live integration, use @ledgerhq/coin-concordium which handles SDK type transformations.
Are you adding Ledger support to your software wallet?
You may be using this package to communicate with the Concordium Nano App.
For a smooth and quick integration:
- See the developers' documentation on the Developer Portal and
- Go on Discord to chat with developer support and the developer community.
API
Table of Contents
- Concordium
- prepareTransferAPDU
- prepareTransferWithMemoAPDU
- serializeTransactionPayloads
- serializeCredentialDeployment
Concordium
Concordium Hardware Wallet API
Provides low-level device communication for Concordium blockchain operations. All transaction types use hw-app-specific formats (raw Buffers, no SDK dependencies).
Parameters
transportTransport Transport for sending commands to a devicescrambleKeyApp-specific key used to scramble APDU data exchanges (optional, default"concordium_default_scramble_key")
getAddress
Get Concordium address for a given path.
Parameters
originalPathstring BIP32 pathdisplayboolean Whether to display/verify address on device (default: false) (optional, defaultfalse)idnumber Identity numbercrednumber Credential numberidpnumber Identity provider number
Returns Promise<Address> Promise with address and publicKey
verifyAddress
Verify address on device.
Parameters
idnumber Identity numbercrednumber Credential numberidpnumber Identity provider numbercredentialIdstring? Credential ID (hex) to compute on-chain address
Returns Promise<VerifyAddressResponse> Promise with status, address, deviceCredId, and devicePrfKey
getPublicKey
Get public key for a given path.
Parameters
pathstring BIP32 pathconfirmRequire user confirmation on device (default: false) (optional, defaultfalse)
Returns Promise<string> Promise with public key (hex string)
signTransaction
Sign a transaction (Transfer or TransferWithMemo). Routes to the appropriate signing method based on transaction type.
Parameters
txTransaction Transaction to signpathstring BIP32 path for signing key
Returns Promise<SigningResult> Promise with signature and serialized transaction
signCredentialDeployment
Sign a credential deployment transaction.
Always creates credentials for new accounts on existing identities. The device displays the expiry time for user verification.
Parameters
txCredentialDeploymentTransaction CredentialDeploymentTransaction in hw-app formatpathstring BIP32 path for signing key
Returns Promise<string> Promise with signature (hex string)
prepareTransferAPDU
Prepares Transfer APDU payloads for device signing.
Transfer uses standard APDU sequence with chunking (255 bytes per chunk). Path is prepended ONLY to the first chunk.
Parameters
Returns Array<Buffer> APDU payloads ready for device transmission (chunked)
prepareTransferWithMemoAPDU
Prepares TransferWithMemo APDU payloads for device signing.
TransferWithMemo requires a special 3-step APDU sequence:
- Header + recipient + memo length
- Memo chunks (255 bytes each)
- Amount
Parameters
Returns {headerPayload: Buffer, memoPayloads: Array<Buffer>, amountPayload: Buffer} Object with headerPayload, memoPayloads array, and amountPayload
serializeTransactionPayloads
Chunks raw data into APDU-sized payloads without derivation path.
Used for credential deployment attribute values and proofs which don't need path prefix. Splits data into MAX_CHUNK_SIZE (255 byte) chunks for APDU transmission.
Parameters
rawTxBuffer Raw data to chunk
Returns Array<Buffer> Array of payload buffers ready for sequential APDU transmission
serializeCredentialDeployment
Serializes a credential deployment transaction for hardware wallet signing.
Takes hw-app format transaction and prepares it for transmission to device by chunking it into appropriate APDU payloads.
Always creates credentials for new accounts on existing identities (Ledger Live use case). The device receives the expiry time to display for user verification.
Parameters
txCredentialDeploymentTransaction Credential deployment transaction in hw-app formatpathstring BIP32 derivation path
Returns any Structured payload components ready for APDU transmission
Usage
Basic Setup
import Concordium from "@ledgerhq/hw-app-concordium";
import TransportWebHID from "@ledgerhq/hw-transport-webhid";
const transport = await TransportWebHID.create();
const ccd = new Concordium(transport);getAddress
Get a Concordium address for a given BIP32 path.
// Without display (returns public key as address during scanning)
const { address, publicKey } = await ccd.getAddress(
"m/44'/919'/0'/0/0",
false, // display
0, // identity
0, // credential
0, // identity provider
);
// With display (user verification on device)
const { address, publicKey } = await ccd.getAddress(
"m/44'/919'/0'/0/0",
true, // display
0, // identity
0, // credential
0, // identity provider
);verifyAddress
Verify an address on the device screen.
// Basic verification
const { status, address } = await ccd.verifyAddress(
0, // identity
0, // credential
0, // identity provider
);
// Verification with credential ID (compute on-chain address)
const { status, address, deviceCredId, devicePrfKey } = await ccd.verifyAddress(
0, // identity
0, // credential
0, // identity provider
"a5119f..." // credential ID (hex)
);getPublicKey
Get a public key for a given path.
// Without confirmation
const publicKey = await ccd.getPublicKey("m/44'/919'/0'/0/0");
// With user confirmation on device
const publicKey = await ccd.getPublicKey("m/44'/919'/0'/0/0", true);signTransfer
Sign a Transfer transaction (simple transfer without memo).
Note: This method expects hw-app format with structured Transaction type. If you're using the Concordium SDK, use @ledgerhq/coin-concordium which handles the transformation.
import { TransactionType, AccountAddress } from "@ledgerhq/concordium-core";
// Example Transfer transaction
const tx = {
type: TransactionType.Transfer,
header: {
sender: AccountAddress.fromBase58("3kBx2h5Y2veb4hZgAJWPrr8RyQESKm5TjzF3ti1QQ4VSYLwK1G"),
nonce: 5n,
expiry: 1745517351n,
energyAmount: 100000n,
},
payload: {
toAddress: AccountAddress.fromBase58("48x2Uo8xCMMxwGuSQnwbqjzKtVqK5MaUud4vG7QEUgDmYkV85e"),
amount: 1000000n, // 1 CCD in microCCD
},
};
const { signature, serialized } = await ccd.signTransfer(tx, "m/44'/919'/0'/0/0");
// signature: hex string for signing
// serialized: hex string ready for network submissionsignTransferWithMemo
Sign a TransferWithMemo transaction (transfer with memo).
import { TransactionType, AccountAddress, encodeMemoToCbor } from "@ledgerhq/concordium-core";
// Example TransferWithMemo transaction
const tx = {
type: TransactionType.TransferWithMemo,
header: {
sender: AccountAddress.fromBase58("3kBx2h5Y2veb4hZgAJWPrr8RyQESKm5TjzF3ti1QQ4VSYLwK1G"),
nonce: 5n,
expiry: 1745517351n,
energyAmount: 150000n,
},
payload: {
toAddress: AccountAddress.fromBase58("48x2Uo8xCMMxwGuSQnwbqjzKtVqK5MaUud4vG7QEUgDmYkV85e"),
amount: 1000000n,
memo: encodeMemoToCbor("Payment for services"),
},
};
const { signature, serialized } = await ccd.signTransferWithMemo(tx, "m/44'/919'/0'/0/0");signCredentialDeployment
Sign a credential deployment transaction.
Note: This method expects hw-app format. Use @ledgerhq/coin-concordium for SDK type handling.
import type { CredentialDeploymentTransaction } from "@ledgerhq/concordium-core";
const tx: CredentialDeploymentTransaction = {
credentialPublicKeys: {
keys: {
0: { schemeId: "Ed25519", verifyKey: "a1b2c3..." }
},
threshold: 1
},
credId: "def456...", // hex string
ipIdentity: 0,
revocationThreshold: 1,
arData: {
"1": { encIdCredPubShare: "abc123..." }
},
policy: {
validTo: "202512",
createdAt: "202501",
revealedAttributes: {}
},
proofs: "fedcba...", // hex string (pre-serialized)
expiry: 1745517351n
};
const signature = await ccd.signCredentialDeployment(
tx,
"m/44'/919'/0'/0/0",
{
isNew: true,
address: Buffer.from("...") // 32 bytes if existing account
}
);Types
All Concordium protocol types are shared from @ledgerhq/concordium-core:
import {
TransactionType,
AccountAddress,
type Transaction,
type TransferPayload,
type TransferWithMemoPayload,
type CredentialDeploymentTransaction,
type IdOwnershipProofs,
type Address,
type VerifyAddressResponse,
type SigningResult,
} from "@ledgerhq/concordium-core";Transaction Type Enum
enum TransactionType {
Transfer = 3, // Simple transfer without memo
TransferWithMemo = 22, // Transfer with memo
}Transaction Structure
// Transfer transaction structure
interface Transaction {
type: TransactionType.Transfer;
header: {
sender: AccountAddress; // Sender's address
nonce: bigint; // Account nonce / sequence number
expiry: bigint; // Transaction expiry (epoch seconds)
energyAmount: bigint; // Maximum energy for transaction
};
payload: {
toAddress: AccountAddress; // Recipient's address
amount: bigint; // Amount in microCCD (1 CCD = 1,000,000 microCCD)
};
}
// TransferWithMemo transaction structure
interface Transaction {
type: TransactionType.TransferWithMemo;
header: {
sender: AccountAddress;
nonce: bigint;
expiry: bigint;
energyAmount: bigint;
};
payload: {
toAddress: AccountAddress;
amount: bigint;
memo: Buffer; // CBOR-encoded memo (use encodeMemoToCbor)
};
}Type Characteristics
hw-app types use:
AccountAddressclass for addresses (handles Base58 ↔ Buffer conversion)- Primitive
bigintfor numeric fields (nonce, expiry, energyAmount, amount) - Structured payloads with type safety (
TransferPayload,TransferWithMemoPayload) - CBOR-encoded
Bufferfor memos (useencodeMemoToCborutility) IdOwnershipProofsobject for credential proofs (hw-app serializes this)
For SDK integration, use @ledgerhq/coin-concordium which provides transformation between SDK and hw-app formats.
Utilities
APDU-specific utilities (this package)
These are device communication utilities exported from @ledgerhq/hw-app-concordium/lib/serialization:
prepareTransferAPDU(serialized, path)- Prepare Transfer APDU payloadsprepareTransferWithMemoAPDU(serialized, path)- Prepare TransferWithMemo APDU payloadsserializeTransactionPayloads(rawTx)- Chunk data into APDU payloadsserializeCredentialDeployment(tx, path)- Serialize credential deployment for device
Protocol utilities (from @ledgerhq/concordium-core)
All protocol-level serialization, CBOR, address, and encoding utilities are now in @ledgerhq/concordium-core. Import them from there:
import {
// Serialization
serializeTransfer, serializeTransferWithMemo, serializeTransaction,
deserializeTransfer, deserializeTransferWithMemo, deserializeTransaction,
getTransactionType,
serializeCredentialDeploymentValues, serializeIdOwnershipProofs,
serializeAccountOwnershipProofs, insertAccountOwnershipProofs,
// CBOR
encodeMemoToCbor, decodeMemoFromCbor, memoEncodedSize,
MAX_MEMO_LENGTH, MAX_CBOR_SIZE,
// Address
AccountAddress,
// Encoding utils
encodeWord8, encodeWord16, encodeWord32, encodeWord64,
decodeWord16, decodeWord32, decodeWord64,
serializeMap, serializeVerifyKey, serializeYearMonth,
pathToBuffer, chunkBuffer,
} from "@ledgerhq/concordium-core";License
This project is licensed under the Apache-2.0 License - see the LICENSE file for details.
