@imtbl/sdk 1.36.0 → 1.36.1-alpha

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.
Files changed (40) hide show
  1. package/dist/blockchain_data.js +2 -2
  2. package/dist/browser/checkout/{BridgeWidget-d624b1bd.js → BridgeWidget-235efe43.js} +1 -1
  3. package/dist/browser/checkout/{OnRampWidget-5abd1f62.js → OnRampWidget-3a89c146.js} +1 -1
  4. package/dist/browser/checkout/SaleWidget-4399a54a.js +1 -0
  5. package/dist/browser/checkout/{SpendingCapHero-22d5c9bb.js → SpendingCapHero-df8963ac.js} +1 -1
  6. package/dist/browser/checkout/{SwapWidget-f40f5b60.js → SwapWidget-a85e6e03.js} +1 -1
  7. package/dist/browser/checkout/{TopUpView-eb812fbe.js → TopUpView-f21628fb.js} +1 -1
  8. package/dist/browser/checkout/{WalletWidget-de3edac3.js → WalletWidget-987f1522.js} +1 -1
  9. package/dist/browser/checkout/{auto-track-382bdef3.js → auto-track-5ee23448.js} +1 -1
  10. package/dist/browser/checkout/{balance-7cbf0236.js → balance-7239bbb5.js} +1 -1
  11. package/dist/browser/checkout/{index-704af722.js → index-04bf2dbb.js} +1 -1
  12. package/dist/browser/checkout/index-0a7c3cbc.js +1 -0
  13. package/dist/browser/checkout/{index-df7e23e2.js → index-3a392928.js} +2 -2
  14. package/dist/browser/checkout/{index-c73df3b2.js → index-62c1f6d9.js} +1 -1
  15. package/dist/browser/checkout/{index-ba76afc7.js → index-82a2edf5.js} +1 -1
  16. package/dist/browser/checkout/{index-8bbe4eda.js → index-8645c324.js} +1 -1
  17. package/dist/browser/checkout/{index-bdae58ab.js → index-a0f1ffb1.js} +1 -1
  18. package/dist/browser/checkout/{index-04ed13fb.js → index-be41adcd.js} +1 -1
  19. package/dist/browser/checkout/{index.umd-669adf6e.js → index.umd-6032c84f.js} +1 -1
  20. package/dist/browser/checkout/{retry-746773e8.js → retry-ce7d1cfd.js} +1 -1
  21. package/dist/browser/checkout/sdk.js +4 -4
  22. package/dist/browser/checkout/widgets-esm.js +1 -1
  23. package/dist/browser/checkout/widgets.js +1 -1
  24. package/dist/checkout.js +4 -4
  25. package/dist/config.js +1 -1
  26. package/dist/index.browser.js +4 -4
  27. package/dist/index.browser.js.map +1 -1
  28. package/dist/index.cjs +608 -15
  29. package/dist/index.d.ts +139 -7
  30. package/dist/index.js +607 -16
  31. package/dist/minting_backend.d.ts +3528 -0
  32. package/dist/minting_backend.js +6596 -0
  33. package/dist/orderbook.js +1 -1
  34. package/dist/passport.js +4 -4
  35. package/dist/webhook.d.ts +11 -0
  36. package/dist/webhook.js +388 -0
  37. package/dist/x.js +3 -3
  38. package/package.json +9 -1
  39. package/dist/browser/checkout/SaleWidget-9e937008.js +0 -1
  40. package/dist/browser/checkout/index-96adfa1b.js +0 -1
package/dist/index.js CHANGED
@@ -33,6 +33,7 @@ import { keccak256 as keccak256$3 } from '@ethersproject/solidity';
33
33
  import { SwapRouter, PaymentsExtended } from '@uniswap/router-sdk';
34
34
  import { parseUnits as parseUnits$1 } from '@ethersproject/units';
35
35
  import { BigNumber as BigNumber$2 } from '@ethersproject/bignumber';
36
+ import MessageValidator from 'sns-validator';
36
37
 
37
38
  const isNode$1 = () => typeof window === 'undefined';
38
39
  const isBrowser$1 = () => !isNode$1();
@@ -160,7 +161,7 @@ const flattenProperties$1 = (properties) => {
160
161
  };
161
162
 
162
163
  // WARNING: DO NOT CHANGE THE STRING BELOW. IT GETS REPLACED AT BUILD TIME.
