@settlemint/sdk-portal 2.2.0-prc00b96af → 2.2.0-prdfa9d68b

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
@@ -27,9 +27,15 @@
27
27
  ## Table of Contents
28
28
 
29
29
  - [About](#about)
30
+ - [Examples](#examples)
31
+ - [Get pending transactions](#get-pending-transactions)
32
+ - [Hd wallet](#hd-wallet)
30
33
  - [API Reference](#api-reference)
31
34
  - [Functions](#functions)
32
35
  - [createPortalClient()](#createportalclient)
36
+ - [handleWalletVerificationChallenge()](#handlewalletverificationchallenge)
37
+ - [Interfaces](#interfaces)
38
+ - [HandleWalletVerificationChallengeOptions\<Setup\>](#handlewalletverificationchallengeoptionssetup)
33
39
  - [Type Aliases](#type-aliases)
34
40
  - [ClientOptions](#clientoptions)
35
41
  - [RequestConfig](#requestconfig)
@@ -43,8 +49,172 @@
43
49
  The SettleMint Smart Contract Portal SDK provides a seamless way to interact with the Smart Contract Portal Middleware API. It enables you to easily interact with your smart contracts using a REST or GraphQL API.
44
50
 
45
51
  The SDK offers a type-safe interface for all Portal API operations, with comprehensive error handling and validation. It integrates smoothly with modern TypeScript applications while providing a simple and intuitive developer experience.
52
+ ## Examples
46
53
 
47
- For detailed information about using the Smart Contract Portal Middleware, check out our [official documentation](https://console.settlemint.com/documentation).
54
+ ### Get pending transactions
55
+
56
+ ```ts
57
+ import { loadEnv } from "@settlemint/sdk-utils/environment";
58
+ import { createLogger, requestLogger } from "@settlemint/sdk-utils/logging";
59
+ import { createPortalClient } from "../portal.js"; // Replace this path with "@settlemint/sdk-portal"
60
+ import type { introspection } from "./schemas/portal-env.d.ts"; // Replace this path with the generated introspection type
61
+
62
+ const env = await loadEnv(false, false);
63
+ const logger = createLogger();
64
+
65
+ const { client: portalClient, graphql: portalGraphql } = createPortalClient<{
66
+ introspection: introspection;
67
+ disableMasking: true;
68
+ scalars: {
69
+ // Change unknown to the type you are using to store metadata
70
+ JSON: unknown;
71
+ };
72
+ }>(
73
+ {
74
+ instance: env.SETTLEMINT_PORTAL_GRAPHQL_ENDPOINT!,
75
+ accessToken: env.SETTLEMINT_ACCESS_TOKEN!,
76
+ },
77
+ {
78
+ fetch: requestLogger(logger, "portal", fetch) as typeof fetch,
79
+ },
80
+ );
81
+
82
+ // Making GraphQL queries
83
+ const query = portalGraphql(`
84
+ query GetPendingTransactions {
85
+ getPendingTransactions {
86
+ count
87
+ }
88
+ }
89
+ `);
90
+
91
+ const result = await portalClient.request(query);
92
+ console.log(`There are ${result.getPendingTransactions?.count} pending transactions`);
93
+
94
+ ```
95
+ ### Hd wallet
96
+
97
+ ```ts
98
+ import { loadEnv } from "@settlemint/sdk-utils/environment";
99
+ import { createLogger, requestLogger } from "@settlemint/sdk-utils/logging";
100
+ import type { Address } from "viem";
101
+ import { createPortalClient } from "../portal.js"; // Replace this path with "@settlemint/sdk-portal"
102
+ import { handleWalletVerificationChallenge } from "../wallet-verification-challenge.js"; // Replace this path with "@settlemint/sdk-portal"
103
+ import type { introspection } from "./schemas/portal-env.d.ts"; // Replace this path with the generated introspection type
104
+
105
+ const env = await loadEnv(false, false);
106
+ const logger = createLogger();
107
+
108
+ const { client: portalClient, graphql: portalGraphql } = createPortalClient<{
109
+ introspection: introspection;
110
+ disableMasking: true;
111
+ scalars: {
112
+ // Change unknown to the type you are using to store metadata
113
+ JSON: unknown;
114
+ };
115
+ }>(
116
+ {
117
+ instance: env.SETTLEMINT_PORTAL_GRAPHQL_ENDPOINT!,
118
+ accessToken: env.SETTLEMINT_ACCESS_TOKEN!,
119
+ },
120
+ {
121
+ fetch: requestLogger(logger, "portal", fetch) as typeof fetch,
122
+ },
123
+ );
124
+
125
+ /**
126
+ * First create a wallet using the HD private key, this needs to be done for every user that is using your app
127
+ */
128
+ const wallet = await portalClient.request(
129
+ portalGraphql(`
130
+ mutation createUserWallet($keyVaultId: String!, $name: String!) {
131
+ createWallet(keyVaultId: $keyVaultId, walletInfo: { name: $name }) {
132
+ address
133
+ }
134
+ }
135
+ `),
136
+ {
137
+ keyVaultId: env.SETTLEMINT_HD_PRIVATE_KEY!,
138
+ name: "My Wallet",
139
+ },
140
+ );
141
+
142
+ /**
143
+ * Set a pincode for the wallet, this is used to verify the wallet when the user is sending a transaction to the chain
144
+ */
145
+ const pincodeVerification = await portalClient.request(
146
+ portalGraphql(`
147
+ mutation setPinCode($address: String!, $pincode: String!) {
148
+ createWalletVerification(
149
+ userWalletAddress: $address
150
+ verificationInfo: {pincode: {name: "PINCODE", pincode: $pincode}}
151
+ ) {
152
+ id
153
+ name
154
+ parameters
155
+ verificationType
156
+ }
157
+ }
158
+ `),
159
+ {
160
+ address: wallet.createWallet?.address!,
161
+ pincode: "123456",
162
+ },
163
+ );
164
+
165
+ /**
166
+ * Generate a challenge response for the pincode verification
167
+ */
168
+ const challengeResponse = await handleWalletVerificationChallenge({
169
+ portalClient,
170
+ portalGraphql,
171
+ verificationId: pincodeVerification.createWalletVerification?.id!,
172
+ userWalletAddress: wallet.createWallet?.address! as Address,
173
+ code: "123456",
174
+ verificationType: "pincode",
175
+ });
176
+
177
+ /**
178
+ * Send a transaction to the chain
179
+ * This is a sample of how to send a transaction to the chain using the portal client and the asset tokenization keyVaultId
180
+ * @see https://github.com/settlemint/asset-tokenization-kit
181
+ */
182
+ const result = await portalClient.request(
183
+ portalGraphql(`
184
+ mutation BondMint(
185
+ $challengeResponse: String!,
186
+ $verificationId: String,
187
+ $address: String!,
188
+ $from: String!,
189
+ $input: BondMintInput!
190
+ ) {
191
+ BondMint(
192
+ challengeResponse: $challengeResponse
193
+ verificationId: $verificationId
194
+ address: $address
195
+ from: $from
196
+ input: $input
197
+ ) {
198
+ transactionHash
199
+ }
200
+ }
201
+ `),
202
+ {
203
+ challengeResponse: challengeResponse.challengeResponse,
204
+ verificationId: pincodeVerification.createWalletVerification?.id!,
205
+ address: wallet.createWallet?.address!,
206
+ from: wallet.createWallet?.address!,
207
+ input: {
208
+ to: "0x0000000000000000000000000000000000000000",
209
+ amount: "1000000000000000000",
210
+ },
211
+ },
212
+ );
213
+
214
+ // Log the transaction hash
215
+ console.log("Transaction hash:", result.BondMint?.transactionHash);
216
+
217
+ ```
48
218
 
49
219
  ## API Reference
50
220
 
@@ -54,7 +224,7 @@ For detailed information about using the Smart Contract Portal Middleware, check
54
224
 
55
225
  > **createPortalClient**\<`Setup`\>(`options`, `clientOptions?`): `object`
56
226
 
57
- Defined in: [sdk/portal/src/portal.ts:66](https://github.com/settlemint/sdk/blob/v2.2.0/sdk/portal/src/portal.ts#L66)
227
+ Defined in: [sdk/portal/src/portal.ts:37](https://github.com/settlemint/sdk/blob/v2.2.0/sdk/portal/src/portal.ts#L37)
58
228
 
59
229
  Creates a Portal GraphQL client with the provided configuration.
60
230
 
@@ -82,8 +252,8 @@ An object containing the configured GraphQL client and graphql helper function
82
252
 
83
253
  | Name | Type | Defined in |
84
254
  | ------ | ------ | ------ |
85
- | `client` | `GraphQLClient` | [sdk/portal/src/portal.ts:70](https://github.com/settlemint/sdk/blob/v2.2.0/sdk/portal/src/portal.ts#L70) |
86
- | `graphql` | `initGraphQLTada`\<`Setup`\> | [sdk/portal/src/portal.ts:71](https://github.com/settlemint/sdk/blob/v2.2.0/sdk/portal/src/portal.ts#L71) |
255
+ | `client` | `GraphQLClient` | [sdk/portal/src/portal.ts:41](https://github.com/settlemint/sdk/blob/v2.2.0/sdk/portal/src/portal.ts#L41) |
256
+ | `graphql` | `initGraphQLTada`\<`Setup`\> | [sdk/portal/src/portal.ts:42](https://github.com/settlemint/sdk/blob/v2.2.0/sdk/portal/src/portal.ts#L42) |
87
257
 
88
258
  ##### Throws
89
259
 
@@ -92,28 +262,32 @@ If the provided options fail validation
92
262
  ##### Example
93
263
 
94
264
  ```ts
95
- import { createPortalClient } from '@settlemint/sdk-portal';
96
- import type { introspection } from "@schemas/portal-env";
97
- import { createLogger, requestLogger } from '@settlemint/sdk-utils/logging';
98
-
265
+ import { createPortalClient } from "@settlemint/sdk-portal";
266
+ import { loadEnv } from "@settlemint/sdk-utils/environment";
267
+ import { createLogger, requestLogger } from "@settlemint/sdk-utils/logging";
268
+ import type { introspection } from "./test-app/portal-env";
269
+ const env = await loadEnv(false, false);
99
270
  const logger = createLogger();
100
271
 
101
- export const { client: portalClient, graphql: portalGraphql } = createPortalClient<{
272
+ const { client: portalClient, graphql: portalGraphql } = createPortalClient<{
102
273
  introspection: introspection;
103
274
  disableMasking: true;
104
275
  scalars: {
105
276
  // Change unknown to the type you are using to store metadata
106
277
  JSON: unknown;
107
278
  };
108
- }>({
109
- instance: process.env.SETTLEMINT_PORTAL_GRAPHQL_ENDPOINT,
110
- accessToken: process.env.SETTLEMINT_ACCESS_TOKEN,
111
- }, {
112
- fetch: requestLogger(logger, "portal", fetch) as typeof fetch,
113
- });
279
+ }>(
280
+ {
281
+ instance: env.SETTLEMINT_PORTAL_GRAPHQL_ENDPOINT!,
282
+ accessToken: env.SETTLEMINT_ACCESS_TOKEN!,
283
+ },
284
+ {
285
+ fetch: requestLogger(logger, "portal", fetch) as typeof fetch,
286
+ },
287
+ );
114
288
 
115
289
  // Making GraphQL queries
116
- const query = graphql(`
290
+ const query = portalGraphql(`
117
291
  query GetPendingTransactions {
118
292
  getPendingTransactions {
119
293
  count
@@ -121,9 +295,74 @@ const query = graphql(`
121
295
  }
122
296
  `);
123
297
 
124
- const result = await client.request(query);
298
+ const result = await portalClient.request(query);
125
299
  ```
126
300
 
301
+ ***
302
+
303
+ #### handleWalletVerificationChallenge()
304
+
305
+ > **handleWalletVerificationChallenge**\<`Setup`\>(`options`): `Promise`\<\{ `challengeResponse`: `string`; `verificationId?`: `string`; \}\>
306
+
307
+ Defined in: [sdk/portal/src/wallet-verification-challenge.ts:106](https://github.com/settlemint/sdk/blob/v2.2.0/sdk/portal/src/wallet-verification-challenge.ts#L106)
308
+
309
+ Handles a wallet verification challenge by generating an appropriate response
310
+
311
+ ##### Type Parameters
312
+
313
+ | Type Parameter |
314
+ | ------ |
315
+ | `Setup` *extends* `AbstractSetupSchema` |
316
+
317
+ ##### Parameters
318
+
319
+ | Parameter | Type | Description |
320
+ | ------ | ------ | ------ |
321
+ | `options` | [`HandleWalletVerificationChallengeOptions`](#handlewalletverificationchallengeoptions)\<`Setup`\> | The options for handling the wallet verification challenge |
322
+
323
+ ##### Returns
324
+
325
+ `Promise`\<\{ `challengeResponse`: `string`; `verificationId?`: `string`; \}\>
326
+
327
+ Promise resolving to an object containing the challenge response and optionally the verification ID
328
+
329
+ ##### Throws
330
+
331
+ If the challenge cannot be created or is invalid
332
+
333
+ ##### Example
334
+
335
+ import { createPortalClient } from "@settlemint/sdk-portal";
336
+ import { handleWalletVerificationChallenge } from "@settlemint/sdk-portal";
337
+
338
+ const { client, graphql } = createPortalClient({
339
+ instance: "https://portal.example.com/graphql",
340
+ accessToken: "your-access-token"
341
+ });
342
+
343
+ const result = await handleWalletVerificationChallenge({
344
+ portalClient: client,
345
+ portalGraphql: graphql,
346
+ verificationId: "verification-123",
347
+ userWalletAddress: "0x123...",
348
+ code: "123456",
349
+ verificationType: "otp"
350
+ });
351
+
352
+ ### Interfaces
353
+
354
+ #### HandleWalletVerificationChallengeOptions\<Setup\>
355
+
356
+ Defined in: [sdk/portal/src/wallet-verification-challenge.ts:73](https://github.com/settlemint/sdk/blob/v2.2.0/sdk/portal/src/wallet-verification-challenge.ts#L73)
357
+
358
+ Options for handling a wallet verification challenge
359
+
360
+ ##### Type Parameters
361
+
362
+ | Type Parameter | Description |
363
+ | ------ | ------ |
364
+ | `Setup` *extends* `AbstractSetupSchema` | The GraphQL schema setup type |
365
+
127
366
  ### Type Aliases
128
367
 
129
368
  #### ClientOptions
package/dist/portal.cjs CHANGED
@@ -22,7 +22,9 @@ var portal_exports = {};
22
22
  __export(portal_exports, {
23
23
  ClientOptionsSchema: () => ClientOptionsSchema,
24
24
  createPortalClient: () => createPortalClient,
25
- readFragment: () => import_gql2.readFragment
25
+ handleWalletVerificationChallenge: () => handleWalletVerificationChallenge,
26
+ readFragment: () => import_gql2.readFragment,
27
+ waitForTransactionReceipt: () => waitForTransactionReceipt
26
28
  });
27
29
  module.exports = __toCommonJS(portal_exports);
28
30
  var import_runtime = require("@settlemint/sdk-utils/runtime");
@@ -30,6 +32,120 @@ var import_validation = require("@settlemint/sdk-utils/validation");
30
32
  var import_gql = require("gql.tada");
31
33
  var import_graphql_request = require("graphql-request");
32
34
  var import_zod = require("zod");
35
+
36
+ // src/utils/wallet-verification-challenge.ts
37
+ var import_node_crypto = require("crypto");
38
+ var ChallengeError = class extends Error {
39
+ code;
40
+ constructor(message, code) {
41
+ super(message);
42
+ this.name = "ChallengeError";
43
+ this.code = code;
44
+ }
45
+ };
46
+ function hashPincode(pincode, salt) {
47
+ return (0, import_node_crypto.createHash)("sha256").update(`${salt}${pincode}`).digest("hex");
48
+ }
49
+ function generateResponse(pincode, salt, challenge) {
50
+ const hashedPincode = hashPincode(pincode, salt);
51
+ return (0, import_node_crypto.createHash)("sha256").update(`${hashedPincode}_${challenge}`).digest("hex");
52
+ }
53
+ async function handleWalletVerificationChallenge({
54
+ portalClient,
55
+ portalGraphql,
56
+ verificationId,
57
+ userWalletAddress,
58
+ code,
59
+ verificationType
60
+ }) {
61
+ try {
62
+ if (verificationType === "otp") {
63
+ return {
64
+ challengeResponse: code.toString(),
65
+ verificationId
66
+ };
67
+ }
68
+ if (verificationType === "secret-code") {
69
+ const formattedCode = code.toString().replace(/(.{5})(?=.)/, "$1-");
70
+ return {
71
+ challengeResponse: formattedCode,
72
+ verificationId
73
+ };
74
+ }
75
+ const verificationChallenges = await portalClient.request(
76
+ portalGraphql(`
77
+ mutation CreateWalletVerificationChallenges($userWalletAddress: String!, $verificationId: String!) {
78
+ createWalletVerificationChallenges(userWalletAddress: $userWalletAddress, verificationId: $verificationId) {
79
+ challenge
80
+ id
81
+ name
82
+ verificationType
83
+ }
84
+ }
85
+ `),
86
+ {
87
+ userWalletAddress,
88
+ verificationId
89
+ }
90
+ );
91
+ if (!verificationChallenges.createWalletVerificationChallenges?.length) {
92
+ throw new ChallengeError("No verification challenges received", "NO_CHALLENGES");
93
+ }
94
+ const walletVerificationChallenge = verificationChallenges.createWalletVerificationChallenges.find(
95
+ (challenge) => challenge.id === verificationId
96
+ );
97
+ if (!walletVerificationChallenge?.challenge?.secret || !walletVerificationChallenge?.challenge?.salt) {
98
+ throw new ChallengeError("Invalid challenge format", "INVALID_CHALLENGE");
99
+ }
100
+ const { secret, salt } = walletVerificationChallenge.challenge;
101
+ const challengeResponse = generateResponse(code.toString(), salt, secret);
102
+ return {
103
+ challengeResponse,
104
+ verificationId
105
+ };
106
+ } catch (error) {
107
+ if (error instanceof ChallengeError) {
108
+ throw error;
109
+ }
110
+ throw new ChallengeError("Failed to process wallet verification challenge", "CHALLENGE_PROCESSING_ERROR");
111
+ }
112
+ }
113
+
114
+ // src/utils/wait-for-transaction-receipt.ts
115
+ async function waitForTransactionReceipt(wsClient, transactionHash) {
116
+ const subscription = wsClient.iterate({
117
+ query: `subscription getTransaction($transactionHash: String!) {
118
+ getTransaction(transactionHash: $transactionHash) {
119
+ receipt {
120
+ transactionHash
121
+ to
122
+ status
123
+ from
124
+ type
125
+ revertReason
126
+ revertReasonDecoded
127
+ logs
128
+ events
129
+ contractAddress
130
+ }
131
+ transactionHash
132
+ from
133
+ createdAt
134
+ address
135
+ functionName
136
+ isContract
137
+ }
138
+ }`,
139
+ variables: { transactionHash }
140
+ });
141
+ for await (const result of subscription) {
142
+ if (result?.data?.getTransaction?.receipt) {
143
+ return result.data.getTransaction;
144
+ }
145
+ }
146
+ }
147
+
148
+ // src/portal.ts
33
149
  var import_gql2 = require("gql.tada");
34
150
  var ClientOptionsSchema = import_zod.z.object({
35
151
  instance: import_validation.UrlOrPathSchema,
@@ -53,6 +169,8 @@ function createPortalClient(options, clientOptions) {
53
169
  0 && (module.exports = {
54
170
  ClientOptionsSchema,
55
171
  createPortalClient,
56
- readFragment
172
+ handleWalletVerificationChallenge,
173
+ readFragment,
174
+ waitForTransactionReceipt
57
175
  });
58
176
  //# sourceMappingURL=portal.cjs.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/portal.ts"],"sourcesContent":["import { ensureServer } from \"@settlemint/sdk-utils/runtime\";\nimport { ApplicationAccessTokenSchema, UrlOrPathSchema, validate } from \"@settlemint/sdk-utils/validation\";\nimport { type AbstractSetupSchema, initGraphQLTada } from \"gql.tada\";\nimport { GraphQLClient } from \"graphql-request\";\nimport { z } from \"zod\";\n\n/**\n * Configuration options for the GraphQL client, excluding 'url' and 'exchanges'.\n */\nexport type RequestConfig = ConstructorParameters<typeof GraphQLClient>[1];\n\n/**\n * Schema for validating Portal client configuration options.\n */\nexport const ClientOptionsSchema = z.object({\n instance: UrlOrPathSchema,\n accessToken: ApplicationAccessTokenSchema,\n cache: z.enum([\"default\", \"force-cache\", \"no-cache\", \"no-store\", \"only-if-cached\", \"reload\"]).optional(),\n});\n\n/**\n * Type representing the validated client options.\n */\nexport type ClientOptions = z.infer<typeof ClientOptionsSchema>;\n\n/**\n * Creates a Portal GraphQL client with the provided configuration.\n *\n * @param options - Configuration options for the Portal client\n * @param clientOptions - Additional GraphQL client configuration options\n * @returns An object containing the configured GraphQL client and graphql helper function\n * @throws If the provided options fail validation\n *\n * @example\n * import { createPortalClient } from '@settlemint/sdk-portal';\n * import type { introspection } from \"@schemas/portal-env\";\n * import { createLogger, requestLogger } from '@settlemint/sdk-utils/logging';\n *\n * const logger = createLogger();\n *\n * export const { client: portalClient, graphql: portalGraphql } = createPortalClient<{\n * introspection: introspection;\n * disableMasking: true;\n * scalars: {\n * // Change unknown to the type you are using to store metadata\n * JSON: unknown;\n * };\n * }>({\n * instance: process.env.SETTLEMINT_PORTAL_GRAPHQL_ENDPOINT,\n * accessToken: process.env.SETTLEMINT_ACCESS_TOKEN,\n * }, {\n * fetch: requestLogger(logger, \"portal\", fetch) as typeof fetch,\n * });\n *\n * // Making GraphQL queries\n * const query = graphql(`\n * query GetPendingTransactions {\n * getPendingTransactions {\n * count\n * }\n * }\n * `);\n *\n * const result = await client.request(query);\n */\nexport function createPortalClient<const Setup extends AbstractSetupSchema>(\n options: ClientOptions,\n clientOptions?: RequestConfig,\n): {\n client: GraphQLClient;\n graphql: initGraphQLTada<Setup>;\n} {\n ensureServer();\n const validatedOptions = validate(ClientOptionsSchema, options);\n const graphql = initGraphQLTada<Setup>();\n const fullUrl = new URL(validatedOptions.instance).toString();\n\n return {\n client: new GraphQLClient(fullUrl, {\n ...clientOptions,\n headers: { ...(clientOptions?.headers ?? {}), \"x-auth-token\": validatedOptions.accessToken },\n }),\n graphql,\n };\n}\n\nexport { readFragment } from \"gql.tada\";\nexport type { FragmentOf, ResultOf, VariablesOf } from \"gql.tada\";\n"],"mappings":";;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,qBAA6B;AAC7B,wBAAwE;AACxE,iBAA0D;AAC1D,6BAA8B;AAC9B,iBAAkB;AAkFlB,IAAAA,cAA6B;AAxEtB,IAAM,sBAAsB,aAAE,OAAO;AAAA,EAC1C,UAAU;AAAA,EACV,aAAa;AAAA,EACb,OAAO,aAAE,KAAK,CAAC,WAAW,eAAe,YAAY,YAAY,kBAAkB,QAAQ,CAAC,EAAE,SAAS;AACzG,CAAC;AA+CM,SAAS,mBACd,SACA,eAIA;AACA,mCAAa;AACb,QAAM,uBAAmB,4BAAS,qBAAqB,OAAO;AAC9D,QAAM,cAAU,4BAAuB;AACvC,QAAM,UAAU,IAAI,IAAI,iBAAiB,QAAQ,EAAE,SAAS;AAE5D,SAAO;AAAA,IACL,QAAQ,IAAI,qCAAc,SAAS;AAAA,MACjC,GAAG;AAAA,MACH,SAAS,EAAE,GAAI,eAAe,WAAW,CAAC,GAAI,gBAAgB,iBAAiB,YAAY;AAAA,IAC7F,CAAC;AAAA,IACD;AAAA,EACF;AACF;","names":["import_gql"]}
1
+ {"version":3,"sources":["../src/portal.ts","../src/utils/wallet-verification-challenge.ts","../src/utils/wait-for-transaction-receipt.ts"],"sourcesContent":["import {} from \"@settlemint/sdk-utils/logging\";\nimport { ensureServer } from \"@settlemint/sdk-utils/runtime\";\nimport { ApplicationAccessTokenSchema, UrlOrPathSchema, validate } from \"@settlemint/sdk-utils/validation\";\nimport { type AbstractSetupSchema, initGraphQLTada } from \"gql.tada\";\nimport { GraphQLClient } from \"graphql-request\";\nimport { z } from \"zod\";\n\n/**\n * Configuration options for the GraphQL client, excluding 'url' and 'exchanges'.\n */\nexport type RequestConfig = ConstructorParameters<typeof GraphQLClient>[1];\n\n/**\n * Schema for validating Portal client configuration options.\n */\nexport const ClientOptionsSchema = z.object({\n instance: UrlOrPathSchema,\n accessToken: ApplicationAccessTokenSchema,\n cache: z.enum([\"default\", \"force-cache\", \"no-cache\", \"no-store\", \"only-if-cached\", \"reload\"]).optional(),\n});\n\n/**\n * Type representing the validated client options.\n */\nexport type ClientOptions = z.infer<typeof ClientOptionsSchema>;\n\n/**\n * Creates a Portal GraphQL client with the provided configuration.\n *\n * @param options - Configuration options for the Portal client\n * @param clientOptions - Additional GraphQL client configuration options\n * @returns An object containing the configured GraphQL client and graphql helper function\n * @throws If the provided options fail validation\n *\n * @example\n * import { createPortalClient } from \"@settlemint/sdk-portal\";\n * import { loadEnv } from \"@settlemint/sdk-utils/environment\";\n * import { createLogger, requestLogger } from \"@settlemint/sdk-utils/logging\";\n * import type { introspection } from \"@schemas/portal-env\";\n *\n * const env = await loadEnv(false, false);\n * const logger = createLogger();\n *\n * const { client: portalClient, graphql: portalGraphql } = createPortalClient<{\n * introspection: introspection;\n * disableMasking: true;\n * scalars: {\n * // Change unknown to the type you are using to store metadata\n * JSON: unknown;\n * };\n * }>(\n * {\n * instance: env.SETTLEMINT_PORTAL_GRAPHQL_ENDPOINT!,\n * accessToken: env.SETTLEMINT_ACCESS_TOKEN!,\n * },\n * {\n * fetch: requestLogger(logger, \"portal\", fetch) as typeof fetch,\n * },\n * );\n *\n * // Making GraphQL queries\n * const query = portalGraphql(`\n * query GetPendingTransactions {\n * getPendingTransactions {\n * count\n * }\n * }\n * `);\n *\n * const result = await portalClient.request(query);\n */\nexport function createPortalClient<const Setup extends AbstractSetupSchema>(\n options: ClientOptions,\n clientOptions?: RequestConfig,\n): {\n client: GraphQLClient;\n graphql: initGraphQLTada<Setup>;\n} {\n ensureServer();\n const validatedOptions = validate(ClientOptionsSchema, options);\n const graphql = initGraphQLTada<Setup>();\n const fullUrl = new URL(validatedOptions.instance).toString();\n\n return {\n client: new GraphQLClient(fullUrl, {\n ...clientOptions,\n headers: { ...(clientOptions?.headers ?? {}), \"x-auth-token\": validatedOptions.accessToken },\n }),\n graphql,\n };\n}\n\nexport {\n handleWalletVerificationChallenge,\n type HandleWalletVerificationChallengeOptions,\n} from \"./utils/wallet-verification-challenge.js\";\nexport { waitForTransactionReceipt, type Transaction } from \"./utils/wait-for-transaction-receipt.js\";\nexport { readFragment } from \"gql.tada\";\nexport type { FragmentOf, ResultOf, VariablesOf } from \"gql.tada\";\n","import { createHash } from \"node:crypto\";\nimport type { AbstractSetupSchema, initGraphQLTada } from \"gql.tada\";\nimport type { Address } from \"viem\";\nimport type { createPortalClient } from \"../portal.js\";\n\n/**\n * Custom error class for challenge-related errors\n */\nexport class ChallengeError extends Error {\n readonly code: string;\n\n constructor(message: string, code: string) {\n super(message);\n this.name = \"ChallengeError\";\n this.code = code;\n }\n}\n\n/**\n * Represents the structure of a wallet verification challenge\n */\ninterface WalletVerificationChallenge {\n challenge: {\n secret: string;\n salt: string;\n };\n id: string;\n name: string;\n verificationType: string;\n}\n\n/**\n * Response type for the CreateWalletVerificationChallenges mutation\n */\ninterface CreateWalletVerificationChallengesResponse {\n createWalletVerificationChallenges: WalletVerificationChallenge[];\n}\n\n/**\n * Hashes a pincode with a salt using SHA-256\n * @param pincode - The pincode to hash\n * @param salt - The salt to use in hashing\n * @returns The hashed pincode as a hex string\n */\nfunction hashPincode(pincode: string, salt: string): string {\n return createHash(\"sha256\").update(`${salt}${pincode}`).digest(\"hex\");\n}\n\n/**\n * Generates a challenge response by combining a hashed pincode with a challenge\n * @param pincode - The user's pincode\n * @param salt - The salt provided in the challenge\n * @param challenge - The challenge secret\n * @returns The challenge response as a hex string\n */\nfunction generateResponse(pincode: string, salt: string, challenge: string): string {\n const hashedPincode = hashPincode(pincode, salt);\n return createHash(\"sha256\").update(`${hashedPincode}_${challenge}`).digest(\"hex\");\n}\n\n/**\n * Options for handling a wallet verification challenge\n *\n * @typedef {Object} HandleWalletVerificationChallengeOptions\n * @template {AbstractSetupSchema} Setup - The GraphQL schema setup type\n * @property {ReturnType<typeof createPortalClient>[\"client\"]} portalClient - The portal client instance\n * @property {initGraphQLTada<Setup>} portalGraphql - The GraphQL query builder\n * @property {string} verificationId - The ID of the verification challenge\n * @property {Address} userWalletAddress - The wallet address to verify\n * @property {string | number} code - The verification code provided by the user\n * @property {\"otp\" | \"secret-code\" | \"pincode\"} verificationType - The type of verification being performed\n */\nexport interface HandleWalletVerificationChallengeOptions<Setup extends AbstractSetupSchema> {\n portalClient: ReturnType<typeof createPortalClient>[\"client\"];\n portalGraphql: initGraphQLTada<Setup>;\n verificationId: string;\n userWalletAddress: Address;\n code: string | number;\n verificationType: \"otp\" | \"secret-code\" | \"pincode\";\n}\n\n/**\n * Handles a wallet verification challenge by generating an appropriate response\n *\n * @param options - The options for handling the wallet verification challenge\n * @returns Promise resolving to an object containing the challenge response and optionally the verification ID\n * @throws {ChallengeError} If the challenge cannot be created or is invalid\n * @example\n * import { createPortalClient } from \"@settlemint/sdk-portal\";\n * import { handleWalletVerificationChallenge } from \"@settlemint/sdk-portal\";\n *\n * const { client, graphql } = createPortalClient({\n * instance: \"https://portal.example.com/graphql\",\n * accessToken: \"your-access-token\"\n * });\n *\n * const result = await handleWalletVerificationChallenge({\n * portalClient: client,\n * portalGraphql: graphql,\n * verificationId: \"verification-123\",\n * userWalletAddress: \"0x123...\",\n * code: \"123456\",\n * verificationType: \"otp\"\n * });\n */\nexport async function handleWalletVerificationChallenge<const Setup extends AbstractSetupSchema>({\n portalClient,\n portalGraphql,\n verificationId,\n userWalletAddress,\n code,\n verificationType,\n}: HandleWalletVerificationChallengeOptions<Setup>): Promise<{\n challengeResponse: string;\n verificationId?: string;\n}> {\n try {\n if (verificationType === \"otp\") {\n return {\n challengeResponse: code.toString(),\n verificationId,\n };\n }\n\n if (verificationType === \"secret-code\") {\n // Add - separator to the code\n const formattedCode = code.toString().replace(/(.{5})(?=.)/, \"$1-\");\n return {\n challengeResponse: formattedCode,\n verificationId,\n };\n }\n\n const verificationChallenges = await portalClient.request<CreateWalletVerificationChallengesResponse>(\n portalGraphql(`\n mutation CreateWalletVerificationChallenges($userWalletAddress: String!, $verificationId: String!) {\n createWalletVerificationChallenges(userWalletAddress: $userWalletAddress, verificationId: $verificationId) {\n challenge\n id\n name\n verificationType\n }\n }\n `),\n {\n userWalletAddress,\n verificationId,\n },\n );\n\n if (!verificationChallenges.createWalletVerificationChallenges?.length) {\n throw new ChallengeError(\"No verification challenges received\", \"NO_CHALLENGES\");\n }\n\n const walletVerificationChallenge = verificationChallenges.createWalletVerificationChallenges.find(\n (challenge) => challenge.id === verificationId,\n );\n\n if (!walletVerificationChallenge?.challenge?.secret || !walletVerificationChallenge?.challenge?.salt) {\n throw new ChallengeError(\"Invalid challenge format\", \"INVALID_CHALLENGE\");\n }\n\n const { secret, salt } = walletVerificationChallenge.challenge;\n const challengeResponse = generateResponse(code.toString(), salt, secret);\n return {\n challengeResponse,\n verificationId,\n };\n } catch (error) {\n if (error instanceof ChallengeError) {\n throw error;\n }\n throw new ChallengeError(\"Failed to process wallet verification challenge\", \"CHALLENGE_PROCESSING_ERROR\");\n }\n}\n","import type { Client } from \"graphql-ws\";\n\n/**\n * Represents the structure of a blockchain transaction with its receipt\n *\n * @typedef {Object} Transaction\n * @property {Object} receipt - The transaction receipt details\n * @property {string} receipt.transactionHash - The hash of the transaction\n * @property {string} receipt.to - The recipient address of the transaction\n * @property {string} receipt.status - The status of the transaction (success/failure)\n * @property {string} receipt.from - The sender address of the transaction\n * @property {string} receipt.type - The type of the transaction\n * @property {string} receipt.revertReason - The reason for transaction reversion, if applicable\n * @property {string} receipt.revertReasonDecoded - Human-readable version of the revert reason\n * @property {string} receipt.contractAddress - The address of the contract deployed in the transaction\n * @property {string[]} receipt.logs - Array of log entries generated by the transaction\n * @property {string[]} receipt.events - Array of events emitted during the transaction\n * @property {string} transactionHash - The hash of the transaction (duplicate of receipt.transactionHash)\n * @property {string} from - The sender address (duplicate of receipt.from)\n * @property {string} createdAt - Timestamp when the transaction was created\n * @property {string} address - The contract address involved in the transaction\n * @property {string} functionName - The name of the function called in the transaction\n * @property {boolean} isContract - Whether the transaction is a contract deployment\n */\nexport interface Transaction {\n receipt: {\n transactionHash: string;\n to: string;\n status: string;\n from: string;\n type: string;\n revertReason: string;\n revertReasonDecoded: string;\n logs: string[];\n events: string[];\n contractAddress: string;\n };\n transactionHash: string;\n from: string;\n createdAt: string;\n address: string;\n functionName: string;\n isContract: boolean;\n}\n\ninterface GetTransactionResponse {\n getTransaction: Transaction;\n}\n\n/**\n * Wait for the transaction receipt\n * @param wsClient websocket client\n * @param transactionHash transaction hash\n * @returns receipt\n */\nexport async function waitForTransactionReceipt(wsClient: Client, transactionHash: string) {\n const subscription = wsClient.iterate<GetTransactionResponse>({\n query: `subscription getTransaction($transactionHash: String!) {\n getTransaction(transactionHash: $transactionHash) {\n receipt {\n transactionHash\n to\n status\n from\n type\n revertReason\n revertReasonDecoded\n logs\n events\n contractAddress\n }\n transactionHash\n from\n createdAt\n address\n functionName\n isContract\n }\n }`,\n variables: { transactionHash },\n });\n\n for await (const result of subscription) {\n if (result?.data?.getTransaction?.receipt) {\n return result.data.getTransaction;\n }\n }\n}\n"],"mappings":"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","names":["import_gql"]}
package/dist/portal.d.cts CHANGED
@@ -2,6 +2,107 @@ import { AbstractSetupSchema, initGraphQLTada } from 'gql.tada';
2
2
  export { FragmentOf, ResultOf, VariablesOf, readFragment } from 'gql.tada';
3
3
  import { GraphQLClient } from 'graphql-request';
4
4
  import { z } from 'zod';
5
+ import { Address } from 'viem';
6
+ import { Client } from 'graphql-ws';
7
+
8
+ /**
9
+ * Options for handling a wallet verification challenge
10
+ *
11
+ * @typedef {Object} HandleWalletVerificationChallengeOptions
12
+ * @template {AbstractSetupSchema} Setup - The GraphQL schema setup type
13
+ * @property {ReturnType<typeof createPortalClient>["client"]} portalClient - The portal client instance
14
+ * @property {initGraphQLTada<Setup>} portalGraphql - The GraphQL query builder
15
+ * @property {string} verificationId - The ID of the verification challenge
16
+ * @property {Address} userWalletAddress - The wallet address to verify
17
+ * @property {string | number} code - The verification code provided by the user
18
+ * @property {"otp" | "secret-code" | "pincode"} verificationType - The type of verification being performed
19
+ */
20
+ interface HandleWalletVerificationChallengeOptions<Setup extends AbstractSetupSchema> {
21
+ portalClient: ReturnType<typeof createPortalClient>["client"];
22
+ portalGraphql: initGraphQLTada<Setup>;
23
+ verificationId: string;
24
+ userWalletAddress: Address;
25
+ code: string | number;
26
+ verificationType: "otp" | "secret-code" | "pincode";
27
+ }
28
+ /**
29
+ * Handles a wallet verification challenge by generating an appropriate response
30
+ *
31
+ * @param options - The options for handling the wallet verification challenge
32
+ * @returns Promise resolving to an object containing the challenge response and optionally the verification ID
33
+ * @throws {ChallengeError} If the challenge cannot be created or is invalid
34
+ * @example
35
+ * import { createPortalClient } from "@settlemint/sdk-portal";
36
+ * import { handleWalletVerificationChallenge } from "@settlemint/sdk-portal";
37
+ *
38
+ * const { client, graphql } = createPortalClient({
39
+ * instance: "https://portal.example.com/graphql",
40
+ * accessToken: "your-access-token"
41
+ * });
42
+ *
43
+ * const result = await handleWalletVerificationChallenge({
44
+ * portalClient: client,
45
+ * portalGraphql: graphql,
46
+ * verificationId: "verification-123",
47
+ * userWalletAddress: "0x123...",
48
+ * code: "123456",
49
+ * verificationType: "otp"
50
+ * });
51
+ */
52
+ declare function handleWalletVerificationChallenge<const Setup extends AbstractSetupSchema>({ portalClient, portalGraphql, verificationId, userWalletAddress, code, verificationType, }: HandleWalletVerificationChallengeOptions<Setup>): Promise<{
53
+ challengeResponse: string;
54
+ verificationId?: string;
55
+ }>;
56
+
57
+ /**
58
+ * Represents the structure of a blockchain transaction with its receipt
59
+ *
60
+ * @typedef {Object} Transaction
61
+ * @property {Object} receipt - The transaction receipt details
62
+ * @property {string} receipt.transactionHash - The hash of the transaction
63
+ * @property {string} receipt.to - The recipient address of the transaction
64
+ * @property {string} receipt.status - The status of the transaction (success/failure)
65
+ * @property {string} receipt.from - The sender address of the transaction
66
+ * @property {string} receipt.type - The type of the transaction
67
+ * @property {string} receipt.revertReason - The reason for transaction reversion, if applicable
68
+ * @property {string} receipt.revertReasonDecoded - Human-readable version of the revert reason
69
+ * @property {string} receipt.contractAddress - The address of the contract deployed in the transaction
70
+ * @property {string[]} receipt.logs - Array of log entries generated by the transaction
71
+ * @property {string[]} receipt.events - Array of events emitted during the transaction
72
+ * @property {string} transactionHash - The hash of the transaction (duplicate of receipt.transactionHash)
73
+ * @property {string} from - The sender address (duplicate of receipt.from)
74
+ * @property {string} createdAt - Timestamp when the transaction was created
75
+ * @property {string} address - The contract address involved in the transaction
76
+ * @property {string} functionName - The name of the function called in the transaction
77
+ * @property {boolean} isContract - Whether the transaction is a contract deployment
78
+ */
79
+ interface Transaction {
80
+ receipt: {
81
+ transactionHash: string;
82
+ to: string;
83
+ status: string;
84
+ from: string;
85
+ type: string;
86
+ revertReason: string;
87
+ revertReasonDecoded: string;
88
+ logs: string[];
89
+ events: string[];
90
+ contractAddress: string;
91
+ };
92
+ transactionHash: string;
93
+ from: string;
94
+ createdAt: string;
95
+ address: string;
96
+ functionName: string;
97
+ isContract: boolean;
98
+ }
99
+ /**
100
+ * Wait for the transaction receipt
101
+ * @param wsClient websocket client
102
+ * @param transactionHash transaction hash
103
+ * @returns receipt
104
+ */
105
+ declare function waitForTransactionReceipt(wsClient: Client, transactionHash: string): Promise<Transaction | undefined>;
5
106
 
6
107
  /**
7
108
  * Configuration options for the GraphQL client, excluding 'url' and 'exchanges'.
@@ -36,28 +137,33 @@ type ClientOptions = z.infer<typeof ClientOptionsSchema>;
36
137
  * @throws If the provided options fail validation
37
138
  *
38
139
  * @example
39
- * import { createPortalClient } from '@settlemint/sdk-portal';
140
+ * import { createPortalClient } from "@settlemint/sdk-portal";
141
+ * import { loadEnv } from "@settlemint/sdk-utils/environment";
142
+ * import { createLogger, requestLogger } from "@settlemint/sdk-utils/logging";
40
143
  * import type { introspection } from "@schemas/portal-env";
41
- * import { createLogger, requestLogger } from '@settlemint/sdk-utils/logging';
42
144
  *
145
+ * const env = await loadEnv(false, false);
43
146
  * const logger = createLogger();
44
147
  *
45
- * export const { client: portalClient, graphql: portalGraphql } = createPortalClient<{
148
+ * const { client: portalClient, graphql: portalGraphql } = createPortalClient<{
46
149
  * introspection: introspection;
47
150
  * disableMasking: true;
48
151
  * scalars: {
49
152
  * // Change unknown to the type you are using to store metadata
50
153
  * JSON: unknown;
51
154
  * };
52
- * }>({
53
- * instance: process.env.SETTLEMINT_PORTAL_GRAPHQL_ENDPOINT,
54
- * accessToken: process.env.SETTLEMINT_ACCESS_TOKEN,
55
- * }, {
56
- * fetch: requestLogger(logger, "portal", fetch) as typeof fetch,
57
- * });
155
+ * }>(
156
+ * {
157
+ * instance: env.SETTLEMINT_PORTAL_GRAPHQL_ENDPOINT!,
158
+ * accessToken: env.SETTLEMINT_ACCESS_TOKEN!,
159
+ * },
160
+ * {
161
+ * fetch: requestLogger(logger, "portal", fetch) as typeof fetch,
162
+ * },
163
+ * );
58
164
  *
59
165
  * // Making GraphQL queries
60
- * const query = graphql(`
166
+ * const query = portalGraphql(`
61
167
  * query GetPendingTransactions {
62
168
  * getPendingTransactions {
63
169
  * count
@@ -65,11 +171,11 @@ type ClientOptions = z.infer<typeof ClientOptionsSchema>;
65
171
  * }
66
172
  * `);
67
173
  *
68
- * const result = await client.request(query);
174
+ * const result = await portalClient.request(query);
69
175
  */
70
176
  declare function createPortalClient<const Setup extends AbstractSetupSchema>(options: ClientOptions, clientOptions?: RequestConfig): {
71
177
  client: GraphQLClient;
72
178
  graphql: initGraphQLTada<Setup>;
73
179
  };
74
180
 
75
- export { type ClientOptions, ClientOptionsSchema, type RequestConfig, createPortalClient };
181
+ export { type ClientOptions, ClientOptionsSchema, type HandleWalletVerificationChallengeOptions, type RequestConfig, type Transaction, createPortalClient, handleWalletVerificationChallenge, waitForTransactionReceipt };
package/dist/portal.d.ts CHANGED
@@ -2,6 +2,107 @@ import { AbstractSetupSchema, initGraphQLTada } from 'gql.tada';
2
2
  export { FragmentOf, ResultOf, VariablesOf, readFragment } from 'gql.tada';
3
3
  import { GraphQLClient } from 'graphql-request';
4
4
  import { z } from 'zod';
5
+ import { Address } from 'viem';
6
+ import { Client } from 'graphql-ws';
7
+
8
+ /**
9
+ * Options for handling a wallet verification challenge
10
+ *
11
+ * @typedef {Object} HandleWalletVerificationChallengeOptions
12
+ * @template {AbstractSetupSchema} Setup - The GraphQL schema setup type
13
+ * @property {ReturnType<typeof createPortalClient>["client"]} portalClient - The portal client instance
14
+ * @property {initGraphQLTada<Setup>} portalGraphql - The GraphQL query builder
15
+ * @property {string} verificationId - The ID of the verification challenge
16
+ * @property {Address} userWalletAddress - The wallet address to verify
17
+ * @property {string | number} code - The verification code provided by the user
18
+ * @property {"otp" | "secret-code" | "pincode"} verificationType - The type of verification being performed
19
+ */
20
+ interface HandleWalletVerificationChallengeOptions<Setup extends AbstractSetupSchema> {
21
+ portalClient: ReturnType<typeof createPortalClient>["client"];
22
+ portalGraphql: initGraphQLTada<Setup>;
23
+ verificationId: string;
24
+ userWalletAddress: Address;
25
+ code: string | number;
26
+ verificationType: "otp" | "secret-code" | "pincode";
27
+ }
28
+ /**
29
+ * Handles a wallet verification challenge by generating an appropriate response
30
+ *
31
+ * @param options - The options for handling the wallet verification challenge
32
+ * @returns Promise resolving to an object containing the challenge response and optionally the verification ID
33
+ * @throws {ChallengeError} If the challenge cannot be created or is invalid
34
+ * @example
35
+ * import { createPortalClient } from "@settlemint/sdk-portal";
36
+ * import { handleWalletVerificationChallenge } from "@settlemint/sdk-portal";
37
+ *
38
+ * const { client, graphql } = createPortalClient({
39
+ * instance: "https://portal.example.com/graphql",
40
+ * accessToken: "your-access-token"
41
+ * });
42
+ *
43
+ * const result = await handleWalletVerificationChallenge({
44
+ * portalClient: client,
45
+ * portalGraphql: graphql,
46
+ * verificationId: "verification-123",
47
+ * userWalletAddress: "0x123...",
48
+ * code: "123456",
49
+ * verificationType: "otp"
50
+ * });
51
+ */
52
+ declare function handleWalletVerificationChallenge<const Setup extends AbstractSetupSchema>({ portalClient, portalGraphql, verificationId, userWalletAddress, code, verificationType, }: HandleWalletVerificationChallengeOptions<Setup>): Promise<{
53
+ challengeResponse: string;
54
+ verificationId?: string;
55
+ }>;
56
+
57
+ /**
58
+ * Represents the structure of a blockchain transaction with its receipt
59
+ *
60
+ * @typedef {Object} Transaction
61
+ * @property {Object} receipt - The transaction receipt details
62
+ * @property {string} receipt.transactionHash - The hash of the transaction
63
+ * @property {string} receipt.to - The recipient address of the transaction
64
+ * @property {string} receipt.status - The status of the transaction (success/failure)
65
+ * @property {string} receipt.from - The sender address of the transaction
66
+ * @property {string} receipt.type - The type of the transaction
67
+ * @property {string} receipt.revertReason - The reason for transaction reversion, if applicable
68
+ * @property {string} receipt.revertReasonDecoded - Human-readable version of the revert reason
69
+ * @property {string} receipt.contractAddress - The address of the contract deployed in the transaction
70
+ * @property {string[]} receipt.logs - Array of log entries generated by the transaction
71
+ * @property {string[]} receipt.events - Array of events emitted during the transaction
72
+ * @property {string} transactionHash - The hash of the transaction (duplicate of receipt.transactionHash)
73
+ * @property {string} from - The sender address (duplicate of receipt.from)
74
+ * @property {string} createdAt - Timestamp when the transaction was created
75
+ * @property {string} address - The contract address involved in the transaction
76
+ * @property {string} functionName - The name of the function called in the transaction
77
+ * @property {boolean} isContract - Whether the transaction is a contract deployment
78
+ */
79
+ interface Transaction {
80
+ receipt: {
81
+ transactionHash: string;
82
+ to: string;
83
+ status: string;
84
+ from: string;
85
+ type: string;
86
+ revertReason: string;
87
+ revertReasonDecoded: string;
88
+ logs: string[];
89
+ events: string[];
90
+ contractAddress: string;
91
+ };
92
+ transactionHash: string;
93
+ from: string;
94
+ createdAt: string;
95
+ address: string;
96
+ functionName: string;
97
+ isContract: boolean;
98
+ }
99
+ /**
100
+ * Wait for the transaction receipt
101
+ * @param wsClient websocket client
102
+ * @param transactionHash transaction hash
103
+ * @returns receipt
104
+ */
105
+ declare function waitForTransactionReceipt(wsClient: Client, transactionHash: string): Promise<Transaction | undefined>;
5
106
 
6
107
  /**
7
108
  * Configuration options for the GraphQL client, excluding 'url' and 'exchanges'.
@@ -36,28 +137,33 @@ type ClientOptions = z.infer<typeof ClientOptionsSchema>;
36
137
  * @throws If the provided options fail validation
37
138
  *
38
139
  * @example
39
- * import { createPortalClient } from '@settlemint/sdk-portal';
140
+ * import { createPortalClient } from "@settlemint/sdk-portal";
141
+ * import { loadEnv } from "@settlemint/sdk-utils/environment";
142
+ * import { createLogger, requestLogger } from "@settlemint/sdk-utils/logging";
40
143
  * import type { introspection } from "@schemas/portal-env";
41
- * import { createLogger, requestLogger } from '@settlemint/sdk-utils/logging';
42
144
  *
145
+ * const env = await loadEnv(false, false);
43
146
  * const logger = createLogger();
44
147
  *
45
- * export const { client: portalClient, graphql: portalGraphql } = createPortalClient<{
148
+ * const { client: portalClient, graphql: portalGraphql } = createPortalClient<{
46
149
  * introspection: introspection;
47
150
  * disableMasking: true;
48
151
  * scalars: {
49
152
  * // Change unknown to the type you are using to store metadata
50
153
  * JSON: unknown;
51
154
  * };
52
- * }>({
53
- * instance: process.env.SETTLEMINT_PORTAL_GRAPHQL_ENDPOINT,
54
- * accessToken: process.env.SETTLEMINT_ACCESS_TOKEN,
55
- * }, {
56
- * fetch: requestLogger(logger, "portal", fetch) as typeof fetch,
57
- * });
155
+ * }>(
156
+ * {
157
+ * instance: env.SETTLEMINT_PORTAL_GRAPHQL_ENDPOINT!,
158
+ * accessToken: env.SETTLEMINT_ACCESS_TOKEN!,
159
+ * },
160
+ * {
161
+ * fetch: requestLogger(logger, "portal", fetch) as typeof fetch,
162
+ * },
163
+ * );
58
164
  *
59
165
  * // Making GraphQL queries
60
- * const query = graphql(`
166
+ * const query = portalGraphql(`
61
167
  * query GetPendingTransactions {
62
168
  * getPendingTransactions {
63
169
  * count
@@ -65,11 +171,11 @@ type ClientOptions = z.infer<typeof ClientOptionsSchema>;
65
171
  * }
66
172
  * `);
67
173
  *
68
- * const result = await client.request(query);
174
+ * const result = await portalClient.request(query);
69
175
  */
70
176
  declare function createPortalClient<const Setup extends AbstractSetupSchema>(options: ClientOptions, clientOptions?: RequestConfig): {
71
177
  client: GraphQLClient;
72
178
  graphql: initGraphQLTada<Setup>;
73
179
  };
74
180
 
75
- export { type ClientOptions, ClientOptionsSchema, type RequestConfig, createPortalClient };
181
+ export { type ClientOptions, ClientOptionsSchema, type HandleWalletVerificationChallengeOptions, type RequestConfig, type Transaction, createPortalClient, handleWalletVerificationChallenge, waitForTransactionReceipt };
package/dist/portal.mjs CHANGED
@@ -4,6 +4,120 @@ import { ApplicationAccessTokenSchema, UrlOrPathSchema, validate } from "@settle
4
4
  import { initGraphQLTada } from "gql.tada";
5
5
  import { GraphQLClient } from "graphql-request";
6
6
  import { z } from "zod";
7
+
8
+ // src/utils/wallet-verification-challenge.ts
9
+ import { createHash } from "node:crypto";
10
+ var ChallengeError = class extends Error {
11
+ code;
12
+ constructor(message, code) {
13
+ super(message);
14
+ this.name = "ChallengeError";
15
+ this.code = code;
16
+ }
17
+ };
18
+ function hashPincode(pincode, salt) {
19
+ return createHash("sha256").update(`${salt}${pincode}`).digest("hex");
20
+ }
21
+ function generateResponse(pincode, salt, challenge) {
22
+ const hashedPincode = hashPincode(pincode, salt);
23
+ return createHash("sha256").update(`${hashedPincode}_${challenge}`).digest("hex");
24
+ }
25
+ async function handleWalletVerificationChallenge({
26
+ portalClient,
27
+ portalGraphql,
28
+ verificationId,
29
+ userWalletAddress,
30
+ code,
31
+ verificationType
32
+ }) {
33
+ try {
34
+ if (verificationType === "otp") {
35
+ return {
36
+ challengeResponse: code.toString(),
37
+ verificationId
38
+ };
39
+ }
40
+ if (verificationType === "secret-code") {
41
+ const formattedCode = code.toString().replace(/(.{5})(?=.)/, "$1-");
42
+ return {
43
+ challengeResponse: formattedCode,
44
+ verificationId
45
+ };
46
+ }
47
+ const verificationChallenges = await portalClient.request(
48
+ portalGraphql(`
49
+ mutation CreateWalletVerificationChallenges($userWalletAddress: String!, $verificationId: String!) {
50
+ createWalletVerificationChallenges(userWalletAddress: $userWalletAddress, verificationId: $verificationId) {
51
+ challenge
52
+ id
53
+ name
54
+ verificationType
55
+ }
56
+ }
57
+ `),
58
+ {
59
+ userWalletAddress,
60
+ verificationId
61
+ }
62
+ );
63
+ if (!verificationChallenges.createWalletVerificationChallenges?.length) {
64
+ throw new ChallengeError("No verification challenges received", "NO_CHALLENGES");
65
+ }
66
+ const walletVerificationChallenge = verificationChallenges.createWalletVerificationChallenges.find(
67
+ (challenge) => challenge.id === verificationId
68
+ );
69
+ if (!walletVerificationChallenge?.challenge?.secret || !walletVerificationChallenge?.challenge?.salt) {
70
+ throw new ChallengeError("Invalid challenge format", "INVALID_CHALLENGE");
71
+ }
72
+ const { secret, salt } = walletVerificationChallenge.challenge;
73
+ const challengeResponse = generateResponse(code.toString(), salt, secret);
74
+ return {
75
+ challengeResponse,
76
+ verificationId
77
+ };
78
+ } catch (error) {
79
+ if (error instanceof ChallengeError) {
80
+ throw error;
81
+ }
82
+ throw new ChallengeError("Failed to process wallet verification challenge", "CHALLENGE_PROCESSING_ERROR");
83
+ }
84
+ }
85
+
86
+ // src/utils/wait-for-transaction-receipt.ts
87
+ async function waitForTransactionReceipt(wsClient, transactionHash) {
88
+ const subscription = wsClient.iterate({
89
+ query: `subscription getTransaction($transactionHash: String!) {
90
+ getTransaction(transactionHash: $transactionHash) {
91
+ receipt {
92
+ transactionHash
93
+ to
94
+ status
95
+ from
96
+ type
97
+ revertReason
98
+ revertReasonDecoded
99
+ logs
100
+ events
101
+ contractAddress
102
+ }
103
+ transactionHash
104
+ from
105
+ createdAt
106
+ address
107
+ functionName
108
+ isContract
109
+ }
110
+ }`,
111
+ variables: { transactionHash }
112
+ });
113
+ for await (const result of subscription) {
114
+ if (result?.data?.getTransaction?.receipt) {
115
+ return result.data.getTransaction;
116
+ }
117
+ }
118
+ }
119
+
120
+ // src/portal.ts
7
121
  import { readFragment } from "gql.tada";
8
122
  var ClientOptionsSchema = z.object({
9
123
  instance: UrlOrPathSchema,
@@ -26,6 +140,8 @@ function createPortalClient(options, clientOptions) {
26
140
  export {
27
141
  ClientOptionsSchema,
28
142
  createPortalClient,
29
- readFragment
143
+ handleWalletVerificationChallenge,
144
+ readFragment,
145
+ waitForTransactionReceipt
30
146
  };
31
147
  //# sourceMappingURL=portal.mjs.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/portal.ts"],"sourcesContent":["import { ensureServer } from \"@settlemint/sdk-utils/runtime\";\nimport { ApplicationAccessTokenSchema, UrlOrPathSchema, validate } from \"@settlemint/sdk-utils/validation\";\nimport { type AbstractSetupSchema, initGraphQLTada } from \"gql.tada\";\nimport { GraphQLClient } from \"graphql-request\";\nimport { z } from \"zod\";\n\n/**\n * Configuration options for the GraphQL client, excluding 'url' and 'exchanges'.\n */\nexport type RequestConfig = ConstructorParameters<typeof GraphQLClient>[1];\n\n/**\n * Schema for validating Portal client configuration options.\n */\nexport const ClientOptionsSchema = z.object({\n instance: UrlOrPathSchema,\n accessToken: ApplicationAccessTokenSchema,\n cache: z.enum([\"default\", \"force-cache\", \"no-cache\", \"no-store\", \"only-if-cached\", \"reload\"]).optional(),\n});\n\n/**\n * Type representing the validated client options.\n */\nexport type ClientOptions = z.infer<typeof ClientOptionsSchema>;\n\n/**\n * Creates a Portal GraphQL client with the provided configuration.\n *\n * @param options - Configuration options for the Portal client\n * @param clientOptions - Additional GraphQL client configuration options\n * @returns An object containing the configured GraphQL client and graphql helper function\n * @throws If the provided options fail validation\n *\n * @example\n * import { createPortalClient } from '@settlemint/sdk-portal';\n * import type { introspection } from \"@schemas/portal-env\";\n * import { createLogger, requestLogger } from '@settlemint/sdk-utils/logging';\n *\n * const logger = createLogger();\n *\n * export const { client: portalClient, graphql: portalGraphql } = createPortalClient<{\n * introspection: introspection;\n * disableMasking: true;\n * scalars: {\n * // Change unknown to the type you are using to store metadata\n * JSON: unknown;\n * };\n * }>({\n * instance: process.env.SETTLEMINT_PORTAL_GRAPHQL_ENDPOINT,\n * accessToken: process.env.SETTLEMINT_ACCESS_TOKEN,\n * }, {\n * fetch: requestLogger(logger, \"portal\", fetch) as typeof fetch,\n * });\n *\n * // Making GraphQL queries\n * const query = graphql(`\n * query GetPendingTransactions {\n * getPendingTransactions {\n * count\n * }\n * }\n * `);\n *\n * const result = await client.request(query);\n */\nexport function createPortalClient<const Setup extends AbstractSetupSchema>(\n options: ClientOptions,\n clientOptions?: RequestConfig,\n): {\n client: GraphQLClient;\n graphql: initGraphQLTada<Setup>;\n} {\n ensureServer();\n const validatedOptions = validate(ClientOptionsSchema, options);\n const graphql = initGraphQLTada<Setup>();\n const fullUrl = new URL(validatedOptions.instance).toString();\n\n return {\n client: new GraphQLClient(fullUrl, {\n ...clientOptions,\n headers: { ...(clientOptions?.headers ?? {}), \"x-auth-token\": validatedOptions.accessToken },\n }),\n graphql,\n };\n}\n\nexport { readFragment } from \"gql.tada\";\nexport type { FragmentOf, ResultOf, VariablesOf } from \"gql.tada\";\n"],"mappings":";AAAA,SAAS,oBAAoB;AAC7B,SAAS,8BAA8B,iBAAiB,gBAAgB;AACxE,SAAmC,uBAAuB;AAC1D,SAAS,qBAAqB;AAC9B,SAAS,SAAS;AAkFlB,SAAS,oBAAoB;AAxEtB,IAAM,sBAAsB,EAAE,OAAO;AAAA,EAC1C,UAAU;AAAA,EACV,aAAa;AAAA,EACb,OAAO,EAAE,KAAK,CAAC,WAAW,eAAe,YAAY,YAAY,kBAAkB,QAAQ,CAAC,EAAE,SAAS;AACzG,CAAC;AA+CM,SAAS,mBACd,SACA,eAIA;AACA,eAAa;AACb,QAAM,mBAAmB,SAAS,qBAAqB,OAAO;AAC9D,QAAM,UAAU,gBAAuB;AACvC,QAAM,UAAU,IAAI,IAAI,iBAAiB,QAAQ,EAAE,SAAS;AAE5D,SAAO;AAAA,IACL,QAAQ,IAAI,cAAc,SAAS;AAAA,MACjC,GAAG;AAAA,MACH,SAAS,EAAE,GAAI,eAAe,WAAW,CAAC,GAAI,gBAAgB,iBAAiB,YAAY;AAAA,IAC7F,CAAC;AAAA,IACD;AAAA,EACF;AACF;","names":[]}
1
+ {"version":3,"sources":["../src/portal.ts","../src/utils/wallet-verification-challenge.ts","../src/utils/wait-for-transaction-receipt.ts"],"sourcesContent":["import {} from \"@settlemint/sdk-utils/logging\";\nimport { ensureServer } from \"@settlemint/sdk-utils/runtime\";\nimport { ApplicationAccessTokenSchema, UrlOrPathSchema, validate } from \"@settlemint/sdk-utils/validation\";\nimport { type AbstractSetupSchema, initGraphQLTada } from \"gql.tada\";\nimport { GraphQLClient } from \"graphql-request\";\nimport { z } from \"zod\";\n\n/**\n * Configuration options for the GraphQL client, excluding 'url' and 'exchanges'.\n */\nexport type RequestConfig = ConstructorParameters<typeof GraphQLClient>[1];\n\n/**\n * Schema for validating Portal client configuration options.\n */\nexport const ClientOptionsSchema = z.object({\n instance: UrlOrPathSchema,\n accessToken: ApplicationAccessTokenSchema,\n cache: z.enum([\"default\", \"force-cache\", \"no-cache\", \"no-store\", \"only-if-cached\", \"reload\"]).optional(),\n});\n\n/**\n * Type representing the validated client options.\n */\nexport type ClientOptions = z.infer<typeof ClientOptionsSchema>;\n\n/**\n * Creates a Portal GraphQL client with the provided configuration.\n *\n * @param options - Configuration options for the Portal client\n * @param clientOptions - Additional GraphQL client configuration options\n * @returns An object containing the configured GraphQL client and graphql helper function\n * @throws If the provided options fail validation\n *\n * @example\n * import { createPortalClient } from \"@settlemint/sdk-portal\";\n * import { loadEnv } from \"@settlemint/sdk-utils/environment\";\n * import { createLogger, requestLogger } from \"@settlemint/sdk-utils/logging\";\n * import type { introspection } from \"@schemas/portal-env\";\n *\n * const env = await loadEnv(false, false);\n * const logger = createLogger();\n *\n * const { client: portalClient, graphql: portalGraphql } = createPortalClient<{\n * introspection: introspection;\n * disableMasking: true;\n * scalars: {\n * // Change unknown to the type you are using to store metadata\n * JSON: unknown;\n * };\n * }>(\n * {\n * instance: env.SETTLEMINT_PORTAL_GRAPHQL_ENDPOINT!,\n * accessToken: env.SETTLEMINT_ACCESS_TOKEN!,\n * },\n * {\n * fetch: requestLogger(logger, \"portal\", fetch) as typeof fetch,\n * },\n * );\n *\n * // Making GraphQL queries\n * const query = portalGraphql(`\n * query GetPendingTransactions {\n * getPendingTransactions {\n * count\n * }\n * }\n * `);\n *\n * const result = await portalClient.request(query);\n */\nexport function createPortalClient<const Setup extends AbstractSetupSchema>(\n options: ClientOptions,\n clientOptions?: RequestConfig,\n): {\n client: GraphQLClient;\n graphql: initGraphQLTada<Setup>;\n} {\n ensureServer();\n const validatedOptions = validate(ClientOptionsSchema, options);\n const graphql = initGraphQLTada<Setup>();\n const fullUrl = new URL(validatedOptions.instance).toString();\n\n return {\n client: new GraphQLClient(fullUrl, {\n ...clientOptions,\n headers: { ...(clientOptions?.headers ?? {}), \"x-auth-token\": validatedOptions.accessToken },\n }),\n graphql,\n };\n}\n\nexport {\n handleWalletVerificationChallenge,\n type HandleWalletVerificationChallengeOptions,\n} from \"./utils/wallet-verification-challenge.js\";\nexport { waitForTransactionReceipt, type Transaction } from \"./utils/wait-for-transaction-receipt.js\";\nexport { readFragment } from \"gql.tada\";\nexport type { FragmentOf, ResultOf, VariablesOf } from \"gql.tada\";\n","import { createHash } from \"node:crypto\";\nimport type { AbstractSetupSchema, initGraphQLTada } from \"gql.tada\";\nimport type { Address } from \"viem\";\nimport type { createPortalClient } from \"../portal.js\";\n\n/**\n * Custom error class for challenge-related errors\n */\nexport class ChallengeError extends Error {\n readonly code: string;\n\n constructor(message: string, code: string) {\n super(message);\n this.name = \"ChallengeError\";\n this.code = code;\n }\n}\n\n/**\n * Represents the structure of a wallet verification challenge\n */\ninterface WalletVerificationChallenge {\n challenge: {\n secret: string;\n salt: string;\n };\n id: string;\n name: string;\n verificationType: string;\n}\n\n/**\n * Response type for the CreateWalletVerificationChallenges mutation\n */\ninterface CreateWalletVerificationChallengesResponse {\n createWalletVerificationChallenges: WalletVerificationChallenge[];\n}\n\n/**\n * Hashes a pincode with a salt using SHA-256\n * @param pincode - The pincode to hash\n * @param salt - The salt to use in hashing\n * @returns The hashed pincode as a hex string\n */\nfunction hashPincode(pincode: string, salt: string): string {\n return createHash(\"sha256\").update(`${salt}${pincode}`).digest(\"hex\");\n}\n\n/**\n * Generates a challenge response by combining a hashed pincode with a challenge\n * @param pincode - The user's pincode\n * @param salt - The salt provided in the challenge\n * @param challenge - The challenge secret\n * @returns The challenge response as a hex string\n */\nfunction generateResponse(pincode: string, salt: string, challenge: string): string {\n const hashedPincode = hashPincode(pincode, salt);\n return createHash(\"sha256\").update(`${hashedPincode}_${challenge}`).digest(\"hex\");\n}\n\n/**\n * Options for handling a wallet verification challenge\n *\n * @typedef {Object} HandleWalletVerificationChallengeOptions\n * @template {AbstractSetupSchema} Setup - The GraphQL schema setup type\n * @property {ReturnType<typeof createPortalClient>[\"client\"]} portalClient - The portal client instance\n * @property {initGraphQLTada<Setup>} portalGraphql - The GraphQL query builder\n * @property {string} verificationId - The ID of the verification challenge\n * @property {Address} userWalletAddress - The wallet address to verify\n * @property {string | number} code - The verification code provided by the user\n * @property {\"otp\" | \"secret-code\" | \"pincode\"} verificationType - The type of verification being performed\n */\nexport interface HandleWalletVerificationChallengeOptions<Setup extends AbstractSetupSchema> {\n portalClient: ReturnType<typeof createPortalClient>[\"client\"];\n portalGraphql: initGraphQLTada<Setup>;\n verificationId: string;\n userWalletAddress: Address;\n code: string | number;\n verificationType: \"otp\" | \"secret-code\" | \"pincode\";\n}\n\n/**\n * Handles a wallet verification challenge by generating an appropriate response\n *\n * @param options - The options for handling the wallet verification challenge\n * @returns Promise resolving to an object containing the challenge response and optionally the verification ID\n * @throws {ChallengeError} If the challenge cannot be created or is invalid\n * @example\n * import { createPortalClient } from \"@settlemint/sdk-portal\";\n * import { handleWalletVerificationChallenge } from \"@settlemint/sdk-portal\";\n *\n * const { client, graphql } = createPortalClient({\n * instance: \"https://portal.example.com/graphql\",\n * accessToken: \"your-access-token\"\n * });\n *\n * const result = await handleWalletVerificationChallenge({\n * portalClient: client,\n * portalGraphql: graphql,\n * verificationId: \"verification-123\",\n * userWalletAddress: \"0x123...\",\n * code: \"123456\",\n * verificationType: \"otp\"\n * });\n */\nexport async function handleWalletVerificationChallenge<const Setup extends AbstractSetupSchema>({\n portalClient,\n portalGraphql,\n verificationId,\n userWalletAddress,\n code,\n verificationType,\n}: HandleWalletVerificationChallengeOptions<Setup>): Promise<{\n challengeResponse: string;\n verificationId?: string;\n}> {\n try {\n if (verificationType === \"otp\") {\n return {\n challengeResponse: code.toString(),\n verificationId,\n };\n }\n\n if (verificationType === \"secret-code\") {\n // Add - separator to the code\n const formattedCode = code.toString().replace(/(.{5})(?=.)/, \"$1-\");\n return {\n challengeResponse: formattedCode,\n verificationId,\n };\n }\n\n const verificationChallenges = await portalClient.request<CreateWalletVerificationChallengesResponse>(\n portalGraphql(`\n mutation CreateWalletVerificationChallenges($userWalletAddress: String!, $verificationId: String!) {\n createWalletVerificationChallenges(userWalletAddress: $userWalletAddress, verificationId: $verificationId) {\n challenge\n id\n name\n verificationType\n }\n }\n `),\n {\n userWalletAddress,\n verificationId,\n },\n );\n\n if (!verificationChallenges.createWalletVerificationChallenges?.length) {\n throw new ChallengeError(\"No verification challenges received\", \"NO_CHALLENGES\");\n }\n\n const walletVerificationChallenge = verificationChallenges.createWalletVerificationChallenges.find(\n (challenge) => challenge.id === verificationId,\n );\n\n if (!walletVerificationChallenge?.challenge?.secret || !walletVerificationChallenge?.challenge?.salt) {\n throw new ChallengeError(\"Invalid challenge format\", \"INVALID_CHALLENGE\");\n }\n\n const { secret, salt } = walletVerificationChallenge.challenge;\n const challengeResponse = generateResponse(code.toString(), salt, secret);\n return {\n challengeResponse,\n verificationId,\n };\n } catch (error) {\n if (error instanceof ChallengeError) {\n throw error;\n }\n throw new ChallengeError(\"Failed to process wallet verification challenge\", \"CHALLENGE_PROCESSING_ERROR\");\n }\n}\n","import type { Client } from \"graphql-ws\";\n\n/**\n * Represents the structure of a blockchain transaction with its receipt\n *\n * @typedef {Object} Transaction\n * @property {Object} receipt - The transaction receipt details\n * @property {string} receipt.transactionHash - The hash of the transaction\n * @property {string} receipt.to - The recipient address of the transaction\n * @property {string} receipt.status - The status of the transaction (success/failure)\n * @property {string} receipt.from - The sender address of the transaction\n * @property {string} receipt.type - The type of the transaction\n * @property {string} receipt.revertReason - The reason for transaction reversion, if applicable\n * @property {string} receipt.revertReasonDecoded - Human-readable version of the revert reason\n * @property {string} receipt.contractAddress - The address of the contract deployed in the transaction\n * @property {string[]} receipt.logs - Array of log entries generated by the transaction\n * @property {string[]} receipt.events - Array of events emitted during the transaction\n * @property {string} transactionHash - The hash of the transaction (duplicate of receipt.transactionHash)\n * @property {string} from - The sender address (duplicate of receipt.from)\n * @property {string} createdAt - Timestamp when the transaction was created\n * @property {string} address - The contract address involved in the transaction\n * @property {string} functionName - The name of the function called in the transaction\n * @property {boolean} isContract - Whether the transaction is a contract deployment\n */\nexport interface Transaction {\n receipt: {\n transactionHash: string;\n to: string;\n status: string;\n from: string;\n type: string;\n revertReason: string;\n revertReasonDecoded: string;\n logs: string[];\n events: string[];\n contractAddress: string;\n };\n transactionHash: string;\n from: string;\n createdAt: string;\n address: string;\n functionName: string;\n isContract: boolean;\n}\n\ninterface GetTransactionResponse {\n getTransaction: Transaction;\n}\n\n/**\n * Wait for the transaction receipt\n * @param wsClient websocket client\n * @param transactionHash transaction hash\n * @returns receipt\n */\nexport async function waitForTransactionReceipt(wsClient: Client, transactionHash: string) {\n const subscription = wsClient.iterate<GetTransactionResponse>({\n query: `subscription getTransaction($transactionHash: String!) {\n getTransaction(transactionHash: $transactionHash) {\n receipt {\n transactionHash\n to\n status\n from\n type\n revertReason\n revertReasonDecoded\n logs\n events\n contractAddress\n }\n transactionHash\n from\n createdAt\n address\n functionName\n isContract\n }\n }`,\n variables: { transactionHash },\n });\n\n for await (const result of subscription) {\n if (result?.data?.getTransaction?.receipt) {\n return result.data.getTransaction;\n }\n }\n}\n"],"mappings":"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","names":[]}
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@settlemint/sdk-portal",
3
3
  "description": "Portal API client module for SettleMint SDK, providing access to smart contract portal services and APIs",
4
- "version": "2.2.0-prc00b96af",
4
+ "version": "2.2.0-prdfa9d68b",
5
5
  "type": "module",
6
6
  "private": false,
7
7
  "license": "FSL-1.1-MIT",
@@ -47,12 +47,13 @@
47
47
  "typecheck": "tsc --noEmit",
48
48
  "publish-npm": "bun publish --tag ${TAG} --access public || exit 0",
49
49
  "prepack": "cp ../../LICENSE .",
50
+ "codegen": "gql-tada generate-output",
50
51
  "docs": "typedoc --options '../../typedoc.config.mjs' --entryPoints src/portal.ts --out ./docs"
51
52
  },
52
53
  "devDependencies": {},
53
54
  "dependencies": {
54
55
  "gql.tada": "^1",
55
- "@settlemint/sdk-utils": "2.2.0-prc00b96af",
56
+ "@settlemint/sdk-utils": "2.2.0-prdfa9d68b",
56
57
  "graphql-request": "^7",
57
58
  "zod": "^3"
58
59
  },