Skip to main content
For the complete documentation index, see llms.txt

Wallet SDK API Reference

Midnight Wallet SDK는 Midnight Network의 지갑을 관리하는 TypeScript 라이브러리입니다. Midnight을 구동하는 세 가지 토큰 체계, 즉 unshielded 토큰(NIGHT), 영지식 증명 기반 shielded 토큰, 그리고 트랜잭션 수수료용 DUST를 모두 지원합니다.

설정 방법과 실습 과정을 담은 상세 개발자 가이드는 Wallet SDK 개발자 가이드를 참고하세요.

Architecture

Wallet SDK는 모듈형 패키지 구조를 사용하며, Midnight의 토큰 타입에 대응하는 세 가지 지갑 모델로 구성됩니다.

wallet-sdk-facade Unified entry point
├── wallet-sdk-unshielded-wallet NIGHT and unshielded token operations
├── wallet-sdk-shielded Shielded token operations with ZK proofs
├── wallet-sdk-dust-wallet DUST management for transaction fees
├── wallet-sdk-hd HD key derivation (BIP 32 / BIP 44 / CIP 1852)
├── wallet-sdk-address-format Bech32m address encoding and decoding
├── wallet-sdk-node-client Node communication
├── wallet-sdk-indexer-client Indexer queries
└── wallet-sdk-prover-client Proof server interface

Packages

PackagePurpose
@midnight-ntwrk/wallet-sdk-facade모든 지갑 작업을 위한 통합 API
@midnight-ntwrk/wallet-sdk-unshielded-walletNIGHT 및 unshielded 토큰 관리
@midnight-ntwrk/wallet-sdk-shieldedZK 증명 기반 shielded 토큰 관리
@midnight-ntwrk/wallet-sdk-dust-wallet트랜잭션 수수료용 DUST 관리
@midnight-ntwrk/wallet-sdk-hd계층적 결정성 키 파생
@midnight-ntwrk/wallet-sdk-address-formatBech32m 주소 인코딩 및 디코딩
@midnight-ntwrk/wallet-sdk-node-clientMidnight 노드와의 통신
@midnight-ntwrk/wallet-sdk-indexer-clientMidnight indexer 조회
@midnight-ntwrk/wallet-sdk-prover-client증명 서버 인터페이스

Wallet Facade

facade는 세 가지 지갑 타입을 함께 관리하며 잔액 조회, 전송, 상태 관리, 트랜잭션 실행을 하나의 인터페이스로 제공합니다.

Initialize

import { type DefaultConfiguration } from '@midnight-ntwrk/wallet-sdk-facade';
import { InMemoryTransactionHistoryStorage } from '@midnight-ntwrk/wallet-sdk-unshielded-wallet';

const configuration: DefaultConfiguration = {
networkId: 'preprod',
costParameters: {
feeBlocksMargin: 5,
},
relayURL: new URL('wss://rpc.preprod.midnight.network'),
provingServerUrl: new URL('http://localhost:6300'),
indexerClientConnection: {
indexerHttpUrl: 'https://indexer.preprod.midnight.network/api/v4/graphql',
indexerWsUrl: 'wss://indexer.preprod.midnight.network/api/v4/graphql/ws',
},
txHistoryStorage: new InMemoryTransactionHistoryStorage(),
};

const wallet = await WalletFacade.init({
configuration,
shielded: (config) => ShieldedWallet(config).startWithSecretKeys(shieldedKeys),
unshielded: (config) => UnshieldedWallet(config).startWithPublicKey(publicKey),
dust: (config) => DustWallet(config).startWithSecretKey(dustKey, dustParams),
});

State

초기 동기화를 기다리거나 업데이트를 구독하여 지갑 상태에 접근합니다.

// 초기 동기화 대기
const syncedState = await wallet.waitForSyncedState();
console.log('Shielded balance:', syncedState.shielded.balances);
console.log('Unshielded balance:', syncedState.unshielded.balances);
console.log('DUST balance:', syncedState.dust.totalCoins);

