@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.cjs CHANGED
@@ -34,6 +34,7 @@ var solidity = require('@ethersproject/solidity');
34
34
  var routerSdk = require('@uniswap/router-sdk');
35
35
  var units = require('@ethersproject/units');
36
36
  var bignumber = require('@ethersproject/bignumber');
37
+ var MessageValidator = require('sns-validator');
37
38
 
38
39
  function _interopNamespaceDefault(e) {
39
40
  var n = Object.create(null);
@@ -183,7 +184,7 @@ const flattenProperties$1 = (properties) => {
183
184
  };
184
185
 
185
186
  // WARNING: DO NOT CHANGE THE STRING BELOW. IT GETS REPLACED AT BUILD TIME.
186
- const SDK_VERSION$1 = '1.36.0';
187
+ const SDK_VERSION$1 = '1.36.1-alpha';
187
188
  const getFrameParentDomain$1 = () => {
188
189
  if (isNode$1()) {
189
190
  return '';
@@ -14210,7 +14211,7 @@ class MultiRollupApiClients {
14210
14211
  }
14211
14212
 
14212
14213
  // eslint-disable-next-line @typescript-eslint/naming-convention
14213
- const defaultHeaders$2 = { 'x-sdk-version': 'ts-immutable-sdk-1.36.0' };
14214
+ const defaultHeaders$2 = { 'x-sdk-version': 'ts-immutable-sdk-1.36.1-alpha' };
14214
14215
  const createConfig$1 = ({ basePath, headers, }) => {
14215
14216
  if (!basePath.trim()) {
14216
14217
  throw Error('basePath can not be empty');
@@ -14282,7 +14283,7 @@ class APIError extends Error {
14282
14283
 
14283
14284
  /* eslint-disable implicit-arrow-linebreak */
14284
14285
  const defaultHeaders$1 = {
14285
- sdkVersion: 'ts-immutable-sdk-multi-rollup-api-client-1.36.0',
14286
+ sdkVersion: 'ts-immutable-sdk-multi-rollup-api-client-1.36.1-alpha',
14286
14287
  };
14287
14288
  /**
14288
14289
  * createAPIConfiguration to create a custom Configuration
@@ -14756,7 +14757,7 @@ var blockchain_data = /*#__PURE__*/Object.freeze({
14756
14757
  /* eslint-disable @typescript-eslint/naming-convention */
14757
14758
  class ApiConfiguration extends index$2.Configuration {
14758
14759
  }
14759
- const defaultHeaders = { 'x-sdk-version': 'ts-immutable-sdk-1.36.0' };
14760
+ const defaultHeaders = { 'x-sdk-version': 'ts-immutable-sdk-1.36.1-alpha' };
14760
14761
  /**
14761
14762
  * @dev use createImmutableXConfiguration instead
14762
14763
  */
@@ -14795,7 +14796,7 @@ const createImmutableXConfiguration = ({ basePath, chainID, coreContractAddress,
14795
14796
  chainID,
14796
14797
  coreContractAddress,
14797
14798
  registrationContractAddress,
14798
- sdkVersion: 'ts-immutable-sdk-1.36.0',
14799
+ sdkVersion: 'ts-immutable-sdk-1.36.1-alpha',
14799
14800
  baseConfig,
14800
14801
  });
14801
14802
  const production = ({ baseConfig }) => createImmutableXConfiguration({
@@ -23617,12 +23618,12 @@ function assertOptions$1(options, schema, allowUnknown) {
23617
23618
  }
23618
23619
  }
23619
23620
 
23620
- var validator$1 = {
23621
+ var validator$2 = {
23621
23622
  assertOptions: assertOptions$1,
23622
23623
  validators: validators$1$1
23623
23624
  };
23624
23625
 
23625
- const validators$2 = validator$1.validators;
23626
+ const validators$2 = validator$2.validators;
23626
23627
 
23627
23628
  /**
23628
23629
  * Create a new instance of Axios
@@ -23663,7 +23664,7 @@ let Axios$2 = class Axios {
23663
23664
  const {transitional, paramsSerializer, headers} = config;
23664
23665
 
23665
23666
  if (transitional !== undefined) {
23666
- validator$1.assertOptions(transitional, {
23667
+ validator$2.assertOptions(transitional, {
23667
23668
  silentJSONParsing: validators$2.transitional(validators$2.boolean),
23668
23669
  forcedJSONParsing: validators$2.transitional(validators$2.boolean),
23669
23670
  clarifyTimeoutError: validators$2.transitional(validators$2.boolean)
@@ -23676,7 +23677,7 @@ let Axios$2 = class Axios {
23676
23677
  serialize: paramsSerializer
23677
23678
  };
23678
23679
  } else {
23679
- validator$1.assertOptions(paramsSerializer, {
23680
+ validator$2.assertOptions(paramsSerializer, {
23680
23681
  encode: validators$2.function,
23681
23682
  serialize: validators$2.function
23682
23683
  }, true);
@@ -32355,12 +32356,12 @@ function assertOptions(options, schema, allowUnknown) {
32355
32356
  }
32356
32357
  }
32357
32358
 
32358
- var validator = {
32359
+ var validator$1 = {
32359
32360
  assertOptions,
32360
32361
  validators: validators$1
32361
32362
  };
32362
32363
 
32363
- const validators = validator.validators;
32364
+ const validators = validator$1.validators;
32364
32365
 
32365
32366
  /**
32366
32367
  * Create a new instance of Axios
@@ -32401,7 +32402,7 @@ class Axios {
32401
32402
  const {transitional, paramsSerializer, headers} = config;
32402
32403
 
32403
32404
  if (transitional !== undefined) {
32404
- validator.assertOptions(transitional, {
32405
+ validator$1.assertOptions(transitional, {
32405
32406
  silentJSONParsing: validators.transitional(validators.boolean),
32406
32407
  forcedJSONParsing: validators.transitional(validators.boolean),
32407
32408
  clarifyTimeoutError: validators.transitional(validators.boolean)
@@ -32414,7 +32415,7 @@ class Axios {
32414
32415
  serialize: paramsSerializer
32415
32416
  };
32416
32417
  } else {
32417
- validator.assertOptions(paramsSerializer, {
32418
+ validator$1.assertOptions(paramsSerializer, {
32418
32419
  encode: validators.function,
32419
32420
  serialize: validators.function
32420
32421
  }, true);
@@ -58156,7 +58157,7 @@ const flattenProperties = (properties) => {
58156
58157
  };
58157
58158
 
58158
58159
  // WARNING: DO NOT CHANGE THE STRING BELOW. IT GETS REPLACED AT BUILD TIME.
58159
- const SDK_VERSION = '1.36.0';
58160
+ const SDK_VERSION = '1.36.1-alpha';
58160
58161
  const getFrameParentDomain = () => {
58161
58162
  if (isNode()) {
58162
58163
  return '';
@@ -63449,7 +63450,7 @@ const IMMUTABLE_ZKVEM_GAS_OVERRIDES = {
63449
63450
  maxPriorityFeePerGas: ethers.BigNumber.from(10e9),
63450
63451
  };
63451
63452
 
63452
- const SDK_VERSION_MARKER = '1.36.0';
63453
+ const SDK_VERSION_MARKER = '1.36.1-alpha';
63453
63454
  // This SDK version is replaced by the `yarn build` command ran on the root level
63454
63455
  const globalPackageVersion = () => SDK_VERSION_MARKER;
63455
63456
 
@@ -69115,9 +69116,601 @@ var x = /*#__PURE__*/Object.freeze({
69115
69116
  sandbox: sandbox
69116
69117
  });
69117
69118
 
69119
+ const validator = new MessageValidator();
69120
+ const allowedTopicArnPrefix = {
69121
+ [Environment$1.PRODUCTION]: 'arn:aws:sns:us-east-2:362750628221:',
69122
+ [Environment$1.SANDBOX]: 'arn:aws:sns:us-east-2:783421985614:'
69123
+ };
69124
+ const init = async (body, env, handlers) => {
69125
+ const msg = await new Promise((resolve, reject) => {
69126
+ validator.validate(body, (err, message) => {
69127
+ if (err) {
69128
+ return reject(err);
69129
+ }
69130
+ // check for topic arn prefix
69131
+ if (!message.TopicArn.startsWith(allowedTopicArnPrefix[env])) {
69132
+ throw new Error('Invalid topic arn');
69133
+ }
69134
+ if (message?.Type === 'SubscriptionConfirmation') {
69135
+ fetch(message.SubscribeURL).then(() => {
69136
+ resolve(message);
69137
+ }).catch((e) => {
69138
+ reject(e);
69139
+ });
69140
+ }
69141
+ return resolve(message);
69142
+ });
69143
+ });
69144
+ if (msg.Type === 'Notification') {
69145
+ const event = JSON.parse(msg.Message);
69146
+ switch (event.event_name) {
69147
+ case 'imtbl_zkevm_mint_request_updated':
69148
+ await handlers.zkevmMintRequestUpdated(event);
69149
+ break;
69150
+ default:
69151
+ if (handlers.others) {
69152
+ await handlers.others(event);
69153
+ }
69154
+ break;
69155
+ }
69156
+ }
69157
+ };
69158
+
69159
+ var webhook = /*#__PURE__*/Object.freeze({
69160
+ __proto__: null,
69161
+ init: init
69162
+ });
69163
+
69164
+ const moduleName = 'minting_backend_sdk';
69165
+ const trackInitializePersistencePG = () => {
69166
+ try {
69167
+ track(moduleName, 'initializePersistencePG');
69168
+ }
69169
+ catch {
69170
+ // ignore
69171
+ }
69172
+ };
69173
+ const trackInitializePersistencePrismaSqlite = () => {
69174
+ try {
69175
+ track(moduleName, 'initializePersistencePrismaSqlite');
69176
+ }
69177
+ catch {
69178
+ // ignore
69179
+ }
69180
+ };
69181
+ const trackSubmitMintingRequests = () => {
69182
+ try {
69183
+ track(moduleName, 'submitMintingRequests');
69184
+ }
69185
+ catch {
69186
+ // ignore
69187
+ }
69188
+ };
69189
+ const trackProcessMint = () => {
69190
+ try {
69191
+ track(moduleName, 'processMint');
69192
+ }
69193
+ catch {
69194
+ // ignore
69195
+ }
69196
+ };
69197
+ const trackRecordMint = () => {
69198
+ try {
69199
+ track(moduleName, 'recordMint');
69200
+ }
69201
+ catch {
69202
+ // ignore
69203
+ }
69204
+ };
69205
+
69206
+ const mintingPersistence$1 = (client) => {
69207
+ trackInitializePersistencePG();
69208
+ return {
69209
+ recordMint: async (request) => {
69210
+ const r = await client.query(`
69211
+ INSERT INTO im_assets (asset_id, contract_address, owner_address, metadata)
69212
+ VALUES ($1, $2, $3, $4) ON CONFLICT (asset_id, contract_address) DO NOTHING;
69213
+ `, [request.asset_id, request.contract_address, request.owner_address, request.metadata]);
69214
+ if (r.rowCount === 0) {
69215
+ throw new Error('Duplicated mint');
69216
+ }
69217
+ },
69218
+ getNextBatchForSubmission: async (limit) => {
69219
+ const res = await client.query(`
69220
+ UPDATE im_assets SET minting_status = 'submitting' WHERE minting_status IS NULL and id in (
69221
+ select id from im_assets where minting_status is null limit $1 for update skip locked
69222
+ ) returning *;
69223
+ `, [limit]);
69224
+ return res.rows;
69225
+ },
69226
+ updateMintingStatusToSubmitted: async (ids) => {
69227
+ await client.query(`
69228
+ UPDATE im_assets SET minting_status = $2 WHERE id = ANY($1);
69229
+ `, [ids, 'submitted']);
69230
+ },
69231
+ syncMintingStatus: async (submittedMintRequest) => {
69232
+ // doing a upsert just in case the row has not been created yet
69233
+ await client.query(`
69234
+ INSERT INTO im_assets (
69235
+ asset_id,
69236
+ contract_address,
69237
+ owner_address,
69238
+ token_id,
69239
+ minting_status,
69240
+ metadata_id,
69241
+ last_imtbl_zkevm_mint_request_updated_id,
69242
+ error
69243
+ ) VALUES ($1, $2, $3, $4, $5, $6, $7, $8) ON CONFLICT (asset_id, contract_address)
69244
+ DO UPDATE SET
69245
+ owner_address = $3,
69246
+ token_id = $4,
69247
+ minting_status = $5,
69248
+ metadata_id = $6,
69249
+ last_imtbl_zkevm_mint_request_updated_id = $7,
69250
+ error = $8
69251
+ where (
69252
+ im_assets.last_imtbl_zkevm_mint_request_updated_id < $7 OR
69253
+ im_assets.last_imtbl_zkevm_mint_request_updated_id is null
69254
+ );
69255
+ `, [
69256
+ submittedMintRequest.assetId,
69257
+ submittedMintRequest.contractAddress,
69258
+ submittedMintRequest.ownerAddress,
69259
+ submittedMintRequest.tokenId,
69260
+ submittedMintRequest.status,
69261
+ submittedMintRequest.metadataId,
69262
+ submittedMintRequest.imtblZkevmMintRequestUpdatedId,
69263
+ submittedMintRequest.error
69264
+ ]);
69265
+ },
69266
+ markAsConflict: async (assetIds, contractAddress) => {
69267
+ await client.query(`
69268
+ UPDATE im_assets
69269
+ SET minting_status = 'conflicting'
69270
+ WHERE asset_id = ANY($1)
69271
+ AND contract_address = $2;
69272
+ `, [assetIds, contractAddress]);
69273
+ },
69274
+ resetMintingStatus: async (ids) => {
69275
+ await client.query(`
69276
+ UPDATE im_assets SET minting_status = null WHERE id = ANY($1);
69277
+ `, [ids]);
69278
+ },
69279
+ markForRetry: async (ids) => {
69280
+ await client.query(`
69281
+ UPDATE im_assets
69282
+ SET minting_status = null, tried_count = tried_count + 1 WHERE id = ANY($1);
69283
+ `, [ids]);
69284
+ },
69285
+ updateMintingStatusToSubmissionFailed: async (ids) => {
69286
+ await client.query(`
69287
+ UPDATE im_assets SET minting_status = 'submission_failed' WHERE id = ANY($1);
69288
+ `, [ids]);
69289
+ },
69290
+ getMintingRequest: async (contractAddress, referenceId) => {
69291
+ const res = await client.query(`
69292
+ SELECT * FROM im_assets WHERE contract_address = $1 and asset_id = $2;
69293
+ `, [contractAddress, referenceId]);
69294
+ return res.rows[0] || null;
69295
+ }
69296
+ };
69297
+ };
69298
+
69299
+ /* eslint-disable no-await-in-loop */
69300
+ /* eslint-disable @typescript-eslint/naming-convention */
69301
+ // client is a PrismaClient instance. it needs to be generated with
69302
+ // additional schema defined inside (TODO: point to repo) file.
69303
+ const mintingPersistence = (client) => {
69304
+ trackInitializePersistencePrismaSqlite();
69305
+ return {
69306
+ recordMint: async (request) => {
69307
+ const result = await client.imAssets.upsert({
69308
+ where: {
69309
+ im_assets_uindex: {
69310
+ assetId: request.asset_id, contractAddress: request.contract_address
69311
+ }
69312
+ },
69313
+ update: {},
69314
+ create: {
69315
+ assetId: request.asset_id,
69316
+ contractAddress: request.contract_address,
69317
+ ownerAddress: request.owner_address,
69318
+ metadata: JSON.stringify(request.metadata), // Serialize JSON metadata
69319
+ },
69320
+ });
69321
+ // Since upsert does not throw on update and does not tell directly if it updated or inserted,
69322
+ // we need to add additional logic to handle this if "result" does not provide enough info.
69323
+ if (!result) {
69324
+ throw new Error('Duplicated mint');
69325
+ }
69326
+ },
69327
+ // WARNING: this is NOT concurrency safe. Please only call this method one at a time.
69328
+ getNextBatchForSubmission: async (limit) => {
69329
+ const assets = await client.imAssets.findMany({
69330
+ where: {
69331
+ mintingStatus: null
69332
+ },
69333
+ take: limit
69334
+ });
69335
+ const assetIds = assets.map((asset) => asset.id);
69336
+ await client.imAssets.updateMany({
69337
+ where: {
69338
+ id: {
69339
+ in: assetIds
69340
+ }
69341
+ },
69342
+ data: {
69343
+ mintingStatus: 'submitting'
69344
+ }
69345
+ });
69346
+ const updatedAssets = await client.imAssets.findMany({
69347
+ where: {
69348
+ id: {
69349
+ in: assetIds
69350
+ }
69351
+ }
69352
+ });
69353
+ return updatedAssets.map((asset) => ({
69354
+ id: asset.id,
69355
+ contract_address: asset.contractAddress,
69356
+ wallet_address: asset.ownerAddress,
69357
+ asset_id: asset.assetId,
69358
+ metadata: asset.metadata ? JSON.parse(asset.metadata) : null,
69359
+ owner_address: asset.ownerAddress,
69360
+ tried_count: asset.triedCount,
69361
+ }));
69362
+ },
69363
+ updateMintingStatusToSubmitted: async (ids) => {
69364
+ await client.imAssets.updateMany({
69365
+ where: {
69366
+ id: {
69367
+ in: ids
69368
+ }
69369
+ },
69370
+ data: {
69371
+ mintingStatus: 'submitted'
69372
+ }
69373
+ });
69374
+ },
69375
+ syncMintingStatus: async (submittedMintRequest) => {
69376
+ // First, attempt to retrieve the existing asset
69377
+ const existingAsset = await client.imAssets.findUnique({
69378
+ where: {
69379
+ im_assets_uindex: {
69380
+ assetId: submittedMintRequest.assetId,
69381
+ contractAddress: submittedMintRequest.contractAddress,
69382
+ },
69383
+ }
69384
+ });
69385
+ // Check if the asset exists and the condition for updating is met
69386
+ if (existingAsset && (existingAsset.lastImtblZkevmMintRequestUpdatedId === null
69387
+ || existingAsset.lastImtblZkevmMintRequestUpdatedId < submittedMintRequest.imtblZkevmMintRequestUpdatedId)) {
69388
+ // Perform update if the existing record's lastImtblZkevmMintRequestUpdatedId is less than the new one or is null
69389
+ await client.imAssets.update({
69390
+ where: {
69391
+ im_assets_uindex: {
69392
+ assetId: submittedMintRequest.assetId,
69393
+ contractAddress: submittedMintRequest.contractAddress,
69394
+ },
69395
+ },
69396
+ data: {
69397
+ ownerAddress: submittedMintRequest.ownerAddress,
69398
+ tokenId: submittedMintRequest.tokenId,
69399
+ mintingStatus: submittedMintRequest.status,
69400
+ metadataId: submittedMintRequest.metadataId,
69401
+ lastImtblZkevmMintRequestUpdatedId: submittedMintRequest.imtblZkevmMintRequestUpdatedId,
69402
+ error: submittedMintRequest.error,
69403
+ }
69404
+ });
69405
+ }
69406
+ else if (!existingAsset) {
69407
+ // Perform insert if no existing record is found
69408
+ await client.imAssets.create({
69409
+ data: {
69410
+ assetId: submittedMintRequest.assetId,
69411
+ contractAddress: submittedMintRequest.contractAddress,
69412
+ ownerAddress: submittedMintRequest.ownerAddress,
69413
+ tokenId: submittedMintRequest.tokenId,
69414
+ mintingStatus: submittedMintRequest.status,
69415
+ metadataId: submittedMintRequest.metadataId,
69416
+ lastImtblZkevmMintRequestUpdatedId: submittedMintRequest.imtblZkevmMintRequestUpdatedId,
69417
+ error: submittedMintRequest.error,
69418
+ }
69419
+ });
69420
+ }
69421
+ // If existing asset does not meet the update condition, do nothing
69422
+ },
69423
+ updateMintingStatusToSubmissionFailed: async (ids) => {
69424
+ await client.imAssets.updateMany({
69425
+ where: {
69426
+ id: {
69427
+ in: ids
69428
+ }
69429
+ },
69430
+ data: {
69431
+ mintingStatus: 'submission_failed'
69432
+ }
69433
+ });
69434
+ },
69435
+ markAsConflict: async (assetIds, contractAddress) => {
69436
+ await client.imAssets.updateMany({
69437
+ where: {
69438
+ assetId: {
69439
+ in: assetIds // Targets assets where assetId is in the provided list
69440
+ },
69441
+ contractAddress // Additional condition for contract address
69442
+ },
69443
+ data: {
69444
+ mintingStatus: 'conflicting' // Set the new status
69445
+ }
69446
+ });
69447
+ },
69448
+ resetMintingStatus: async (ids) => {
69449
+ await client.imAssets.updateMany({
69450
+ where: {
69451
+ id: {
69452
+ in: ids // Condition to match ids
69453
+ }
69454
+ },
69455
+ data: {
69456
+ mintingStatus: null // Setting minting_status to null
69457
+ }
69458
+ });
69459
+ },
69460
+ // this method is not concurrency safe
69461
+ markForRetry: async (ids) => {
69462
+ // Retrieve the current values of tried_count for the specified ids
69463
+ const assets = await client.imAssets.findMany({
69464
+ where: {
69465
+ id: {
69466
+ in: ids
69467
+ }
69468
+ },
69469
+ select: {
69470
+ id: true,
69471
+ triedCount: true // Assuming the field is named triedCount
69472
+ }
69473
+ });
69474
+ // Update each asset with the new tried_count and nullify minting_status
69475
+ for (const asset of assets) {
69476
+ await client.imAssets.update({
69477
+ where: {
69478
+ id: asset.id
69479
+ },
69480
+ data: {
69481
+ mintingStatus: null,
69482
+ triedCount: asset.triedCount + 1
69483
+ }
69484
+ });
69485
+ }
69486
+ },
69487
+ getMintingRequest: async (contractAddress, referenceId) => {
69488
+ // Retrieve the asset from the database based on contract_address and asset_id
69489
+ const asset = await client.imAssets.findFirst({
69490
+ where: {
69491
+ contractAddress,
69492
+ assetId: referenceId
69493
+ }
69494
+ });
69495
+ if (!asset) {
69496
+ return null;
69497
+ }
69498
+ return {
69499
+ asset_id: asset.assetId,
69500
+ contract_address: asset.contractAddress,
69501
+ id: asset.id,
69502
+ metadata: asset.metadata ? JSON.parse(asset.metadata) : null,
69503
+ owner_address: asset.ownerAddress,
69504
+ tried_count: asset.triedCount,
69505
+ wallet_address: asset.ownerAddress
69506
+ };
69507
+ }
69508
+ };
69509
+ };
69510
+
69511
+ // TODO: expose metrics
69512
+ // - submitting status count, conflicting status count
69513
+ // - failed events count
69514
+ const recordMint = async (mintingPersistence, mintRequest) => {
69515
+ trackRecordMint();
69516
+ mintingPersistence.recordMint(mintRequest);
69517
+ };
69518
+ const defaultMintingDelay = 1000;
69519
+ // This function can be called in different node process and will run in parallel to mint assets.
69520
+ // Each process will NOT mint the same asset.
69521
+ // Monitor your database to see if parallel processes are saturating the database CPU and triggering excessive vacuuming.
69522
+ // default batch size will be treated as 100 when it exceeds 100 because minting API has a limit of 100 assets per request.
69523
+ const submitMintingRequests = async (mintingPersistence, blockchainDataSDKClient, { defaultBatchSize = 1000, chainName = 'imtbl-zkevm-testnet', maxNumberOfTries = 3, }, logger = console) => {
69524
+ trackSubmitMintingRequests();
69525
+ let mintingResponse;
69526
+ // eslint-disable-next-line no-constant-condition
69527
+ while (true) {
69528
+ await new Promise((resolve) => {
69529
+ setTimeout(resolve, defaultMintingDelay);
69530
+ });
69531
+ let batchSize = Math.min(mintingResponse?.imx_remaining_mint_requests
69532
+ ? parseInt(mintingResponse.imx_remaining_mint_requests, 10)
69533
+ : defaultBatchSize, defaultBatchSize);
69534
+ if (batchSize === 0
69535
+ && mintingResponse
69536
+ && new Date(mintingResponse.imx_mint_requests_limit_reset) > new Date()) {
69537
+ logger.info(`minting limit reached, waiting for reset at ${mintingResponse?.imx_mint_requests_limit_reset}`);
69538
+ continue;
69539
+ }
69540
+ if (batchSize === 0) {
69541
+ logger.info(`minting limit has been reset, use default batch size: ${defaultBatchSize}`);
69542
+ mintingResponse = undefined;
69543
+ batchSize = defaultBatchSize;
69544
+ }
69545
+ // get mints to be submitted
69546
+ const pendingMints = await mintingPersistence.getNextBatchForSubmission(batchSize);
69547
+ if (pendingMints.length === 0) {
69548
+ logger.info('no assets to mint');
69549
+ continue;
69550
+ }
69551
+ // chunk assets by every 100 assets. every chunk should all be for the same contract address.
69552
+ const chunkedAssets = pendingMints.sort((a, b) => (a.contract_address > b.contract_address ? 1 : -1)).reduce((acc, row) => {
69553
+ if (acc.length === 0) {
69554
+ return [{ contractAddress: row.contract_address, assets: [row] }];
69555
+ }
69556
+ const lastBatch = acc[acc.length - 1];
69557
+ if (lastBatch.contractAddress === row.contract_address && lastBatch.assets.length < 100) {
69558
+ return [...acc.slice(0, -1), { ...lastBatch, assets: [...lastBatch.assets, row] }];
69559
+ }
69560
+ return [...acc, { contractAddress: row.contract_address, assets: [row] }];
69561
+ }, []);
69562
+ // submit minting request for each contract address in parallel
69563
+ const mintingResults = await Promise.allSettled(chunkedAssets.map(async ({ contractAddress, assets }) => {
69564
+ const mintingRequest = {
69565
+ chainName,
69566
+ contractAddress,
69567
+ createMintRequestRequest: {
69568
+ assets: assets.map((row) => ({
69569
+ reference_id: row.asset_id,
69570
+ owner_address: row.owner_address,
69571
+ metadata: row.metadata,
69572
+ })),
69573
+ },
69574
+ };
69575
+ try {
69576
+ const response = await blockchainDataSDKClient.createMintRequest(mintingRequest);
69577
+ logger.info(`mintingResponse: ${JSON.stringify(response, null, 2)}`);
69578
+ // update minting status to submitted
69579
+ await mintingPersistence.updateMintingStatusToSubmitted(assets.map(({ id }) => id));
69580
+ return response;
69581
+ }
69582
+ catch (e) {
69583
+ logger.error(e);
69584
+ if (e.code === 'CONFLICT_ERROR'
69585
+ && e.details?.id === 'reference_id') {
69586
+ try {
69587
+ // mark the assets as conflicting, so that we don't send them again.
69588
+ await mintingPersistence.markAsConflict(e.details.values, contractAddress);
69589
+ // remove non conflicting assets status so that they can be retried.
69590
+ await mintingPersistence.resetMintingStatus(assets
69591
+ .map(({ id }) => id)
69592
+ .filter((id) => !e.details.values.includes(id)));
69593
+ }
69594
+ catch (e2) {
69595
+ logger.error(e2);
69596
+ }
69597
+ }
69598
+ else {
69599
+ // separate assets into "need to be retied" and "exceeded max number of tries."
69600
+ const { assetsToRetry, assetsExceededMaxNumberOfTries } = assets.reduce((acc, { tried_count = 0, id }) => {
69601
+ if (tried_count < maxNumberOfTries) {
69602
+ acc.assetsToRetry.push(id);
69603
+ }
69604
+ else {
69605
+ acc.assetsExceededMaxNumberOfTries.push(id);
69606
+ }
69607
+ return acc;
69608
+ }, {
69609
+ assetsToRetry: [],
69610
+ assetsExceededMaxNumberOfTries: [],
69611
+ });
69612
+ // remove all assets status so that they can be retried.
69613
+ await mintingPersistence.markForRetry(assetsToRetry);
69614
+ // mark assets that have exceeded the max number of tries as submission_failed
69615
+ await mintingPersistence.updateMintingStatusToSubmissionFailed(assetsExceededMaxNumberOfTries);
69616
+ }
69617
+ return e;
69618
+ }
69619
+ }));
69620
+ mintingResponse = mintingResults
69621
+ .reverse()
69622
+ .find((r) => r.status === 'fulfilled')?.value;
69623
+ }
69624
+ };
69625
+ const processMint = async (mintingPersistence, event, logger = console) => {
69626
+ trackProcessMint();
69627
+ if (event.event_name !== 'imtbl_zkevm_mint_request_updated') {
69628
+ logger.info(`${event.event_name} is not imtbl_zkevm_mint_request_updated, skip.`);
69629
+ return;
69630
+ }
69631
+ const referenceId = event.data.reference_id;
69632
+ if (!referenceId) {
69633
+ throw new Error('reference_id not found in webhook event');
69634
+ }
69635
+ const contractAddress = event.data.contract_address;
69636
+ if (!contractAddress) {
69637
+ throw new Error('contract_address not found in webhook event');
69638
+ }
69639
+ if (event.data.status === 'failed') {
69640
+ logger.error(`mint failed: ${JSON.stringify(event.data, null, 2)}`);
69641
+ }
69642
+ const mintReq = await mintingPersistence.getMintingRequest(contractAddress, referenceId);
69643
+ if (!mintReq) {
69644
+ logger.info(`minting request not found in the database, ${JSON.stringify(event.data)}`);
69645
+ }
69646
+ const ownerAddress = mintReq?.wallet_address || event.data.owner_address;
69647
+ if (!ownerAddress) {
69648
+ logger.error('owner_address missing');
69649
+ throw new Error('owner_address missing');
69650
+ }
69651
+ await mintingPersistence.syncMintingStatus({
69652
+ tokenId: event.data.token_id,
69653
+ status: event.data.status,
69654
+ assetId: referenceId,
69655
+ contractAddress,
69656
+ ownerAddress,
69657
+ metadataId: event.data.metadata_id,
69658
+ imtblZkevmMintRequestUpdatedId: event.event_id,
69659
+ error: event.data.error ? JSON.stringify(event.data.error) : null,
69660
+ });
69661
+ };
69662
+
69663
+ const noopHandlers = {
69664
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
69665
+ zkevmMintRequestUpdated: async (event) => { },
69666
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
69667
+ others: async (..._args) => { }
69668
+ };
69669
+ class MintingBackendModule {
69670
+ baseConfig;
69671
+ persistence;
69672
+ blockchainDataClient;
69673
+ logger;
69674
+ constructor(config) {
69675
+ this.baseConfig = config.baseConfig;
69676
+ this.persistence = config.persistence;
69677
+ this.logger = config.logger || console;
69678
+ this.blockchainDataClient = new BlockchainData({
69679
+ baseConfig: config.baseConfig
69680
+ });
69681
+ }
69682
+ async recordMint(mintRequest) {
69683
+ await recordMint(this.persistence, mintRequest);
69684
+ }
69685
+ async submitMintingRequests(config) {
69686
+ await submitMintingRequests(this.persistence, this.blockchainDataClient, config);
69687
+ }
69688
+ async processMint(body, otherHandlers = noopHandlers) {
69689
+ await init(body, this.baseConfig.environment, {
69690
+ zkevmMintRequestUpdated: async (event) => {
69691
+ await processMint(this.persistence, event, this.logger);
69692
+ otherHandlers.zkevmMintRequestUpdated(event);
69693
+ },
69694
+ others: otherHandlers.others
69695
+ });
69696
+ }
69697
+ }
69698
+
69699
+ var minting_backend = /*#__PURE__*/Object.freeze({
69700
+ __proto__: null,
69701
+ MintingBackendModule: MintingBackendModule,
69702
+ mintingPersistencePg: mintingPersistence$1,
69703
+ mintingPersistencePrismaSqlite: mintingPersistence,
69704
+ processMint: processMint,
69705
+ recordMint: recordMint,
69706
+ submitMintingRequests: submitMintingRequests
69707
+ });
69708
+
69118
69709
  exports.blockchainData = blockchain_data;
69119
69710
  exports.checkout = checkout;
69120
69711
  exports.config = config;
69712
+ exports.mintingBackend = minting_backend;
69121
69713
  exports.orderbook = orderbook;
69122
69714
  exports.passport = passport;
69715
+ exports.webhook = webhook;
69123
69716
  exports.x = x;