@settlemint/sdk-portal 2.2.0-pradaf999e → 2.2.0-prc49c3ef3
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 +141 -22
- package/dist/portal.cjs.map +1 -1
- package/dist/portal.mjs.map +1 -1
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -29,13 +29,16 @@
|
|
|
29
29
|
- [About](#about)
|
|
30
30
|
- [Examples](#examples)
|
|
31
31
|
- [Get pending transactions](#get-pending-transactions)
|
|
32
|
-
- [
|
|
32
|
+
- [Deploy contract](#deploy-contract)
|
|
33
|
+
- [Send transaction using hd wallet](#send-transaction-using-hd-wallet)
|
|
33
34
|
- [API Reference](#api-reference)
|
|
34
35
|
- [Functions](#functions)
|
|
35
36
|
- [createPortalClient()](#createportalclient)
|
|
36
37
|
- [handleWalletVerificationChallenge()](#handlewalletverificationchallenge)
|
|
38
|
+
- [waitForTransactionReceipt()](#waitfortransactionreceipt)
|
|
37
39
|
- [Interfaces](#interfaces)
|
|
38
40
|
- [HandleWalletVerificationChallengeOptions\<Setup\>](#handlewalletverificationchallengeoptionssetup)
|
|
41
|
+
- [Transaction](#transaction)
|
|
39
42
|
- [Type Aliases](#type-aliases)
|
|
40
43
|
- [ClientOptions](#clientoptions)
|
|
41
44
|
- [RequestConfig](#requestconfig)
|
|
@@ -92,14 +95,14 @@ const result = await portalClient.request(query);
|
|
|
92
95
|
console.log(`There are ${result.getPendingTransactions?.count} pending transactions`);
|
|
93
96
|
|
|
94
97
|
```
|
|
95
|
-
###
|
|
98
|
+
### Deploy contract
|
|
96
99
|
|
|
97
100
|
```ts
|
|
98
101
|
import { loadEnv } from "@settlemint/sdk-utils/environment";
|
|
99
102
|
import { createLogger, requestLogger } from "@settlemint/sdk-utils/logging";
|
|
100
|
-
import
|
|
103
|
+
import { getAddress } from "viem";
|
|
101
104
|
import { createPortalClient } from "../portal.js"; // Replace this path with "@settlemint/sdk-portal"
|
|
102
|
-
import {
|
|
105
|
+
import { waitForTransactionReceipt } from "../utils/wait-for-transaction-receipt.js";
|
|
103
106
|
import type { introspection } from "./schemas/portal-env.d.ts"; // Replace this path with the generated introspection type
|
|
104
107
|
|
|
105
108
|
const env = await loadEnv(false, false);
|
|
@@ -122,6 +125,85 @@ const { client: portalClient, graphql: portalGraphql } = createPortalClient<{
|
|
|
122
125
|
},
|
|
123
126
|
);
|
|
124
127
|
|
|
128
|
+
// Replace with the address of your private key which you use to deploy smart contracts
|
|
129
|
+
const FROM = getAddress("0x4B03331cF2db1497ec58CAa4AFD8b93611906960");
|
|
130
|
+
|
|
131
|
+
/**
|
|
132
|
+
* Deploy a forwarder contract
|
|
133
|
+
*/
|
|
134
|
+
const deployForwarder = await portalClient.request(
|
|
135
|
+
portalGraphql(`
|
|
136
|
+
mutation DeployContractForwarder($from: String!) {
|
|
137
|
+
DeployContractForwarder(from: $from, gasLimit: "0x3d0900") {
|
|
138
|
+
transactionHash
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
`),
|
|
142
|
+
{
|
|
143
|
+
from: FROM,
|
|
144
|
+
},
|
|
145
|
+
);
|
|
146
|
+
|
|
147
|
+
/**
|
|
148
|
+
* Wait for the forwared contract deployment to be finalized
|
|
149
|
+
*/
|
|
150
|
+
const transaction = await waitForTransactionReceipt(deployForwarder.DeployContractForwarder?.transactionHash!, {
|
|
151
|
+
portalGraphqlEndpoint: env.SETTLEMINT_PORTAL_GRAPHQL_ENDPOINT!,
|
|
152
|
+
accessToken: env.SETTLEMINT_ACCESS_TOKEN!,
|
|
153
|
+
});
|
|
154
|
+
|
|
155
|
+
/**
|
|
156
|
+
* Deploy a stablecoin factory contract
|
|
157
|
+
*/
|
|
158
|
+
const deployStableCoinFactory = await portalClient.request(
|
|
159
|
+
portalGraphql(`
|
|
160
|
+
mutation DeployContractStableCoinFactory($from: String!, $constructorArguments: DeployContractStableCoinFactoryInput!) {
|
|
161
|
+
DeployContractStableCoinFactory(from: $from, constructorArguments: $constructorArguments, gasLimit: "0x3d0900") {
|
|
162
|
+
transactionHash
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
`),
|
|
166
|
+
{
|
|
167
|
+
from: FROM,
|
|
168
|
+
constructorArguments: {
|
|
169
|
+
forwarder: getAddress(transaction?.receipt.contractAddress!),
|
|
170
|
+
},
|
|
171
|
+
},
|
|
172
|
+
);
|
|
173
|
+
|
|
174
|
+
console.log(deployStableCoinFactory?.DeployContractStableCoinFactory?.transactionHash);
|
|
175
|
+
|
|
176
|
+
```
|
|
177
|
+
### Send transaction using hd wallet
|
|
178
|
+
|
|
179
|
+
```ts
|
|
180
|
+
import { loadEnv } from "@settlemint/sdk-utils/environment";
|
|
181
|
+
import { createLogger, requestLogger } from "@settlemint/sdk-utils/logging";
|
|
182
|
+
import type { Address } from "viem";
|
|
183
|
+
import { createPortalClient } from "../portal.js"; // Replace this path with "@settlemint/sdk-portal"
|
|
184
|
+
import { handleWalletVerificationChallenge } from "../utils/wallet-verification-challenge.js"; // Replace this path with "@settlemint/sdk-portal"
|
|
185
|
+
import type { introspection } from "./schemas/portal-env.js"; // Replace this path with the generated introspection type
|
|
186
|
+
|
|
187
|
+
const env = await loadEnv(false, false);
|
|
188
|
+
const logger = createLogger();
|
|
189
|
+
|
|
190
|
+
const { client: portalClient, graphql: portalGraphql } = createPortalClient<{
|
|
191
|
+
introspection: introspection;
|
|
192
|
+
disableMasking: true;
|
|
193
|
+
scalars: {
|
|
194
|
+
// Change unknown to the type you are using to store metadata
|
|
195
|
+
JSON: unknown;
|
|
196
|
+
};
|
|
197
|
+
}>(
|
|
198
|
+
{
|
|
199
|
+
instance: env.SETTLEMINT_PORTAL_GRAPHQL_ENDPOINT!,
|
|
200
|
+
accessToken: env.SETTLEMINT_ACCESS_TOKEN!,
|
|
201
|
+
},
|
|
202
|
+
{
|
|
203
|
+
fetch: requestLogger(logger, "portal", fetch) as typeof fetch,
|
|
204
|
+
},
|
|
205
|
+
);
|
|
206
|
+
|
|
125
207
|
/**
|
|
126
208
|
* First create a wallet using the HD private key, this needs to be done for every user that is using your app
|
|
127
209
|
*/
|
|
@@ -176,19 +258,20 @@ const challengeResponse = await handleWalletVerificationChallenge({
|
|
|
176
258
|
|
|
177
259
|
/**
|
|
178
260
|
* 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
|
|
261
|
+
* This is a sample of how to send a transaction to the chain using the portal client and the asset tokenization kit
|
|
262
|
+
* The challenge response is generated using the handleWalletVerificationChallenge function, this is used to verifiy wallet access
|
|
180
263
|
* @see https://github.com/settlemint/asset-tokenization-kit
|
|
181
264
|
*/
|
|
182
265
|
const result = await portalClient.request(
|
|
183
266
|
portalGraphql(`
|
|
184
|
-
mutation
|
|
185
|
-
$challengeResponse: String
|
|
186
|
-
$verificationId: String
|
|
187
|
-
$address: String
|
|
188
|
-
$from: String
|
|
189
|
-
$input:
|
|
267
|
+
mutation StableCoinFactoryCreate(
|
|
268
|
+
$challengeResponse: String!
|
|
269
|
+
$verificationId: String
|
|
270
|
+
$address: String!
|
|
271
|
+
$from: String!
|
|
272
|
+
$input: StableCoinFactoryCreateInput!
|
|
190
273
|
) {
|
|
191
|
-
|
|
274
|
+
StableCoinFactoryCreate(
|
|
192
275
|
challengeResponse: $challengeResponse
|
|
193
276
|
verificationId: $verificationId
|
|
194
277
|
address: $address
|
|
@@ -202,17 +285,19 @@ const result = await portalClient.request(
|
|
|
202
285
|
{
|
|
203
286
|
challengeResponse: challengeResponse.challengeResponse,
|
|
204
287
|
verificationId: pincodeVerification.createWalletVerification?.id!,
|
|
205
|
-
address:
|
|
288
|
+
address: "0x5e771e1417100000000000000000000000000004",
|
|
206
289
|
from: wallet.createWallet?.address!,
|
|
207
290
|
input: {
|
|
208
|
-
|
|
209
|
-
|
|
291
|
+
name: "Test Coin",
|
|
292
|
+
symbol: "TEST",
|
|
293
|
+
decimals: 18,
|
|
294
|
+
collateralLivenessSeconds: 3_600,
|
|
210
295
|
},
|
|
211
296
|
},
|
|
212
297
|
);
|
|
213
298
|
|
|
214
299
|
// Log the transaction hash
|
|
215
|
-
console.log("Transaction hash:", result.
|
|
300
|
+
console.log("Transaction hash:", result.StableCoinFactoryCreate?.transactionHash);
|
|
216
301
|
|
|
217
302
|
```
|
|
218
303
|
|
|
@@ -224,7 +309,7 @@ console.log("Transaction hash:", result.BondMint?.transactionHash);
|
|
|
224
309
|
|
|
225
310
|
> **createPortalClient**\<`Setup`\>(`options`, `clientOptions?`): `object`
|
|
226
311
|
|
|
227
|
-
Defined in: [sdk/portal/src/portal.ts:
|
|
312
|
+
Defined in: [sdk/portal/src/portal.ts:71](https://github.com/settlemint/sdk/blob/v2.2.0/sdk/portal/src/portal.ts#L71)
|
|
228
313
|
|
|
229
314
|
Creates a Portal GraphQL client with the provided configuration.
|
|
230
315
|
|
|
@@ -252,8 +337,8 @@ An object containing the configured GraphQL client and graphql helper function
|
|
|
252
337
|
|
|
253
338
|
| Name | Type | Defined in |
|
|
254
339
|
| ------ | ------ | ------ |
|
|
255
|
-
| `client` | `GraphQLClient` | [sdk/portal/src/portal.ts:
|
|
256
|
-
| `graphql` | `initGraphQLTada`\<`Setup`\> | [sdk/portal/src/portal.ts:
|
|
340
|
+
| `client` | `GraphQLClient` | [sdk/portal/src/portal.ts:75](https://github.com/settlemint/sdk/blob/v2.2.0/sdk/portal/src/portal.ts#L75) |
|
|
341
|
+
| `graphql` | `initGraphQLTada`\<`Setup`\> | [sdk/portal/src/portal.ts:76](https://github.com/settlemint/sdk/blob/v2.2.0/sdk/portal/src/portal.ts#L76) |
|
|
257
342
|
|
|
258
343
|
##### Throws
|
|
259
344
|
|
|
@@ -265,7 +350,8 @@ If the provided options fail validation
|
|
|
265
350
|
import { createPortalClient } from "@settlemint/sdk-portal";
|
|
266
351
|
import { loadEnv } from "@settlemint/sdk-utils/environment";
|
|
267
352
|
import { createLogger, requestLogger } from "@settlemint/sdk-utils/logging";
|
|
268
|
-
import type { introspection } from "
|
|
353
|
+
import type { introspection } from "@schemas/portal-env";
|
|
354
|
+
|
|
269
355
|
const env = await loadEnv(false, false);
|
|
270
356
|
const logger = createLogger();
|
|
271
357
|
|
|
@@ -304,7 +390,7 @@ const result = await portalClient.request(query);
|
|
|
304
390
|
|
|
305
391
|
> **handleWalletVerificationChallenge**\<`Setup`\>(`options`): `Promise`\<\{ `challengeResponse`: `string`; `verificationId?`: `string`; \}\>
|
|
306
392
|
|
|
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)
|
|
393
|
+
Defined in: [sdk/portal/src/utils/wallet-verification-challenge.ts:106](https://github.com/settlemint/sdk/blob/v2.2.0/sdk/portal/src/utils/wallet-verification-challenge.ts#L106)
|
|
308
394
|
|
|
309
395
|
Handles a wallet verification challenge by generating an appropriate response
|
|
310
396
|
|
|
@@ -332,6 +418,7 @@ If the challenge cannot be created or is invalid
|
|
|
332
418
|
|
|
333
419
|
##### Example
|
|
334
420
|
|
|
421
|
+
```ts
|
|
335
422
|
import { createPortalClient } from "@settlemint/sdk-portal";
|
|
336
423
|
import { handleWalletVerificationChallenge } from "@settlemint/sdk-portal";
|
|
337
424
|
|
|
@@ -348,12 +435,36 @@ const result = await handleWalletVerificationChallenge({
|
|
|
348
435
|
code: "123456",
|
|
349
436
|
verificationType: "otp"
|
|
350
437
|
});
|
|
438
|
+
```
|
|
439
|
+
|
|
440
|
+
***
|
|
441
|
+
|
|
442
|
+
#### waitForTransactionReceipt()
|
|
443
|
+
|
|
444
|
+
> **waitForTransactionReceipt**(`transactionHash`, `options`): `Promise`\<`undefined` \| [`Transaction`](#transaction)\>
|
|
445
|
+
|
|
446
|
+
Defined in: [sdk/portal/src/utils/wait-for-transaction-receipt.ts:70](https://github.com/settlemint/sdk/blob/v2.2.0/sdk/portal/src/utils/wait-for-transaction-receipt.ts#L70)
|
|
447
|
+
|
|
448
|
+
Wait for the transaction receipt
|
|
449
|
+
|
|
450
|
+
##### Parameters
|
|
451
|
+
|
|
452
|
+
| Parameter | Type | Description |
|
|
453
|
+
| ------ | ------ | ------ |
|
|
454
|
+
| `transactionHash` | `string` | transaction hash |
|
|
455
|
+
| `options` | `WaitForTransactionReceiptOptions` | options |
|
|
456
|
+
|
|
457
|
+
##### Returns
|
|
458
|
+
|
|
459
|
+
`Promise`\<`undefined` \| [`Transaction`](#transaction)\>
|
|
460
|
+
|
|
461
|
+
receipt
|
|
351
462
|
|
|
352
463
|
### Interfaces
|
|
353
464
|
|
|
354
465
|
#### HandleWalletVerificationChallengeOptions\<Setup\>
|
|
355
466
|
|
|
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)
|
|
467
|
+
Defined in: [sdk/portal/src/utils/wallet-verification-challenge.ts:73](https://github.com/settlemint/sdk/blob/v2.2.0/sdk/portal/src/utils/wallet-verification-challenge.ts#L73)
|
|
357
468
|
|
|
358
469
|
Options for handling a wallet verification challenge
|
|
359
470
|
|
|
@@ -363,6 +474,14 @@ Options for handling a wallet verification challenge
|
|
|
363
474
|
| ------ | ------ |
|
|
364
475
|
| `Setup` *extends* `AbstractSetupSchema` | The GraphQL schema setup type |
|
|
365
476
|
|
|
477
|
+
***
|
|
478
|
+
|
|
479
|
+
#### Transaction
|
|
480
|
+
|
|
481
|
+
Defined in: [sdk/portal/src/utils/wait-for-transaction-receipt.ts:25](https://github.com/settlemint/sdk/blob/v2.2.0/sdk/portal/src/utils/wait-for-transaction-receipt.ts#L25)
|
|
482
|
+
|
|
483
|
+
Represents the structure of a blockchain transaction with its receipt
|
|
484
|
+
|
|
366
485
|
### Type Aliases
|
|
367
486
|
|
|
368
487
|
#### ClientOptions
|
package/dist/portal.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
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 { GraphQLClient } from \"graphql-request\";\nimport type { Address } from \"viem\";\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 {GraphQLClient} 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: GraphQLClient;\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 { createClient } 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 * Options for waiting for a transaction receipt\n *\n * @typedef {Object} WaitForTransactionReceiptOptions\n * @property {string} portalGraphqlEndpoint - The GraphQL endpoint URL for the Portal API\n * @property {string} accessToken - The access token for authentication with the Portal API\n * @property {number} [timeout] - Optional timeout in milliseconds before the operation fails\n */\ninterface WaitForTransactionReceiptOptions {\n portalGraphqlEndpoint: string;\n accessToken: string;\n timeout?: number;\n}\n\n/**\n * Wait for the transaction receipt\n * @param transactionHash transaction hash\n * @param options options\n * @returns receipt\n */\nexport async function waitForTransactionReceipt(transactionHash: string, options: WaitForTransactionReceiptOptions) {\n const wsClient = createClient({\n url: options.portalGraphqlEndpoint.toLowerCase().replace(\"/graphql\", `/${options.accessToken}/graphql`),\n });\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 return Promise.race([\n new Promise<undefined>((_resolve, reject) => {\n if (options.timeout) {\n setTimeout(() => {\n reject(new Error(\"Transaction receipt not found\"));\n }, options.timeout);\n }\n }),\n (async () => {\n for await (const result of subscription) {\n if (result?.data?.getTransaction?.receipt) {\n return result.data.getTransaction;\n }\n }\n })(),\n ]);\n}\n"],"mappings":"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","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 { 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 { GraphQLClient } from \"graphql-request\";\nimport type { Address } from \"viem\";\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 {GraphQLClient} 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: GraphQLClient;\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 { createClient } 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 * Options for waiting for a transaction receipt\n *\n * @typedef {Object} WaitForTransactionReceiptOptions\n * @property {string} portalGraphqlEndpoint - The GraphQL endpoint URL for the Portal API\n * @property {string} accessToken - The access token for authentication with the Portal API\n * @property {number} [timeout] - Optional timeout in milliseconds before the operation fails\n */\ninterface WaitForTransactionReceiptOptions {\n portalGraphqlEndpoint: string;\n accessToken: string;\n timeout?: number;\n}\n\n/**\n * Wait for the transaction receipt\n * @param transactionHash transaction hash\n * @param options options\n * @returns receipt\n */\nexport async function waitForTransactionReceipt(transactionHash: string, options: WaitForTransactionReceiptOptions) {\n const wsClient = createClient({\n url: options.portalGraphqlEndpoint.toLowerCase().replace(\"/graphql\", `/${options.accessToken}/graphql`),\n });\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 return Promise.race([\n new Promise<undefined>((_resolve, reject) => {\n if (options.timeout) {\n setTimeout(() => {\n reject(new Error(\"Transaction receipt not found\"));\n }, options.timeout);\n }\n }),\n (async () => {\n for await (const result of subscription) {\n if (result?.data?.getTransaction?.receipt) {\n return result.data.getTransaction;\n }\n }\n })(),\n ]);\n}\n"],"mappings":"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","names":["import_gql"]}
|
package/dist/portal.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
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 { GraphQLClient } from \"graphql-request\";\nimport type { Address } from \"viem\";\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 {GraphQLClient} 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: GraphQLClient;\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 { createClient } 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 * Options for waiting for a transaction receipt\n *\n * @typedef {Object} WaitForTransactionReceiptOptions\n * @property {string} portalGraphqlEndpoint - The GraphQL endpoint URL for the Portal API\n * @property {string} accessToken - The access token for authentication with the Portal API\n * @property {number} [timeout] - Optional timeout in milliseconds before the operation fails\n */\ninterface WaitForTransactionReceiptOptions {\n portalGraphqlEndpoint: string;\n accessToken: string;\n timeout?: number;\n}\n\n/**\n * Wait for the transaction receipt\n * @param transactionHash transaction hash\n * @param options options\n * @returns receipt\n */\nexport async function waitForTransactionReceipt(transactionHash: string, options: WaitForTransactionReceiptOptions) {\n const wsClient = createClient({\n url: options.portalGraphqlEndpoint.toLowerCase().replace(\"/graphql\", `/${options.accessToken}/graphql`),\n });\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 return Promise.race([\n new Promise<undefined>((_resolve, reject) => {\n if (options.timeout) {\n setTimeout(() => {\n reject(new Error(\"Transaction receipt not found\"));\n }, options.timeout);\n }\n }),\n (async () => {\n for await (const result of subscription) {\n if (result?.data?.getTransaction?.receipt) {\n return result.data.getTransaction;\n }\n }\n })(),\n ]);\n}\n"],"mappings":"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","names":[]}
|
|
1
|
+
{"version":3,"sources":["../src/portal.ts","../src/utils/wallet-verification-challenge.ts","../src/utils/wait-for-transaction-receipt.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 { 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 { GraphQLClient } from \"graphql-request\";\nimport type { Address } from \"viem\";\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 {GraphQLClient} 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: GraphQLClient;\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 { createClient } 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 * Options for waiting for a transaction receipt\n *\n * @typedef {Object} WaitForTransactionReceiptOptions\n * @property {string} portalGraphqlEndpoint - The GraphQL endpoint URL for the Portal API\n * @property {string} accessToken - The access token for authentication with the Portal API\n * @property {number} [timeout] - Optional timeout in milliseconds before the operation fails\n */\ninterface WaitForTransactionReceiptOptions {\n portalGraphqlEndpoint: string;\n accessToken: string;\n timeout?: number;\n}\n\n/**\n * Wait for the transaction receipt\n * @param transactionHash transaction hash\n * @param options options\n * @returns receipt\n */\nexport async function waitForTransactionReceipt(transactionHash: string, options: WaitForTransactionReceiptOptions) {\n const wsClient = createClient({\n url: options.portalGraphqlEndpoint.toLowerCase().replace(\"/graphql\", `/${options.accessToken}/graphql`),\n });\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 return Promise.race([\n new Promise<undefined>((_resolve, reject) => {\n if (options.timeout) {\n setTimeout(() => {\n reject(new Error(\"Transaction receipt not found\"));\n }, options.timeout);\n }\n }),\n (async () => {\n for await (const result of subscription) {\n if (result?.data?.getTransaction?.receipt) {\n return result.data.getTransaction;\n }\n }\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-
|
|
4
|
+
"version": "2.2.0-prc49c3ef3",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"private": false,
|
|
7
7
|
"license": "FSL-1.1-MIT",
|
|
@@ -56,7 +56,7 @@
|
|
|
56
56
|
"dependencies": {
|
|
57
57
|
"gql.tada": "^1",
|
|
58
58
|
"graphql-ws": "^6",
|
|
59
|
-
"@settlemint/sdk-utils": "2.2.0-
|
|
59
|
+
"@settlemint/sdk-utils": "2.2.0-prc49c3ef3",
|
|
60
60
|
"graphql-request": "^7",
|
|
61
61
|
"zod": "^3"
|
|
62
62
|
},
|