@quicknode/sdk 1.0.0 → 1.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +2 -0
- package/cjs/index.js +314 -1
- package/esm/package.json +2 -1
- package/esm/package.json.js +3 -0
- package/esm/src/api/api.js +85 -0
- package/esm/src/api/controllers/contracts.js +36 -0
- package/esm/src/api/controllers/events.js +121 -0
- package/esm/src/api/controllers/nfts.js +244 -0
- package/esm/src/api/controllers/tokens.js +98 -0
- package/esm/src/api/controllers/transactions.js +125 -0
- package/esm/src/api/controllers/utils.js +55 -0
- package/esm/src/api/graphql/customUrqlClient.js +23 -0
- package/esm/{index.js → src/api/graphql/generatedTypes.js} +1 -1099
- package/esm/src/api/graphql/schema.json.js +3 -0
- package/esm/src/api/index.d.ts +2687 -0
- package/esm/src/api/index.js +2 -0
- package/esm/src/api/types/chains.js +7 -0
- package/esm/src/api/types/contracts/getContractDetails.js +12 -0
- package/esm/src/api/types/events/getAll.js +7 -0
- package/esm/src/api/types/events/getByContract.js +12 -0
- package/esm/src/api/types/nfts/getByContractAddress.js +10 -0
- package/esm/src/api/types/nfts/getByWalletAddress.js +18 -0
- package/esm/src/api/types/nfts/getCollectionDetails.js +11 -0
- package/esm/src/api/types/nfts/getCollectionEvents.js +12 -0
- package/esm/src/api/types/nfts/getNFTDetails.js +9 -0
- package/esm/src/api/types/nfts/getNFTEvents.js +13 -0
- package/esm/src/api/types/nfts/getTrendingCollections.js +7 -0
- package/esm/src/api/types/nfts/verifyOwnershipByAddress.js +12 -0
- package/esm/src/api/types/tokens/getBalancesByWalletAddress.js +12 -0
- package/esm/src/api/types/transactions/getByHash.js +11 -0
- package/esm/src/api/types/transactions/getBySearch.js +7 -0
- package/esm/src/api/types/utils/gasPrices.js +12 -0
- package/esm/src/api/utils/constants.js +3 -0
- package/esm/src/api/utils/helpers.js +11 -0
- package/esm/src/api/utils/isValidENSAddress.js +21 -0
- package/esm/src/api/utils/postQueryFormatter.js +24 -0
- package/esm/src/api/utils/removeNodesAndEdges.js +51 -0
- package/esm/src/client/client.js +9 -0
- package/esm/src/client/index.js +2 -0
- package/esm/src/core/addOns/nftTokenV2/actions.js +107 -0
- package/esm/src/core/addOns/nftTokenV2/types/qn_fetchNFTCollectionDetails.js +10 -0
- package/esm/src/core/addOns/nftTokenV2/types/qn_fetchNFTs.js +13 -0
- package/esm/src/core/addOns/nftTokenV2/types/qn_fetchNFTsByCollection.js +13 -0
- package/esm/src/core/addOns/nftTokenV2/types/qn_getTokenMetadataByContractAddress.js +10 -0
- package/esm/src/core/addOns/nftTokenV2/types/qn_getTokenMetadataBySymbol.js +11 -0
- package/esm/src/core/addOns/nftTokenV2/types/qn_getTransactionsByAddress.js +18 -0
- package/esm/src/core/addOns/nftTokenV2/types/qn_getTransfersByNFT.js +12 -0
- package/esm/src/core/addOns/nftTokenV2/types/qn_getWalletTokenBalance.js +12 -0
- package/esm/src/core/addOns/nftTokenV2/types/qn_getWalletTokenTransactions.js +14 -0
- package/esm/src/core/addOns/nftTokenV2/types/qn_verifyNFTsOwner.js +11 -0
- package/esm/src/core/addOns/shared/helpers.js +10 -0
- package/esm/src/core/chains.js +60 -0
- package/esm/src/core/core.js +24 -0
- package/esm/src/core/index.d.ts +555 -0
- package/esm/src/core/index.js +2 -0
- package/esm/src/index.js +10 -0
- package/esm/src/lib/errors/QNChainNotSupported.js +7 -0
- package/esm/src/lib/errors/QNInputValidationError.js +10 -0
- package/esm/src/lib/errors/QNInvalidEnpointUrl.js +7 -0
- package/esm/src/lib/helpers/globalFetch.js +13 -0
- package/esm/src/lib/validation/ValidateInput.js +35 -0
- package/esm/src/lib/validation/codegenDerivedValidators.js +28 -0
- package/esm/src/lib/validation/validators.js +105 -0
- package/index.d.ts +560 -1
- package/package.json +25 -3
package/README.md
CHANGED
|
@@ -50,6 +50,8 @@ Full example app implementation [here](https://github.com/quiknode-labs/qn-oss/t
|
|
|
50
50
|
|
|
51
51
|
Please see [the official QuickNode SDK documentation](https://www.quicknode.com/docs/quicknode-sdk/getting-started) for the full documentation of SDK functions.
|
|
52
52
|
|
|
53
|
+
<br>
|
|
54
|
+
|
|
53
55
|
## Contributing corner
|
|
54
56
|
|
|
55
57
|
### Issues
|
package/cjs/index.js
CHANGED
|
@@ -7,10 +7,31 @@ var core = require('@urql/core');
|
|
|
7
7
|
var exchangeGraphcache = require('@urql/exchange-graphcache');
|
|
8
8
|
var tslib = require('tslib');
|
|
9
9
|
var zod = require('zod');
|
|
10
|
+
var viem = require('viem');
|
|
11
|
+
var chains = require('viem/chains');
|
|
10
12
|
|
|
11
13
|
function _interopDefaultLegacy (e) { return e && typeof e === 'object' && 'default' in e ? e : { 'default': e }; }
|
|
12
14
|
|
|
15
|
+
function _interopNamespace(e) {
|
|
16
|
+
if (e && e.__esModule) return e;
|
|
17
|
+
var n = Object.create(null);
|
|
18
|
+
if (e) {
|
|
19
|
+
Object.keys(e).forEach(function (k) {
|
|
20
|
+
if (k !== 'default') {
|
|
21
|
+
var d = Object.getOwnPropertyDescriptor(e, k);
|
|
22
|
+
Object.defineProperty(n, k, d.get ? d : {
|
|
23
|
+
enumerable: true,
|
|
24
|
+
get: function () { return e[k]; }
|
|
25
|
+
});
|
|
26
|
+
}
|
|
27
|
+
});
|
|
28
|
+
}
|
|
29
|
+
n["default"] = e;
|
|
30
|
+
return Object.freeze(n);
|
|
31
|
+
}
|
|
32
|
+
|
|
13
33
|
var fetch__default = /*#__PURE__*/_interopDefaultLegacy(fetch);
|
|
34
|
+
var viem__namespace = /*#__PURE__*/_interopNamespace(viem);
|
|
14
35
|
|
|
15
36
|
function isConnection(object) {
|
|
16
37
|
return (typeof object === 'object' &&
|
|
@@ -225,6 +246,12 @@ const contractTokensFilter = zod.z
|
|
|
225
246
|
})
|
|
226
247
|
.strict())
|
|
227
248
|
.nonempty();
|
|
249
|
+
const rpcPaginationParams = zod.z
|
|
250
|
+
.object({
|
|
251
|
+
perPage: zod.z.number().positive().nullish(),
|
|
252
|
+
page: zod.z.number().positive().nullish(),
|
|
253
|
+
})
|
|
254
|
+
.strict();
|
|
228
255
|
|
|
229
256
|
const walletByAddressValidator = zod.z
|
|
230
257
|
.object({
|
|
@@ -375,6 +402,18 @@ class QNInputValidationError extends Error {
|
|
|
375
402
|
}
|
|
376
403
|
}
|
|
377
404
|
|
|
405
|
+
class QNInvalidEndpointUrl extends Error {
|
|
406
|
+
constructor() {
|
|
407
|
+
super('Endpoint URL is not in a valid QuickNode URL format. Please check the URL and try again');
|
|
408
|
+
}
|
|
409
|
+
}
|
|
410
|
+
|
|
411
|
+
class QNChainNotSupported extends Error {
|
|
412
|
+
constructor(endpointUrl) {
|
|
413
|
+
super(`The chain for endpoint URL ${endpointUrl} is not currently supported by the QuickNode SDK.`);
|
|
414
|
+
}
|
|
415
|
+
}
|
|
416
|
+
|
|
378
417
|
function formatErrors(baseError) {
|
|
379
418
|
const errorMessages = [];
|
|
380
419
|
baseError.errors.forEach((error) => {
|
|
@@ -1088,7 +1127,7 @@ tslib.__decorate([
|
|
|
1088
1127
|
tslib.__metadata("design:returntype", Promise)
|
|
1089
1128
|
], TransactionsController.prototype, "getByHash", null);
|
|
1090
1129
|
|
|
1091
|
-
var name="@quicknode/sdk";var repository={type:"git",url:"https://github.com/quiknode-labs/qn-oss.git",directory:"packages/libs/sdk"};var license="MIT";var version="1.
|
|
1130
|
+
var name="@quicknode/sdk";var repository={type:"git",url:"https://github.com/quiknode-labs/qn-oss.git",directory:"packages/libs/sdk"};var license="MIT";var version="1.1.0";var main="./cjs/index.js";var module$1="./esm/src/index.js";var types="./index.d.ts";var sideEffects=false;var dependencies={"@urql/core":"^4.0.7","@urql/exchange-graphcache":"^6.0.4","cross-fetch":"^3.1.6",viem:"^1.2.0",tslib:"^2.5.3",zod:"^3.21.4"};var devDependencies={"@graphql-codegen/cli":"4.0.1","@graphql-codegen/fragment-matcher":"^3.3.1","@graphql-codegen/introspection":"^3.0.1","@graphql-codegen/typed-document-node":"^4.0.1","@graphql-codegen/typescript":"2.8.0","@graphql-codegen/typescript-operations":"^2.5.5","@pollyjs/adapter-node-http":"^6.0.5","@pollyjs/core":"^6.0.5","@pollyjs/persister-fs":"^6.0.5","@types/jest":"^29.5.1","@types/mocha":"^10.0.1","@types/node":"^18.13.0","@types/supertest":"^2.0.12",dotenv:"^16.0.3","eslint-plugin-no-only-tests":"^3.1.0",graphql:"^16.6.0",supertest:"^6.3.3"};var scripts={codegen:"npx graphql-codegen --require dotenv/config"};var exports$1={".":{"import":"./esm/src/index.js",require:"./cjs/index.js"},"./api":{"import":"./esm/src/api/index.js","default":"./cjs/src/api/index.js",types:"./esm/src/api/index.d.ts"},"./core":{"import":"./esm/src/core/index.js","default":"./cjs/src/core/index.js",types:"./esm/src/core/index.d.ts"}};var typesVersions={"*":{api:["./esm/src/api/index.d.ts"],core:["./esm/src/core/index.d.ts"]}};var packageJson = {name:name,repository:repository,license:license,version:version,main:main,module:module$1,types:types,sideEffects:sideEffects,dependencies:dependencies,devDependencies:devDependencies,scripts:scripts,exports:exports$1,typesVersions:typesVersions};
|
|
1092
1131
|
|
|
1093
1132
|
class API {
|
|
1094
1133
|
constructor({ graphApiKey, additionalHeaders, defaultChain, } = {}) {
|
|
@@ -1160,14 +1199,288 @@ class API {
|
|
|
1160
1199
|
}
|
|
1161
1200
|
}
|
|
1162
1201
|
|
|
1202
|
+
// We can't dynamically extend the viem client based on which add-ons are specified, which would
|
|
1203
|
+
// make the types fully align with the add-ons for the client, so instead we do run-time checks to
|
|
1204
|
+
// prevent calling add-ons not explicitly added in the config
|
|
1205
|
+
function checkAddOnEnabled(enabled, humanName, configName) {
|
|
1206
|
+
if (!enabled) {
|
|
1207
|
+
throw new Error(`${humanName} is not set as enabled. Please ensure the addon is enabled on your QuickNode endpoint and enable ${configName} in the Core configuration argument`);
|
|
1208
|
+
}
|
|
1209
|
+
}
|
|
1210
|
+
|
|
1211
|
+
const qnFetchNFTInputSchema = zod.z
|
|
1212
|
+
.object({
|
|
1213
|
+
wallet: isEvmAddress,
|
|
1214
|
+
contracts: zod.z.array(isEvmAddress).nullish(),
|
|
1215
|
+
omitFields: zod.z.array(zod.z.string()).nullish(),
|
|
1216
|
+
})
|
|
1217
|
+
.merge(rpcPaginationParams)
|
|
1218
|
+
.strict();
|
|
1219
|
+
|
|
1220
|
+
const qnFetchNFTCollectionDetailsInputSchema = zod.z
|
|
1221
|
+
.object({
|
|
1222
|
+
contracts: zod.z.array(isEvmAddress),
|
|
1223
|
+
})
|
|
1224
|
+
.strict();
|
|
1225
|
+
|
|
1226
|
+
const qnFetchNFTsByCollectionInputSchema = zod.z
|
|
1227
|
+
.object({
|
|
1228
|
+
collection: isEvmAddress,
|
|
1229
|
+
tokens: zod.z.array(zod.z.string()).nullish(),
|
|
1230
|
+
omitFields: zod.z.array(zod.z.string()).nullish(),
|
|
1231
|
+
})
|
|
1232
|
+
.merge(rpcPaginationParams)
|
|
1233
|
+
.strict();
|
|
1234
|
+
|
|
1235
|
+
const qnGetTransfersByNFTInputSchema = zod.z
|
|
1236
|
+
.object({
|
|
1237
|
+
collection: isEvmAddress,
|
|
1238
|
+
collectionTokenId: zod.z.string(),
|
|
1239
|
+
})
|
|
1240
|
+
.merge(rpcPaginationParams)
|
|
1241
|
+
.strict();
|
|
1242
|
+
|
|
1243
|
+
const qnVerifyNFTsOwnerInputSchema = zod.z
|
|
1244
|
+
.object({
|
|
1245
|
+
wallet: isEvmAddress,
|
|
1246
|
+
contracts: zod.z.array(zod.z.string()), // TODO: make this enforce the address:id format
|
|
1247
|
+
})
|
|
1248
|
+
.strict();
|
|
1249
|
+
|
|
1250
|
+
const qnGetTokenMetadataByCAInputSchema = zod.z
|
|
1251
|
+
.object({
|
|
1252
|
+
contract: isEvmAddress,
|
|
1253
|
+
})
|
|
1254
|
+
.strict();
|
|
1255
|
+
|
|
1256
|
+
const qnGetTokenMetadataBySymbolInputSchema = zod.z
|
|
1257
|
+
.object({
|
|
1258
|
+
symbol: zod.z.string(),
|
|
1259
|
+
})
|
|
1260
|
+
.merge(rpcPaginationParams)
|
|
1261
|
+
.strict();
|
|
1262
|
+
|
|
1263
|
+
const qnGetTransactionsByAddressInputSchema = zod.z
|
|
1264
|
+
.object({
|
|
1265
|
+
address: isEvmAddress,
|
|
1266
|
+
fromBlock: zod.z.number().positive().nullish(),
|
|
1267
|
+
toBlock: zod.z.number().positive().nullish(),
|
|
1268
|
+
})
|
|
1269
|
+
.merge(rpcPaginationParams)
|
|
1270
|
+
.strict()
|
|
1271
|
+
.refine(({ fromBlock, toBlock }) => {
|
|
1272
|
+
if (fromBlock && toBlock)
|
|
1273
|
+
return fromBlock < toBlock;
|
|
1274
|
+
return true;
|
|
1275
|
+
}, { message: 'fromBlock must be less than toBlock' });
|
|
1276
|
+
|
|
1277
|
+
const qnGetWalletTokenBalanceInputSchema = zod.z
|
|
1278
|
+
.object({
|
|
1279
|
+
wallet: isEvmAddress,
|
|
1280
|
+
contracts: zod.z.array(isEvmAddress).nullish(),
|
|
1281
|
+
})
|
|
1282
|
+
.merge(rpcPaginationParams)
|
|
1283
|
+
.strict();
|
|
1284
|
+
|
|
1285
|
+
const qnGetWalletTokenTransactionsInputSchema = zod.z
|
|
1286
|
+
.object({
|
|
1287
|
+
address: isEvmAddress,
|
|
1288
|
+
contract: isEvmAddress,
|
|
1289
|
+
fromBlock: zod.z.number().positive().nullish(),
|
|
1290
|
+
toBlock: zod.z.number().positive().nullish(),
|
|
1291
|
+
})
|
|
1292
|
+
.merge(rpcPaginationParams)
|
|
1293
|
+
.strict();
|
|
1294
|
+
|
|
1295
|
+
function nftAndTokenValidator(config, schema, args) {
|
|
1296
|
+
checkAddOnEnabled(config.addOns?.nftTokenV2 ?? false, 'NFT And Token RPC API V2', 'nftTokenV2');
|
|
1297
|
+
// Uses zod to validate schema at runtime
|
|
1298
|
+
const validation = schema.safeParse(args);
|
|
1299
|
+
if (!validation.success) {
|
|
1300
|
+
const formattedErrors = formatErrors(validation.error);
|
|
1301
|
+
if (formattedErrors)
|
|
1302
|
+
throw formattedErrors;
|
|
1303
|
+
}
|
|
1304
|
+
}
|
|
1305
|
+
const nftAndTokenActions = (client, config) => ({
|
|
1306
|
+
async qn_fetchNFTCollectionDetails(args) {
|
|
1307
|
+
nftAndTokenValidator(config, qnFetchNFTCollectionDetailsInputSchema, args);
|
|
1308
|
+
const response = await client.request({
|
|
1309
|
+
method: 'qn_fetchNFTCollectionDetails',
|
|
1310
|
+
params: [args],
|
|
1311
|
+
});
|
|
1312
|
+
return response;
|
|
1313
|
+
},
|
|
1314
|
+
async qn_fetchNFTs(args) {
|
|
1315
|
+
nftAndTokenValidator(config, qnFetchNFTInputSchema, args);
|
|
1316
|
+
const response = await client.request({
|
|
1317
|
+
method: 'qn_fetchNFTs',
|
|
1318
|
+
params: [args],
|
|
1319
|
+
});
|
|
1320
|
+
return response;
|
|
1321
|
+
},
|
|
1322
|
+
async qn_fetchNFTsByCollection(args) {
|
|
1323
|
+
nftAndTokenValidator(config, qnFetchNFTsByCollectionInputSchema, args);
|
|
1324
|
+
const response = await client.request({
|
|
1325
|
+
method: 'qn_fetchNFTsByCollection',
|
|
1326
|
+
params: [args],
|
|
1327
|
+
});
|
|
1328
|
+
return response;
|
|
1329
|
+
},
|
|
1330
|
+
async qn_getTransfersByNFT(args) {
|
|
1331
|
+
nftAndTokenValidator(config, qnGetTransfersByNFTInputSchema, args);
|
|
1332
|
+
const response = await client.request({
|
|
1333
|
+
method: 'qn_getTransfersByNFT',
|
|
1334
|
+
params: [args],
|
|
1335
|
+
});
|
|
1336
|
+
return response;
|
|
1337
|
+
},
|
|
1338
|
+
async qn_verifyNFTsOwner(args) {
|
|
1339
|
+
nftAndTokenValidator(config, qnVerifyNFTsOwnerInputSchema, args);
|
|
1340
|
+
const response = await client.request({
|
|
1341
|
+
method: 'qn_verifyNFTsOwner',
|
|
1342
|
+
params: [args],
|
|
1343
|
+
});
|
|
1344
|
+
return response;
|
|
1345
|
+
},
|
|
1346
|
+
async qn_getTokenMetadataByContractAddress(args) {
|
|
1347
|
+
nftAndTokenValidator(config, qnGetTokenMetadataByCAInputSchema, args);
|
|
1348
|
+
const response = await client.request({
|
|
1349
|
+
method: 'qn_getTokenMetadataByContractAddress',
|
|
1350
|
+
params: [args],
|
|
1351
|
+
});
|
|
1352
|
+
return response;
|
|
1353
|
+
},
|
|
1354
|
+
async qn_getTokenMetadataBySymbol(args) {
|
|
1355
|
+
nftAndTokenValidator(config, qnGetTokenMetadataBySymbolInputSchema, args);
|
|
1356
|
+
const response = await client.request({
|
|
1357
|
+
method: 'qn_getTokenMetadataBySymbol',
|
|
1358
|
+
params: [args],
|
|
1359
|
+
});
|
|
1360
|
+
return response;
|
|
1361
|
+
},
|
|
1362
|
+
async qn_getTransactionsByAddress(args) {
|
|
1363
|
+
nftAndTokenValidator(config, qnGetTransactionsByAddressInputSchema, args);
|
|
1364
|
+
const response = await client.request({
|
|
1365
|
+
method: 'qn_getTransactionsByAddress',
|
|
1366
|
+
params: [args],
|
|
1367
|
+
});
|
|
1368
|
+
return response;
|
|
1369
|
+
},
|
|
1370
|
+
async qn_getWalletTokenBalance(args) {
|
|
1371
|
+
nftAndTokenValidator(config, qnGetWalletTokenBalanceInputSchema, args);
|
|
1372
|
+
const response = await client.request({
|
|
1373
|
+
method: 'qn_getWalletTokenBalance',
|
|
1374
|
+
params: [args],
|
|
1375
|
+
});
|
|
1376
|
+
return response;
|
|
1377
|
+
},
|
|
1378
|
+
async qn_getWalletTokenTransactions(args) {
|
|
1379
|
+
nftAndTokenValidator(config, qnGetWalletTokenTransactionsInputSchema, args);
|
|
1380
|
+
const response = await client.request({
|
|
1381
|
+
method: 'qn_getWalletTokenTransactions',
|
|
1382
|
+
params: [args],
|
|
1383
|
+
});
|
|
1384
|
+
return response;
|
|
1385
|
+
},
|
|
1386
|
+
});
|
|
1387
|
+
|
|
1388
|
+
const ETH_MAINNET_NETWORK = 'ethereum-mainnet';
|
|
1389
|
+
const qnChainToViemChain = {
|
|
1390
|
+
'arbitrum-mainnet': chains.arbitrum,
|
|
1391
|
+
'arbitrum-goerli': chains.arbitrumGoerli,
|
|
1392
|
+
'avalanche-mainnet': chains.avalanche,
|
|
1393
|
+
'avalanche-testnet': chains.avalancheFuji,
|
|
1394
|
+
'base-goerli': chains.baseGoerli,
|
|
1395
|
+
['bsc']: chains.bsc,
|
|
1396
|
+
'bsc-testnet': chains.bscTestnet,
|
|
1397
|
+
'celo-mainnet': chains.celo,
|
|
1398
|
+
['fantom']: chains.fantom,
|
|
1399
|
+
['xdai']: chains.gnosis,
|
|
1400
|
+
['gnosis']: chains.gnosis,
|
|
1401
|
+
'ethereum-goerli': chains.goerli,
|
|
1402
|
+
'harmony-mainnet': chains.harmonyOne,
|
|
1403
|
+
[ETH_MAINNET_NETWORK]: chains.mainnet,
|
|
1404
|
+
['optimism']: chains.optimism,
|
|
1405
|
+
'optimism-goerli': chains.optimismGoerli,
|
|
1406
|
+
['matic']: chains.polygon,
|
|
1407
|
+
['polygon']: chains.polygon,
|
|
1408
|
+
'matic-testnet': chains.polygonMumbai,
|
|
1409
|
+
'zkevm-mainnet': chains.polygonZkEvm,
|
|
1410
|
+
'zkevm-testnet': chains.polygonZkEvmTestnet,
|
|
1411
|
+
'ethereum-sepolia': chains.sepolia,
|
|
1412
|
+
};
|
|
1413
|
+
function chainNameFromEndpoint(endpointUrl) {
|
|
1414
|
+
let hostnameParts;
|
|
1415
|
+
try {
|
|
1416
|
+
const parsedUrl = new URL(endpointUrl);
|
|
1417
|
+
hostnameParts = parsedUrl.hostname.split('.');
|
|
1418
|
+
}
|
|
1419
|
+
catch (e) {
|
|
1420
|
+
throw new QNInvalidEndpointUrl();
|
|
1421
|
+
}
|
|
1422
|
+
const quiknode = hostnameParts.at(-2);
|
|
1423
|
+
const chainOrDiscover = hostnameParts.at(-3);
|
|
1424
|
+
if (quiknode !== 'quiknode' || !chainOrDiscover)
|
|
1425
|
+
throw new QNInvalidEndpointUrl();
|
|
1426
|
+
const indexOfName = chainOrDiscover === 'discover' ? -4 : -3;
|
|
1427
|
+
const lengthOfEthereum = chainOrDiscover === 'discover' ? 4 : 3;
|
|
1428
|
+
if (hostnameParts.length === lengthOfEthereum)
|
|
1429
|
+
return ETH_MAINNET_NETWORK;
|
|
1430
|
+
const potentialChainName = hostnameParts.at(indexOfName);
|
|
1431
|
+
if (potentialChainName)
|
|
1432
|
+
return potentialChainName;
|
|
1433
|
+
throw new QNInvalidEndpointUrl();
|
|
1434
|
+
}
|
|
1435
|
+
function deriveChainFromUrl(endpointUrl) {
|
|
1436
|
+
const chainName = chainNameFromEndpoint(endpointUrl);
|
|
1437
|
+
const viemChain = qnChainToViemChain[chainName];
|
|
1438
|
+
if (viemChain)
|
|
1439
|
+
return viemChain;
|
|
1440
|
+
throw new QNChainNotSupported(endpointUrl);
|
|
1441
|
+
}
|
|
1442
|
+
|
|
1443
|
+
function setupGlobalFetch() {
|
|
1444
|
+
// Required for viem to work in node
|
|
1445
|
+
if (!globalThis.fetch) {
|
|
1446
|
+
globalThis.fetch = fetch__default["default"];
|
|
1447
|
+
globalThis.Headers = fetch.Headers;
|
|
1448
|
+
globalThis.Request = fetch.Request;
|
|
1449
|
+
globalThis.Response = fetch.Response;
|
|
1450
|
+
}
|
|
1451
|
+
}
|
|
1452
|
+
|
|
1453
|
+
const buildQNActions = (config) => {
|
|
1454
|
+
return (client) => ({
|
|
1455
|
+
...nftAndTokenActions(client, config),
|
|
1456
|
+
});
|
|
1457
|
+
};
|
|
1458
|
+
class Core {
|
|
1459
|
+
constructor({ endpointUrl, chain, config = {} }) {
|
|
1460
|
+
setupGlobalFetch();
|
|
1461
|
+
this.endpointUrl = endpointUrl;
|
|
1462
|
+
const baseClient = viem.createClient({
|
|
1463
|
+
chain: chain || deriveChainFromUrl(endpointUrl),
|
|
1464
|
+
transport: viem.http(this.endpointUrl),
|
|
1465
|
+
}).extend(viem.publicActions);
|
|
1466
|
+
const qnClient = baseClient.extend(buildQNActions(config));
|
|
1467
|
+
this.client = qnClient;
|
|
1468
|
+
}
|
|
1469
|
+
}
|
|
1470
|
+
|
|
1163
1471
|
const QuickNode = {
|
|
1164
1472
|
API: API,
|
|
1473
|
+
Core: Core,
|
|
1165
1474
|
};
|
|
1166
1475
|
|
|
1167
1476
|
Object.defineProperty(exports, 'gql', {
|
|
1168
1477
|
enumerable: true,
|
|
1169
1478
|
get: function () { return core.gql; }
|
|
1170
1479
|
});
|
|
1480
|
+
exports.viem = viem__namespace;
|
|
1171
1481
|
exports.API = API;
|
|
1482
|
+
exports.Core = Core;
|
|
1483
|
+
exports.QNChainNotSupported = QNChainNotSupported;
|
|
1172
1484
|
exports.QNInputValidationError = QNInputValidationError;
|
|
1485
|
+
exports.QNInvalidEndpointUrl = QNInvalidEndpointUrl;
|
|
1173
1486
|
exports["default"] = QuickNode;
|
package/esm/package.json
CHANGED
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
var name="@quicknode/sdk";var repository={type:"git",url:"https://github.com/quiknode-labs/qn-oss.git",directory:"packages/libs/sdk"};var license="MIT";var version="1.1.0";var main="./cjs/index.js";var module="./esm/src/index.js";var types="./index.d.ts";var sideEffects=false;var dependencies={"@urql/core":"^4.0.7","@urql/exchange-graphcache":"^6.0.4","cross-fetch":"^3.1.6",viem:"^1.2.0",tslib:"^2.5.3",zod:"^3.21.4"};var devDependencies={"@graphql-codegen/cli":"4.0.1","@graphql-codegen/fragment-matcher":"^3.3.1","@graphql-codegen/introspection":"^3.0.1","@graphql-codegen/typed-document-node":"^4.0.1","@graphql-codegen/typescript":"2.8.0","@graphql-codegen/typescript-operations":"^2.5.5","@pollyjs/adapter-node-http":"^6.0.5","@pollyjs/core":"^6.0.5","@pollyjs/persister-fs":"^6.0.5","@types/jest":"^29.5.1","@types/mocha":"^10.0.1","@types/node":"^18.13.0","@types/supertest":"^2.0.12",dotenv:"^16.0.3","eslint-plugin-no-only-tests":"^3.1.0",graphql:"^16.6.0",supertest:"^6.3.3"};var scripts={codegen:"npx graphql-codegen --require dotenv/config"};var exports={".":{"import":"./esm/src/index.js",require:"./cjs/index.js"},"./api":{"import":"./esm/src/api/index.js","default":"./cjs/src/api/index.js",types:"./esm/src/api/index.d.ts"},"./core":{"import":"./esm/src/core/index.js","default":"./cjs/src/core/index.js",types:"./esm/src/core/index.d.ts"}};var typesVersions={"*":{api:["./esm/src/api/index.d.ts"],core:["./esm/src/core/index.d.ts"]}};var packageJson = {name:name,repository:repository,license:license,version:version,main:main,module:module,types:types,sideEffects:sideEffects,dependencies:dependencies,devDependencies:devDependencies,scripts:scripts,exports:exports,typesVersions:typesVersions};
|
|
2
|
+
|
|
3
|
+
export { packageJson as default, dependencies, devDependencies, exports, license, main, module, name, repository, scripts, sideEffects, types, typesVersions, version };
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
import fetch from 'cross-fetch';
|
|
2
|
+
import { CustomUrqlClient } from './graphql/customUrqlClient.js';
|
|
3
|
+
import { Client, fetchExchange } from '@urql/core';
|
|
4
|
+
import { cacheExchange } from '@urql/exchange-graphcache';
|
|
5
|
+
import { NftsController } from './controllers/nfts.js';
|
|
6
|
+
import { TokensController } from './controllers/tokens.js';
|
|
7
|
+
import { UtilsController } from './controllers/utils.js';
|
|
8
|
+
import { ContractsController } from './controllers/contracts.js';
|
|
9
|
+
import { EventsController } from './controllers/events.js';
|
|
10
|
+
import { DEFAULT_CHAIN } from './utils/constants.js';
|
|
11
|
+
import schema from './graphql/schema.json.js';
|
|
12
|
+
import { TransactionsController } from './controllers/transactions.js';
|
|
13
|
+
import packageJson from '../../package.json.js';
|
|
14
|
+
|
|
15
|
+
class API {
|
|
16
|
+
constructor({ graphApiKey, additionalHeaders, defaultChain, } = {}) {
|
|
17
|
+
if (!graphApiKey) {
|
|
18
|
+
console.warn('QuickNode SDK warning: no apiKey provided. Access with no apiKey is heavily rate limited and intended for development use only. For higher rate limits or production usage, create an account on https://www.quicknode.com/');
|
|
19
|
+
}
|
|
20
|
+
this.graphApiKey = graphApiKey;
|
|
21
|
+
this.additionalHeaders = additionalHeaders;
|
|
22
|
+
this.urqlClient = this.createUrqlClient();
|
|
23
|
+
this.customUrqlClient = new CustomUrqlClient(this.urqlClient);
|
|
24
|
+
this.defaultChain = defaultChain || DEFAULT_CHAIN;
|
|
25
|
+
this.nfts = new NftsController(this.customUrqlClient, this.defaultChain);
|
|
26
|
+
this.tokens = new TokensController(this.customUrqlClient, this.defaultChain);
|
|
27
|
+
this.utils = new UtilsController(this.customUrqlClient, this.defaultChain);
|
|
28
|
+
this.contracts = new ContractsController(this.customUrqlClient, this.defaultChain);
|
|
29
|
+
this.transactions = new TransactionsController(this.customUrqlClient, this.defaultChain);
|
|
30
|
+
this.events = new EventsController(this.customUrqlClient, this.defaultChain);
|
|
31
|
+
// Re-export the Urql client configured to use the Graph API for use with custom queries
|
|
32
|
+
this.graphApiClient = this.urqlClient;
|
|
33
|
+
}
|
|
34
|
+
createUrqlClient() {
|
|
35
|
+
const headers = { ...this.additionalHeaders };
|
|
36
|
+
if (this.graphApiKey)
|
|
37
|
+
headers['x-api-key'] = this.graphApiKey;
|
|
38
|
+
headers['x-quicknode-sdk'] = 'js-sdk';
|
|
39
|
+
headers['x-quicknode-sdk-version'] = packageJson?.version || 'n/a';
|
|
40
|
+
const useNftKey = (data) => `${data['contractAddress']}:${data['tokenId']}`;
|
|
41
|
+
const useAddressAsKey = (data) => `${data['address']}`;
|
|
42
|
+
const useTransactionHashAndIndex = (data) => `${data['transactionHash']}:${data['transferIndex']}`;
|
|
43
|
+
const urqlCache = cacheExchange({
|
|
44
|
+
schema,
|
|
45
|
+
keys: {
|
|
46
|
+
EVMSchemaType: () => null,
|
|
47
|
+
Collection: useAddressAsKey,
|
|
48
|
+
CollectionOHLCVChart: () => null,
|
|
49
|
+
Contract: useAddressAsKey,
|
|
50
|
+
ERC721NFT: useNftKey,
|
|
51
|
+
ERC721Collection: useAddressAsKey,
|
|
52
|
+
ERC1155NFT: useNftKey,
|
|
53
|
+
ERC1155Collection: useAddressAsKey,
|
|
54
|
+
GasPrice: () => null,
|
|
55
|
+
NFT: useNftKey,
|
|
56
|
+
NFTContract: useAddressAsKey,
|
|
57
|
+
TokenAttribute: () => null,
|
|
58
|
+
TokenContract: useAddressAsKey,
|
|
59
|
+
TokenEvent: useTransactionHashAndIndex,
|
|
60
|
+
TokenMintEvent: useTransactionHashAndIndex,
|
|
61
|
+
TokenBurnEvent: useTransactionHashAndIndex,
|
|
62
|
+
TokenSaleEvent: useTransactionHashAndIndex,
|
|
63
|
+
TokenSwapEvent: useTransactionHashAndIndex,
|
|
64
|
+
TokenTransferEvent: useTransactionHashAndIndex,
|
|
65
|
+
TokenUpload: () => null,
|
|
66
|
+
OpenSeaMetadata: () => null,
|
|
67
|
+
Transaction: (data) => `${data['hash']}`,
|
|
68
|
+
TrendingCollection: () => null,
|
|
69
|
+
Wallet: (data) => `${data['address']}`,
|
|
70
|
+
WalletNFT: () => null,
|
|
71
|
+
WalletTokenBalance: () => null,
|
|
72
|
+
},
|
|
73
|
+
});
|
|
74
|
+
const client = new Client({
|
|
75
|
+
fetch,
|
|
76
|
+
url: process.env['NX_GRAPHQL_API_URI'] ||
|
|
77
|
+
'https://api.quicknode.com/graphql',
|
|
78
|
+
exchanges: [urqlCache, fetchExchange],
|
|
79
|
+
fetchOptions: () => ({ headers }),
|
|
80
|
+
});
|
|
81
|
+
return client;
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
export { API };
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import { __decorate, __metadata } from 'tslib';
|
|
2
|
+
import { DEFAULT_CHAIN } from '../utils/constants.js';
|
|
3
|
+
import { contractDetailsValidator } from '../types/contracts/getContractDetails.js';
|
|
4
|
+
import { CodegenEthMainnetContractDetailsDocument, CodegenPolygonMainnetContractDetailsDocument, CodegenEthSepoliaContractDetailsDocument } from '../graphql/generatedTypes.js';
|
|
5
|
+
import { ValidateInput } from '../../lib/validation/ValidateInput.js';
|
|
6
|
+
|
|
7
|
+
class ContractsController {
|
|
8
|
+
constructor(client, defaultChain = DEFAULT_CHAIN) {
|
|
9
|
+
this.client = client;
|
|
10
|
+
this.defaultChain = defaultChain;
|
|
11
|
+
}
|
|
12
|
+
async getDetails(variables) {
|
|
13
|
+
const { chain, ...queryVariables } = variables;
|
|
14
|
+
const userChain = chain || this.defaultChain;
|
|
15
|
+
const query = {
|
|
16
|
+
ethereum: CodegenEthMainnetContractDetailsDocument,
|
|
17
|
+
polygon: CodegenPolygonMainnetContractDetailsDocument,
|
|
18
|
+
ethereumSepolia: CodegenEthSepoliaContractDetailsDocument,
|
|
19
|
+
};
|
|
20
|
+
const { data: { [userChain]: { contract }, }, } = await this.client.query({
|
|
21
|
+
variables: queryVariables,
|
|
22
|
+
query: query[userChain],
|
|
23
|
+
});
|
|
24
|
+
if (contract)
|
|
25
|
+
return { contract };
|
|
26
|
+
return { contract: null };
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
__decorate([
|
|
30
|
+
ValidateInput(contractDetailsValidator),
|
|
31
|
+
__metadata("design:type", Function),
|
|
32
|
+
__metadata("design:paramtypes", [Object]),
|
|
33
|
+
__metadata("design:returntype", Promise)
|
|
34
|
+
], ContractsController.prototype, "getDetails", null);
|
|
35
|
+
|
|
36
|
+
export { ContractsController };
|
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
import { __decorate, __metadata } from 'tslib';
|
|
2
|
+
import { contractEventsValidator } from '../types/events/getByContract.js';
|
|
3
|
+
import { collectionEventsValidator } from '../types/nfts/getCollectionEvents.js';
|
|
4
|
+
import { nftEventsValidator } from '../types/nfts/getNFTEvents.js';
|
|
5
|
+
import { allEventsValidator } from '../types/events/getAll.js';
|
|
6
|
+
import { CodegenEthereumMainnetEventsByContractDocument, CodegenPolygonMainnetEventsByContractDocument, CodegenEthereumSepoliaEventsByContractDocument, CodegenEthMainnetEventsByCollectionDocument, CodegenPolygonMainnetEventsByCollectionDocument, CodegenEthSepoliaEventsByCollectionDocument, CodegenEthereumMainnetEventsByNftDocument, CodegenPolygonMainnetEventsByNftDocument, CodegenEthSepoliaEventsByNftDocument, CodegenEthereumMainnetEventsGetAllDocument, CodegenPolygonMainnetEventsGetAllDocument, CodegenEthereumSepoliaEventsGetAllDocument } from '../graphql/generatedTypes.js';
|
|
7
|
+
import { formatQueryResult } from '../utils/postQueryFormatter.js';
|
|
8
|
+
import { emptyPageInfo } from '../utils/helpers.js';
|
|
9
|
+
import { DEFAULT_CHAIN } from '../utils/constants.js';
|
|
10
|
+
import { ValidateInput } from '../../lib/validation/ValidateInput.js';
|
|
11
|
+
|
|
12
|
+
class EventsController {
|
|
13
|
+
constructor(client, defaultChain = DEFAULT_CHAIN) {
|
|
14
|
+
this.client = client;
|
|
15
|
+
this.defaultChain = defaultChain;
|
|
16
|
+
}
|
|
17
|
+
async getByContract(variables) {
|
|
18
|
+
const { chain, ...queryVariables } = variables;
|
|
19
|
+
const userChain = chain || this.defaultChain;
|
|
20
|
+
const query = {
|
|
21
|
+
ethereum: CodegenEthereumMainnetEventsByContractDocument,
|
|
22
|
+
polygon: CodegenPolygonMainnetEventsByContractDocument,
|
|
23
|
+
ethereumSepolia: CodegenEthereumSepoliaEventsByContractDocument,
|
|
24
|
+
};
|
|
25
|
+
const { data: { [userChain]: { contract }, }, } = await this.client.query({
|
|
26
|
+
query: query[userChain],
|
|
27
|
+
variables: queryVariables,
|
|
28
|
+
});
|
|
29
|
+
if (!contract?.tokenEvents?.length) {
|
|
30
|
+
return {
|
|
31
|
+
results: [],
|
|
32
|
+
pageInfo: emptyPageInfo,
|
|
33
|
+
};
|
|
34
|
+
}
|
|
35
|
+
const formattedResult = formatQueryResult(contract, 'tokenEvents', 'tokenEventsPageInfo');
|
|
36
|
+
return formattedResult;
|
|
37
|
+
}
|
|
38
|
+
async getByNFTCollection(variables) {
|
|
39
|
+
const { chain, ...queryVariables } = variables;
|
|
40
|
+
const userChain = chain || this.defaultChain;
|
|
41
|
+
const query = {
|
|
42
|
+
ethereum: CodegenEthMainnetEventsByCollectionDocument,
|
|
43
|
+
polygon: CodegenPolygonMainnetEventsByCollectionDocument,
|
|
44
|
+
ethereumSepolia: CodegenEthSepoliaEventsByCollectionDocument,
|
|
45
|
+
};
|
|
46
|
+
const { data: { [userChain]: { collection }, }, } = await this.client.query({
|
|
47
|
+
query: query[userChain],
|
|
48
|
+
variables: queryVariables,
|
|
49
|
+
});
|
|
50
|
+
if (!collection?.tokenEvents?.length)
|
|
51
|
+
return { results: [], pageInfo: emptyPageInfo };
|
|
52
|
+
function removeKeyFields(results) {
|
|
53
|
+
const { address, ...newResults } = results;
|
|
54
|
+
return newResults;
|
|
55
|
+
}
|
|
56
|
+
const formattedResult = formatQueryResult(collection, 'tokenEvents', 'tokenEventsPageInfo', null, removeKeyFields);
|
|
57
|
+
return formattedResult;
|
|
58
|
+
}
|
|
59
|
+
async getByNFT(variables) {
|
|
60
|
+
const { chain, ...queryVariables } = variables;
|
|
61
|
+
const userChain = chain || this.defaultChain;
|
|
62
|
+
const query = {
|
|
63
|
+
ethereum: CodegenEthereumMainnetEventsByNftDocument,
|
|
64
|
+
polygon: CodegenPolygonMainnetEventsByNftDocument,
|
|
65
|
+
ethereumSepolia: CodegenEthSepoliaEventsByNftDocument,
|
|
66
|
+
};
|
|
67
|
+
const { data: { [userChain]: { nft }, }, } = await this.client.query({
|
|
68
|
+
query: query[userChain],
|
|
69
|
+
variables: queryVariables,
|
|
70
|
+
});
|
|
71
|
+
if (!nft?.tokenEvents?.length)
|
|
72
|
+
return { results: [], pageInfo: emptyPageInfo };
|
|
73
|
+
function removeKeyFields(results) {
|
|
74
|
+
const { contractAddress, tokenId, ...newResults } = results;
|
|
75
|
+
return newResults;
|
|
76
|
+
}
|
|
77
|
+
const formattedResult = formatQueryResult(nft, 'tokenEvents', 'tokenEventsPageInfo', null, removeKeyFields);
|
|
78
|
+
return formattedResult;
|
|
79
|
+
}
|
|
80
|
+
async getAll(variables) {
|
|
81
|
+
const { chain, ...queryVariables } = variables;
|
|
82
|
+
const userChain = chain || this.defaultChain;
|
|
83
|
+
const query = {
|
|
84
|
+
ethereum: CodegenEthereumMainnetEventsGetAllDocument,
|
|
85
|
+
polygon: CodegenPolygonMainnetEventsGetAllDocument,
|
|
86
|
+
ethereumSepolia: CodegenEthereumSepoliaEventsGetAllDocument,
|
|
87
|
+
};
|
|
88
|
+
const { data: { [userChain]: tokenEvents }, } = await this.client.query({
|
|
89
|
+
query: query[userChain],
|
|
90
|
+
variables: queryVariables,
|
|
91
|
+
});
|
|
92
|
+
const formattedResult = formatQueryResult(tokenEvents, 'tokenEvents', 'tokenEventsPageInfo');
|
|
93
|
+
return formattedResult;
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
__decorate([
|
|
97
|
+
ValidateInput(contractEventsValidator),
|
|
98
|
+
__metadata("design:type", Function),
|
|
99
|
+
__metadata("design:paramtypes", [Object]),
|
|
100
|
+
__metadata("design:returntype", Promise)
|
|
101
|
+
], EventsController.prototype, "getByContract", null);
|
|
102
|
+
__decorate([
|
|
103
|
+
ValidateInput(collectionEventsValidator),
|
|
104
|
+
__metadata("design:type", Function),
|
|
105
|
+
__metadata("design:paramtypes", [Object]),
|
|
106
|
+
__metadata("design:returntype", Promise)
|
|
107
|
+
], EventsController.prototype, "getByNFTCollection", null);
|
|
108
|
+
__decorate([
|
|
109
|
+
ValidateInput(nftEventsValidator),
|
|
110
|
+
__metadata("design:type", Function),
|
|
111
|
+
__metadata("design:paramtypes", [Object]),
|
|
112
|
+
__metadata("design:returntype", Promise)
|
|
113
|
+
], EventsController.prototype, "getByNFT", null);
|
|
114
|
+
__decorate([
|
|
115
|
+
ValidateInput(allEventsValidator),
|
|
116
|
+
__metadata("design:type", Function),
|
|
117
|
+
__metadata("design:paramtypes", [Object]),
|
|
118
|
+
__metadata("design:returntype", Promise)
|
|
119
|
+
], EventsController.prototype, "getAll", null);
|
|
120
|
+
|
|
121
|
+
export { EventsController };
|