@novasamatech/product-sdk 0.7.8 → 0.7.9-1

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
@@ -211,15 +211,12 @@ subscription.unsubscribe();
211
211
  The Accounts Provider allows you to access product accounts and create signers for signing transactions.
212
212
 
213
213
  ```ts
214
- import { createAccountsProvider } from '@novasamatech/product-sdk';
214
+ import { accounts } from '@novasamatech/product-sdk';
215
215
  import type { ProductAccount } from '@novasamatech/product-sdk';
216
216
 
217
- // Create accounts provider instance
218
- const accountsProvider = createAccountsProvider();
219
-
220
217
  // Get the user's primary DotNS username (RFC-0014)
221
218
  // — prompts for permission on first call
222
- const userIdResult = await accountsProvider.getUserId();
219
+ const userIdResult = await accounts.getUserId();
223
220
 
224
221
  if (userIdResult.isOk()) {
225
222
  const { primaryUsername } = userIdResult.value;
@@ -234,7 +231,7 @@ if (userIdResult.isOk()) {
234
231
  }
235
232
 
236
233
  // Request login — triggers host sign-in UI; reason is shown to the user
237
- const loginResult = await accountsProvider.requestLogin('Sign in to access your account');
234
+ const loginResult = await accounts.requestLogin('Sign in to access your account');
238
235
 
239
236
  if (loginResult.isOk()) {
240
237
  const outcome = loginResult.value; // 'success' | 'alreadyConnected' | 'rejected'
@@ -246,7 +243,7 @@ if (loginResult.isOk()) {
246
243
  }
247
244
 
248
245
  // Get a product account by DotNS identifier and derivation index
249
- const accountResult = await accountsProvider.getProductAccount('product.dot', 0);
246
+ const accountResult = await accounts.getProductAccount('product.dot', 0);
250
247
 
251
248
  if (accountResult.isOk()) {
252
249
  const account: ProductAccount = accountResult.value;
@@ -254,42 +251,49 @@ if (accountResult.isOk()) {
254
251
  }
255
252
 
256
253
  // Get account alias
257
- const aliasResult = await accountsProvider.getProductAccountAlias('product.dot', 0);
254
+ const aliasResult = await accounts.getProductAccountAlias('product.dot', 0);
258
255
 
259
256
  if (aliasResult.isOk()) {
260
257
  console.log('Alias:', aliasResult.value);
261
258
  }
262
259
 
263
260
  // Get legacy accounts (external wallets)
264
- const legacyAccountsResult = await accountsProvider.getLegacyAccounts();
261
+ const legacyAccountsResult = await accounts.getLegacyAccounts();
265
262
 
266
263
  if (legacyAccountsResult.isOk()) {
267
264
  console.log('Legacy accounts:', legacyAccountsResult.value);
268
265
  }
269
266
 
270
267
  // Subscribe to account connection status changes
271
- const unsubscribe = accountsProvider.subscribeAccountConnectionStatus((status) => {
268
+ const unsubscribe = accounts.subscribeAccountConnectionStatus((status) => {
272
269
  // status: 'connected' | 'disconnected'
273
270
  console.log('Account connection status:', status);
274
271
  });
275
272
 
276
- // Create a signer for a product account (for use with PAPI)
277
- const account: ProductAccount = {
278
- dotNsIdentifier: 'product.dot',
279
- derivationIndex: 0,
280
- publicKey: new Uint8Array([/* ... */])
281
- };
282
- const signer = accountsProvider.getProductAccountSigner(account);
273
+ // Create a signer for a product account (for use with PAPI).
274
+ // Resolve the account first, then hand it to the signer factory.
275
+ const productAccountResult = await accounts.getProductAccount('product.dot', 0);
283
276
 
284
- // Create a signer for a legacy account
285
- const legacySigner = accountsProvider.getLegacyAccountSigner(account);
277
+ if (productAccountResult.isOk()) {
278
+ const productSigner = accounts.getProductAccountSigner(productAccountResult.value);
279
+ const signedTx = await tx.signAndSubmit(productSigner);
280
+ }
286
281
 
287
- // PAPI transaction signing example
282
+ // Create a signer for a legacy account.
283
+ // Fetch the legacy account list, pick one, then pass it to the signer factory.
284
+ const legacyAccountsResult = await accounts.getLegacyAccounts();
288
285
 
289
- const productAccountSignedTx = await tx.signAndSubmit(signer);
290
- const legacyAccountSignedTx = await tx.signAndSubmit(legacySigner);
286
+ if (legacyAccountsResult.isOk()) {
287
+ const [legacyAccount] = legacyAccountsResult.value;
288
+ if (legacyAccount) {
289
+ const legacySigner = accounts.getLegacyAccountSigner(legacyAccount);
290
+ const signedTx = await tx.signAndSubmit(legacySigner);
291
+ }
292
+ }
291
293
  ```