163
- const SDK_VERSION$1 = '1.36.0';
164
+ const SDK_VERSION$1 = '1.36.1-alpha';
164
165
  const getFrameParentDomain$1 = () => {
165
166
  if (isNode$1()) {
166
167
  return '';
@@ -14187,7 +14188,7 @@ class MultiRollupApiClients {
14187
14188
  }
14188
14189
 
14189
14190
  // eslint-disable-next-line @typescript-eslint/naming-convention
14190
- const defaultHeaders$2 = { 'x-sdk-version': 'ts-immutable-sdk-1.36.0' };
14191
+ const defaultHeaders$2 = { 'x-sdk-version': 'ts-immutable-sdk-1.36.1-alpha' };
14191
14192
  const createConfig$1 = ({ basePath, headers, }) => {
14192
14193
  if (!basePath.trim()) {
14193
14194
  throw Error('basePath can not be empty');
@@ -14259,7 +14260,7 @@ class APIError extends Error {
14259
14260
 
14260
14261
  /* eslint-disable implicit-arrow-linebreak */
14261
14262
  const defaultHeaders$1 = {
14262
- sdkVersion: 'ts-immutable-sdk-multi-rollup-api-client-1.36.0',
14263
+ sdkVersion: 'ts-immutable-sdk-multi-rollup-api-client-1.36.1-alpha',
14263
14264
  };
14264
14265
  /**
14265
14266
  * createAPIConfiguration to create a custom Configuration
@@ -14733,7 +14734,7 @@ var blockchain_data = /*#__PURE__*/Object.freeze({
14733
14734
  /* eslint-disable @typescript-eslint/naming-convention */
14734
14735
  class ApiConfiguration extends index$2.Configuration {
14735
14736
  }
14736
- const defaultHeaders = { 'x-sdk-version': 'ts-immutable-sdk-1.36.0' };
14737
+ const defaultHeaders = { 'x-sdk-version': 'ts-immutable-sdk-1.36.1-alpha' };
14737
14738
  /**
14738
14739
  * @dev use createImmutableXConfiguration instead
14739
14740
  */
@@ -14772,7 +14773,7 @@ const createImmutableXConfiguration = ({ basePath, chainID, coreContractAddress,
14772
14773
  chainID,
14773
14774
  coreContractAddress,
14774
14775
  registrationContractAddress,
14775
- sdkVersion: 'ts-immutable-sdk-1.36.0',
14776
+ sdkVersion: 'ts-immutable-sdk-1.36.1-alpha',
14776
14777
  baseConfig,
14777
14778
  });
14778
14779
  const production = ({ baseConfig }) => createImmutableXConfiguration({
@@ -23594,12 +23595,12 @@ function assertOptions$1(options, schema, allowUnknown) {
23594
23595
  }
23595
23596
  }
23596
23597
 
23597
- var validator$1 = {
23598
+ var validator$2 = {
23598
23599
  assertOptions: assertOptions$1,
23599
23600
  validators: validators$1$1
23600
23601
  };
23601
23602
 
23602
- const validators$2 = validator$1.validators;
23603
+ const validators$2 = validator$2.validators;
23603
23604
 
23604
23605
  /**
23605
23606
  * Create a new instance of Axios
@@ -23640,7 +23641,7 @@ let Axios$2 = class Axios {
23640
23641
  const {transitional, paramsSerializer, headers} = config;
23641
23642
 
23642
23643
  if (transitional !== undefined) {
23643
- validator$1.assertOptions(transitional, {
23644
+ validator$2.assertOptions(transitional, {
23644
23645
  silentJSONParsing: validators$2.transitional(validators$2.boolean),
23645
23646
  forcedJSONParsing: validators$2.transitional(validators$2.boolean),
23646
23647
  clarifyTimeoutError: validators$2.transitional(validators$2.boolean)
@@ -23653,7 +23654,7 @@ let Axios$2 = class Axios {
23653
23654
  serialize: paramsSerializer
23654
23655
  };
23655
23656
  } else {
23656
- validator$1.assertOptions(paramsSerializer, {
23657
+ validator$2.assertOptions(paramsSerializer, {
23657
23658
  encode: validators$2.function,
23658
23659
  serialize: validators$2.function
23659
23660
  }, true);
@@ -32332,12 +32333,12 @@ function assertOptions(options, schema, allowUnknown) {
32332
32333
  }
32333
32334
  }
32334
32335
 
32335
- var validator = {
32336
+ var validator$1 = {
32336
32337
  assertOptions,
32337
32338
  validators: validators$1
32338
32339
  };
32339
32340
 
32340
- const validators = validator.validators;
32341
+ const validators = validator$1.validators;
32341
32342
 
32342
32343
  /**
32343
32344
  * Create a new instance of Axios
@@ -32378,7 +32379,7 @@ class Axios {
32378
32379
  const {transitional, paramsSerializer, headers} = config;
32379
32380
 
32380
32381
  if (transitional !== undefined) {
32381
- validator.assertOptions(transitional, {
32382
+ validator$1.assertOptions(transitional, {
32382
32383
  silentJSONParsing: validators.transitional(validators.boolean),
32383
32384
  forcedJSONParsing: validators.transitional(validators.boolean),
32384
32385
  clarifyTimeoutError: validators.transitional(validators.boolean)
@@ -32391,7 +32392,7 @@ class Axios {
32391
32392
  serialize: paramsSerializer
32392
32393
  };
32393
32394
  } else {
32394
- validator.assertOptions(paramsSerializer, {
32395
+ validator$1.assertOptions(paramsSerializer, {
32395
32396
  encode: validators.function,
32396
32397
  serialize: validators.function
32397
32398
  }, true);
@@ -58133,7 +58134,7 @@ const flattenProperties = (properties) => {
58133
58134
  };
58134
58135
 
58135
58136
  // WARNING: DO NOT CHANGE THE STRING BELOW. IT GETS REPLACED AT BUILD TIME.
58136
- const SDK_VERSION = '1.36.0';
58137
+ const SDK_VERSION = '1.36.1-alpha';
58137
58138
  const getFrameParentDomain = () => {
58138
58139
  if (isNode()) {
58139
58140
  return '';
@@ -63426,7 +63427,7 @@ const IMMUTABLE_ZKVEM_GAS_OVERRIDES = {
63426
63427
  maxPriorityFeePerGas: BigNumber$1.from(10e9),
63427
63428
  };
63428
63429
 
63429
- const SDK_VERSION_MARKER = '1.36.0';
63430
+ const SDK_VERSION_MARKER = '1.36.1-alpha';
63430
63431
  // This SDK version is replaced by the `yarn build` command ran on the root level
63431
63432
  const globalPackageVersion = () => SDK_VERSION_MARKER;
63432
63433
 
@@ -69092,4 +69093,594 @@ var x = /*#__PURE__*/Object.freeze({
69092
69093
  sandbox: sandbox
69093
69094
  });
69094
69095
 
69095
- export { blockchain_data as blockchainData, checkout, config, orderbook, passport, x };
69096
+ const validator = new MessageValidator();
69097
+ const allowedTopicArnPrefix = {
69098
+ [Environment$1.PRODUCTION]: 'arn:aws:sns:us-east-2:362750628221:',
69099
+ [Environment$1.SANDBOX]: 'arn:aws:sns:us-east-2:783421985614:'
69100
+ };
69101
+ const init = async (body, env, handlers) => {
69102
+ const msg = await new Promise((resolve, reject) => {
69103
+ validator.validate(body, (err, message) => {
69104
+ if (err) {
69105
+ return reject(err);
69106
+ }
69107
+ // check for topic arn prefix
69108
+ if (!message.TopicArn.startsWith(allowedTopicArnPrefix[env])) {
69109
+ throw new Error('Invalid topic arn');
69110
+ }
69111
+ if (message?.Type === 'SubscriptionConfirmation') {
69112
+ fetch(message.SubscribeURL).then(() => {
69113
+ resolve(message);
69114
+ }).catch((e) => {
69115
+ reject(e);
69116
+ });
69117
+ }
69118
+ return resolve(message);
69119
+ });
69120
+ });
69121
+ if (msg.Type === 'Notification') {
69122
+ const event = JSON.parse(msg.Message);
69123
+ switch (event.event_name) {
69124
+ case 'imtbl_zkevm_mint_request_updated':
69125
+ await handlers.zkevmMintRequestUpdated(event);
69126
+ break;
69127
+ default:
69128
+ if (handlers.others) {
69129
+ await handlers.others(event);
69130
+ }
69131
+ break;
69132
+ }
69133
+ }
69134
+ };
69135
+
69136
+ var webhook = /*#__PURE__*/Object.freeze({
69137
+ __proto__: null,
69138
+ init: init
69139
+ });
69140
+
69141
+ const moduleName = 'minting_backend_sdk';
69142
+ const trackInitializePersistencePG = () => {
69143
+ try {
69144
+ track(moduleName, 'initializePersistencePG');
69145
+ }
69146
+ catch {
69147
+ // ignore
69148
+ }
69149
+ };
69150
+ const trackInitializePersistencePrismaSqlite = () => {
69151
+ try {
69152
+ track(moduleName, 'initializePersistencePrismaSqlite');
69153
+ }
69154
+ catch {
69155
+ // ignore
69156
+ }
69157
+ };
69158
+ const trackSubmitMintingRequests = () => {
69159
+ try {
69160
+ track(moduleName, 'submitMintingRequests');
69161
+ }
69162
+ catch {
69163
+ // ignore
69164
+ }
69165
+ };
69166
+ const trackProcessMint = () => {
69167
+ try {
69168
+ track(moduleName, 'processMint');
69169
+ }
69170
+ catch {
69171
+ // ignore
69172
+ }
69173
+ };
69174
+ const trackRecordMint = () => {
69175
+ try {
69176
+ track(moduleName, 'recordMint');
69177
+ }
69178
+ catch {
69179
+ // ignore
69180
+ }
69181
+ };
69182
+
69183
+ const mintingPersistence$1 = (client) => {
69184
+ trackInitializePersistencePG();
69185
+ return {
69186
+ recordMint: async (request) => {
69187
+ const r = await client.query(`
69188
+ INSERT INTO im_assets (asset_id, contract_address, owner_address, metadata)
69189
+ VALUES ($1, $2, $3, $4) ON CONFLICT (asset_id, contract_address) DO NOTHING;
69190
+ `, [request.asset_id, request.contract_address, request.owner_address, request.metadata]);
69191
+ if (r.rowCount === 0) {
69192
+ throw new Error('Duplicated mint');
69193
+ }
69194
+ },
69195
+ getNextBatchForSubmission: async (limit) => {
69196
+ const res = await client.query(`
69197
+ UPDATE im_assets SET minting_status = 'submitting' WHERE minting_status IS NULL and id in (
69198
+ select id from im_assets where minting_status is null limit $1 for update skip locked
69199
+ ) returning *;
69200
+ `, [limit]);
69201
+ return res.rows;
69202
+ },
69203
+ updateMintingStatusToSubmitted: async (ids) => {
69204
+ await client.query(`
69205
+ UPDATE im_assets SET minting_status = $2 WHERE id = ANY($1);
69206
+ `, [ids, 'submitted']);
69207
+ },
69208
+ syncMintingStatus: async (submittedMintRequest) => {
69209
+ // doing a upsert just in case the row has not been created yet
69210
+ await client.query(`
69211
+ INSERT INTO im_assets (
69212
+ asset_id,
69213
+ contract_address,
69214
+ owner_address,
69215
+ token_id,
69216
+ minting_status,
69217
+ metadata_id,
69218
+ last_imtbl_zkevm_mint_request_updated_id,
69219
+ error
69220
+ ) VALUES ($1, $2, $3, $4, $5, $6, $7, $8) ON CONFLICT (asset_id, contract_address)
69221
+ DO UPDATE SET
69222
+ owner_address = $3,
69223
+ token_id = $4,
69224
+ minting_status = $5,
69225
+ metadata_id = $6,
69226
+ last_imtbl_zkevm_mint_request_updated_id = $7,
69227
+ error = $8
69228
+ where (
69229
+ im_assets.last_imtbl_zkevm_mint_request_updated_id < $7 OR
69230
+ im_assets.last_imtbl_zkevm_mint_request_updated_id is null
69231
+ );
69232
+ `, [
69233
+ submittedMintRequest.assetId,
69234
+ submittedMintRequest.contractAddress,
69235
+ submittedMintRequest.ownerAddress,
69236
+ submittedMintRequest.tokenId,
69237
+ submittedMintRequest.status,
69238
+ submittedMintRequest.metadataId,
69239
+ submittedMintRequest.imtblZkevmMintRequestUpdatedId,
69240
+ submittedMintRequest.error
69241
+ ]);
69242
+ },
69243
+ markAsConflict: async (assetIds, contractAddress) => {
69244
+ await client.query(`
69245
+ UPDATE im_assets
69246
+ SET minting_status = 'conflicting'
69247
+ WHERE asset_id = ANY($1)
69248
+ AND contract_address = $2;
69249
+ `, [assetIds, contractAddress]);
69250
+ },
69251
+ resetMintingStatus: async (ids) => {
69252
+ await client.query(`
69253
+ UPDATE im_assets SET minting_status = null WHERE id = ANY($1);
69254
+ `, [ids]);
69255
+ },
69256
+ markForRetry: async (ids) => {
69257
+ await client.query(`
69258
+ UPDATE im_assets
69259
+ SET minting_status = null, tried_count = tried_count + 1 WHERE id = ANY($1);
69260
+ `, [ids]);
69261
+ },
69262
+ updateMintingStatusToSubmissionFailed: async (ids) => {
69263
+ await client.query(`
69264
+ UPDATE im_assets SET minting_status = 'submission_failed' WHERE id = ANY($1);
69265
+ `, [ids]);
69266
+ },
69267
+ getMintingRequest: async (contractAddress, referenceId) => {
69268
+ const res = await client.query(`
69269
+ SELECT * FROM im_assets WHERE contract_address = $1 and asset_id = $2;
69270
+ `, [contractAddress, referenceId]);
69271
+ return res.rows[0] || null;
69272
+ }
69273
+ };
69274
+ };
69275
+
69276
+ /* eslint-disable no-await-in-loop */
69277
+ /* eslint-disable @typescript-eslint/naming-convention */
69278
+ // client is a PrismaClient instance. it needs to be generated with
69279
+ // additional schema defined inside (TODO: point to repo) file.
69280
+ const mintingPersistence = (client) => {
69281
+ trackInitializePersistencePrismaSqlite();
69282
+ return {
69283
+ recordMint: async (request) => {
69284
+ const result = await client.imAssets.upsert({
69285
+ where: {
69286
+ im_assets_uindex: {
69287
+ assetId: request.asset_id, contractAddress: request.contract_address
69288
+ }
69289
+ },
69290
+ update: {},
69291
+ create: {
69292
+ assetId: request.asset_id,
69293
+ contractAddress: request.contract_address,
69294
+ ownerAddress: request.owner_address,
69295
+ metadata: JSON.stringify(request.metadata), // Serialize JSON metadata
69296
+ },
69297
+ });
69298
+ // Since upsert does not throw on update and does not tell directly if it updated or inserted,
69299
+ // we need to add additional logic to handle this if "result" does not provide enough info.
69300
+ if (!result) {
69301
+ throw new Error('Duplicated mint');
69302
+ }
69303
+ },
69304
+ // WARNING: this is NOT concurrency safe. Please only call this method one at a time.
69305
+ getNextBatchForSubmission: async (limit) => {
69306
+ const assets = await client.imAssets.findMany({
69307
+ where: {
69308
+ mintingStatus: null
69309
+ },
69310
+ take: limit
69311
+ });
69312
+ const assetIds = assets.map((asset) => asset.id);
69313
+ await client.imAssets.updateMany({
69314
+ where: {
69315
+ id: {
69316
+ in: assetIds
69317
+ }
69318
+ },
69319
+ data: {
69320
+ mintingStatus: 'submitting'
69321
+ }
69322
+ });
69323
+ const updatedAssets = await client.imAssets.findMany({
69324
+ where: {
69325
+ id: {
69326
+ in: assetIds
69327
+ }
69328
+ }
69329
+ });
69330
+ return updatedAssets.map((asset) => ({
69331
+ id: asset.id,
69332
+ contract_address: asset.contractAddress,
69333
+ wallet_address: asset.ownerAddress,
69334
+ asset_id: asset.assetId,
69335
+ metadata: asset.metadata ? JSON.parse(asset.metadata) : null,
69336
+ owner_address: asset.ownerAddress,
69337
+ tried_count: asset.triedCount,
69338
+ }));
69339
+ },
69340
+ updateMintingStatusToSubmitted: async (ids) => {
69341
+ await client.imAssets.updateMany({
69342
+ where: {
69343
+ id: {
69344
+ in: ids
69345
+ }
69346
+ },
69347
+ data: {
69348
+ mintingStatus: 'submitted'
69349
+ }
69350
+ });
69351
+ },
69352
+ syncMintingStatus: async (submittedMintRequest) => {
69353
+ // First, attempt to retrieve the existing asset
69354
+ const existingAsset = await client.imAssets.findUnique({
69355
+ where: {
69356
+ im_assets_uindex: {
69357
+ assetId: submittedMintRequest.assetId,
69358
+ contractAddress: submittedMintRequest.contractAddress,
69359
+ },
69360
+ }
69361
+ });
69362
+ // Check if the asset exists and the condition for updating is met
69363
+ if (existingAsset && (existingAsset.lastImtblZkevmMintRequestUpdatedId === null
69364
+ || existingAsset.lastImtblZkevmMintRequestUpdatedId < submittedMintRequest.imtblZkevmMintRequestUpdatedId)) {
69365
+ // Perform update if the existing record's lastImtblZkevmMintRequestUpdatedId is less than the new one or is null
69366
+ await client.imAssets.update({
69367
+ where: {
69368
+ im_assets_uindex: {
69369
+ assetId: submittedMintRequest.assetId,
69370
+ contractAddress: submittedMintRequest.contractAddress,
69371
+ },
69372
+ },
69373
+ data: {
69374
+ ownerAddress: submittedMintRequest.ownerAddress,
69375
+ tokenId: submittedMintRequest.tokenId,
69376
+ mintingStatus: submittedMintRequest.status,
69377
+ metadataId: submittedMintRequest.metadataId,
69378
+ lastImtblZkevmMintRequestUpdatedId: submittedMintRequest.imtblZkevmMintRequestUpdatedId,
69379
+ error: submittedMintRequest.error,
69380
+ }
69381
+ });
69382
+ }
69383
+ else if (!existingAsset) {
69384
+ // Perform insert if no existing record is found
69385
+ await client.imAssets.create({
69386
+ data: {
69387
+ assetId: submittedMintRequest.assetId,
69388
+ contractAddress: submittedMintRequest.contractAddress,
69389
+ ownerAddress: submittedMintRequest.ownerAddress,
69390
+ tokenId: submittedMintRequest.tokenId,
69391
+ mintingStatus: submittedMintRequest.status,
69392
+ metadataId: submittedMintRequest.metadataId,
69393
+ lastImtblZkevmMintRequestUpdatedId: submittedMintRequest.imtblZkevmMintRequestUpdatedId,
69394
+ error: submittedMintRequest.error,
69395
+ }
69396
+ });
69397
+ }
69398
+ // If existing asset does not meet the update condition, do nothing
69399
+ },
69400
+ updateMintingStatusToSubmissionFailed: async (ids) => {
69401
+ await client.imAssets.updateMany({
69402
+ where: {
69403
+ id: {
69404
+ in: ids
69405
+ }
69406
+ },
69407
+ data: {
69408
+ mintingStatus: 'submission_failed'
69409
+ }
69410
+ });
69411
+ },
69412
+ markAsConflict: async (assetIds, contractAddress) => {
69413
+ await client.imAssets.updateMany({
69414
+ where: {
69415
+ assetId: {
69416
+ in: assetIds // Targets assets where assetId is in the provided list
69417
+ },
69418
+ contractAddress // Additional condition for contract address
69419
+ },
69420
+ data: {
69421
+ mintingStatus: 'conflicting' // Set the new status
69422
+ }
69423
+ });
69424
+ },
69425
+ resetMintingStatus: async (ids) => {
69426
+ await client.imAssets.updateMany({
69427
+ where: {
69428
+ id: {
69429
+ in: ids // Condition to match ids
69430
+ }
69431
+ },
69432
+ data: {
69433
+ mintingStatus: null // Setting minting_status to null
69434
+ }
69435
+ });
69436
+ },
69437
+ // this method is not concurrency safe
69438
+ markForRetry: async (ids) => {
69439
+ // Retrieve the current values of tried_count for the specified ids
69440
+ const assets = await client.imAssets.findMany({
69441
+ where: {
69442
+ id: {
69443
+ in: ids
69444
+ }
69445
+ },
69446
+ select: {
69447
+ id: true,
69448
+ triedCount: true // Assuming the field is named triedCount
69449
+ }
69450
+ });
69451
+ // Update each asset with the new tried_count and nullify minting_status
69452
+ for (const asset of assets) {
69453
+ await client.imAssets.update({
69454
+ where: {
69455
+ id: asset.id
69456
+ },
69457
+ data: {
69458
+ mintingStatus: null,
69459
+ triedCount: asset.triedCount + 1
69460
+ }
69461
+ });
69462
+ }
69463
+ },
69464
+ getMintingRequest: async (contractAddress, referenceId) => {
69465
+ // Retrieve the asset from the database based on contract_address and asset_id
69466
+ const asset = await client.imAssets.findFirst({
69467
+ where: {
69468
+ contractAddress,
69469
+ assetId: referenceId
69470
+ }
69471
+ });
69472
+ if (!asset) {
69473
+ return null;
69474
+ }
69475
+ return {
69476
+ asset_id: asset.assetId,
69477
+ contract_address: asset.contractAddress,
69478
+ id: asset.id,
69479
+ metadata: asset.metadata ? JSON.parse(asset.metadata) : null,
69480
+ owner_address: asset.ownerAddress,
69481
+ tried_count: asset.triedCount,
69482
+ wallet_address: asset.ownerAddress
69483
+ };
69484
+ }
69485
+ };
69486
+ };
69487
+
69488
+ // TODO: expose metrics
69489
+ // - submitting status count, conflicting status count
69490
+ // - failed events count
69491
+ const recordMint = async (mintingPersistence, mintRequest) => {
69492
+ trackRecordMint();
69493
+ mintingPersistence.recordMint(mintRequest);
69494
+ };
69495
+ const defaultMintingDelay = 1000;
69496
+ // This function can be called in different node process and will run in parallel to mint assets.
69497
+ // Each process will NOT mint the same asset.
69498
+ // Monitor your database to see if parallel processes are saturating the database CPU and triggering excessive vacuuming.
69499
+ // default batch size will be treated as 100 when it exceeds 100 because minting API has a limit of 100 assets per request.
69500
+ const submitMintingRequests = async (mintingPersistence, blockchainDataSDKClient, { defaultBatchSize = 1000, chainName = 'imtbl-zkevm-testnet', maxNumberOfTries = 3, }, logger = console) => {
69501
+ trackSubmitMintingRequests();
69502
+ let mintingResponse;
69503
+ // eslint-disable-next-line no-constant-condition
69504
+ while (true) {
69505
+ await new Promise((resolve) => {
69506
+ setTimeout(resolve, defaultMintingDelay);
69507
+ });
69508
+ let batchSize = Math.min(mintingResponse?.imx_remaining_mint_requests
69509
+ ? parseInt(mintingResponse.imx_remaining_mint_requests, 10)
69510
+ : defaultBatchSize, defaultBatchSize);
69511
+ if (batchSize === 0
69512
+ && mintingResponse
69513
+ && new Date(mintingResponse.imx_mint_requests_limit_reset) > new Date()) {
69514
+ logger.info(`minting limit reached, waiting for reset at ${mintingResponse?.imx_mint_requests_limit_reset}`);
69515
+ continue;
69516
+ }
69517
+ if (batchSize === 0) {
69518
+ logger.info(`minting limit has been reset, use default batch size: ${defaultBatchSize}`);
69519
+ mintingResponse = undefined;
69520
+ batchSize = defaultBatchSize;
69521
+ }
69522
+ // get mints to be submitted
69523
+ const pendingMints = await mintingPersistence.getNextBatchForSubmission(batchSize);
69524
+ if (pendingMints.length === 0) {
69525
+ logger.info('no assets to mint');
69526
+ continue;
69527
+ }
69528
+ // chunk assets by every 100 assets. every chunk should all be for the same contract address.
69529
+ const chunkedAssets = pendingMints.sort((a, b) => (a.contract_address > b.contract_address ? 1 : -1)).reduce((acc, row) => {
69530
+ if (acc.length === 0) {
69531
+ return [{ contractAddress: row.contract_address, assets: [row] }];
69532
+ }
69533
+ const lastBatch = acc[acc.length - 1];
69534
+ if (lastBatch.contractAddress === row.contract_address && lastBatch.assets.length < 100) {
69535
+ return [...acc.slice(0, -1), { ...lastBatch, assets: [...lastBatch.assets, row] }];
69536
+ }
69537
+ return [...acc, { contractAddress: row.contract_address, assets: [row] }];
69538
+ }, []);
69539
+ // submit minting request for each contract address in parallel
69540
+ const mintingResults = await Promise.allSettled(chunkedAssets.map(async ({ contractAddress, assets }) => {
69541
+ const mintingRequest = {
69542
+ chainName,
69543
+ contractAddress,
69544
+ createMintRequestRequest: {
69545
+ assets: assets.map((row) => ({
69546
+ reference_id: row.asset_id,
69547
+ owner_address: row.owner_address,
69548
+ metadata: row.metadata,
69549
+ })),
69550
+ },
69551
+ };
69552
+ try {
69553
+ const response = await blockchainDataSDKClient.createMintRequest(mintingRequest);
69554
+ logger.info(`mintingResponse: ${JSON.stringify(response, null, 2)}`);
69555
+ // update minting status to submitted
69556
+ await mintingPersistence.updateMintingStatusToSubmitted(assets.map(({ id }) => id));
69557
+ return response;
69558
+ }
69559
+ catch (e) {
69560
+ logger.error(e);
69561
+ if (e.code === 'CONFLICT_ERROR'
69562
+ && e.details?.id === 'reference_id') {
69563
+ try {
69564
+ // mark the assets as conflicting, so that we don't send them again.
69565
+ await mintingPersistence.markAsConflict(e.details.values, contractAddress);
69566
+ // remove non conflicting assets status so that they can be retried.
69567
+ await mintingPersistence.resetMintingStatus(assets
69568
+ .map(({ id }) => id)
69569
+ .filter((id) => !e.details.values.includes(id)));
69570
+ }
69571
+ catch (e2) {
69572
+ logger.error(e2);
69573
+ }
69574
+ }
69575
+ else {
69576
+ // separate assets into "need to be retied" and "exceeded max number of tries."
69577
+ const { assetsToRetry, assetsExceededMaxNumberOfTries } = assets.reduce((acc, { tried_count = 0, id }) => {
69578
+ if (tried_count < maxNumberOfTries) {
69579
+ acc.assetsToRetry.push(id);
69580
+ }
69581
+ else {
69582
+ acc.assetsExceededMaxNumberOfTries.push(id);
69583
+ }
69584
+ return acc;
69585
+ }, {
69586
+ assetsToRetry: [],
69587
+ assetsExceededMaxNumberOfTries: [],
69588
+ });
69589
+ // remove all assets status so that they can be retried.
69590
+ await mintingPersistence.markForRetry(assetsToRetry);
69591
+ // mark assets that have exceeded the max number of tries as submission_failed
69592
+ await mintingPersistence.updateMintingStatusToSubmissionFailed(assetsExceededMaxNumberOfTries);
69593
+ }
69594
+ return e;
69595
+ }
69596
+ }));
69597
+ mintingResponse = mintingResults
69598
+ .reverse()
69599
+ .find((r) => r.status === 'fulfilled')?.value;
69600
+ }
69601
+ };
69602
+ const processMint = async (mintingPersistence, event, logger = console) => {
69603
+ trackProcessMint();
69604
+ if (event.event_name !== 'imtbl_zkevm_mint_request_updated') {
69605
+ logger.info(`${event.event_name} is not imtbl_zkevm_mint_request_updated, skip.`);
69606
+ return;
69607
+ }
69608
+ const referenceId = event.data.reference_id;
69609
+ if (!referenceId) {
69610
+ throw new Error('reference_id not found in webhook event');
69611
+ }
69612
+ const contractAddress = event.data.contract_address;
69613
+ if (!contractAddress) {
69614
+ throw new Error('contract_address not found in webhook event');
69615
+ }
69616
+ if (event.data.status === 'failed') {
69617
+ logger.error(`mint failed: ${JSON.stringify(event.data, null, 2)}`);
69618
+ }
69619
+ const mintReq = await mintingPersistence.getMintingRequest(contractAddress, referenceId);
69620
+ if (!mintReq) {
69621
+ logger.info(`minting request not found in the database, ${JSON.stringify(event.data)}`);
69622
+ }
69623
+ const ownerAddress = mintReq?.wallet_address || event.data.owner_address;
69624
+ if (!ownerAddress) {
69625
+ logger.error('owner_address missing');
69626
+ throw new Error('owner_address missing');
69627
+ }
69628
+ await mintingPersistence.syncMintingStatus({
69629
+ tokenId: event.data.token_id,
69630
+ status: event.data.status,
69631
+ assetId: referenceId,
69632
+ contractAddress,
69633
+ ownerAddress,
69634
+ metadataId: event.data.metadata_id,
69635
+ imtblZkevmMintRequestUpdatedId: event.event_id,
69636
+ error: event.data.error ? JSON.stringify(event.data.error) : null,
69637
+ });
69638
+ };
69639
+
69640
+ const noopHandlers = {
69641
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
69642
+ zkevmMintRequestUpdated: async (event) => { },
69643
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
69644
+ others: async (..._args) => { }
69645
+ };
69646
+ class MintingBackendModule {
69647
+ baseConfig;
69648
+ persistence;
69649
+ blockchainDataClient;
69650
+ logger;
69651
+ constructor(config) {
69652
+ this.baseConfig = config.baseConfig;
69653
+ this.persistence = config.persistence;
69654
+ this.logger = config.logger || console;
69655
+ this.blockchainDataClient = new BlockchainData({
69656
+ baseConfig: config.baseConfig
69657
+ });
69658
+ }
69659
+ async recordMint(mintRequest) {
69660
+ await recordMint(this.persistence, mintRequest);
69661
+ }
69662
+ async submitMintingRequests(config) {
69663
+ await submitMintingRequests(this.persistence, this.blockchainDataClient, config);
69664
+ }
69665
+ async processMint(body, otherHandlers = noopHandlers) {
69666
+ await init(body, this.baseConfig.environment, {
69667
+ zkevmMintRequestUpdated: async (event) => {
69668
+ await processMint(this.persistence, event, this.logger);
69669
+ otherHandlers.zkevmMintRequestUpdated(event);
69670
+ },
69671
+ others: otherHandlers.others
69672
+ });
69673
+ }
69674
+ }
69675
+
69676
+ var minting_backend = /*#__PURE__*/Object.freeze({
69677
+ __proto__: null,
69678
+ MintingBackendModule: MintingBackendModule,
69679
+ mintingPersistencePg: mintingPersistence$1,
69680
+ mintingPersistencePrismaSqlite: mintingPersistence,
69681
+ processMint: processMint,
69682
+ recordMint: recordMint,
69683
+ submitMintingRequests: submitMintingRequests
69684
+ });
69685
+
69686
+ export { blockchain_data as blockchainData, checkout, config, minting_backend as mintingBackend, orderbook, passport, webhook, x };