@novasamatech/host-api-wrapper 0.8.11 → 0.9.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 CHANGED
@@ -166,7 +166,13 @@ It can be used for various purposes like p2p communication, storing temp data, e
166
166
 
167
167
  ```ts
168
168
  import { createStatementStore } from '@novasamatech/host-api-wrapper';
169
- import type { Topic, Statement, SignedStatement, StatementTopicFilter } from '@novasamatech/host-api-wrapper';
169
+ import type {
170
+ Topic,
171
+ Statement,
172
+ SignedStatement,
173
+ StatementTopicFilter,
174
+ ProductAccountRef,
175
+ } from '@novasamatech/host-api-wrapper';
170
176
 
171
177
  // Create statement store instance
172
178
  const statementStore = createStatementStore();
@@ -182,7 +188,9 @@ const subscription = statementStore.subscribe(filter, (page) => {
182
188
  });
183
189
 
184
190
  // Create a proof for a new statement
185
- const accountId = ['product.dot', 0]; // [DotNS identifier, derivation index]
191
+ // [DotNS identifier, account selector]. The selector is a plain index or a raw
192
+ // 32-byte index (RFC 0022).
193
+ const accountId: ProductAccountRef = ['product.dot', 0];
186
194
  const statement: Statement = {
187
195
  proof: undefined,
188
196
  decryptionKey: undefined,
@@ -212,7 +220,7 @@ The Accounts Provider allows you to access product accounts and create signers f
212
220
 
213
221
  ```ts
214
222
  import { accounts } from '@novasamatech/host-api-wrapper';
215
- import type { ProductAccount } from '@novasamatech/host-api-wrapper';
223
+ import type { ProductAccount, ProofContext } from '@novasamatech/host-api-wrapper';
216
224
 
217
225
  // Get the user's primary DotNS username (RFC-0014)
218
226
  // — prompts for permission on first call
@@ -242,8 +250,12 @@ if (loginResult.isOk()) {
242
250
  console.error('Login error:', loginResult.error);
243
251
  }
244
252
 
245
- // Get a product account by DotNS identifier and derivation index
253
+ // Get a product account by DotNS identifier and account selector. The selector
254
+ // is a plain index (the primary, enumerable form) or a raw 32-byte index
255
+ // (RFC 0022); it defaults to index 0, the product's default account.
246
256
  const accountResult = await accounts.getProductAccount('product.dot', 0);
257
+ // …or, for a byte-valued selector:
258
+ // const accountResult = await accounts.getProductAccount('product.dot', raw32);
247
259
 