292
294
 
295
+ > If you need a non-default transport (e.g. for tests or multi-host setups), use `createAccountsProvider(transport)` to build your own instance with the same API.
296
+
293
297
  ### Local Storage
294
298
 
295
299
  The Local Storage module provides a way to persist data in the host application's storage.
@@ -1,11 +1,13 @@
1
- import type { AccountConnectionStatus as AccountConnectionStatusCodec, CodecType, Subscription, Transport } from '@novasamatech/host-api';
1
+ import type { AccountConnectionStatus as AccountConnectionStatusCodec, CodecType, LegacyAccount as LegacyAccountCodec, ProductAccountId as ProductAccountIdCodec, Subscription, Transport } from '@novasamatech/host-api';
2
2
  import { RingLocation } from '@novasamatech/host-api';
3
3
  import type { PolkadotSigner } from 'polkadot-api';
4
+ export type ProductAccountId = CodecType<typeof ProductAccountIdCodec>;
4
5
  export type ProductAccount = {
5
6
  dotNsIdentifier: string;
6
7
  derivationIndex: number;
7
8
  publicKey: Uint8Array;
8
9
  };
10
+ export type LegacyAccount = CodecType<typeof LegacyAccountCodec>;
9
11
  export type AccountConnectionStatus = CodecType<typeof AccountConnectionStatusCodec>;