// 상태 변경 구독
wallet.state().subscribe((state) => {
if (state.isSynced) {
console.log('Shielded coins:', state.shielded.availableCoins.length);
console.log('Unshielded UTxOs:', state.unshielded.availableCoins.length);
}
});

Transfers

unshielded 전송은 Schnorr 서명을 사용하는 UTxO 기반 트랜잭션입니다. shielded 전송은 영지식 증명을 사용하므로 별도의 서명 작업이 필요 없습니다.

import * as ledger from '@midnight-ntwrk/ledger-v8';

// unshielded 전송
await wallet
.transferTransaction(
[
{
type: 'unshielded',
outputs: [
{
amount: 1_000_000n,
receiverAddress: await receiverWallet.unshielded.getAddress(),
type: ledger.unshieldedToken().raw,
},
],
},
],
{ shieldedSecretKeys, dustSecretKey },
{ ttl: new Date(Date.now() + 30 * 60 * 1000) }
)
.then((recipe) => wallet.signRecipe(recipe, (payload) => keystore.signData(payload)))
.then((recipe) => wallet.finalizeRecipe(recipe))
.then((tx) => wallet.submitTransaction(tx));

// shielded 전송 (서명 불필요)
await wallet
.transferTransaction(
[
{
type: 'shielded',
outputs: [
{
amount: 1_000_000n,
receiverAddress: await receiverWallet.shielded.getAddress(),
type: ledger.shieldedToken().raw,
},
],
},
],
{ shieldedSecretKeys, dustSecretKey },
{ ttl: new Date(Date.now() + 30 * 60 * 1000) }
)
.then((recipe) => wallet.finalizeRecipe(recipe))
.then((tx) => wallet.submitTransaction(tx));

Lifecycle

await wallet.start(shieldedSecretKeys, dustSecretKey);
await wallet.stop();

Terms and Conditions

const terms = await WalletFacade.fetchTermsAndConditions(networkId);
await wallet.acceptTermsAndConditions(terms);

HD Wallet

BIP 32 / BIP 44 / CIP 1852 파생 방식으로 하나의 시드에서 세 가지 키를 모두 파생합니다.

import * as ledger from '@midnight-ntwrk/ledger-v8';
import { HDWallet, Roles } from '@midnight-ntwrk/wallet-sdk-hd';

function deriveRoleKey(accountKey, role, addressIndex = 0) {
const result = accountKey.selectRole(role).deriveKeyAt(addressIndex);
if (result.type === 'keyDerived') {
return Buffer.from(result.key);
}
return deriveRoleKey(accountKey, role, addressIndex + 1);
}

const hdWallet = HDWallet.fromSeed(seed);
const account = hdWallet.hdWallet.selectAccount(0);
const shieldedSeed = deriveRoleKey(account, Roles.Zswap);
const dustSeed = deriveRoleKey(account, Roles.Dust);
const unshieldedKey = deriveRoleKey(account, Roles.NightExternal);
hdWallet.hdWallet.clear();

Address Format

Midnight은 주소에 Bech32m 형식을 사용하며, 네트워크별 접두사를 붙입니다.

import {
MidnightBech32m,
UnshieldedAddress,
ShieldedAddress,
DustAddress,
ShieldedCoinPublicKey,
ShieldedEncryptionPublicKey,
} from '@midnight-ntwrk/wallet-sdk-address-format';
import * as ledger from '@midnight-ntwrk/ledger-v8';

const networkId = 'preprod';

// unshielded 주소 인코딩
const verifyingKey = ledger.signatureVerifyingKey(unshieldedSecretKey.toString('hex'));
const unshieldedAddress = new UnshieldedAddress(
Buffer.from(ledger.addressFromKey(verifyingKey), 'hex')
);
const unshieldedBech32m = MidnightBech32m.encode(networkId, unshieldedAddress).toString();

// shielded 주소 인코딩
const shieldedAddress = new ShieldedAddress(
new ShieldedCoinPublicKey(Buffer.from(shieldedKeys.coinPublicKey, 'hex')),
new ShieldedEncryptionPublicKey(Buffer.from(shieldedKeys.encryptionPublicKey, 'hex'))
);
const shieldedBech32m = MidnightBech32m.encode(networkId, shieldedAddress).toString();

