@digitalshieldfe/airgap-cold
v0.1.3
Published
Cold/device-peer air-gap SDK (export multi-accounts, parse sign requests)
Readme
@digitalshieldfe/airgap-cold
Cold/device-peer SDK. Production apps construct AirGapColdSdk with a ColdSigner from @digitalshieldfe/airgap-secure-keyring (or SoftKeyring for tests only).
Public exports
The package entry intentionally exposes a narrow surface:
import {
AirGapColdSdk,
parseDeviceCall,
type SignAirGapRequestResult,
type HandleDeviceCallResult,
type DeviceCallData,
} from "@digitalshieldfe/airgap-cold";Lower-level sign/export helpers remain internal; call them via AirGapColdSdk methods.
AirGapColdSdk
const cold = new AirGapColdSdk({
signer,
deviceId: "qr-<stable-id>", // DS App: match hot wallet import
deviceName,
version,
});| Method | Description |
|--------|-------------|
| exportDefaultMultiAccounts / exportDefaultMultiAccountsFrames | Bitget-aligned crypto-multi-accounts |
| exportEthCryptoHDKey / exportEthCryptoHDKeyFrames | MetaMask-style ETH crypto-hdkey |
| exportCryptoHDKey | Custom HDKey export options |
| signRequest | ETH / PSBT / SOL / TRON / Keystone(TRON) sign-request → signature frames |
| handleDeviceCall | DS digitalshield-app-call-device |
| handleIncoming | Route sign-request or DeviceCall from scanned frames |
| decodeFrames / encodeAnimated | UR frame utilities (re-exported behavior from core) |
Pass a stable deviceId when integrating with DS App (qr-${deviceId}). Hardware uses a 24-char uppercase hex id; software cold may use any stable string.
Sign requests
signRequest / handleIncoming dispatch by UR type:
| Request | Response |
|---------|----------|
| eth-sign-request | eth-signature |
| crypto-psbt | signed crypto-psbt |
| sol-sign-request | sol-signature |
| tron-sign-request | tron-signature |
| keystone-sign-request (OKX TRON only) | keystone-sign-result |
signKeystoneTronRequest — parse gzipped Keystone protobuf, rebuild TRON tx, return keystone-sign-result. Other coinCode values are rejected for now.
DS DeviceCall (digitalshield-app-call-device)
handleDeviceCall / handleIncoming:
| method | Cold response |
|--------|----------------|
| getMultiAccounts | crypto-multi-accounts frames — echo request deviceId when present |
| verifyAddress | plaintext address (not a UR) — host UI must show it as a static QR for the hot wallet’s next scan |
See the root README §2.3 / §4.4 for the full flow and deviceId pitfalls.
Errors
Signing, DeviceCall, and UR parsing failures throw AirGapError with codes such as SIGN_XFP_MISMATCH, SIGN_PSBT_NO_MATCHING_DERIVATION, DEVICE_CALL_XFP_MISMATCH, etc.
import { isAirGapError, getAirGapErrorCode } from "@digitalshieldfe/airgap-core";
try {
await cold.signRequest(frames);
} catch (e) {
if (isAirGapError(e)) {
showToast(mapCode(e.code, e.params) ?? e.message);
}
}See root README §12 and airgap-core/src/errors.ts.
RN QR UI
For animated export/sign QR shells, use @digitalshieldfe/airgap-qr-ui with this SDK — see packages/airgap-qr-ui/README.md.