10
12
  export declare const createAccountsProvider: (transport?: Transport) => {
11
13
  getUserId(): import("neverthrow").ResultAsync<{
@@ -18,6 +20,8 @@ export declare const createAccountsProvider: (transport?: Transport) => {
18
20
  }, "LoginErr::Unknown">>;
19
21
  getProductAccount(dotNsIdentifier: string, derivationIndex?: number): import("neverthrow").ResultAsync<{
20
22
  publicKey: Uint8Array<ArrayBufferLike>;
23
+ dotNsIdentifier: string;
24
+ derivationIndex: number;
21
25
  }, 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<{
22
26
  reason: string;
23
27
  }, "RequestCredentialsErr::Unknown">>;
@@ -36,7 +40,54 @@ export declare const createAccountsProvider: (transport?: Transport) => {
36
40
  createRingVRFProof(dotNsIdentifier: string, derivationIndex: number | undefined, location: CodecType<typeof RingLocation>, message: Uint8Array): import("neverthrow").ResultAsync<Uint8Array<ArrayBufferLike>, import("@novasamatech/scale").CodecError<undefined, "CreateProofErr::Rejected"> | import("@novasamatech/scale").CodecError<{
37
41
  reason: string;
38
42
  }, "CreateProofErr::Unknown"> | import("@novasamatech/scale").CodecError<undefined, "CreateProofErr::RingNotFound">>;
39
- getProductAccountSigner(account: ProductAccount): PolkadotSigner;
43
+ /**
44
+ * Builds a `PolkadotSigner` that delegates to the host via `host_create_transaction`.
45
+ *
46
+ * The factory is async because `PolkadotSigner.publicKey` must be a synchronous
47
+ * `Uint8Array` on the returned object — it is fetched up front via `host_account_get`.
48
+ */
49
+ getProductAccountSigner(account: ProductAccount, signerType?: "signPayload" | "createTransaction"): PolkadotSigner;
40
50
  subscribeAccountConnectionStatus(callback: (status: AccountConnectionStatus) => void): Subscription<void>;
41
- getLegacyAccountSigner(account: ProductAccount): PolkadotSigner;
51
+ getLegacyAccountSigner(account: LegacyAccount): PolkadotSigner;
52
+ };
53
+ export declare const accounts: {
54
+ getUserId(): import("neverthrow").ResultAsync<{
55
+ primaryUsername: string;
56
+ }, import("@novasamatech/scale").CodecError<undefined, "GetUserIdErr::NotConnected"> | import("@novasamatech/scale").CodecError<{
57
+ reason: string;
58
+ }, "GetUserIdErr::Unknown"> | import("@novasamatech/scale").CodecError<undefined, "GetUserIdErr::PermissionDenied">>;
59
+ requestLogin(reason?: string): import("neverthrow").ResultAsync<"success" | "alreadyConnected" | "rejected", import("@novasamatech/scale").CodecError<{
60
+ reason: string;
61
+ }, "LoginErr::Unknown">>;
62
+ getProductAccount(dotNsIdentifier: string, derivationIndex?: number): import("neverthrow").ResultAsync<{
63
+ publicKey: Uint8Array<ArrayBufferLike>;
64
+ dotNsIdentifier: string;
65
+ derivationIndex: number;
66
+ }, 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<{
67
+ reason: string;
68
+ }, "RequestCredentialsErr::Unknown">>;
69
+ getProductAccountAlias(dotNsIdentifier: string, derivationIndex?: number): import("neverthrow").ResultAsync<{
70
+ context: Uint8Array<ArrayBufferLike>;
71
+ alias: Uint8Array<ArrayBufferLike>;
72
+ }, 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<{
73
+ reason: string;
74
+ }, "RequestCredentialsErr::Unknown">>;
75
+ getLegacyAccounts(): import("neverthrow").ResultAsync<{
76
+ publicKey: Uint8Array<ArrayBufferLike>;
77
+ name: string | undefined;
78
+ }[], 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<{
79
+ reason: string;
80
+ }, "RequestCredentialsErr::Unknown">>;
81
+ createRingVRFProof(dotNsIdentifier: string, derivationIndex: number | undefined, location: CodecType<typeof RingLocation>, message: Uint8Array): import("neverthrow").ResultAsync<Uint8Array<ArrayBufferLike>, import("@novasamatech/scale").CodecError<undefined, "CreateProofErr::Rejected"> | import("@novasamatech/scale").CodecError<{
82
+ reason: string;
83
+ }, "CreateProofErr::Unknown"> | import("@novasamatech/scale").CodecError<undefined, "CreateProofErr::RingNotFound">>;
84
+ /**
85
+ * Builds a `PolkadotSigner` that delegates to the host via `host_create_transaction`.
86
+ *
87
+ * The factory is async because `PolkadotSigner.publicKey` must be a synchronous
88
+ * `Uint8Array` on the returned object — it is fetched up front via `host_account_get`.
89
+ */
90
+ getProductAccountSigner(account: ProductAccount, signerType?: "signPayload" | "createTransaction"): PolkadotSigner;
91
+ subscribeAccountConnectionStatus(callback: (status: AccountConnectionStatus) => void): Subscription<void>;
92
+ getLegacyAccountSigner(account: LegacyAccount): PolkadotSigner;
42
93
  };
package/dist/accounts.js CHANGED
@@ -1,4 +1,5 @@
1
1
  import { CreateProofErr, GetUserIdErr, LoginErr, RequestCredentialsErr, RingLocation, SigningPayload, SigningPayloadWithoutAccount, SigningRawPayload, SigningRawPayloadWithoutAccount, assertEnumVariant, createHostApi, enumValue, fromHex, isEnumVariant, toHex, } from '@novasamatech/host-api';
2
+ import { decAnyMetadata, unifyMetadata } from '@polkadot-api/substrate-bindings';
2
3
  import { err, ok } from 'neverthrow';
3
4
  import { getPolkadotSignerFromPjs } from 'polkadot-api/pjs-signer';
4
5
  import { sandboxTransport } from './sandboxTransport.js';
@@ -36,7 +37,11 @@ export const createAccountsProvider = (transport = sandboxTransport) => {
36
37
  .mapErr(e => e.value)
37
38
  .andThen(response => {
38
39
  if (isEnumVariant(response, 'v1')) {
39
- return ok(response.value);
40
+ return ok({
41
+ publicKey: response.value.publicKey,
42
+ dotNsIdentifier,
43
+ derivationIndex,
44
+ });
40
45
  }
41
46
  // @ts-expect-error response.tag is never here
42
47
  return err(new RequestCredentialsErr.Unknown({ reason: `Unsupported response version ${response.tag}` }));
@@ -78,50 +83,103 @@ export const createAccountsProvider = (transport = sandboxTransport) => {
78
83
  return err(new CreateProofErr.Unknown({ reason: `Unsupported response version ${response.tag}` }));
79
84
  });
80
85
  },
81
- getProductAccountSigner(account) {
82
- return getPolkadotSignerFromPjs(toHex(account.publicKey), async (payload) => {
83
- const codecPayload = {
84
- account: [account.dotNsIdentifier, account.derivationIndex],
85
- payload: buildSigningPayloadFields(payload),
86
- };
87
- const response = await hostApi.signPayload(enumValue('v1', codecPayload));
88
- return response.match(response => {
89
- assertEnumVariant(response, 'v1', UNSUPPORTED_VERSION_ERROR);
90
- return {
91
- id: 0,
92
- signature: response.value.signature,
93
- signedTransaction: response.value.signedTransaction,
86
+ /**
87
+ * Builds a `PolkadotSigner` that delegates to the host via `host_create_transaction`.
88
+ *
89
+ * The factory is async because `PolkadotSigner.publicKey` must be a synchronous
90
+ * `Uint8Array` on the returned object — it is fetched up front via `host_account_get`.
91
+ */
92
+ getProductAccountSigner(account, signerType = 'signPayload') {
93
+ const hostApi = createHostApi(transport);
94
+ const productAccountId = [account.dotNsIdentifier, account.derivationIndex];
95
+ /**
96
+ * @deprecated added for backward compatibility
97
+ */
98
+ if (signerType === 'signPayload') {
99
+ return getPolkadotSignerFromPjs(toHex(account.publicKey), async (payload) => {
100
+ const codecPayload = {
101
+ account: [account.dotNsIdentifier, account.derivationIndex],
102
+ payload: buildSigningPayloadFields(payload),
94
103
  };
95
- }, err => {
96
- assertEnumVariant(err, 'v1', UNSUPPORTED_VERSION_ERROR);
97
- throw err.value;
98
- });
99
- }, async (raw) => {
100
- const payload = {
101
- account: [account.dotNsIdentifier, account.derivationIndex],
102
- payload: raw.type === 'bytes'
103
- ? {
104
- tag: 'Bytes',
105
- value: fromHex(asHex(raw.data)),
106
- }
107
- : {
108
- tag: 'Payload',
109
- value: raw.data,
110
- },
111
- };
112
- const response = await hostApi.signRaw(enumValue('v1', payload));
113
- return response.match(response => {
114
- assertEnumVariant(response, 'v1', UNSUPPORTED_VERSION_ERROR);
115
- return {
116
- id: 0,
117
- signature: response.value.signature,
118
- signedTransaction: response.value.signedTransaction,
104
+ const response = await hostApi.signPayload(enumValue('v1', codecPayload));
105
+ return response.match(response => {
106
+ assertEnumVariant(response, 'v1', UNSUPPORTED_VERSION_ERROR);
107
+ return {
108
+ id: 0,
109
+ signature: response.value.signature,
110
+ signedTransaction: response.value.signedTransaction,
111
+ };
112
+ }, err => {
113
+ assertEnumVariant(err, 'v1', UNSUPPORTED_VERSION_ERROR);
114
+ throw err.value;
115
+ });
116
+ }, async (raw) => {
117
+ const payload = {
118
+ account: [account.dotNsIdentifier, account.derivationIndex],
119
+ payload: raw.type === 'bytes'
120
+ ? {
121
+ tag: 'Bytes',
122
+ value: fromHex(asHex(raw.data)),
123
+ }
124
+ : {
125
+ tag: 'Payload',
126
+ value: raw.data,
127
+ },
119
128
  };
120
- }, err => {
121
- assertEnumVariant(err, 'v1', UNSUPPORTED_VERSION_ERROR);
122
- throw err.value;
129
+ const response = await hostApi.signRaw(enumValue('v1', payload));
130
+ return response.match(response => {
131
+ assertEnumVariant(response, 'v1', UNSUPPORTED_VERSION_ERROR);
132
+ return {
133
+ id: 0,
134
+ signature: response.value.signature,
135
+ signedTransaction: response.value.signedTransaction,
136
+ };
137
+ }, err => {
138
+ assertEnumVariant(err, 'v1', UNSUPPORTED_VERSION_ERROR);
139
+ throw err.value;
140
+ });
123
141
  });
124
- });
142
+ }
143
+ return {
144
+ publicKey: account.publicKey,
145
+ async signTx(callData, signedExtensions, metadata) {
146
+ const decMeta = unifyMetadata(decAnyMetadata(metadata));
147
+ const { version: versions } = decMeta.extrinsic;
148
+ const latestVersion = versions.reduce((acc, v) => Math.max(acc, v), 0);
149
+ const txExtVersion = latestVersion === 4 ? 0 : latestVersion;
150
+ const txPayload = {
151
+ signer: productAccountId,
152
+ callData,
153
+ extensions: Object.values(signedExtensions).map(({ identifier, value, additionalSigned }) => ({
154
+ id: identifier,
155
+ extra: value,
156
+ additionalSigned: additionalSigned,
157
+ })),
158
+ txExtVersion,
159
+ };
160
+ const response = await hostApi.createTransaction(enumValue('v1', txPayload));
161
+ return response.match(response => {
162
+ assertEnumVariant(response, 'v1', UNSUPPORTED_VERSION_ERROR);
163
+ return response.value;
164
+ }, err => {
165
+ assertEnumVariant(err, 'v1', UNSUPPORTED_VERSION_ERROR);
166
+ throw err.value;
167
+ });
168
+ },
169
+ async signBytes(data) {
170
+ const response = await hostApi.signRaw(enumValue('v1', {
171
+ account: productAccountId,
172
+ payload: { tag: 'Bytes', value: data },
173
+ }));
174
+ return response.match(response => {
175
+ assertEnumVariant(response, 'v1', UNSUPPORTED_VERSION_ERROR);
176
+ return fromHex(response.value.signature);
177
+ }, err => {
178
+ assertEnumVariant(err, 'v1', UNSUPPORTED_VERSION_ERROR);
179
+ throw err.value;
180
+ });
181
+ },
182
+ };
125
183
  },
126
184
  subscribeAccountConnectionStatus(callback) {
127
185
  const subscriber = hostApi.accountConnectionStatusSubscribe(enumValue('v1', undefined), status => {
@@ -173,6 +231,7 @@ export const createAccountsProvider = (transport = sandboxTransport) => {
173
231
  },
174
232
  };
175
233
  };
234
+ export const accounts = createAccountsProvider();
176
235
  function asHex(v) {
177
236
  if (v.startsWith('0x'))
178
237
  return v;
package/dist/index.d.ts CHANGED
@@ -8,8 +8,8 @@ export type { ChatBotRegistrationResult, ChatCustomMessageRenderer, ChatCustomMe
8
8
  export { createProductChatManager, matchChatCustomRenderers } from './chat.js';
9
9
  export type { ProductAccountId, SignedStatement, Statement, StatementTopicFilter, StatementsPage, Topic, } from './statementStore.js';
10
10
  export { createStatementStore } from './statementStore.js';
11
- export type { AccountConnectionStatus, ProductAccount } from './accounts.js';
12
- export { createAccountsProvider } from './accounts.js';
11
+ export type { AccountConnectionStatus, LegacyAccount, ProductAccount } from './accounts.js';
12
+ export { accounts, createAccountsProvider } from './accounts.js';
13
13
  export type { ThemeMode } from './theme.js';
14
14
  export { createThemeProvider } from './theme.js';
15
15
  export { createLocalStorage, hostLocalStorage } from './localStorage.js';
package/dist/index.js CHANGED
@@ -6,7 +6,7 @@ export { createLegacyExtensionEnableFactory, injectSpektrExtension } from './inj
6
6
  export { createPapiProvider } from './papiProvider.js';
7
7
  export { createProductChatManager, matchChatCustomRenderers } from './chat.js';
8
8
  export { createStatementStore } from './statementStore.js';
9
- export { createAccountsProvider } from './accounts.js';
9
+ export { accounts, createAccountsProvider } from './accounts.js';
10
10
  export { createThemeProvider } from './theme.js';
11
11
  export { createLocalStorage, hostLocalStorage } from './localStorage.js';
12
12
  export { createPreimageManager, preimageManager } from './preimage.js';
@@ -1,6 +1,72 @@
1
- import type { CodecType, HexString, Transport, VersionedPublicTxPayload } from '@novasamatech/host-api';
1
+ import type { HexString, Transport } from '@novasamatech/host-api';
2
2
  import type { InjectedAccounts } from '@polkadot/extension-inject/types';
3
3
  import type { SignerPayloadJSON, SignerPayloadRaw, SignerResult } from '@polkadot/types/types/extrinsic';
4
+ /**
5
+ * expected interface derived from specification
6
+ */
7
+ export interface TxPayloadV1 {
8
+ /** Payload version. MUST be 1. */
9
+ version: 1;
10
+ /**
11
+ * Signer selection hint. Allows the implementer to identify which private-key / scheme to use.
12
+ * - Use a wallet-defined handle (e.g., address/SS58, account-name, etc). This identifier
13
+ * was previously made available to the consumer.
14
+ * - Set `null` to let the implementer pick the signer (or if the signer is implied).
15
+ */
16
+ signer: string | null;
17
+ /**
18
+ * SCALE-encoded Call (module indicator + function indicator + params).
19
+ */
20
+ callData: HexString;
21
+ /**
22
+ * Transaction extensions supplied by the caller (order irrelevant).
23
+ * The consumer SHOULD provide every extension that is relevant to them.
24
+ * The implementer MAY infer missing ones.
25
+ */
26
+ extensions: Array<{
27
+ /** Identifier as defined in metadata (e.g., "CheckSpecVersion", "ChargeAssetTxPayment"). */
28
+ id: string;
29
+ /**
30
+ * Explicit "extra" to sign (goes into the extrinsic body).
31
+ * SCALE-encoded per the extension's "extra" type as defined in the metadata.
32
+ */
33
+ extra: HexString;
34
+ /**
35
+ * "Implicit" data to sign (known by the chain, not included into the extrinsic body).
36
+ * SCALE-encoded per the extension's "additionalSigned" type as defined in the metadata.
37
+ */
38
+ additionalSigned: HexString;
39
+ }>;
40
+ /**
41
+ * Transaction Extension Version.
42
+ * - For Extrinsic V4 MUST be 0.
43
+ * - For Extrinsic V5, set to any version supported by the runtime.
44
+ * The implementer:
45
+ * - MUST use this field to determine the required extensions for creating the extrinsic.
46
+ * - MAY use this field to infer missing extensions that the implementer could know how to handle.
47
+ */
48
+ txExtVersion: number;
49
+ /**
50
+ * Context needed for decoding, display, and (optionally) inferring certain extensions.
51
+ */
52
+ context: {
53
+ /**
54
+ * RuntimeMetadataPrefixed blob (SCALE), starting with ASCII "meta" magic (`0x6d657461`),
55
+ * then a metadata version (V14+). For V5+ versioned extensions, MUST provide V16+.
56
+ */
57
+ metadata: HexString;
58
+ /**
59
+ * Native token display info (used by some implementers), also needed to compute
60
+ * the `CheckMetadataHash` value.
61
+ */
62
+ tokenSymbol: string;
63
+ tokenDecimals: number;
64
+ /**
65
+ * Highest known block number to aid mortality UX.
66
+ */
67
+ bestBlockHeight: number;
68
+ };
69
+ }
4
70
  interface Signer {
5
71
  /**
6
72
  * @description signs an extrinsic payload from a serialized form
@@ -13,7 +79,7 @@ interface Signer {
13
79
  /**
14
80
  * @description signs a transaction according to https://github.com/polkadot-js/api/issues/6213
15
81
  */
16
- createTransaction?: (payload: CodecType<typeof VersionedPublicTxPayload>) => Promise<HexString>;
82
+ createTransaction?: (payload: TxPayloadV1) => Promise<HexString>;
17
83
  }
18
84
  interface Injected {
19
85
  accounts: InjectedAccounts;
@@ -1,6 +1,7 @@
1
1
  import { assertEnumVariant, createHostApi, enumValue, fromHex, toHex } from '@novasamatech/host-api';
2
2
  import { injectExtension } from '@polkadot/extension-inject';
3
3
  import { AccountId } from 'polkadot-api';
4
+ import { createAccountsProvider } from './accounts.js';
4
5
  import { SpektrExtensionName, Version } from './constants.js';
5
6
  import { sandboxTransport } from './sandboxTransport.js';
6
7
  const UNSUPPORTED_VERSION_ERROR = 'Unsupported message version';
@@ -8,21 +9,22 @@ export async function createLegacyExtensionEnableFactory(transport) {
8
9
  const ready = await transport.isReady();
9
10
  if (!ready)
10
11
  return null;
12
+ const accountsManager = createAccountsProvider(transport);
11
13
  const hostApi = createHostApi(transport);
12
14
  const accountId = AccountId();
13
15
  async function enable() {
14
16
  async function getAccounts() {
15
- const response = await hostApi.getLegacyAccounts(enumValue('v1', undefined));
16
- return response.match(response => {
17
- assertEnumVariant(response, 'v1', UNSUPPORTED_VERSION_ERROR);
18
- return response.value.map(account => ({
17
+ return await accountsManager
18
+ .getLegacyAccounts()
19
+ .map(response => {
20
+ return response.map(account => ({
19
21
  name: account.name,
20
22
  address: accountId.dec(account.publicKey),
21
23
  type: 'sr25519',
22
24
  }));
23
- }, err => {
24
- assertEnumVariant(err, 'v1', UNSUPPORTED_VERSION_ERROR);
25
- throw err.value;
25
+ })
26
+ .match(x => x, x => {
27
+ throw x;
26
28
  });
27
29
  }
28
30
  return {
@@ -99,7 +101,24 @@ export async function createLegacyExtensionEnableFactory(transport) {
99
101
  });
100
102
  },
101
103
  async createTransaction(payload) {
102
- const response = await hostApi.createTransactionWithLegacyAccount(enumValue('v1', payload));
104
+ if (payload.version !== 1) {
105
+ throw new Error(`Signer support only v1 transaction, got version = ${payload.version}`);
106
+ }
107
+ const { signer } = payload;
108
+ if (!signer) {
109
+ throw new Error("Signer can't route transaction to the right account without signer hint.");
110
+ }
111
+ const possibleAccountId = accountId.enc(signer);
112
+ const response = await hostApi.createTransactionWithLegacyAccount(enumValue('v1', {
113
+ signer: possibleAccountId,
114
+ callData: fromHex(payload.callData),
115
+ txExtVersion: payload.txExtVersion,
116
+ extensions: payload.extensions.map(e => ({
117
+ id: e.id,
118
+ additionalSigned: fromHex(e.additionalSigned),
119
+ extra: fromHex(e.extra),
120
+ })),
121
+ }));
103
122
  return response.match(response => {
104
123
  assertEnumVariant(response, 'v1', UNSUPPORTED_VERSION_ERROR);
105
124
  return toHex(response.value);
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@novasamatech/product-sdk",
3
3
  "type": "module",
4
- "version": "0.7.8",
4
+ "version": "0.7.9-1",
5
5
  "description": "Polkadot product SDK: integrate and run your product inside Polkadot browser.",
6
6
  "license": "Apache-2.0",
7
7
  "repository": {
@@ -27,7 +27,8 @@
27
27
  "dependencies": {
28
28
  "@polkadot/extension-inject": "^0.63.1",
29
29
  "@polkadot-api/json-rpc-provider-proxy": "^0.4.0",
30
- "@novasamatech/host-api": "0.7.8",
30
+ "@polkadot-api/substrate-bindings": "^0.20.2",
31
+ "@novasamatech/host-api": "0.7.9-1",
31
32
  "polkadot-api": ">=2",
32
33
  "neverthrow": "^8.2.0"
33
34
  },