@kingdomchain/wallet-client 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +96 -0
- package/dist/index.d.ts +220 -0
- package/dist/index.js +1723 -0
- package/dist/index.js.map +1 -0
- package/package.json +72 -0
package/README.md
ADDED
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
# Kingdom Chain TypeScript / CosmJS client
|
|
2
|
+
|
|
3
|
+
Self-contained TypeScript package for constructing, signing, and broadcasting Kingdom Chain transactions via [CosmJS](https://github.com/cosmos/cosm-js). Includes a Keplr/Leap browser wallet connector for non-custodial signing.
|
|
4
|
+
|
|
5
|
+
## Scope (current)
|
|
6
|
+
|
|
7
|
+
- **MsgSubmitApplication** (citizenship application)
|
|
8
|
+
- **MsgSubmitRecoveryAttestation** (wallet recovery attestation)
|
|
9
|
+
- **Browser wallet connector** (`src/browserSigner.ts`) — Keplr / Leap via `experimentalSuggestChain` + `OfflineDirectSigner`
|
|
10
|
+
- Ed25519 attestation signing ported from `x/compliance/types/attestation.go`
|
|
11
|
+
- Proto codegen via `ts-proto` + `buf`
|
|
12
|
+
|
|
13
|
+
## Setup
|
|
14
|
+
|
|
15
|
+
```bash
|
|
16
|
+
cd clients/ts
|
|
17
|
+
npm install
|
|
18
|
+
npm run codegen # regenerate from ../../proto (requires buf + repo root)
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
## Testing
|
|
22
|
+
|
|
23
|
+
```bash
|
|
24
|
+
cd clients/ts
|
|
25
|
+
npm test # unit + property fuzz (1500 cross-lang iterations)
|
|
26
|
+
npm run test:mutate # Stryker mutation testing on attestation.ts + registry.ts
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
Cross-language fuzz compares TS `attestationSignPayload` against a compiled Go helper (`payload_attestation.go`) for 1000 citizenship + 500 recovery inputs.
|
|
30
|
+
|
|
31
|
+
## Live E2E (Ona devnet)
|
|
32
|
+
|
|
33
|
+
Requires a running node at `~/.kingdomchain-e2e` (see `scripts/citizen-compliance-e2e/run.sh`).
|
|
34
|
+
|
|
35
|
+
```bash
|
|
36
|
+
# Build CLI if needed
|
|
37
|
+
go build -o /tmp/kingdomchaind ./cmd/kingdomchaind
|
|
38
|
+
|
|
39
|
+
cd clients/ts
|
|
40
|
+
npm run e2e:submit-application
|
|
41
|
+
npm run e2e:submit-recovery
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
Environment overrides:
|
|
45
|
+
|
|
46
|
+
| Variable | Default |
|
|
47
|
+
|----------|---------|
|
|
48
|
+
| `CHAIN_ID` | `kingdomchain-e2e` |
|
|
49
|
+
| `RPC_URL` | `http://127.0.0.1:26657` |
|
|
50
|
+
| `REST_URL` | `http://127.0.0.1:1317` |
|
|
51
|
+
| `HOME_DIR` | `~/.kingdomchain-e2e` |
|
|
52
|
+
| `KINGDOMCHAIND` | `/tmp/kingdomchaind` |
|
|
53
|
+
| `PROVIDER_SEED_HEX` | devnet provider-alpha seed from e2e script |
|
|
54
|
+
|
|
55
|
+
## Browser wallet demo (Keplr / Leap)
|
|
56
|
+
|
|
57
|
+
Manual click-through demo for Isa — **not automated in CI**. Unit tests mock `window.keplr` / `window.leap`; the demo requires a real extension in your browser.
|
|
58
|
+
|
|
59
|
+
1. Start the Ona devnet (`scripts/citizen-compliance-e2e/run.sh` or your existing node).
|
|
60
|
+
2. Fund the Keplr/Leap account you will connect with (`ukdr` on `kingdomchain-e2e`).
|
|
61
|
+
3. From `clients/ts`:
|
|
62
|
+
|
|
63
|
+
```bash
|
|
64
|
+
npm run demo
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
4. Open the printed URL (default `http://localhost:5173`) in a browser with Keplr or Leap installed.
|
|
68
|
+
5. Click **Connect Keplr** or **Connect Leap**, approve the chain suggestion + connection, then **Submit test application**.
|
|
69
|
+
|
|
70
|
+
Optional Vite env overrides (prefix `VITE_`):
|
|
71
|
+
|
|
72
|
+
| Variable | Default |
|
|
73
|
+
|----------|---------|
|
|
74
|
+
| `VITE_CHAIN_ID` | `kingdomchain-e2e` |
|
|
75
|
+
| `VITE_RPC_URL` | `http://127.0.0.1:26657` |
|
|
76
|
+
| `VITE_REST_URL` | `http://127.0.0.1:1317` |
|
|
77
|
+
| `VITE_PROVIDER_ID` | `provider-alpha` |
|
|
78
|
+
| `VITE_POLICY_VERSION` | `policy-v1` |
|
|
79
|
+
| `VITE_PROVIDER_SEED_HEX` | devnet provider-alpha seed |
|
|
80
|
+
|
|
81
|
+
The demo signs the provider attestation off-chain (devnet seed) and broadcasts `MsgSubmitApplication` using your connected wallet as the on-chain tx signer.
|
|
82
|
+
|
|
83
|
+
### Browser wallet API (`src/browserSigner.ts`)
|
|
84
|
+
|
|
85
|
+
- `isKeplrAvailable()` / `isLeapAvailable()`
|
|
86
|
+
- `buildKingdomChainInfo(chainId, rpcUrl, restUrl)` — `ukdr` / KDR with **6 decimals** (`x/supply/types/constants.go`, `TOKENOMICS_COSMOS_SPEC.md`), bech32 prefix `king`, coin type 118
|
|
87
|
+
- `connectKeplr(chainInfo)` / `connectLeap(chainInfo)` — suggest chain + enable + offline signer
|
|
88
|
+
- `createBrowserSigningClient(rpcUrl, signer)` — `SigningStargateClient` + `createKingdomChainRegistry()`
|
|
89
|
+
|
|
90
|
+
## Encoding notes (for Base44 frontend)
|
|
91
|
+
|
|
92
|
+
1. **Custom protobuf registry** — CosmJS `SigningStargateClient` must be constructed with a `Registry` that includes Kingdom Chain message type URLs (e.g. `/isatheword.kingdomchain.compliance.v1.MsgSubmitApplication`) alongside `defaultRegistryTypes`.
|
|
93
|
+
2. **Attestation signing is off-chain** — providers sign a canonical SHA256-payload (not the tx bytes). The TS port in `src/attestation.ts` must match Go `AttestationSignPayload` exactly; the E2E script cross-checks against `scripts/citizen-compliance-e2e/sign_attestation.go`.
|
|
94
|
+
3. **Timestamps** — proto `google.protobuf.Timestamp` fields (`issued_at`, `expires_at`) are `Date` in generated TS; encoding uses `@bufbuild/protobuf` wire format.
|
|
95
|
+
4. **Uint64 fields** — `provider_key_version` is `bigint` in generated types.
|
|
96
|
+
5. **Tx signer** — `MsgSubmitApplication` signer is `applicant_wallet`; the fee payer / signer must be the applicant's secp256k1 account (`king` bech32 prefix, coin type 118).
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,220 @@
|
|
|
1
|
+
import { Registry, OfflineDirectSigner, EncodeObject } from '@cosmjs/proto-signing';
|
|
2
|
+
import { SigningStargateClient } from '@cosmjs/stargate';
|
|
3
|
+
import { BinaryWriter, BinaryReader } from '@bufbuild/protobuf/wire';
|
|
4
|
+
|
|
5
|
+
/** Must match x/compliance/types/keys.go AttestationTypeCitizenshipApplication */
|
|
6
|
+
declare const ATTESTATION_TYPE_CITIZENSHIP_APPLICATION = "citizenship_application";
|
|
7
|
+
/** Must match x/compliance/types/keys.go AttestationTypeRecovery */
|
|
8
|
+
declare const ATTESTATION_TYPE_RECOVERY = "recovery";
|
|
9
|
+
interface AttestationPayloadInput {
|
|
10
|
+
attestationType: string;
|
|
11
|
+
chainId: string;
|
|
12
|
+
intendedWallet: string;
|
|
13
|
+
caseId: string;
|
|
14
|
+
policyVersion: string;
|
|
15
|
+
nonce: string;
|
|
16
|
+
uniquenessReference: string;
|
|
17
|
+
issuedAt: Date;
|
|
18
|
+
expiresAt: Date;
|
|
19
|
+
providerId: string;
|
|
20
|
+
providerKeyVersion: bigint;
|
|
21
|
+
citizenId?: bigint;
|
|
22
|
+
oldWallet?: string;
|
|
23
|
+
newWallet?: string;
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* Canonical attestation payload — must match Go types.AttestationSignPayload bit-for-bit.
|
|
27
|
+
*/
|
|
28
|
+
declare function attestationSignPayload(input: AttestationPayloadInput): string;
|
|
29
|
+
declare function signAttestationPayload(privateKeySeed: Uint8Array, payload: string): Promise<string>;
|
|
30
|
+
declare function publicKeyFromPrivateSeed(privateKeySeed: Uint8Array): Promise<string>;
|
|
31
|
+
declare function providerSeedFromHex(hex: string): Uint8Array;
|
|
32
|
+
|
|
33
|
+
interface MsgSubmitApplication {
|
|
34
|
+
applicant_wallet: string;
|
|
35
|
+
application_id: string;
|
|
36
|
+
provider_id: string;
|
|
37
|
+
provider_key_version: bigint;
|
|
38
|
+
chain_id: string;
|
|
39
|
+
case_id: string;
|
|
40
|
+
policy_version: string;
|
|
41
|
+
nonce: string;
|
|
42
|
+
uniqueness_reference: string;
|
|
43
|
+
issued_at?: Date | undefined;
|
|
44
|
+
expires_at?: Date | undefined;
|
|
45
|
+
signature: string;
|
|
46
|
+
}
|
|
47
|
+
declare const MsgSubmitApplication: MessageFns<MsgSubmitApplication>;
|
|
48
|
+
interface MsgSubmitRecoveryAttestation {
|
|
49
|
+
applicant_wallet: string;
|
|
50
|
+
recovery_case_id: string;
|
|
51
|
+
provider_id: string;
|
|
52
|
+
provider_key_version: bigint;
|
|
53
|
+
chain_id: string;
|
|
54
|
+
case_id: string;
|
|
55
|
+
policy_version: string;
|
|
56
|
+
nonce: string;
|
|
57
|
+
uniqueness_reference: string;
|
|
58
|
+
citizen_id: bigint;
|
|
59
|
+
old_wallet: string;
|
|
60
|
+
new_wallet: string;
|
|
61
|
+
issued_at?: Date | undefined;
|
|
62
|
+
expires_at?: Date | undefined;
|
|
63
|
+
signature: string;
|
|
64
|
+
}
|
|
65
|
+
declare const MsgSubmitRecoveryAttestation: MessageFns<MsgSubmitRecoveryAttestation>;
|
|
66
|
+
type Builtin = Date | Function | Uint8Array | string | number | boolean | bigint | undefined;
|
|
67
|
+
type DeepPartial<T> = T extends bigint ? string | number | bigint : T extends Builtin ? T : T extends globalThis.Array<infer U> ? globalThis.Array<DeepPartial<U>> : T extends ReadonlyArray<infer U> ? ReadonlyArray<DeepPartial<U>> : T extends {} ? {
|
|
68
|
+
[K in keyof T]?: DeepPartial<T[K]>;
|
|
69
|
+
} : Partial<T>;
|
|
70
|
+
interface MessageFns<T> {
|
|
71
|
+
encode(message: T, writer?: BinaryWriter): BinaryWriter;
|
|
72
|
+
decode(input: BinaryReader | Uint8Array, length?: number): T;
|
|
73
|
+
create(base?: DeepPartial<T>): T;
|
|
74
|
+
fromPartial(object: DeepPartial<T>): T;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
declare enum ApplicationStatus {
|
|
78
|
+
APPLICATION_STATUS_UNSPECIFIED = 0,
|
|
79
|
+
APPLICATION_STATUS_SUBMITTED = 1,
|
|
80
|
+
APPLICATION_STATUS_PENDING_REVIEW = 2,
|
|
81
|
+
APPLICATION_STATUS_APPROVED = 3,
|
|
82
|
+
APPLICATION_STATUS_REJECTED = 4,
|
|
83
|
+
UNRECOGNIZED = -1
|
|
84
|
+
}
|
|
85
|
+
declare enum RecoveryAttestationStatus {
|
|
86
|
+
RECOVERY_ATTESTATION_STATUS_UNSPECIFIED = 0,
|
|
87
|
+
RECOVERY_ATTESTATION_STATUS_SUBMITTED = 1,
|
|
88
|
+
RECOVERY_ATTESTATION_STATUS_PENDING_REVIEW = 2,
|
|
89
|
+
RECOVERY_ATTESTATION_STATUS_APPROVED = 3,
|
|
90
|
+
RECOVERY_ATTESTATION_STATUS_REJECTED = 4,
|
|
91
|
+
UNRECOGNIZED = -1
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
/** CosmJS registry: standard Cosmos SDK types + Kingdom Chain citizen/compliance messages. */
|
|
95
|
+
declare function createKingdomChainRegistry(): Registry;
|
|
96
|
+
|
|
97
|
+
/** Keplr/Leap-compatible currency entry. */
|
|
98
|
+
interface ChainCurrency {
|
|
99
|
+
coinDenom: string;
|
|
100
|
+
coinMinimalDenom: string;
|
|
101
|
+
coinDecimals: number;
|
|
102
|
+
gasPriceStep?: {
|
|
103
|
+
low: number;
|
|
104
|
+
average: number;
|
|
105
|
+
high: number;
|
|
106
|
+
};
|
|
107
|
+
}
|
|
108
|
+
/** Keplr/Leap-compatible ChainInfo for experimentalSuggestChain. */
|
|
109
|
+
interface ChainInfo {
|
|
110
|
+
chainId: string;
|
|
111
|
+
chainName: string;
|
|
112
|
+
rpc: string;
|
|
113
|
+
rest: string;
|
|
114
|
+
bip44: {
|
|
115
|
+
coinType: number;
|
|
116
|
+
};
|
|
117
|
+
bech32Config: {
|
|
118
|
+
bech32PrefixAccAddr: string;
|
|
119
|
+
bech32PrefixAccPub: string;
|
|
120
|
+
bech32PrefixValAddr: string;
|
|
121
|
+
bech32PrefixValPub: string;
|
|
122
|
+
bech32PrefixConsAddr: string;
|
|
123
|
+
bech32PrefixConsPub: string;
|
|
124
|
+
};
|
|
125
|
+
currencies: ChainCurrency[];
|
|
126
|
+
feeCurrencies: ChainCurrency[];
|
|
127
|
+
stakeCurrency: ChainCurrency;
|
|
128
|
+
}
|
|
129
|
+
/** Subset of Keplr/Leap window API used for chain connect. */
|
|
130
|
+
interface BrowserWalletApi {
|
|
131
|
+
experimentalSuggestChain(chainInfo: ChainInfo): Promise<void>;
|
|
132
|
+
enable(chainId: string): Promise<void>;
|
|
133
|
+
getOfflineSigner(chainId: string): OfflineDirectSigner;
|
|
134
|
+
}
|
|
135
|
+
declare class WalletNotInstalledError extends Error {
|
|
136
|
+
readonly walletName: string;
|
|
137
|
+
constructor(walletName: string);
|
|
138
|
+
}
|
|
139
|
+
declare class WalletConnectionError extends Error {
|
|
140
|
+
readonly walletName: string;
|
|
141
|
+
readonly step: "suggestChain" | "enable" | "getOfflineSigner";
|
|
142
|
+
constructor(walletName: string, step: "suggestChain" | "enable" | "getOfflineSigner", cause?: unknown);
|
|
143
|
+
}
|
|
144
|
+
/** @deprecated Use WalletConnectionError — kept for backward compatibility in tests/demo. */
|
|
145
|
+
declare class WalletConnectionRejectedError extends WalletConnectionError {
|
|
146
|
+
constructor(walletName: string, step: "suggestChain" | "enable", cause?: unknown);
|
|
147
|
+
}
|
|
148
|
+
declare class WalletAccountError extends Error {
|
|
149
|
+
readonly walletName: string;
|
|
150
|
+
constructor(walletName: string);
|
|
151
|
+
}
|
|
152
|
+
declare class InvalidChainConfigError extends Error {
|
|
153
|
+
constructor(message: string);
|
|
154
|
+
}
|
|
155
|
+
declare class RpcConnectionError extends Error {
|
|
156
|
+
readonly rpcUrl: string;
|
|
157
|
+
constructor(rpcUrl: string, cause?: unknown);
|
|
158
|
+
}
|
|
159
|
+
declare global {
|
|
160
|
+
interface Window {
|
|
161
|
+
keplr?: BrowserWalletApi;
|
|
162
|
+
leap?: BrowserWalletApi;
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
/** Validate chain endpoint inputs before passing to Keplr/Leap. */
|
|
166
|
+
declare function validateChainConfig(chainId: string, rpcUrl: string, restUrl: string): void;
|
|
167
|
+
declare function isKeplrAvailable(): boolean;
|
|
168
|
+
declare function isLeapAvailable(): boolean;
|
|
169
|
+
/** Build ChainInfo for Keplr/Leap experimentalSuggestChain. */
|
|
170
|
+
declare function buildKingdomChainInfo(chainId: string, rpcUrl: string, restUrl: string, chainName?: string): ChainInfo;
|
|
171
|
+
/** Suggest chain, request access, return CosmJS OfflineDirectSigner. */
|
|
172
|
+
declare function suggestAndConnect(walletApi: BrowserWalletApi, chainInfo: ChainInfo, walletName?: string): Promise<OfflineDirectSigner>;
|
|
173
|
+
declare function connectKeplr(chainInfo: ChainInfo): Promise<OfflineDirectSigner>;
|
|
174
|
+
declare function connectLeap(chainInfo: ChainInfo): Promise<OfflineDirectSigner>;
|
|
175
|
+
/** SigningStargateClient wired with Kingdom Chain custom message registry. */
|
|
176
|
+
declare function createBrowserSigningClient(rpcUrl: string, signer: OfflineDirectSigner): Promise<SigningStargateClient>;
|
|
177
|
+
|
|
178
|
+
/**
|
|
179
|
+
* Kingdom Chain on-chain denom and display metadata.
|
|
180
|
+
*
|
|
181
|
+
* Sources:
|
|
182
|
+
* - x/supply/types/constants.go (UkdrDenom = "ukdr")
|
|
183
|
+
* - TOKENOMICS_COSMOS_SPEC.md (1 KDR = 1,000,000 ukdr)
|
|
184
|
+
* - app/app.go + app/config.go (bech32 prefix, coin type)
|
|
185
|
+
*/
|
|
186
|
+
/** Base (minimal) denom registered in x/supply. */
|
|
187
|
+
declare const UKDR_MINIMAL_DENOM = "ukdr";
|
|
188
|
+
/** Human-readable display symbol. */
|
|
189
|
+
declare const UKDR_DISPLAY_DENOM = "KDR";
|
|
190
|
+
/** ukdr is a micro-unit: 10^6 ukdr = 1 KDR. */
|
|
191
|
+
declare const UKDR_DECIMALS = 6;
|
|
192
|
+
/** Account / validator bech32 prefix (AccountAddressPrefix in app/app.go). */
|
|
193
|
+
declare const BECH32_PREFIX = "king";
|
|
194
|
+
/** SLIP-0044 coin type (ChainCoinType in app/app.go). */
|
|
195
|
+
declare const CHAIN_COIN_TYPE = 118;
|
|
196
|
+
/** Devnet default chain ID (override via env when a permanent node exists). */
|
|
197
|
+
declare const DEFAULT_CHAIN_ID = "kingdomchain-e2e";
|
|
198
|
+
declare const DEFAULT_RPC_URL = "http://127.0.0.1:26657";
|
|
199
|
+
declare const DEFAULT_REST_URL = "http://127.0.0.1:1317";
|
|
200
|
+
|
|
201
|
+
interface SubmitApplicationParams {
|
|
202
|
+
applicantWallet: string;
|
|
203
|
+
applicationId: string;
|
|
204
|
+
chainId: string;
|
|
205
|
+
providerId: string;
|
|
206
|
+
policyVersion: string;
|
|
207
|
+
providerSeedHex: string;
|
|
208
|
+
nonce: string;
|
|
209
|
+
uniquenessReference: string;
|
|
210
|
+
issuedAt: Date;
|
|
211
|
+
expiresAt: Date;
|
|
212
|
+
providerKeyVersion?: bigint;
|
|
213
|
+
}
|
|
214
|
+
declare function buildSubmitApplicationMsg(applicantWallet: string, applicationId: string, attestationInput: AttestationPayloadInput, signature: string): EncodeObject;
|
|
215
|
+
declare function signCitizenshipAttestation(params: SubmitApplicationParams): Promise<{
|
|
216
|
+
signature: string;
|
|
217
|
+
input: AttestationPayloadInput;
|
|
218
|
+
}>;
|
|
219
|
+
|
|
220
|
+
export { ATTESTATION_TYPE_CITIZENSHIP_APPLICATION, ATTESTATION_TYPE_RECOVERY, ApplicationStatus, type AttestationPayloadInput, BECH32_PREFIX, type BrowserWalletApi, CHAIN_COIN_TYPE, type ChainCurrency, type ChainInfo, DEFAULT_CHAIN_ID, DEFAULT_REST_URL, DEFAULT_RPC_URL, InvalidChainConfigError, MsgSubmitApplication, MsgSubmitRecoveryAttestation, RecoveryAttestationStatus, RpcConnectionError, type SubmitApplicationParams, UKDR_DECIMALS, UKDR_DISPLAY_DENOM, UKDR_MINIMAL_DENOM, WalletAccountError, WalletConnectionError, WalletConnectionRejectedError, WalletNotInstalledError, attestationSignPayload, buildKingdomChainInfo, buildSubmitApplicationMsg, connectKeplr, connectLeap, createBrowserSigningClient, createKingdomChainRegistry, isKeplrAvailable, isLeapAvailable, providerSeedFromHex, publicKeyFromPrivateSeed, signAttestationPayload, signCitizenshipAttestation, suggestAndConnect, validateChainConfig };
|