// DUST 주소 인코딩
const dustAddress = new DustAddress(dustSecretKey.publicKey);
const dustBech32m = MidnightBech32m.encode(networkId, dustAddress).toString();

// 주소 디코딩
const parsed = MidnightBech32m.parse(unshieldedBech32m);
const decoded = parsed.decode(UnshieldedAddress, networkId);

DUST Management

NIGHT 코인을 등록하면 트랜잭션 수수료로 쓸 DUST가 생성됩니다.

const { unshielded } = await wallet.waitForSyncedState();

// NIGHT를 등록해 DUST 생성 시작
await wallet
.registerNightUtxosForDustGeneration(
unshielded.availableCoins,
unshieldedKeystore.getPublicKey(),
(payload) => unshieldedKeystore.signData(payload)
)
.then((recipe) => wallet.finalizeRecipe(recipe))
.then((tx) => wallet.submitTransaction(tx));

DUST Sponsorship

스폰서가 사용자를 대신해 트랜잭션 수수료를 낼 수 있습니다.

// 사용자는 DUST 밸런싱 없이 트랜잭션을 준비
const userRecipe = await userWallet.balanceUnboundTransaction(
transaction,
{ shieldedSecretKeys, dustSecretKey },
{
ttl: new Date(Date.now() + 30 * 60 * 1000),
tokenKindsToBalance: ['shielded', 'unshielded'],
}
);

// 스폰서가 DUST를 추가하고 제출
const finalized = await userWallet.finalizeRecipe(
await userWallet.signRecipe(userRecipe, (payload) => keystore.signData(payload))
);

await sponsorWallet
.balanceFinalizedTransaction(
finalized,
{ shieldedSecretKeys: sponsorKeys, dustSecretKey: sponsorDust },
{
ttl: new Date(Date.now() + 30 * 60 * 1000),
tokenKindsToBalance: ['dust'],
}
)
.then((recipe) => sponsorWallet.finalizeRecipe(recipe))
.then((tx) => sponsorWallet.submitTransaction(tx));

Atomic Swaps

단일 아토믹 트랜잭션으로 당사자 간 토큰을 신뢰 없이 교환합니다.

// Alice가 token1을 내주고 token2를 받는 스왑을 개시
const aliceSwapTx = await aliceWallet
.initSwap(
{ shielded: { [token1]: 1_000_000n } },
[
{
type: 'shielded',
outputs: [{
type: token2,
amount: 1_000_000n,
receiverAddress: aliceShieldedAddress,
}],
},
],
{ shieldedSecretKeys: aliceKeys, dustSecretKey: aliceDust },
{ ttl: new Date(Date.now() + 30 * 60 * 1000) }
)
.then((recipe) => aliceWallet.finalizeRecipe(recipe));

// Bob이 스왑을 완료
await bobWallet
.balanceFinalizedTransaction(
aliceSwapTx,
{ shieldedSecretKeys: bobKeys, dustSecretKey: bobDust },
{ ttl: new Date(Date.now() + 30 * 60 * 1000) }
)
.then((recipe) => bobWallet.finalizeRecipe(recipe))
.then((tx) => bobWallet.submitTransaction(tx));

Alternative Proving

증명 서버에 HTTP로 접근할 수 없는 환경에서는 WASM 기반 증명을 사용합니다.

import { makeWasmProvingService } from '@midnight-ntwrk/wallet-sdk-capabilities';

const wallet = await WalletFacade.init({
configuration,
shielded: (config) => ShieldedWallet(config).startWithSecretKeys(shieldedKeys),
unshielded: (config) => UnshieldedWallet(config).startWithPublicKey(publicKey),
dust: (config) => DustWallet(config).startWithSecretKey(dustKey, dustParams),
provingService: () => makeWasmProvingService(),
});

Release History

버전 이력과 변경 내역은 Wallet SDK 릴리스 노트를 참고하세요.