@settlemint/sdk-portal 2.2.0-pr503fed4b → 2.2.0-pr72a2ad5d
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 +382 -15
- package/dist/portal.cjs +137 -2
- package/dist/portal.cjs.map +1 -1
- package/dist/portal.d.cts +130 -12
- package/dist/portal.d.ts +130 -12
- package/dist/portal.mjs +134 -1
- package/dist/portal.mjs.map +1 -1
- package/package.json +7 -3
package/README.md
CHANGED
|
@@ -27,9 +27,19 @@
|
|
|
27
27
|
## Table of Contents
|
|
28
28
|
|
|
29
29
|
- [About](#about)
|
|
30
|
+
- [Examples](#examples)
|
|
31
|
+
- [Get pending transactions](#get-pending-transactions)
|
|
32
|
+
- [Deploy contract](#deploy-contract)
|
|
33
|
+
- [Send transaction using hd wallet](#send-transaction-using-hd-wallet)
|
|
30
34
|
- [API Reference](#api-reference)
|
|
31
35
|
- [Functions](#functions)
|
|
32
36
|
- [createPortalClient()](#createportalclient)
|
|
37
|
+
- [handleWalletVerificationChallenge()](#handlewalletverificationchallenge)
|
|
38
|
+
- [waitForTransactionReceipt()](#waitfortransactionreceipt)
|
|
39
|
+
- [Interfaces](#interfaces)
|
|
40
|
+
- [HandleWalletVerificationChallengeOptions\<Setup\>](#handlewalletverificationchallengeoptionssetup)
|
|
41
|
+
- [Transaction](#transaction)
|
|
42
|
+
- [WaitForTransactionReceiptOptions](#waitfortransactionreceiptoptions)
|
|
33
43
|
- [Type Aliases](#type-aliases)
|
|
34
44
|
- [ClientOptions](#clientoptions)
|
|
35
45
|
- [RequestConfig](#requestconfig)
|
|
@@ -43,8 +53,254 @@
|
|
|
43
53
|
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
54
|
|
|
45
55
|
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.
|
|
56
|
+
## Examples
|
|
46
57
|
|
|
47
|
-
|
|
58
|
+
### Get pending transactions
|
|
59
|
+
|
|
60
|
+
```ts
|
|
61
|
+
import { loadEnv } from "@settlemint/sdk-utils/environment";
|
|
62
|
+
import { createLogger, requestLogger } from "@settlemint/sdk-utils/logging";
|
|
63
|
+
import { createPortalClient } from "../portal.js"; // Replace this path with "@settlemint/sdk-portal"
|
|
64
|
+
import type { introspection } from "./schemas/portal-env.d.ts"; // Replace this path with the generated introspection type
|
|
65
|
+
|
|
66
|
+
const env = await loadEnv(false, false);
|
|
67
|
+
const logger = createLogger();
|
|
68
|
+
|
|
69
|
+
const { client: portalClient, graphql: portalGraphql } = createPortalClient<{
|
|
70
|
+
introspection: introspection;
|
|
71
|
+
disableMasking: true;
|
|
72
|
+
scalars: {
|
|
73
|
+
// Change unknown to the type you are using to store metadata
|
|
74
|
+
JSON: unknown;
|
|
75
|
+
};
|
|
76
|
+
}>(
|
|
77
|
+
{
|
|
78
|
+
instance: env.SETTLEMINT_PORTAL_GRAPHQL_ENDPOINT!,
|
|
79
|
+
accessToken: env.SETTLEMINT_ACCESS_TOKEN!,
|
|
80
|
+
},
|
|
81
|
+
{
|
|
82
|
+
fetch: requestLogger(logger, "portal", fetch) as typeof fetch,
|
|
83
|
+
},
|
|
84
|
+
);
|
|
85
|
+
|
|
86
|
+
// Making GraphQL queries
|
|
87
|
+
const query = portalGraphql(`
|
|
88
|
+
query GetPendingTransactions {
|
|
89
|
+
getPendingTransactions {
|
|
90
|
+
count
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
`);
|
|
94
|
+
|
|
95
|
+
const result = await portalClient.request(query);
|
|
96
|
+
console.log(`There are ${result.getPendingTransactions?.count} pending transactions`);
|
|
97
|
+
|
|
98
|
+
```
|
|
99
|
+
### Deploy contract
|
|
100
|
+
|
|
101
|
+
```ts
|
|
102
|
+
import { loadEnv } from "@settlemint/sdk-utils/environment";
|
|
103
|
+
import { createLogger, requestLogger } from "@settlemint/sdk-utils/logging";
|
|
104
|
+
import { getAddress } from "viem";
|
|
105
|
+
import { createPortalClient } from "../portal.js"; // Replace this path with "@settlemint/sdk-portal"
|
|
106
|
+
import { waitForTransactionReceipt } from "../utils/wait-for-transaction-receipt.js";
|
|
107
|
+
import type { introspection } from "./schemas/portal-env.d.ts"; // Replace this path with the generated introspection type
|
|
108
|
+
|
|
109
|
+
const env = await loadEnv(false, false);
|
|
110
|
+
const logger = createLogger();
|
|
111
|
+
|
|
112
|
+
const { client: portalClient, graphql: portalGraphql } = createPortalClient<{
|
|
113
|
+
introspection: introspection;
|
|
114
|
+
disableMasking: true;
|
|
115
|
+
scalars: {
|
|
116
|
+
// Change unknown to the type you are using to store metadata
|
|
117
|
+
JSON: unknown;
|
|
118
|
+
};
|
|
119
|
+
}>(
|
|
120
|
+
{
|
|
121
|
+
instance: env.SETTLEMINT_PORTAL_GRAPHQL_ENDPOINT!,
|
|
122
|
+
accessToken: env.SETTLEMINT_ACCESS_TOKEN!,
|
|
123
|
+
},
|
|
124
|
+
{
|
|
125
|
+
fetch: requestLogger(logger, "portal", fetch) as typeof fetch,
|
|
126
|
+
},
|
|
127
|
+
);
|
|
128
|
+
|
|
129
|
+
// Replace with the address of your private key which you use to deploy smart contracts
|
|
130
|
+
const FROM = getAddress("0x4B03331cF2db1497ec58CAa4AFD8b93611906960");
|
|
131
|
+
|
|
132
|
+
/**
|
|
133
|
+
* Deploy a forwarder contract
|
|
134
|
+
*/
|
|
135
|
+
const deployForwarder = await portalClient.request(
|
|
136
|
+
portalGraphql(`
|
|
137
|
+
mutation DeployContractForwarder($from: String!) {
|
|
138
|
+
DeployContractForwarder(from: $from, gasLimit: "0x3d0900") {
|
|
139
|
+
transactionHash
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
`),
|
|
143
|
+
{
|
|
144
|
+
from: FROM,
|
|
145
|
+
},
|
|
146
|
+
);
|
|
147
|
+
|
|
148
|
+
/**
|
|
149
|
+
* Wait for the forwarder contract deployment to be finalized
|
|
150
|
+
*/
|
|
151
|
+
const transaction = await waitForTransactionReceipt(deployForwarder.DeployContractForwarder?.transactionHash!, {
|
|
152
|
+
portalGraphqlEndpoint: env.SETTLEMINT_PORTAL_GRAPHQL_ENDPOINT!,
|
|
153
|
+
accessToken: env.SETTLEMINT_ACCESS_TOKEN!,
|
|
154
|
+
});
|
|
155
|
+
|
|
156
|
+
/**
|
|
157
|
+
* Deploy a stablecoin factory contract
|
|
158
|
+
*/
|
|
159
|
+
const deployStableCoinFactory = await portalClient.request(
|
|
160
|
+
portalGraphql(`
|
|
161
|
+
mutation DeployContractStableCoinFactory($from: String!, $constructorArguments: DeployContractStableCoinFactoryInput!) {
|
|
162
|
+
DeployContractStableCoinFactory(from: $from, constructorArguments: $constructorArguments, gasLimit: "0x3d0900") {
|
|
163
|
+
transactionHash
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
`),
|
|
167
|
+
{
|
|
168
|
+
from: FROM,
|
|
169
|
+
constructorArguments: {
|
|
170
|
+
forwarder: getAddress(transaction?.receipt.contractAddress!),
|
|
171
|
+
},
|
|
172
|
+
},
|
|
173
|
+
);
|
|
174
|
+
|
|
175
|
+
console.log(deployStableCoinFactory?.DeployContractStableCoinFactory?.transactionHash);
|
|
176
|
+
|
|
177
|
+
```
|
|
178
|
+
### Send transaction using hd wallet
|
|
179
|
+
|
|
180
|
+
```ts
|
|
181
|
+
import { loadEnv } from "@settlemint/sdk-utils/environment";
|
|
182
|
+
import { createLogger, requestLogger } from "@settlemint/sdk-utils/logging";
|
|
183
|
+
import type { Address } from "viem";
|
|
184
|
+
import { createPortalClient } from "../portal.js"; // Replace this path with "@settlemint/sdk-portal"
|
|
185
|
+
import { handleWalletVerificationChallenge } from "../utils/wallet-verification-challenge.js"; // Replace this path with "@settlemint/sdk-portal"
|
|
186
|
+
import type { introspection } from "./schemas/portal-env.js"; // Replace this path with the generated introspection type
|
|
187
|
+
|
|
188
|
+
const env = await loadEnv(false, false);
|
|
189
|
+
const logger = createLogger();
|
|
190
|
+
|
|
191
|
+
const { client: portalClient, graphql: portalGraphql } = createPortalClient<{
|
|
192
|
+
introspection: introspection;
|
|
193
|
+
disableMasking: true;
|
|
194
|
+
scalars: {
|
|
195
|
+
// Change unknown to the type you are using to store metadata
|
|
196
|
+
JSON: unknown;
|
|
197
|
+
};
|
|
198
|
+
}>(
|
|
199
|
+
{
|
|
200
|
+
instance: env.SETTLEMINT_PORTAL_GRAPHQL_ENDPOINT!,
|
|
201
|
+
accessToken: env.SETTLEMINT_ACCESS_TOKEN!,
|
|
202
|
+
},
|
|
203
|
+
{
|
|
204
|
+
fetch: requestLogger(logger, "portal", fetch) as typeof fetch,
|
|
205
|
+
},
|
|
206
|
+
);
|
|
207
|
+
|
|
208
|
+
/**
|
|
209
|
+
* First create a wallet using the HD private key, this needs to be done for every user that is using your app
|
|
210
|
+
*/
|
|
211
|
+
const wallet = await portalClient.request(
|
|
212
|
+
portalGraphql(`
|
|
213
|
+
mutation createUserWallet($keyVaultId: String!, $name: String!) {
|
|
214
|
+
createWallet(keyVaultId: $keyVaultId, walletInfo: { name: $name }) {
|
|
215
|
+
address
|
|
216
|
+
}
|
|
217
|
+
}
|
|
218
|
+
`),
|
|
219
|
+
{
|
|
220
|
+
keyVaultId: env.SETTLEMINT_HD_PRIVATE_KEY!,
|
|
221
|
+
name: "My Wallet",
|
|
222
|
+
},
|
|
223
|
+
);
|
|
224
|
+
|
|
225
|
+
/**
|
|
226
|
+
* Set a pincode for the wallet, this is used to verify the wallet when the user is sending a transaction to the chain
|
|
227
|
+
*/
|
|
228
|
+
const pincodeVerification = await portalClient.request(
|
|
229
|
+
portalGraphql(`
|
|
230
|
+
mutation setPinCode($address: String!, $pincode: String!) {
|
|
231
|
+
createWalletVerification(
|
|
232
|
+
userWalletAddress: $address
|
|
233
|
+
verificationInfo: {pincode: {name: "PINCODE", pincode: $pincode}}
|
|
234
|
+
) {
|
|
235
|
+
id
|
|
236
|
+
name
|
|
237
|
+
parameters
|
|
238
|
+
verificationType
|
|
239
|
+
}
|
|
240
|
+
}
|
|
241
|
+
`),
|
|
242
|
+
{
|
|
243
|
+
address: wallet.createWallet?.address!,
|
|
244
|
+
pincode: "123456",
|
|
245
|
+
},
|
|
246
|
+
);
|
|
247
|
+
|
|
248
|
+
/**
|
|
249
|
+
* Generate a challenge response for the pincode verification
|
|
250
|
+
*/
|
|
251
|
+
const challengeResponse = await handleWalletVerificationChallenge({
|
|
252
|
+
portalClient,
|
|
253
|
+
portalGraphql,
|
|
254
|
+
verificationId: pincodeVerification.createWalletVerification?.id!,
|
|
255
|
+
userWalletAddress: wallet.createWallet?.address! as Address,
|
|
256
|
+
code: "123456",
|
|
257
|
+
verificationType: "pincode",
|
|
258
|
+
});
|
|
259
|
+
|
|
260
|
+
/**
|
|
261
|
+
* Send a transaction to the chain
|
|
262
|
+
* This is a sample of how to send a transaction to the chain using the portal client and the asset tokenization kit
|
|
263
|
+
* The challenge response is generated using the handleWalletVerificationChallenge function, this is used to verifiy wallet access
|
|
264
|
+
* @see https://github.com/settlemint/asset-tokenization-kit
|
|
265
|
+
*/
|
|
266
|
+
const result = await portalClient.request(
|
|
267
|
+
portalGraphql(`
|
|
268
|
+
mutation StableCoinFactoryCreate(
|
|
269
|
+
$challengeResponse: String!
|
|
270
|
+
$verificationId: String
|
|
271
|
+
$address: String!
|
|
272
|
+
$from: String!
|
|
273
|
+
$input: StableCoinFactoryCreateInput!
|
|
274
|
+
) {
|
|
275
|
+
StableCoinFactoryCreate(
|
|
276
|
+
challengeResponse: $challengeResponse
|
|
277
|
+
verificationId: $verificationId
|
|
278
|
+
address: $address
|
|
279
|
+
from: $from
|
|
280
|
+
input: $input
|
|
281
|
+
) {
|
|
282
|
+
transactionHash
|
|
283
|
+
}
|
|
284
|
+
}
|
|
285
|
+
`),
|
|
286
|
+
{
|
|
287
|
+
challengeResponse: challengeResponse.challengeResponse,
|
|
288
|
+
verificationId: pincodeVerification.createWalletVerification?.id!,
|
|
289
|
+
address: "0x5e771e1417100000000000000000000000000004",
|
|
290
|
+
from: wallet.createWallet?.address!,
|
|
291
|
+
input: {
|
|
292
|
+
name: "Test Coin",
|
|
293
|
+
symbol: "TEST",
|
|
294
|
+
decimals: 18,
|
|
295
|
+
collateralLivenessSeconds: 3_600,
|
|
296
|
+
},
|
|
297
|
+
},
|
|
298
|
+
);
|
|
299
|
+
|
|
300
|
+
// Log the transaction hash
|
|
301
|
+
console.log("Transaction hash:", result.StableCoinFactoryCreate?.transactionHash);
|
|
302
|
+
|
|
303
|
+
```
|
|
48
304
|
|
|
49
305
|
## API Reference
|
|
50
306
|
|
|
@@ -54,7 +310,7 @@ For detailed information about using the Smart Contract Portal Middleware, check
|
|
|
54
310
|
|
|
55
311
|
> **createPortalClient**\<`Setup`\>(`options`, `clientOptions?`): `object`
|
|
56
312
|
|
|
57
|
-
Defined in: [sdk/portal/src/portal.ts:
|
|
313
|
+
Defined in: [sdk/portal/src/portal.ts:71](https://github.com/settlemint/sdk/blob/v2.2.0/sdk/portal/src/portal.ts#L71)
|
|
58
314
|
|
|
59
315
|
Creates a Portal GraphQL client with the provided configuration.
|
|
60
316
|
|
|
@@ -82,8 +338,8 @@ An object containing the configured GraphQL client and graphql helper function
|
|
|
82
338
|
|
|
83
339
|
| Name | Type | Defined in |
|
|
84
340
|
| ------ | ------ | ------ |
|
|
85
|
-
| `client` | `GraphQLClient` | [sdk/portal/src/portal.ts:
|
|
86
|
-
| `graphql` | `initGraphQLTada`\<`Setup`\> | [sdk/portal/src/portal.ts:
|
|
341
|
+
| `client` | `GraphQLClient` | [sdk/portal/src/portal.ts:75](https://github.com/settlemint/sdk/blob/v2.2.0/sdk/portal/src/portal.ts#L75) |
|
|
342
|
+
| `graphql` | `initGraphQLTada`\<`Setup`\> | [sdk/portal/src/portal.ts:76](https://github.com/settlemint/sdk/blob/v2.2.0/sdk/portal/src/portal.ts#L76) |
|
|
87
343
|
|
|
88
344
|
##### Throws
|
|
89
345
|
|
|
@@ -92,28 +348,33 @@ If the provided options fail validation
|
|
|
92
348
|
##### Example
|
|
93
349
|
|
|
94
350
|
```ts
|
|
95
|
-
import { createPortalClient } from
|
|
351
|
+
import { createPortalClient } from "@settlemint/sdk-portal";
|
|
352
|
+
import { loadEnv } from "@settlemint/sdk-utils/environment";
|
|
353
|
+
import { createLogger, requestLogger } from "@settlemint/sdk-utils/logging";
|
|
96
354
|
import type { introspection } from "@schemas/portal-env";
|
|
97
|
-
import { createLogger, requestLogger } from '@settlemint/sdk-utils/logging';
|
|
98
355
|
|
|
356
|
+
const env = await loadEnv(false, false);
|
|
99
357
|
const logger = createLogger();
|
|
100
358
|
|
|
101
|
-
|
|
359
|
+
const { client: portalClient, graphql: portalGraphql } = createPortalClient<{
|
|
102
360
|
introspection: introspection;
|
|
103
361
|
disableMasking: true;
|
|
104
362
|
scalars: {
|
|
105
363
|
// Change unknown to the type you are using to store metadata
|
|
106
364
|
JSON: unknown;
|
|
107
365
|
};
|
|
108
|
-
}>(
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
366
|
+
}>(
|
|
367
|
+
{
|
|
368
|
+
instance: env.SETTLEMINT_PORTAL_GRAPHQL_ENDPOINT!,
|
|
369
|
+
accessToken: env.SETTLEMINT_ACCESS_TOKEN!,
|
|
370
|
+
},
|
|
371
|
+
{
|
|
372
|
+
fetch: requestLogger(logger, "portal", fetch) as typeof fetch,
|
|
373
|
+
},
|
|
374
|
+
);
|
|
114
375
|
|
|
115
376
|
// Making GraphQL queries
|
|
116
|
-
const query =
|
|
377
|
+
const query = portalGraphql(`
|
|
117
378
|
query GetPendingTransactions {
|
|
118
379
|
getPendingTransactions {
|
|
119
380
|
count
|
|
@@ -121,9 +382,115 @@ const query = graphql(`
|
|
|
121
382
|
}
|
|
122
383
|
`);
|
|
123
384
|
|
|
124
|
-
const result = await
|
|
385
|
+
const result = await portalClient.request(query);
|
|
386
|
+
```
|
|
387
|
+
|
|
388
|
+
***
|
|
389
|
+
|
|
390
|
+
#### handleWalletVerificationChallenge()
|
|
391
|
+
|
|
392
|
+
> **handleWalletVerificationChallenge**\<`Setup`\>(`options`): `Promise`\<\{ `challengeResponse`: `string`; `verificationId?`: `string`; \}\>
|
|
393
|
+
|
|
394
|
+
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)
|
|
395
|
+
|
|
396
|
+
Handles a wallet verification challenge by generating an appropriate response
|
|
397
|
+
|
|
398
|
+
##### Type Parameters
|
|
399
|
+
|
|
400
|
+
| Type Parameter |
|
|
401
|
+
| ------ |
|
|
402
|
+
| `Setup` *extends* `AbstractSetupSchema` |
|
|
403
|
+
|
|
404
|
+
##### Parameters
|
|
405
|
+
|
|
406
|
+
| Parameter | Type | Description |
|
|
407
|
+
| ------ | ------ | ------ |
|
|
408
|
+
| `options` | [`HandleWalletVerificationChallengeOptions`](#handlewalletverificationchallengeoptions)\<`Setup`\> | The options for handling the wallet verification challenge |
|
|
409
|
+
|
|
410
|
+
##### Returns
|
|
411
|
+
|
|
412
|
+
`Promise`\<\{ `challengeResponse`: `string`; `verificationId?`: `string`; \}\>
|
|
413
|
+
|
|
414
|
+
Promise resolving to an object containing the challenge response and optionally the verification ID
|
|
415
|
+
|
|
416
|
+
##### Throws
|
|
417
|
+
|
|
418
|
+
If the challenge cannot be created or is invalid
|
|
419
|
+
|
|
420
|
+
##### Example
|
|
421
|
+
|
|
422
|
+
```ts
|
|
423
|
+
import { createPortalClient } from "@settlemint/sdk-portal";
|
|
424
|
+
import { handleWalletVerificationChallenge } from "@settlemint/sdk-portal";
|
|
425
|
+
|
|
426
|
+
const { client, graphql } = createPortalClient({
|
|
427
|
+
instance: "https://portal.example.com/graphql",
|
|
428
|
+
accessToken: "your-access-token"
|
|
429
|
+
});
|
|
430
|
+
|
|
431
|
+
const result = await handleWalletVerificationChallenge({
|
|
432
|
+
portalClient: client,
|
|
433
|
+
portalGraphql: graphql,
|
|
434
|
+
verificationId: "verification-123",
|
|
435
|
+
userWalletAddress: "0x123...",
|
|
436
|
+
code: "123456",
|
|
437
|
+
verificationType: "otp"
|
|
438
|
+
});
|
|
125
439
|
```
|
|
126
440
|
|
|
441
|
+
***
|
|
442
|
+
|
|
443
|
+
#### waitForTransactionReceipt()
|
|
444
|
+
|
|
445
|
+
> **waitForTransactionReceipt**(`transactionHash`, `options`): `Promise`\<`undefined` \| [`Transaction`](#transaction)\>
|
|
446
|
+
|
|
447
|
+
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)
|
|
448
|
+
|
|
449
|
+
Wait for the transaction receipt
|
|
450
|
+
|
|
451
|
+
##### Parameters
|
|
452
|
+
|
|
453
|
+
| Parameter | Type | Description |
|
|
454
|
+
| ------ | ------ | ------ |
|
|
455
|
+
| `transactionHash` | `string` | transaction hash |
|
|
456
|
+
| `options` | [`WaitForTransactionReceiptOptions`](#waitfortransactionreceiptoptions) | options |
|
|
457
|
+
|
|
458
|
+
##### Returns
|
|
459
|
+
|
|
460
|
+
`Promise`\<`undefined` \| [`Transaction`](#transaction)\>
|
|
461
|
+
|
|
462
|
+
receipt
|
|
463
|
+
|
|
464
|
+
### Interfaces
|
|
465
|
+
|
|
466
|
+
#### HandleWalletVerificationChallengeOptions\<Setup\>
|
|
467
|
+
|
|
468
|
+
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)
|
|
469
|
+
|
|
470
|
+
Options for handling a wallet verification challenge
|
|
471
|
+
|
|
472
|
+
##### Type Parameters
|
|
473
|
+
|
|
474
|
+
| Type Parameter | Description |
|
|
475
|
+
| ------ | ------ |
|
|
476
|
+
| `Setup` *extends* `AbstractSetupSchema` | The GraphQL schema setup type |
|
|
477
|
+
|
|
478
|
+
***
|
|
479
|
+
|
|
480
|
+
#### Transaction
|
|
481
|
+
|
|
482
|
+
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)
|
|
483
|
+
|
|
484
|
+
Represents the structure of a blockchain transaction with its receipt
|
|
485
|
+
|
|
486
|
+
***
|
|
487
|
+
|
|
488
|
+
#### WaitForTransactionReceiptOptions
|
|
489
|
+
|
|
490
|
+
Defined in: [sdk/portal/src/utils/wait-for-transaction-receipt.ts:58](https://github.com/settlemint/sdk/blob/v2.2.0/sdk/portal/src/utils/wait-for-transaction-receipt.ts#L58)
|
|
491
|
+
|
|
492
|
+
Options for waiting for a transaction receipt
|
|
493
|
+
|
|
127
494
|
### Type Aliases
|
|
128
495
|
|
|
129
496
|
#### 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
|
-
|
|
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,137 @@ 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
|
+
var import_graphql_ws = require("graphql-ws");
|
|
116
|
+
async function waitForTransactionReceipt(transactionHash, options) {
|
|
117
|
+
const wsClient = (0, import_graphql_ws.createClient)({
|
|
118
|
+
url: options.portalGraphqlEndpoint.toLowerCase().replace("/graphql", `/${options.accessToken}/graphql`)
|
|
119
|
+
});
|
|
120
|
+
const subscription = wsClient.iterate({
|
|
121
|
+
query: `subscription getTransaction($transactionHash: String!) {
|
|
122
|
+
getTransaction(transactionHash: $transactionHash) {
|
|
123
|
+
receipt {
|
|
124
|
+
transactionHash
|
|
125
|
+
to
|
|
126
|
+
status
|
|
127
|
+
from
|
|
128
|
+
type
|
|
129
|
+
revertReason
|
|
130
|
+
revertReasonDecoded
|
|
131
|
+
logs
|
|
132
|
+
events
|
|
133
|
+
contractAddress
|
|
134
|
+
}
|
|
135
|
+
transactionHash
|
|
136
|
+
from
|
|
137
|
+
createdAt
|
|
138
|
+
address
|
|
139
|
+
functionName
|
|
140
|
+
isContract
|
|
141
|
+
}
|
|
142
|
+
}`,
|
|
143
|
+
variables: { transactionHash }
|
|
144
|
+
});
|
|
145
|
+
const promises = [getTransactionFromSubscription(subscription)];
|
|
146
|
+
if (options.timeout) {
|
|
147
|
+
promises.push(createTimeoutPromise(options.timeout));
|
|
148
|
+
}
|
|
149
|
+
return Promise.race(promises);
|
|
150
|
+
}
|
|
151
|
+
function createTimeoutPromise(timeout) {
|
|
152
|
+
return new Promise((_, reject) => {
|
|
153
|
+
setTimeout(() => reject(new Error("Transaction receipt not found")), timeout);
|
|
154
|
+
});
|
|
155
|
+
}
|
|
156
|
+
async function getTransactionFromSubscription(subscription) {
|
|
157
|
+
for await (const result of subscription) {
|
|
158
|
+
if (result?.data?.getTransaction?.receipt) {
|
|
159
|
+
return result.data.getTransaction;
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
throw new Error("No transaction found");
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
// src/portal.ts
|
|
33
166
|
var import_gql2 = require("gql.tada");
|
|
34
167
|
var ClientOptionsSchema = import_zod.z.object({
|
|
35
168
|
instance: import_validation.UrlOrPathSchema,
|
|
@@ -53,6 +186,8 @@ function createPortalClient(options, clientOptions) {
|
|
|
53
186
|
0 && (module.exports = {
|
|
54
187
|
ClientOptionsSchema,
|
|
55
188
|
createPortalClient,
|
|
56
|
-
|
|
189
|
+
handleWalletVerificationChallenge,
|
|
190
|
+
readFragment,
|
|
191
|
+
waitForTransactionReceipt
|
|
57
192
|
});
|
|
58
193
|
//# sourceMappingURL=portal.cjs.map
|
package/dist/portal.cjs.map
CHANGED
|
@@ -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 { 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 {\n waitForTransactionReceipt,\n type Transaction,\n type WaitForTransactionReceiptOptions,\n} 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 { type FormattedExecutionResult, 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 */\nexport interface 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 const promises = [getTransactionFromSubscription(subscription)];\n if (options.timeout) {\n promises.push(createTimeoutPromise(options.timeout));\n }\n\n return Promise.race(promises);\n}\n\nfunction createTimeoutPromise(timeout: number): Promise<never> {\n return new Promise((_, reject) => {\n setTimeout(() => reject(new Error(\"Transaction receipt not found\")), timeout);\n });\n}\n\nasync function getTransactionFromSubscription(\n subscription: AsyncIterableIterator<FormattedExecutionResult<GetTransactionResponse, unknown>>,\n): Promise<Transaction> {\n for await (const result of subscription) {\n if (result?.data?.getTransaction?.receipt) {\n return result.data.getTransaction;\n }\n }\n throw new Error(\"No transaction found\");\n}\n"],"mappings":"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","names":["import_gql"]}
|
package/dist/portal.d.cts
CHANGED
|
@@ -2,6 +2,119 @@ 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
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Options for handling a wallet verification challenge
|
|
9
|
+
*
|
|
10
|
+
* @typedef {Object} HandleWalletVerificationChallengeOptions
|
|
11
|
+
* @template {AbstractSetupSchema} Setup - The GraphQL schema setup type
|
|
12
|
+
* @property {GraphQLClient} portalClient - The portal client instance
|
|
13
|
+
* @property {initGraphQLTada<Setup>} portalGraphql - The GraphQL query builder
|
|
14
|
+
* @property {string} verificationId - The ID of the verification challenge
|
|
15
|
+
* @property {Address} userWalletAddress - The wallet address to verify
|
|
16
|
+
* @property {string | number} code - The verification code provided by the user
|
|
17
|
+
* @property {"otp" | "secret-code" | "pincode"} verificationType - The type of verification being performed
|
|
18
|
+
*/
|
|
19
|
+
interface HandleWalletVerificationChallengeOptions<Setup extends AbstractSetupSchema> {
|
|
20
|
+
portalClient: GraphQLClient;
|
|
21
|
+
portalGraphql: initGraphQLTada<Setup>;
|
|
22
|
+
verificationId: string;
|
|
23
|
+
userWalletAddress: Address;
|
|
24
|
+
code: string | number;
|
|
25
|
+
verificationType: "otp" | "secret-code" | "pincode";
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* Handles a wallet verification challenge by generating an appropriate response
|
|
29
|
+
*
|
|
30
|
+
* @param options - The options for handling the wallet verification challenge
|
|
31
|
+
* @returns Promise resolving to an object containing the challenge response and optionally the verification ID
|
|
32
|
+
* @throws {ChallengeError} If the challenge cannot be created or is invalid
|
|
33
|
+
* @example
|
|
34
|
+
* import { createPortalClient } from "@settlemint/sdk-portal";
|
|
35
|
+
* import { handleWalletVerificationChallenge } from "@settlemint/sdk-portal";
|
|
36
|
+
*
|
|
37
|
+
* const { client, graphql } = createPortalClient({
|
|
38
|
+
* instance: "https://portal.example.com/graphql",
|
|
39
|
+
* accessToken: "your-access-token"
|
|
40
|
+
* });
|
|
41
|
+
*
|
|
42
|
+
* const result = await handleWalletVerificationChallenge({
|
|
43
|
+
* portalClient: client,
|
|
44
|
+
* portalGraphql: graphql,
|
|
45
|
+
* verificationId: "verification-123",
|
|
46
|
+
* userWalletAddress: "0x123...",
|
|
47
|
+
* code: "123456",
|
|
48
|
+
* verificationType: "otp"
|
|
49
|
+
* });
|
|
50
|
+
*/
|
|
51
|
+
declare function handleWalletVerificationChallenge<const Setup extends AbstractSetupSchema>({ portalClient, portalGraphql, verificationId, userWalletAddress, code, verificationType, }: HandleWalletVerificationChallengeOptions<Setup>): Promise<{
|
|
52
|
+
challengeResponse: string;
|
|
53
|
+
verificationId?: string;
|
|
54
|
+
}>;
|
|
55
|
+
|
|
56
|
+
/**
|
|
57
|
+
* Represents the structure of a blockchain transaction with its receipt
|
|
58
|
+
*
|
|
59
|
+
* @typedef {Object} Transaction
|
|
60
|
+
* @property {Object} receipt - The transaction receipt details
|
|
61
|
+
* @property {string} receipt.transactionHash - The hash of the transaction
|
|
62
|
+
* @property {string} receipt.to - The recipient address of the transaction
|
|
63
|
+
* @property {string} receipt.status - The status of the transaction (success/failure)
|
|
64
|
+
* @property {string} receipt.from - The sender address of the transaction
|
|
65
|
+
* @property {string} receipt.type - The type of the transaction
|
|
66
|
+
* @property {string} receipt.revertReason - The reason for transaction reversion, if applicable
|
|
67
|
+
* @property {string} receipt.revertReasonDecoded - Human-readable version of the revert reason
|
|
68
|
+
* @property {string} receipt.contractAddress - The address of the contract deployed in the transaction
|
|
69
|
+
* @property {string[]} receipt.logs - Array of log entries generated by the transaction
|
|
70
|
+
* @property {string[]} receipt.events - Array of events emitted during the transaction
|
|
71
|
+
* @property {string} transactionHash - The hash of the transaction (duplicate of receipt.transactionHash)
|
|
72
|
+
* @property {string} from - The sender address (duplicate of receipt.from)
|
|
73
|
+
* @property {string} createdAt - Timestamp when the transaction was created
|
|
74
|
+
* @property {string} address - The contract address involved in the transaction
|
|
75
|
+
* @property {string} functionName - The name of the function called in the transaction
|
|
76
|
+
* @property {boolean} isContract - Whether the transaction is a contract deployment
|
|
77
|
+
*/
|
|
78
|
+
interface Transaction {
|
|
79
|
+
receipt: {
|
|
80
|
+
transactionHash: string;
|
|
81
|
+
to: string;
|
|
82
|
+
status: string;
|
|
83
|
+
from: string;
|
|
84
|
+
type: string;
|
|
85
|
+
revertReason: string;
|
|
86
|
+
revertReasonDecoded: string;
|
|
87
|
+
logs: string[];
|
|
88
|
+
events: string[];
|
|
89
|
+
contractAddress: string;
|
|
90
|
+
};
|
|
91
|
+
transactionHash: string;
|
|
92
|
+
from: string;
|
|
93
|
+
createdAt: string;
|
|
94
|
+
address: string;
|
|
95
|
+
functionName: string;
|
|
96
|
+
isContract: boolean;
|
|
97
|
+
}
|
|
98
|
+
/**
|
|
99
|
+
* Options for waiting for a transaction receipt
|
|
100
|
+
*
|
|
101
|
+
* @typedef {Object} WaitForTransactionReceiptOptions
|
|
102
|
+
* @property {string} portalGraphqlEndpoint - The GraphQL endpoint URL for the Portal API
|
|
103
|
+
* @property {string} accessToken - The access token for authentication with the Portal API
|
|
104
|
+
* @property {number} [timeout] - Optional timeout in milliseconds before the operation fails
|
|
105
|
+
*/
|
|
106
|
+
interface WaitForTransactionReceiptOptions {
|
|
107
|
+
portalGraphqlEndpoint: string;
|
|
108
|
+
accessToken: string;
|
|
109
|
+
timeout?: number;
|
|
110
|
+
}
|
|
111
|
+
/**
|
|
112
|
+
* Wait for the transaction receipt
|
|
113
|
+
* @param transactionHash transaction hash
|
|
114
|
+
* @param options options
|
|
115
|
+
* @returns receipt
|
|
116
|
+
*/
|
|
117
|
+
declare function waitForTransactionReceipt(transactionHash: string, options: WaitForTransactionReceiptOptions): Promise<Transaction>;
|
|
5
118
|
|
|
6
119
|
/**
|
|
7
120
|
* Configuration options for the GraphQL client, excluding 'url' and 'exchanges'.
|
|
@@ -36,28 +149,33 @@ type ClientOptions = z.infer<typeof ClientOptionsSchema>;
|
|
|
36
149
|
* @throws If the provided options fail validation
|
|
37
150
|
*
|
|
38
151
|
* @example
|
|
39
|
-
* import { createPortalClient } from
|
|
152
|
+
* import { createPortalClient } from "@settlemint/sdk-portal";
|
|
153
|
+
* import { loadEnv } from "@settlemint/sdk-utils/environment";
|
|
154
|
+
* import { createLogger, requestLogger } from "@settlemint/sdk-utils/logging";
|
|
40
155
|
* import type { introspection } from "@schemas/portal-env";
|
|
41
|
-
* import { createLogger, requestLogger } from '@settlemint/sdk-utils/logging';
|
|
42
156
|
*
|
|
157
|
+
* const env = await loadEnv(false, false);
|
|
43
158
|
* const logger = createLogger();
|
|
44
159
|
*
|
|
45
|
-
*
|
|
160
|
+
* const { client: portalClient, graphql: portalGraphql } = createPortalClient<{
|
|
46
161
|
* introspection: introspection;
|
|
47
162
|
* disableMasking: true;
|
|
48
163
|
* scalars: {
|
|
49
164
|
* // Change unknown to the type you are using to store metadata
|
|
50
165
|
* JSON: unknown;
|
|
51
166
|
* };
|
|
52
|
-
* }>(
|
|
53
|
-
*
|
|
54
|
-
*
|
|
55
|
-
*
|
|
56
|
-
*
|
|
57
|
-
*
|
|
167
|
+
* }>(
|
|
168
|
+
* {
|
|
169
|
+
* instance: env.SETTLEMINT_PORTAL_GRAPHQL_ENDPOINT!,
|
|
170
|
+
* accessToken: env.SETTLEMINT_ACCESS_TOKEN!,
|
|
171
|
+
* },
|
|
172
|
+
* {
|
|
173
|
+
* fetch: requestLogger(logger, "portal", fetch) as typeof fetch,
|
|
174
|
+
* },
|
|
175
|
+
* );
|
|
58
176
|
*
|
|
59
177
|
* // Making GraphQL queries
|
|
60
|
-
* const query =
|
|
178
|
+
* const query = portalGraphql(`
|
|
61
179
|
* query GetPendingTransactions {
|
|
62
180
|
* getPendingTransactions {
|
|
63
181
|
* count
|
|
@@ -65,11 +183,11 @@ type ClientOptions = z.infer<typeof ClientOptionsSchema>;
|
|
|
65
183
|
* }
|
|
66
184
|
* `);
|
|
67
185
|
*
|
|
68
|
-
* const result = await
|
|
186
|
+
* const result = await portalClient.request(query);
|
|
69
187
|
*/
|
|
70
188
|
declare function createPortalClient<const Setup extends AbstractSetupSchema>(options: ClientOptions, clientOptions?: RequestConfig): {
|
|
71
189
|
client: GraphQLClient;
|
|
72
190
|
graphql: initGraphQLTada<Setup>;
|
|
73
191
|
};
|
|
74
192
|
|
|
75
|
-
export { type ClientOptions, ClientOptionsSchema, type RequestConfig, createPortalClient };
|
|
193
|
+
export { type ClientOptions, ClientOptionsSchema, type HandleWalletVerificationChallengeOptions, type RequestConfig, type Transaction, type WaitForTransactionReceiptOptions, createPortalClient, handleWalletVerificationChallenge, waitForTransactionReceipt };
|
package/dist/portal.d.ts
CHANGED
|
@@ -2,6 +2,119 @@ 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
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Options for handling a wallet verification challenge
|
|
9
|
+
*
|
|
10
|
+
* @typedef {Object} HandleWalletVerificationChallengeOptions
|
|
11
|
+
* @template {AbstractSetupSchema} Setup - The GraphQL schema setup type
|
|
12
|
+
* @property {GraphQLClient} portalClient - The portal client instance
|
|
13
|
+
* @property {initGraphQLTada<Setup>} portalGraphql - The GraphQL query builder
|
|
14
|
+
* @property {string} verificationId - The ID of the verification challenge
|
|
15
|
+
* @property {Address} userWalletAddress - The wallet address to verify
|
|
16
|
+
* @property {string | number} code - The verification code provided by the user
|
|
17
|
+
* @property {"otp" | "secret-code" | "pincode"} verificationType - The type of verification being performed
|
|
18
|
+
*/
|
|
19
|
+
interface HandleWalletVerificationChallengeOptions<Setup extends AbstractSetupSchema> {
|
|
20
|
+
portalClient: GraphQLClient;
|
|
21
|
+
portalGraphql: initGraphQLTada<Setup>;
|
|
22
|
+
verificationId: string;
|
|
23
|
+
userWalletAddress: Address;
|
|
24
|
+
code: string | number;
|
|
25
|
+
verificationType: "otp" | "secret-code" | "pincode";
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* Handles a wallet verification challenge by generating an appropriate response
|
|
29
|
+
*
|
|
30
|
+
* @param options - The options for handling the wallet verification challenge
|
|
31
|
+
* @returns Promise resolving to an object containing the challenge response and optionally the verification ID
|
|
32
|
+
* @throws {ChallengeError} If the challenge cannot be created or is invalid
|
|
33
|
+
* @example
|
|
34
|
+
* import { createPortalClient } from "@settlemint/sdk-portal";
|
|
35
|
+
* import { handleWalletVerificationChallenge } from "@settlemint/sdk-portal";
|
|
36
|
+
*
|
|
37
|
+
* const { client, graphql } = createPortalClient({
|
|
38
|
+
* instance: "https://portal.example.com/graphql",
|
|
39
|
+
* accessToken: "your-access-token"
|
|
40
|
+
* });
|
|
41
|
+
*
|
|
42
|
+
* const result = await handleWalletVerificationChallenge({
|
|
43
|
+
* portalClient: client,
|
|
44
|
+
* portalGraphql: graphql,
|
|
45
|
+
* verificationId: "verification-123",
|
|
46
|
+
* userWalletAddress: "0x123...",
|
|
47
|
+
* code: "123456",
|
|
48
|
+
* verificationType: "otp"
|
|
49
|
+
* });
|
|
50
|
+
*/
|
|
51
|
+
declare function handleWalletVerificationChallenge<const Setup extends AbstractSetupSchema>({ portalClient, portalGraphql, verificationId, userWalletAddress, code, verificationType, }: HandleWalletVerificationChallengeOptions<Setup>): Promise<{
|
|
52
|
+
challengeResponse: string;
|
|
53
|
+
verificationId?: string;
|
|
54
|
+
}>;
|
|
55
|
+
|
|
56
|
+
/**
|
|
57
|
+
* Represents the structure of a blockchain transaction with its receipt
|
|
58
|
+
*
|
|
59
|
+
* @typedef {Object} Transaction
|
|
60
|
+
* @property {Object} receipt - The transaction receipt details
|
|
61
|
+
* @property {string} receipt.transactionHash - The hash of the transaction
|
|
62
|
+
* @property {string} receipt.to - The recipient address of the transaction
|
|
63
|
+
* @property {string} receipt.status - The status of the transaction (success/failure)
|
|
64
|
+
* @property {string} receipt.from - The sender address of the transaction
|
|
65
|
+
* @property {string} receipt.type - The type of the transaction
|
|
66
|
+
* @property {string} receipt.revertReason - The reason for transaction reversion, if applicable
|
|
67
|
+
* @property {string} receipt.revertReasonDecoded - Human-readable version of the revert reason
|
|
68
|
+
* @property {string} receipt.contractAddress - The address of the contract deployed in the transaction
|
|
69
|
+
* @property {string[]} receipt.logs - Array of log entries generated by the transaction
|
|
70
|
+
* @property {string[]} receipt.events - Array of events emitted during the transaction
|
|
71
|
+
* @property {string} transactionHash - The hash of the transaction (duplicate of receipt.transactionHash)
|
|
72
|
+
* @property {string} from - The sender address (duplicate of receipt.from)
|
|
73
|
+
* @property {string} createdAt - Timestamp when the transaction was created
|
|
74
|
+
* @property {string} address - The contract address involved in the transaction
|
|
75
|
+
* @property {string} functionName - The name of the function called in the transaction
|
|
76
|
+
* @property {boolean} isContract - Whether the transaction is a contract deployment
|
|
77
|
+
*/
|
|
78
|
+
interface Transaction {
|
|
79
|
+
receipt: {
|
|
80
|
+
transactionHash: string;
|
|
81
|
+
to: string;
|
|
82
|
+
status: string;
|
|
83
|
+
from: string;
|
|
84
|
+
type: string;
|
|
85
|
+
revertReason: string;
|
|
86
|
+
revertReasonDecoded: string;
|
|
87
|
+
logs: string[];
|
|
88
|
+
events: string[];
|
|
89
|
+
contractAddress: string;
|
|
90
|
+
};
|
|
91
|
+
transactionHash: string;
|
|
92
|
+
from: string;
|
|
93
|
+
createdAt: string;
|
|
94
|
+
address: string;
|
|
95
|
+
functionName: string;
|
|
96
|
+
isContract: boolean;
|
|
97
|
+
}
|
|
98
|
+
/**
|
|
99
|
+
* Options for waiting for a transaction receipt
|
|
100
|
+
*
|
|
101
|
+
* @typedef {Object} WaitForTransactionReceiptOptions
|
|
102
|
+
* @property {string} portalGraphqlEndpoint - The GraphQL endpoint URL for the Portal API
|
|
103
|
+
* @property {string} accessToken - The access token for authentication with the Portal API
|
|
104
|
+
* @property {number} [timeout] - Optional timeout in milliseconds before the operation fails
|
|
105
|
+
*/
|
|
106
|
+
interface WaitForTransactionReceiptOptions {
|
|
107
|
+
portalGraphqlEndpoint: string;
|
|
108
|
+
accessToken: string;
|
|
109
|
+
timeout?: number;
|
|
110
|
+
}
|
|
111
|
+
/**
|
|
112
|
+
* Wait for the transaction receipt
|
|
113
|
+
* @param transactionHash transaction hash
|
|
114
|
+
* @param options options
|
|
115
|
+
* @returns receipt
|
|
116
|
+
*/
|
|
117
|
+
declare function waitForTransactionReceipt(transactionHash: string, options: WaitForTransactionReceiptOptions): Promise<Transaction>;
|
|
5
118
|
|
|
6
119
|
/**
|
|
7
120
|
* Configuration options for the GraphQL client, excluding 'url' and 'exchanges'.
|
|
@@ -36,28 +149,33 @@ type ClientOptions = z.infer<typeof ClientOptionsSchema>;
|
|
|
36
149
|
* @throws If the provided options fail validation
|
|
37
150
|
*
|
|
38
151
|
* @example
|
|
39
|
-
* import { createPortalClient } from
|
|
152
|
+
* import { createPortalClient } from "@settlemint/sdk-portal";
|
|
153
|
+
* import { loadEnv } from "@settlemint/sdk-utils/environment";
|
|
154
|
+
* import { createLogger, requestLogger } from "@settlemint/sdk-utils/logging";
|
|
40
155
|
* import type { introspection } from "@schemas/portal-env";
|
|
41
|
-
* import { createLogger, requestLogger } from '@settlemint/sdk-utils/logging';
|
|
42
156
|
*
|
|
157
|
+
* const env = await loadEnv(false, false);
|
|
43
158
|
* const logger = createLogger();
|
|
44
159
|
*
|
|
45
|
-
*
|
|
160
|
+
* const { client: portalClient, graphql: portalGraphql } = createPortalClient<{
|
|
46
161
|
* introspection: introspection;
|
|
47
162
|
* disableMasking: true;
|
|
48
163
|
* scalars: {
|
|
49
164
|
* // Change unknown to the type you are using to store metadata
|
|
50
165
|
* JSON: unknown;
|
|
51
166
|
* };
|
|
52
|
-
* }>(
|
|
53
|
-
*
|
|
54
|
-
*
|
|
55
|
-
*
|
|
56
|
-
*
|
|
57
|
-
*
|
|
167
|
+
* }>(
|
|
168
|
+
* {
|
|
169
|
+
* instance: env.SETTLEMINT_PORTAL_GRAPHQL_ENDPOINT!,
|
|
170
|
+
* accessToken: env.SETTLEMINT_ACCESS_TOKEN!,
|
|
171
|
+
* },
|
|
172
|
+
* {
|
|
173
|
+
* fetch: requestLogger(logger, "portal", fetch) as typeof fetch,
|
|
174
|
+
* },
|
|
175
|
+
* );
|
|
58
176
|
*
|
|
59
177
|
* // Making GraphQL queries
|
|
60
|
-
* const query =
|
|
178
|
+
* const query = portalGraphql(`
|
|
61
179
|
* query GetPendingTransactions {
|
|
62
180
|
* getPendingTransactions {
|
|
63
181
|
* count
|
|
@@ -65,11 +183,11 @@ type ClientOptions = z.infer<typeof ClientOptionsSchema>;
|
|
|
65
183
|
* }
|
|
66
184
|
* `);
|
|
67
185
|
*
|
|
68
|
-
* const result = await
|
|
186
|
+
* const result = await portalClient.request(query);
|
|
69
187
|
*/
|
|
70
188
|
declare function createPortalClient<const Setup extends AbstractSetupSchema>(options: ClientOptions, clientOptions?: RequestConfig): {
|
|
71
189
|
client: GraphQLClient;
|
|
72
190
|
graphql: initGraphQLTada<Setup>;
|
|
73
191
|
};
|
|
74
192
|
|
|
75
|
-
export { type ClientOptions, ClientOptionsSchema, type RequestConfig, createPortalClient };
|
|
193
|
+
export { type ClientOptions, ClientOptionsSchema, type HandleWalletVerificationChallengeOptions, type RequestConfig, type Transaction, type WaitForTransactionReceiptOptions, createPortalClient, handleWalletVerificationChallenge, waitForTransactionReceipt };
|
package/dist/portal.mjs
CHANGED
|
@@ -4,6 +4,137 @@ 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
|
+
import { createClient } from "graphql-ws";
|
|
88
|
+
async function waitForTransactionReceipt(transactionHash, options) {
|
|
89
|
+
const wsClient = createClient({
|
|
90
|
+
url: options.portalGraphqlEndpoint.toLowerCase().replace("/graphql", `/${options.accessToken}/graphql`)
|
|
91
|
+
});
|
|
92
|
+
const subscription = wsClient.iterate({
|
|
93
|
+
query: `subscription getTransaction($transactionHash: String!) {
|
|
94
|
+
getTransaction(transactionHash: $transactionHash) {
|
|
95
|
+
receipt {
|
|
96
|
+
transactionHash
|
|
97
|
+
to
|
|
98
|
+
status
|
|
99
|
+
from
|
|
100
|
+
type
|
|
101
|
+
revertReason
|
|
102
|
+
revertReasonDecoded
|
|
103
|
+
logs
|
|
104
|
+
events
|
|
105
|
+
contractAddress
|
|
106
|
+
}
|
|
107
|
+
transactionHash
|
|
108
|
+
from
|
|
109
|
+
createdAt
|
|
110
|
+
address
|
|
111
|
+
functionName
|
|
112
|
+
isContract
|
|
113
|
+
}
|
|
114
|
+
}`,
|
|
115
|
+
variables: { transactionHash }
|
|
116
|
+
});
|
|
117
|
+
const promises = [getTransactionFromSubscription(subscription)];
|
|
118
|
+
if (options.timeout) {
|
|
119
|
+
promises.push(createTimeoutPromise(options.timeout));
|
|
120
|
+
}
|
|
121
|
+
return Promise.race(promises);
|
|
122
|
+
}
|
|
123
|
+
function createTimeoutPromise(timeout) {
|
|
124
|
+
return new Promise((_, reject) => {
|
|
125
|
+
setTimeout(() => reject(new Error("Transaction receipt not found")), timeout);
|
|
126
|
+
});
|
|
127
|
+
}
|
|
128
|
+
async function getTransactionFromSubscription(subscription) {
|
|
129
|
+
for await (const result of subscription) {
|
|
130
|
+
if (result?.data?.getTransaction?.receipt) {
|
|
131
|
+
return result.data.getTransaction;
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
throw new Error("No transaction found");
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
// src/portal.ts
|
|
7
138
|
import { readFragment } from "gql.tada";
|
|
8
139
|
var ClientOptionsSchema = z.object({
|
|
9
140
|
instance: UrlOrPathSchema,
|
|
@@ -26,6 +157,8 @@ function createPortalClient(options, clientOptions) {
|
|
|
26
157
|
export {
|
|
27
158
|
ClientOptionsSchema,
|
|
28
159
|
createPortalClient,
|
|
29
|
-
|
|
160
|
+
handleWalletVerificationChallenge,
|
|
161
|
+
readFragment,
|
|
162
|
+
waitForTransactionReceipt
|
|
30
163
|
};
|
|
31
164
|
//# sourceMappingURL=portal.mjs.map
|
package/dist/portal.mjs.map
CHANGED
|
@@ -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 { 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 {\n waitForTransactionReceipt,\n type Transaction,\n type WaitForTransactionReceiptOptions,\n} 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 { type FormattedExecutionResult, 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 */\nexport interface 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 const promises = [getTransactionFromSubscription(subscription)];\n if (options.timeout) {\n promises.push(createTimeoutPromise(options.timeout));\n }\n\n return Promise.race(promises);\n}\n\nfunction createTimeoutPromise(timeout: number): Promise<never> {\n return new Promise((_, reject) => {\n setTimeout(() => reject(new Error(\"Transaction receipt not found\")), timeout);\n });\n}\n\nasync function getTransactionFromSubscription(\n subscription: AsyncIterableIterator<FormattedExecutionResult<GetTransactionResponse, unknown>>,\n): Promise<Transaction> {\n for await (const result of subscription) {\n if (result?.data?.getTransaction?.receipt) {\n return result.data.getTransaction;\n }\n }\n throw new Error(\"No transaction found\");\n}\n"],"mappings":";AAAA,SAAS,oBAAoB;AAC7B,SAAS,8BAA8B,iBAAiB,gBAAgB;AACxE,SAAmC,uBAAuB;AAC1D,SAAS,qBAAqB;AAC9B,SAAS,SAAS;;;ACJlB,SAAS,kBAAkB;AAQpB,IAAM,iBAAN,cAA6B,MAAM;AAAA,EAC/B;AAAA,EAET,YAAY,SAAiB,MAAc;AACzC,UAAM,OAAO;AACb,SAAK,OAAO;AACZ,SAAK,OAAO;AAAA,EACd;AACF;AA4BA,SAAS,YAAY,SAAiB,MAAsB;AAC1D,SAAO,WAAW,QAAQ,EAAE,OAAO,GAAG,IAAI,GAAG,OAAO,EAAE,EAAE,OAAO,KAAK;AACtE;AASA,SAAS,iBAAiB,SAAiB,MAAc,WAA2B;AAClF,QAAM,gBAAgB,YAAY,SAAS,IAAI;AAC/C,SAAO,WAAW,QAAQ,EAAE,OAAO,GAAG,aAAa,IAAI,SAAS,EAAE,EAAE,OAAO,KAAK;AAClF;AA+CA,eAAsB,kCAA2E;AAAA,EAC/F;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,GAGG;AACD,MAAI;AACF,QAAI,qBAAqB,OAAO;AAC9B,aAAO;AAAA,QACL,mBAAmB,KAAK,SAAS;AAAA,QACjC;AAAA,MACF;AAAA,IACF;AAEA,QAAI,qBAAqB,eAAe;AAEtC,YAAM,gBAAgB,KAAK,SAAS,EAAE,QAAQ,eAAe,KAAK;AAClE,aAAO;AAAA,QACL,mBAAmB;AAAA,QACnB;AAAA,MACF;AAAA,IACF;AAEA,UAAM,yBAAyB,MAAM,aAAa;AAAA,MAChD,cAAc;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,OASb;AAAA,MACD;AAAA,QACE;AAAA,QACA;AAAA,MACF;AAAA,IACF;AAEA,QAAI,CAAC,uBAAuB,oCAAoC,QAAQ;AACtE,YAAM,IAAI,eAAe,uCAAuC,eAAe;AAAA,IACjF;AAEA,UAAM,8BAA8B,uBAAuB,mCAAmC;AAAA,MAC5F,CAAC,cAAc,UAAU,OAAO;AAAA,IAClC;AAEA,QAAI,CAAC,6BAA6B,WAAW,UAAU,CAAC,6BAA6B,WAAW,MAAM;AACpG,YAAM,IAAI,eAAe,4BAA4B,mBAAmB;AAAA,IAC1E;AAEA,UAAM,EAAE,QAAQ,KAAK,IAAI,4BAA4B;AACrD,UAAM,oBAAoB,iBAAiB,KAAK,SAAS,GAAG,MAAM,MAAM;AACxE,WAAO;AAAA,MACL;AAAA,MACA;AAAA,IACF;AAAA,EACF,SAAS,OAAO;AACd,QAAI,iBAAiB,gBAAgB;AACnC,YAAM;AAAA,IACR;AACA,UAAM,IAAI,eAAe,mDAAmD,4BAA4B;AAAA,EAC1G;AACF;;;AC9KA,SAAwC,oBAAoB;AAqE5D,eAAsB,0BAA0B,iBAAyB,SAA2C;AAClH,QAAM,WAAW,aAAa;AAAA,IAC5B,KAAK,QAAQ,sBAAsB,YAAY,EAAE,QAAQ,YAAY,IAAI,QAAQ,WAAW,UAAU;AAAA,EACxG,CAAC;AACD,QAAM,eAAe,SAAS,QAAgC;AAAA,IAC5D,OAAO;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,IAsBP,WAAW,EAAE,gBAAgB;AAAA,EAC/B,CAAC;AACD,QAAM,WAAW,CAAC,+BAA+B,YAAY,CAAC;AAC9D,MAAI,QAAQ,SAAS;AACnB,aAAS,KAAK,qBAAqB,QAAQ,OAAO,CAAC;AAAA,EACrD;AAEA,SAAO,QAAQ,KAAK,QAAQ;AAC9B;AAEA,SAAS,qBAAqB,SAAiC;AAC7D,SAAO,IAAI,QAAQ,CAAC,GAAG,WAAW;AAChC,eAAW,MAAM,OAAO,IAAI,MAAM,+BAA+B,CAAC,GAAG,OAAO;AAAA,EAC9E,CAAC;AACH;AAEA,eAAe,+BACb,cACsB;AACtB,mBAAiB,UAAU,cAAc;AACvC,QAAI,QAAQ,MAAM,gBAAgB,SAAS;AACzC,aAAO,OAAO,KAAK;AAAA,IACrB;AAAA,EACF;AACA,QAAM,IAAI,MAAM,sBAAsB;AACxC;;;AFrBA,SAAS,oBAAoB;AAtFtB,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;AAoDM,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":[]}
|
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-pr72a2ad5d",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"private": false,
|
|
7
7
|
"license": "FSL-1.1-MIT",
|
|
@@ -47,12 +47,16 @@
|
|
|
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
|
-
"devDependencies": {
|
|
53
|
+
"devDependencies": {
|
|
54
|
+
"viem": "^2"
|
|
55
|
+
},
|
|
53
56
|
"dependencies": {
|
|
54
57
|
"gql.tada": "^1",
|
|
55
|
-
"
|
|
58
|
+
"graphql-ws": "^6",
|
|
59
|
+
"@settlemint/sdk-utils": "2.2.0-pr72a2ad5d",
|
|
56
60
|
"graphql-request": "^7",
|
|
57
61
|
"zod": "^3"
|
|
58
62
|
},
|