248
260
  if (accountResult.isOk()) {
249
261
  const account: ProductAccount = accountResult.value;
@@ -252,7 +264,9 @@ if (accountResult.isOk()) {
252
264
 
253
265
  // Ring VRF: a contextual alias and a proof are addressed by a product-scoped
254
266
  // `context` (`[productId, suffix]`) and a `ring` location on a chain (RFC 0004).
255
- const context: [string, string] = ['product.dot', '0x00']; // [productId, 0x-hex suffix]
267
+ // The suffix is the same selector as an account's derivation index and expands
268
+ // to the same 32-byte value (RFC 0022).
269
+ const context: ProofContext = ['product.dot', 0]; // [productId, selector]
256
270
  const ring = {
257
271
  chainId: '0x…', // 32-byte chain genesis hash
258
272
  junctions: [{ tag: 'PalletInstance', value: 42 }],
@@ -274,6 +288,26 @@ if (proofResult.isOk()) {
274
288
  console.log('Proof:', proof, 'at ring index', ringIndex, 'revision', ringRevision);
275
289
  }
276
290
 
291
+ // sr25519 VRF signature over a product account (RFC-0023). The transcript is a
292
+ // recipe — a root label plus ordered `(label, value)` items — that the host
293
+ // replays verbatim (`Transcript::new(label)` then one `append_message` per item)
294
+ // and signs. It never injects a `signer` item; pass the account's public key
295
+ // yourself if the transcript needs one.
296
+ import type { VrfTranscriptItem } from '@novasamatech/host-api-wrapper';
297
+
298
+ const transcriptLabel = new TextEncoder().encode('my-product-lottery');
299
+ const items: VrfTranscriptItem[] = [{ label: new TextEncoder().encode('round'), value: new Uint8Array([7]) }];
300
+
301
+ const vrfResult = await accounts.signVrf('product.dot', 0, transcriptLabel, items);
302
+
303
+ if (vrfResult.isOk()) {
304
+ const { preOutput, proof } = vrfResult.value; // 32-byte VRFPreOut, 64-byte VRFProof
305
+ console.log('VRF pre-output:', preOutput, 'proof:', proof);
306
+ } else {
307
+ // err.tag: 'NotConnected' | 'Rejected' | 'Unknown'
308
+ console.error('signVrf failed:', vrfResult.error.tag);
309
+ }
310
+
277
311
  // Get legacy accounts (external wallets)
278
312
  const legacyAccountsResult = await accounts.getLegacyAccounts();
279
313
 
@@ -427,10 +461,11 @@ const balanceSub = payments.subscribeBalance(balance => {
427
461
  });
428
462
  balanceSub.onInterrupt(() => console.log('Balance access denied or lost'));
429
463
 
430
- // Top up the user's balance from a product account
464
+ // Top up the user's balance from one of the calling product's accounts.
465
+ // `derivationIndex` is the same selector as `accounts.getProductAccount` takes:
466
+ // a plain index or a raw 32-byte index (RFC 0022).
431
467
  await payments.topUp(1_000_000n, {
432
468
  type: 'productAccount',
433
- dotNsIdentifier: 'my-product.dot',
434
469
  derivationIndex: 0,
435
470
  });
436
471
 
@@ -1,14 +1,27 @@
1
- import type { AccountConnectionStatus as AccountConnectionStatusCodec, CodecType, LegacyAccount as LegacyAccountCodec, ProductAccountId as ProductAccountIdCodec, Subscription, Transport } from '@novasamatech/host-api';
2
- import { ProductProofContext, RingLocation } from '@novasamatech/host-api';
1
+ import type { AccountConnectionStatus as AccountConnectionStatusCodec, AccountSelector, CodecType, LegacyAccount as LegacyAccountCodec, ProductAccountId as ProductAccountIdCodec, Subscription, Transport, VrfTranscriptItem as VrfTranscriptItemCodec } from '@novasamatech/host-api';
2
+ import { RingLocation } from '@novasamatech/host-api';
3
3
  import type { PolkadotSigner } from 'polkadot-api';
4
+ export type { AccountSelector } from '@novasamatech/host-api';
4
5
  export type ProductAccountId = CodecType<typeof ProductAccountIdCodec>;
5
6
  export type ProductAccount = {
6
7
  dotNsIdentifier: string;
7
- derivationIndex: number;
8
+ /**
9
+ * Account selector within the product subtree (RFC 0022): a plain index or a
10
+ * raw 32-byte index.
11
+ */
12
+ derivationIndex: AccountSelector;
8
13
  publicKey: Uint8Array;
9
14
  };
15
+ /**
16
+ * Product-scoped proof context (RFC 0004, amended by RFC 0022): the product id
17
+ * plus a selector that expands to the same 32-byte derivation index as a
18
+ * product account's.
19
+ */
20
+ export type ProofContext = [productId: string, suffix: AccountSelector];
10
21
  export type LegacyAccount = CodecType<typeof LegacyAccountCodec>;
11
22
  export type AccountConnectionStatus = CodecType<typeof AccountConnectionStatusCodec>;
23
+ /** One `transcript.append_message(label, value)` call replayed by the host (RFC-0023). */
24
+ export type VrfTranscriptItem = CodecType<typeof VrfTranscriptItemCodec>;
12
25
  export declare const createAccountsProvider: (transport?: Transport) => {
13
26
  getUserId(): import("neverthrow").ResultAsync<{
14
27
  primaryUsername: string;
@@ -18,14 +31,14 @@ export declare const createAccountsProvider: (transport?: Transport) => {
18
31
  requestLogin(reason?: string): import("neverthrow").ResultAsync<"success" | "alreadyConnected" | "rejected", import("@novasamatech/scale").CodecError<{
19
32
  reason: string;
20
33
  }, "LoginErr::Unknown">>;
21
- getProductAccount(dotNsIdentifier: string, derivationIndex?: number): import("neverthrow").ResultAsync<{
34
+ getProductAccount(dotNsIdentifier: string, derivationIndex?: AccountSelector): import("neverthrow").ResultAsync<{
22
35
  publicKey: Uint8Array<ArrayBufferLike>;
23
36
  dotNsIdentifier: string;
24
- derivationIndex: number;
37
+ derivationIndex: AccountSelector;
25
38
  }, import("@novasamatech/scale").CodecError<undefined, "RequestCredentialsErr::NotConnected"> | import("@novasamatech/scale").CodecError<undefined, "RequestCredentialsErr::Rejected"> | import("@novasamatech/scale").CodecError<undefined, "RequestCredentialsErr::DomainNotValid"> | import("@novasamatech/scale").CodecError<{
26
39
  reason: string;
27
40
  }, "RequestCredentialsErr::Unknown">>;
28
- getContextualAlias(context: CodecType<typeof ProductProofContext>, ring: CodecType<typeof RingLocation>): import("neverthrow").ResultAsync<{
41
+ getContextualAlias(context: ProofContext, ring: CodecType<typeof RingLocation>): import("neverthrow").ResultAsync<{
29
42
  context: Uint8Array<ArrayBufferLike>;
30
43
  alias: Uint8Array<ArrayBufferLike>;
31
44
  }, import("@novasamatech/scale").CodecError<undefined, "GetAliasErr::Rejected"> | import("@novasamatech/scale").CodecError<{
@@ -37,7 +50,7 @@ export declare const createAccountsProvider: (transport?: Transport) => {
37
50
  }[], import("@novasamatech/scale").CodecError<undefined, "RequestCredentialsErr::NotConnected"> | import("@novasamatech/scale").CodecError<undefined, "RequestCredentialsErr::Rejected"> | import("@novasamatech/scale").CodecError<undefined, "RequestCredentialsErr::DomainNotValid"> | import("@novasamatech/scale").CodecError<{
38
51
  reason: string;
39
52
  }, "RequestCredentialsErr::Unknown">>;
40
- createRingVRFProof(context: CodecType<typeof ProductProofContext>, ring: CodecType<typeof RingLocation>, message: Uint8Array): import("neverthrow").ResultAsync<{
53
+ createRingVRFProof(context: ProofContext, ring: CodecType<typeof RingLocation>, message: Uint8Array): import("neverthrow").ResultAsync<{
41
54
  proof: Uint8Array<ArrayBufferLike>;
42
55
  contextualAlias: {
43
56
  context: Uint8Array<ArrayBufferLike>;
@@ -48,6 +61,20 @@ export declare const createAccountsProvider: (transport?: Transport) => {
48
61
  }, import("@novasamatech/scale").CodecError<undefined, "CreateProofErr::Rejected"> | import("@novasamatech/scale").CodecError<{
49
62
  reason: string;
50
63
  }, "CreateProofErr::Unknown"> | import("@novasamatech/scale").CodecError<undefined, "CreateProofErr::RingNotFound"> | import("@novasamatech/scale").CodecError<undefined, "CreateProofErr::NotMember">>;
64
+ /**
65
+ * Produces an sr25519 (schnorrkel) VRF signature from a product account (RFC-0023).
66
+ *
67
+ * The host replays `transcriptLabel` and `items` into a Merlin transcript verbatim —
68
+ * `Transcript::new(transcriptLabel)` then one `append_message(label, value)` per item,
69
+ * in order — and signs it. Callers that need a `signer` item must pass their own public
70
+ * key (from `getProductAccount`); the host never injects it.
71
+ */
72
+ signVrf(dotNsIdentifier: string, derivationIndex: AccountSelector, transcriptLabel: Uint8Array, items: VrfTranscriptItem[]): import("neverthrow").ResultAsync<{
73
+ preOutput: Uint8Array<ArrayBufferLike>;
74
+ proof: Uint8Array<ArrayBufferLike>;
75
+ }, import("@novasamatech/scale").CodecError<undefined, "SignVrfErr::NotConnected"> | import("@novasamatech/scale").CodecError<undefined, "SignVrfErr::Rejected"> | import("@novasamatech/scale").CodecError<{
76
+ reason: string;
77
+ }, "SignVrfErr::Unknown">>;
51
78
  /**
52
79
  * Builds a `PolkadotSigner` that delegates to the host via `host_create_transaction`.
53
80
  *
@@ -67,14 +94,14 @@ export declare const accounts: {
67
94
  requestLogin(reason?: string): import("neverthrow").ResultAsync<"success" | "alreadyConnected" | "rejected", import("@novasamatech/scale").CodecError<{
68
95
  reason: string;
69
96
  }, "LoginErr::Unknown">>;
70
- getProductAccount(dotNsIdentifier: string, derivationIndex?: number): import("neverthrow").ResultAsync<{
97
+ getProductAccount(dotNsIdentifier: string, derivationIndex?: AccountSelector): import("neverthrow").ResultAsync<{
71
98
  publicKey: Uint8Array<ArrayBufferLike>;
72
99
  dotNsIdentifier: string;
73
- derivationIndex: number;
100
+ derivationIndex: AccountSelector;
74
101
  }, import("@novasamatech/scale").CodecError<undefined, "RequestCredentialsErr::NotConnected"> | import("@novasamatech/scale").CodecError<undefined, "RequestCredentialsErr::Rejected"> | import("@novasamatech/scale").CodecError<undefined, "RequestCredentialsErr::DomainNotValid"> | import("@novasamatech/scale").CodecError<{
75
102
  reason: string;
76
103
  }, "RequestCredentialsErr::Unknown">>;
77
- getContextualAlias(context: CodecType<typeof ProductProofContext>, ring: CodecType<typeof RingLocation>): import("neverthrow").ResultAsync<{
104
+ getContextualAlias(context: ProofContext, ring: CodecType<typeof RingLocation>): import("neverthrow").ResultAsync<{
78
105
  context: Uint8Array<ArrayBufferLike>;
79
106
  alias: Uint8Array<ArrayBufferLike>;
80
107
  }, import("@novasamatech/scale").CodecError<undefined, "GetAliasErr::Rejected"> | import("@novasamatech/scale").CodecError<{
@@ -86,7 +113,7 @@ export declare const accounts: {
86
113
  }[], import("@novasamatech/scale").CodecError<undefined, "RequestCredentialsErr::NotConnected"> | import("@novasamatech/scale").CodecError<undefined, "RequestCredentialsErr::Rejected"> | import("@novasamatech/scale").CodecError<undefined, "RequestCredentialsErr::DomainNotValid"> | import("@novasamatech/scale").CodecError<{
87
114
  reason: string;
88
115
  }, "RequestCredentialsErr::Unknown">>;
89
- createRingVRFProof(context: CodecType<typeof ProductProofContext>, ring: CodecType<typeof RingLocation>, message: Uint8Array): import("neverthrow").ResultAsync<{
116
+ createRingVRFProof(context: ProofContext, ring: CodecType<typeof RingLocation>, message: Uint8Array): import("neverthrow").ResultAsync<{
90
117
  proof: Uint8Array<ArrayBufferLike>;
91
118
  contextualAlias: {
92
119
  context: Uint8Array<ArrayBufferLike>;
@@ -97,6 +124,20 @@ export declare const accounts: {
97
124
  }, import("@novasamatech/scale").CodecError<undefined, "CreateProofErr::Rejected"> | import("@novasamatech/scale").CodecError<{
98
125
  reason: string;
99
126
  }, "CreateProofErr::Unknown"> | import("@novasamatech/scale").CodecError<undefined, "CreateProofErr::RingNotFound"> | import("@novasamatech/scale").CodecError<undefined, "CreateProofErr::NotMember">>;
127
+ /**
128
+ * Produces an sr25519 (schnorrkel) VRF signature from a product account (RFC-0023).
129
+ *
130
+ * The host replays `transcriptLabel` and `items` into a Merlin transcript verbatim —
131
+ * `Transcript::new(transcriptLabel)` then one `append_message(label, value)` per item,
132
+ * in order — and signs it. Callers that need a `signer` item must pass their own public
133
+ * key (from `getProductAccount`); the host never injects it.
134
+ */
135
+ signVrf(dotNsIdentifier: string, derivationIndex: AccountSelector, transcriptLabel: Uint8Array, items: VrfTranscriptItem[]): import("neverthrow").ResultAsync<{
136
+ preOutput: Uint8Array<ArrayBufferLike>;
137
+ proof: Uint8Array<ArrayBufferLike>;
138
+ }, import("@novasamatech/scale").CodecError<undefined, "SignVrfErr::NotConnected"> | import("@novasamatech/scale").CodecError<undefined, "SignVrfErr::Rejected"> | import("@novasamatech/scale").CodecError<{
139
+ reason: string;
140
+ }, "SignVrfErr::Unknown">>;
100
141
  /**
101
142
  * Builds a `PolkadotSigner` that delegates to the host via `host_create_transaction`.
102
143
  *
package/dist/accounts.js CHANGED
@@ -1,4 +1,4 @@
1
- import { CreateProofErr, GetAliasErr, GetUserIdErr, LoginErr, ProductProofContext, RequestCredentialsErr, RingLocation, SigningPayload, SigningPayloadWithoutAccount, SigningRawPayload, SigningRawPayloadWithoutAccount, assertEnumVariant, createHostApi, enumValue, fromHex, isEnumVariant, toHex, } from '@novasamatech/host-api';
1
+ import { CreateProofErr, GetAliasErr, GetUserIdErr, LoginErr, ProductProofContext, RequestCredentialsErr, RingLocation, SignVrfErr, SigningPayload, SigningPayloadWithoutAccount, SigningRawPayload, SigningRawPayloadWithoutAccount, assertEnumVariant, createHostApi, derivationIndexOf, enumValue, fromHex, isEnumVariant, toHex, } from '@novasamatech/host-api';
2
2
  import { decAnyMetadata, unifyMetadata } from '@polkadot-api/substrate-bindings';
3
3
  import { err, ok } from 'neverthrow';
4
4
  import { AccountId } from 'polkadot-api';
@@ -34,7 +34,7 @@ export const createAccountsProvider = (transport = sandboxTransport) => {
34
34
  },
35
35
  getProductAccount(dotNsIdentifier, derivationIndex = 0) {
36
36
  return hostApi
37
- .accountGet(enumValue('v1', [dotNsIdentifier, derivationIndex]))
37
+ .accountGet(enumValue('v1', [dotNsIdentifier, derivationIndexOf(derivationIndex)]))
38
38
  .mapErr(e => e.value)
39
39
  .andThen(response => {
40
40
  if (isEnumVariant(response, 'v1')) {
@@ -50,7 +50,7 @@ export const createAccountsProvider = (transport = sandboxTransport) => {
50
50
  },
51
51
  getContextualAlias(context, ring) {
52
52
  return hostApi
53
- .accountGetAlias(enumValue('v1', [context, ring]))
53
+ .accountGetAlias(enumValue('v1', [toProofContext(context), ring]))
54
54
  .mapErr(e => e.value)
55
55
  .andThen(response => {
56
56
  if (isEnumVariant(response, 'v1')) {
@@ -74,7 +74,7 @@ export const createAccountsProvider = (transport = sandboxTransport) => {
74
74
  },
75
75
  createRingVRFProof(context, ring, message) {
76
76
  return hostApi
77
- .accountCreateProof(enumValue('v1', [context, ring, message]))
77
+ .accountCreateProof(enumValue('v1', [toProofContext(context), ring, message]))
78
78
  .mapErr(e => e.value)
79
79
  .andThen(response => {
80
80
  if (isEnumVariant(response, 'v1')) {
@@ -84,6 +84,26 @@ export const createAccountsProvider = (transport = sandboxTransport) => {
84
84
  return err(new CreateProofErr.Unknown({ reason: `Unsupported response version ${response.tag}` }));
85
85
  });
86
86
  },
87
+ /**
88
+ * Produces an sr25519 (schnorrkel) VRF signature from a product account (RFC-0023).
89
+ *
90
+ * The host replays `transcriptLabel` and `items` into a Merlin transcript verbatim —
91
+ * `Transcript::new(transcriptLabel)` then one `append_message(label, value)` per item,
92
+ * in order — and signs it. Callers that need a `signer` item must pass their own public
93
+ * key (from `getProductAccount`); the host never injects it.
94
+ */
95
+ signVrf(dotNsIdentifier, derivationIndex, transcriptLabel, items) {
96
+ return hostApi
97
+ .accountSignVrf(enumValue('v1', { account: [dotNsIdentifier, derivationIndexOf(derivationIndex)], transcriptLabel, items }))
98
+ .mapErr(e => e.value)
99
+ .andThen(response => {
100
+ if (isEnumVariant(response, 'v1')) {
101
+ return ok(response.value);
102
+ }
103
+ // @ts-expect-error response.tag is never here
104
+ return err(new SignVrfErr.Unknown({ reason: `Unsupported response version ${response.tag}` }));
105
+ });
106
+ },
87
107
  /**
88
108
  * Builds a `PolkadotSigner` that delegates to the host via `host_create_transaction`.
89
109
  *
@@ -92,14 +112,14 @@ export const createAccountsProvider = (transport = sandboxTransport) => {
92
112
  */
93
113
  getProductAccountSigner(account, signerType = 'createTransaction') {
94
114
  const hostApi = createHostApi(transport);
95
- const productAccountId = [account.dotNsIdentifier, account.derivationIndex];
115
+ const productAccountId = [account.dotNsIdentifier, derivationIndexOf(account.derivationIndex)];
96
116
  /**
97
117
  * @deprecated added for backward compatibility
98
118
  */
99
119
  if (signerType === 'signPayload') {
100
120
  return getPolkadotSignerFromPjs(toHex(account.publicKey), async (payload) => {
101
121
  const codecPayload = {
102
- account: [account.dotNsIdentifier, account.derivationIndex],
122
+ account: productAccountId,
103
123
  payload: buildSigningPayloadFields(payload),
104
124
  };
105
125
  const response = await hostApi.signPayload(enumValue('v1', codecPayload));
@@ -116,7 +136,7 @@ export const createAccountsProvider = (transport = sandboxTransport) => {
116
136
  });
117
137
  }, async (raw) => {
118
138
  const payload = {
119
- account: [account.dotNsIdentifier, account.derivationIndex],
139
+ account: productAccountId,
120
140
  payload: raw.type === 'bytes'
121
141
  ? {
122
142
  tag: 'Bytes',
@@ -154,7 +174,7 @@ export const createAccountsProvider = (transport = sandboxTransport) => {
154
174
  }
155
175
  const txPayload = {
156
176
  signer: productAccountId,
157
- genesisHash: checkGenesis.additionalSigned,
177
+ genesisHash: toHex(checkGenesis.additionalSigned),
158
178
  callData,
159
179
  extensions: Object.values(signedExtensions).map(({ identifier, value, additionalSigned }) => ({
160
180
  id: identifier,
@@ -243,6 +263,9 @@ export const createAccountsProvider = (transport = sandboxTransport) => {
243
263
  };
244
264
  };
245
265
  export const accounts = createAccountsProvider();
266
+ function toProofContext([productId, suffix]) {
267
+ return [productId, derivationIndexOf(suffix)];
268
+ }
246
269
  function asHex(v) {
247
270
  if (v.startsWith('0x'))
248
271
  return v;
package/dist/index.d.ts CHANGED
@@ -6,9 +6,9 @@ export { createLegacyExtensionEnableFactory, injectSpektrExtension } from './inj
6
6
  export { createPapiProvider } from './papiProvider.js';
7
7
  export type { ChatBotRegistrationResult, ChatCustomMessageRenderer, ChatCustomMessageRendererParams, ChatMessageContent, ChatReceivedAction, ChatRoom, ChatRoomRegistrationResult, } from './chat.js';
8
8
  export { createProductChatManager, matchChatCustomRenderers } from './chat.js';
9
- export type { ProductAccountId, SignedStatement, Statement, StatementTopicFilter, StatementsPage, Topic, } from './statementStore.js';
9
+ export type { ProductAccountId, ProductAccountRef, SignedStatement, Statement, StatementTopicFilter, StatementsPage, Topic, } from './statementStore.js';
10
10
  export { createStatementStore } from './statementStore.js';
11
- export type { AccountConnectionStatus, LegacyAccount, ProductAccount } from './accounts.js';
11
+ export type { AccountConnectionStatus, AccountSelector, LegacyAccount, ProductAccount, ProofContext, VrfTranscriptItem, } from './accounts.js';
12
12
  export { accounts, createAccountsProvider } from './accounts.js';
13
13
  export type { ThemeMode } from './theme.js';
14
14
  export { createThemeProvider } from './theme.js';
@@ -115,7 +115,7 @@ export async function createLegacyExtensionEnableFactory(transport) {
115
115
  const possibleAccountId = accountId.enc(signer);
116
116
  const response = await hostApi.createTransactionWithLegacyAccount(enumValue('v1', {
117
117
  signer: possibleAccountId,
118
- genesisHash: fromHex(checkGenesis.additionalSigned),
118
+ genesisHash: checkGenesis.additionalSigned,
119
119
  callData: fromHex(payload.callData),
120
120
  txExtVersion: payload.txExtVersion,
121
121
  extensions: payload.extensions.map(e => ({
@@ -32,9 +32,10 @@ export const createLocalStorage = (transport = sandboxTransport) => {
32
32
  return writeBytes(key, textEncoder.encode(value));
33
33
  },
34
34
  async readJSON(key) {
35
- return readBytes(key)
36
- .then(bytes => textDecoder.decode(bytes))
37
- .then(JSON.parse);
35
+ const bytes = await readBytes(key);
36
+ if (bytes === undefined || bytes.length === 0)
37
+ return undefined;
38
+ return JSON.parse(textDecoder.decode(bytes));
38
39
  },
39
40
  async writeJSON(key, value) {
40
41
  return writeBytes(key, textEncoder.encode(JSON.stringify(value)));
@@ -1,4 +1,4 @@
1
- import type { CodecType, PaymentBalanceErr, Subscription, Transport } from '@novasamatech/host-api';
1
+ import type { AccountSelector, CodecType, PaymentBalanceErr, Subscription, Transport } from '@novasamatech/host-api';
2
2
  export type PaymentBalance = {
3
3
  available: bigint;
4
4
  };
@@ -10,9 +10,11 @@ export type PaymentStatus = {
10
10
  type: 'failed';
11
11
  reason: string;
12
12
  };
13
- export type TopUpSource = {
13
+ export type TopUpSource =
14
+ /** `derivationIndex` is the RFC-0022 selector: a plain index or a raw 32-byte index. */
15
+ {
14
16
  type: 'productAccount';
15
- derivationIndex: number;
17
+ derivationIndex: AccountSelector;
16
18
  } | {
17
19
  type: 'privateKey';
18
20
  key: Uint8Array;
package/dist/payments.js CHANGED
@@ -1,4 +1,4 @@
1
- import { createHostApi, enumValue } from '@novasamatech/host-api';
1
+ import { createHostApi, derivationIndexOf, enumValue } from '@novasamatech/host-api';
2
2
  import { resultToPromise, unwrapVersionedResult } from './helpers.js';
3
3
  import { sandboxTransport } from './sandboxTransport.js';
4
4
  export const createPaymentManager = (transport = sandboxTransport) => {
@@ -20,7 +20,7 @@ export const createPaymentManager = (transport = sandboxTransport) => {
20
20
  const sourceCodec = source.type === 'productAccount'
21
21
  ? {
22
22
  tag: 'ProductAccount',
23
- value: source.derivationIndex,
23
+ value: derivationIndexOf(source.derivationIndex),
24
24
  }
25
25
  : source.type === 'privateKey'
26
26
  ? { tag: 'PrivateKey', value: source.key }
@@ -1,8 +1,14 @@
1
- import type { CodecType, ProductAccountId as ProductAccountIdCodec, SignedStatement as SignedStatementCodec, Statement as StatementCodec, Subscription, Topic as TopicCodec, Transport } from '@novasamatech/host-api';
1
+ import type { AccountSelector, CodecType, ProductAccountId as ProductAccountIdCodec, SignedStatement as SignedStatementCodec, Statement as StatementCodec, Subscription, Topic as TopicCodec, Transport } from '@novasamatech/host-api';
2
2
  export type Statement = CodecType<typeof StatementCodec>;
3
3
  export type SignedStatement = CodecType<typeof SignedStatementCodec>;
4
4
  export type Topic = CodecType<typeof TopicCodec>;
5
+ /** Wire-level product account id — the selector in its `Index`/`Raw` form. */
5
6
  export type ProductAccountId = CodecType<typeof ProductAccountIdCodec>;
7
+ /**
8
+ * Product account reference in ergonomic form: the dotNS identifier plus a
9
+ * plain index or a raw 32-byte index (RFC 0022).
10
+ */
11
+ export type ProductAccountRef = [dotNsIdentifier: string, derivationIndex: AccountSelector];
6
12
  export type StatementTopicFilter = {
7
13
  matchAll: Topic[];
8
14
  } | {
@@ -14,7 +20,7 @@ export type StatementsPage = {
14
20
  };
15
21
  export declare const createStatementStore: (transport?: Transport) => {
16
22
  subscribe(filter: StatementTopicFilter, callback: (page: StatementsPage) => void): Subscription<void>;
17
- createProof(accountId: ProductAccountId, statement: Statement): Promise<{
23
+ createProof([dotNsIdentifier, derivationIndex]: ProductAccountRef, statement: Statement): Promise<{
18
24
  tag: "Sr25519";
19
25
  value: {
20
26
  signature: Uint8Array<ArrayBufferLike>;
@@ -1,4 +1,4 @@
1
- import { createHostApi, enumValue } from '@novasamatech/host-api';
1
+ import { createHostApi, derivationIndexOf, enumValue } from '@novasamatech/host-api';
2
2
  import { sandboxTransport } from './sandboxTransport.js';
3
3
  export const createStatementStore = (transport = sandboxTransport) => {
4
4
  const hostApi = createHostApi(transport);
@@ -15,7 +15,8 @@ export const createStatementStore = (transport = sandboxTransport) => {
15
15
  onInterrupt: cb => subscriber.onInterrupt(v => cb(v.value)),
16
16
  };
17
17
  },
18
- async createProof(accountId, statement) {
18
+ async createProof([dotNsIdentifier, derivationIndex], statement) {
19
+ const accountId = [dotNsIdentifier, derivationIndexOf(derivationIndex)];
19
20
  const result = await hostApi.statementStoreCreateProof(enumValue('v1', [accountId, statement]));
20
21
  return result.match(payload => {
21
22
  if (payload.tag === 'v1') {
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@novasamatech/host-api-wrapper",
3
3
  "type": "module",
4
- "version": "0.8.11",
4
+ "version": "0.9.0",
5
5
  "description": "Host API wrapper: integrate and run your product inside Polkadot browser.",
6
6
  "license": "Apache-2.0",
7
7
  "repository": {
@@ -28,7 +28,7 @@
28
28
  "@polkadot/extension-inject": "^0.63.1",
29
29
  "@polkadot-api/json-rpc-provider-proxy": "^0.4.0",
30
30
  "@polkadot-api/substrate-bindings": "^0.20.3",
31
- "@novasamatech/host-api": "0.8.11",
31
+ "@novasamatech/host-api": "0.9.0",
32
32
  "polkadot-api": ">=2",
33
33
  "neverthrow": "^8.2.0"
34
34
  },