@imtbl/minting-backend 2.0.0-alpha.7 → 2.0.0-alpha.8
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/dist/index.cjs +10 -572
- package/dist/index.js +10 -572
- package/package.json +6 -6
package/dist/index.cjs
CHANGED
|
@@ -1,86 +1,7 @@
|
|
|
1
|
-
"use strict";Object.defineProperty(exports, "__esModule", {value: true}); function _optionalChain(ops) { let lastAccessLHS = undefined; let value = ops[0]; let i = 1; while (i < ops.length) { const op = ops[i]; const fn = ops[i + 1]; i += 2; if ((op === 'optionalAccess' || op === 'optionalCall') && value == null) { return undefined; } if (op === 'access' || op === 'optionalAccess') { lastAccessLHS = value; value = fn(value); } else if (op === 'call' || op === 'optionalCall') { value = fn((...args) => value.call(lastAccessLHS, ...args)); lastAccessLHS = undefined; } } return value; }
|
|
2
|
-
var _blockchaindata = require('@imtbl/blockchain-data');
|
|
3
|
-
var _webhook = require('@imtbl/webhook');
|
|
4
|
-
var _metrics = require('@imtbl/metrics');
|
|
5
|
-
|
|
6
|
-
// src/analytics/index.ts
|
|
7
|
-
|
|
8
|
-
var moduleName = "minting_backend_sdk";
|
|
9
|
-
var trackInitializePersistencePG = () => {
|
|
10
|
-
try {
|
|
11
|
-
_metrics.track.call(void 0, moduleName, "initializePersistencePG");
|
|
12
|
-
} catch (e3) {
|
|
13
|
-
}
|
|
14
|
-
};
|
|
15
|
-
var trackInitializePersistencePrismaSqlite = () => {
|
|
16
|
-
try {
|
|
17
|
-
_metrics.track.call(void 0, moduleName, "initializePersistencePrismaSqlite");
|
|
18
|
-
} catch (e4) {
|
|
19
|
-
}
|
|
20
|
-
};
|
|
21
|
-
var trackSubmitMintingRequests = () => {
|
|
22
|
-
try {
|
|
23
|
-
_metrics.track.call(void 0, moduleName, "submitMintingRequests");
|
|
24
|
-
} catch (e5) {
|
|
25
|
-
}
|
|
26
|
-
};
|
|
27
|
-
var trackProcessMint = () => {
|
|
28
|
-
try {
|
|
29
|
-
_metrics.track.call(void 0, moduleName, "processMint");
|
|
30
|
-
} catch (e6) {
|
|
31
|
-
}
|
|
32
|
-
};
|
|
33
|
-
var trackRecordMint = () => {
|
|
34
|
-
try {
|
|
35
|
-
_metrics.track.call(void 0, moduleName, "recordMint");
|
|
36
|
-
} catch (e7) {
|
|
37
|
-
}
|
|
38
|
-
};
|
|
39
|
-
var trackError = (error) => {
|
|
40
|
-
try {
|
|
41
|
-
_metrics.track.call(void 0, moduleName, "error", {
|
|
42
|
-
name: error.name,
|
|
43
|
-
message: error.message
|
|
44
|
-
});
|
|
45
|
-
} catch (e8) {
|
|
46
|
-
}
|
|
47
|
-
};
|
|
48
|
-
var trackUncaughtException = (error, origin) => {
|
|
49
|
-
try {
|
|
50
|
-
_metrics.track.call(void 0, moduleName, "error", {
|
|
51
|
-
name: error.name,
|
|
52
|
-
message: error.message,
|
|
53
|
-
origin
|
|
54
|
-
});
|
|
55
|
-
} catch (e9) {
|
|
56
|
-
}
|
|
57
|
-
};
|
|
58
|
-
|
|
59
|
-
// src/persistence/pg/postgres.ts
|
|
60
|
-
var mintingPersistence = (client) => {
|
|
61
|
-
trackInitializePersistencePG();
|
|
62
|
-
return {
|
|
63
|
-
recordMint: async (request) => {
|
|
64
|
-
const r = await client.query(
|
|
65
|
-
`
|
|
1
|
+
"use strict";Object.defineProperty(exports, "__esModule", {value: true}); function _optionalChain(ops) { let lastAccessLHS = undefined; let value = ops[0]; let i = 1; while (i < ops.length) { const op = ops[i]; const fn = ops[i + 1]; i += 2; if ((op === 'optionalAccess' || op === 'optionalCall') && value == null) { return undefined; } if (op === 'access' || op === 'optionalAccess') { lastAccessLHS = value; value = fn(value); } else if (op === 'call' || op === 'optionalCall') { value = fn((...args) => value.call(lastAccessLHS, ...args)); lastAccessLHS = undefined; } } return value; } async function _asyncOptionalChain(ops) { let lastAccessLHS = undefined; let value = ops[0]; let i = 1; while (i < ops.length) { const op = ops[i]; const fn = ops[i + 1]; i += 2; if ((op === 'optionalAccess' || op === 'optionalCall') && value == null) { return undefined; } if (op === 'access' || op === 'optionalAccess') { lastAccessLHS = value; value = await fn(value); } else if (op === 'call' || op === 'optionalCall') { value = await fn((...args) => value.call(lastAccessLHS, ...args)); lastAccessLHS = undefined; } } return value; }var _blockchaindata = require('@imtbl/blockchain-data');var _webhook = require('@imtbl/webhook');var _metrics = require('@imtbl/metrics');var u="minting_backend_sdk",M=()=>{try{_metrics.track.call(void 0, u,"initializePersistencePG")}catch (e2){}},h=()=>{try{_metrics.track.call(void 0, u,"initializePersistencePrismaSqlite")}catch (e3){}},I=()=>{try{_metrics.track.call(void 0, u,"submitMintingRequests")}catch (e4){}},A=()=>{try{_metrics.track.call(void 0, u,"processMint")}catch (e5){}},S=()=>{try{_metrics.track.call(void 0, u,"recordMint")}catch (e6){}},w=e=>{try{_metrics.track.call(void 0, u,"error",{name:e.name,message:e.message})}catch (e7){}},E=(e,t)=>{try{_metrics.track.call(void 0, u,"error",{name:e.name,message:e.message,origin:t})}catch (e8){}};var q=e=>(M(),{recordMint:async t=>{if((await e.query(`
|
|
66
2
|
INSERT INTO im_assets (asset_id, contract_address, owner_address, metadata, amount, token_id)
|
|
67
3
|
VALUES ($1, $2, $3, $4, $5, $6) ON CONFLICT (asset_id, contract_address) DO NOTHING;
|
|
68
|
-
`,
|
|
69
|
-
[
|
|
70
|
-
request.asset_id,
|
|
71
|
-
request.contract_address,
|
|
72
|
-
request.owner_address,
|
|
73
|
-
request.metadata,
|
|
74
|
-
request.amount,
|
|
75
|
-
request.token_id
|
|
76
|
-
]
|
|
77
|
-
);
|
|
78
|
-
if (r.rowCount === 0) {
|
|
79
|
-
throw new Error("Duplicated mint");
|
|
80
|
-
}
|
|
81
|
-
},
|
|
82
|
-
getNextBatchForSubmission: async (limit) => {
|
|
83
|
-
const res = await client.query(`
|
|
4
|
+
`,[t.asset_id,t.contract_address,t.owner_address,t.metadata,t.amount,t.token_id])).rowCount===0)throw new Error("Duplicated mint")},getNextBatchForSubmission:async t=>(await e.query(`
|
|
84
5
|
WITH limited_assets AS (
|
|
85
6
|
SELECT id
|
|
86
7
|
FROM im_assets
|
|
@@ -93,16 +14,9 @@ var mintingPersistence = (client) => {
|
|
|
93
14
|
WHERE minting_status IS NULL
|
|
94
15
|
AND id IN (SELECT id FROM limited_assets)
|
|
95
16
|
RETURNING *;
|
|
96
|
-
`,
|
|
97
|
-
return res.rows;
|
|
98
|
-
},
|
|
99
|
-
updateMintingStatusToSubmitted: async (ids) => {
|
|
100
|
-
await client.query(`
|
|
17
|
+
`,[t])).rows,updateMintingStatusToSubmitted:async t=>{await e.query(`
|
|
101
18
|
UPDATE im_assets SET minting_status = $2 WHERE id = ANY($1);
|
|
102
|
-
`,
|
|
103
|
-
},
|
|
104
|
-
syncMintingStatus: async (submittedMintRequest) => {
|
|
105
|
-
await client.query(`
|
|
19
|
+
`,[t,"submitted"])},syncMintingStatus:async t=>{await e.query(`
|
|
106
20
|
INSERT INTO im_assets (
|
|
107
21
|
asset_id,
|
|
108
22
|
contract_address,
|
|
@@ -125,494 +39,18 @@ var mintingPersistence = (client) => {
|
|
|
125
39
|
im_assets.last_imtbl_zkevm_mint_request_updated_id < $7 OR
|
|
126
40
|
im_assets.last_imtbl_zkevm_mint_request_updated_id is null
|
|
127
41
|
);
|
|
128
|
-
`,
|
|
129
|
-
submittedMintRequest.assetId,
|
|
130
|
-
submittedMintRequest.contractAddress,
|
|
131
|
-
submittedMintRequest.ownerAddress,
|
|
132
|
-
submittedMintRequest.tokenId,
|
|
133
|
-
submittedMintRequest.status,
|
|
134
|
-
submittedMintRequest.metadataId,
|
|
135
|
-
submittedMintRequest.imtblZkevmMintRequestUpdatedId,
|
|
136
|
-
submittedMintRequest.error,
|
|
137
|
-
submittedMintRequest.amount
|
|
138
|
-
]);
|
|
139
|
-
},
|
|
140
|
-
markAsConflict: async (assetIds, contractAddress) => {
|
|
141
|
-
await client.query(`
|
|
42
|
+
`,[t.assetId,t.contractAddress,t.ownerAddress,t.tokenId,t.status,t.metadataId,t.imtblZkevmMintRequestUpdatedId,t.error,t.amount])},markAsConflict:async(t,s)=>{await e.query(`
|
|
142
43
|
UPDATE im_assets
|
|
143
44
|
SET minting_status = 'conflicting'
|
|
144
45
|
WHERE asset_id = ANY($1)
|
|
145
46
|
AND contract_address = $2;
|
|
146
|
-
`,
|
|
147
|
-
},
|
|
148
|
-
resetMintingStatus: async (ids) => {
|
|
149
|
-
await client.query(`
|
|
47
|
+
`,[t,s])},resetMintingStatus:async t=>{await e.query(`
|
|
150
48
|
UPDATE im_assets SET minting_status = null WHERE id = ANY($1);
|
|
151
|
-
`,
|
|
152
|
-
},
|
|
153
|
-
markForRetry: async (ids) => {
|
|
154
|
-
await client.query(`
|
|
49
|
+
`,[t])},markForRetry:async t=>{await e.query(`
|
|
155
50
|
UPDATE im_assets
|
|
156
51
|
SET minting_status = null, tried_count = tried_count + 1 WHERE id = ANY($1);
|
|
157
|
-
`,
|
|
158
|
-
},
|
|
159
|
-
updateMintingStatusToSubmissionFailed: async (ids) => {
|
|
160
|
-
await client.query(`
|
|
52
|
+
`,[t])},updateMintingStatusToSubmissionFailed:async t=>{await e.query(`
|
|
161
53
|
UPDATE im_assets SET minting_status = 'submission_failed' WHERE id = ANY($1);
|
|
162
|
-
`,
|
|
163
|
-
},
|
|
164
|
-
getMintingRequest: async (contractAddress, referenceId) => {
|
|
165
|
-
const res = await client.query(`
|
|
54
|
+
`,[t])},getMintingRequest:async(t,s)=>(await e.query(`
|
|
166
55
|
SELECT * FROM im_assets WHERE contract_address = $1 and asset_id = $2;
|
|
167
|
-
`, [contractAddress,
|
|
168
|
-
return res.rows[0] || null;
|
|
169
|
-
}
|
|
170
|
-
};
|
|
171
|
-
};
|
|
172
|
-
|
|
173
|
-
// src/persistence/prismaSqlite/sqlite.ts
|
|
174
|
-
var mintingPersistence2 = (client) => {
|
|
175
|
-
trackInitializePersistencePrismaSqlite();
|
|
176
|
-
return {
|
|
177
|
-
recordMint: async (request) => {
|
|
178
|
-
const result = await client.imAssets.upsert({
|
|
179
|
-
where: {
|
|
180
|
-
im_assets_uindex: {
|
|
181
|
-
assetId: request.asset_id,
|
|
182
|
-
contractAddress: request.contract_address
|
|
183
|
-
}
|
|
184
|
-
},
|
|
185
|
-
update: {},
|
|
186
|
-
// Do nothing on conflict
|
|
187
|
-
create: {
|
|
188
|
-
assetId: request.asset_id,
|
|
189
|
-
contractAddress: request.contract_address,
|
|
190
|
-
ownerAddress: request.owner_address,
|
|
191
|
-
metadata: JSON.stringify(request.metadata),
|
|
192
|
-
// Serialize JSON metadata
|
|
193
|
-
amount: request.amount || null,
|
|
194
|
-
tokenId: request.token_id || null
|
|
195
|
-
}
|
|
196
|
-
});
|
|
197
|
-
if (!result) {
|
|
198
|
-
throw new Error("Duplicated mint");
|
|
199
|
-
}
|
|
200
|
-
},
|
|
201
|
-
// WARNING: this is NOT concurrency safe. Please only call this method one at a time.
|
|
202
|
-
getNextBatchForSubmission: async (limit) => {
|
|
203
|
-
const assets = await client.imAssets.findMany({
|
|
204
|
-
where: {
|
|
205
|
-
mintingStatus: null
|
|
206
|
-
},
|
|
207
|
-
take: limit
|
|
208
|
-
});
|
|
209
|
-
const assetIds = assets.map((asset) => asset.id);
|
|
210
|
-
await client.imAssets.updateMany({
|
|
211
|
-
where: {
|
|
212
|
-
id: {
|
|
213
|
-
in: assetIds
|
|
214
|
-
}
|
|
215
|
-
},
|
|
216
|
-
data: {
|
|
217
|
-
mintingStatus: "submitting"
|
|
218
|
-
}
|
|
219
|
-
});
|
|
220
|
-
const updatedAssets = await client.imAssets.findMany({
|
|
221
|
-
where: {
|
|
222
|
-
id: {
|
|
223
|
-
in: assetIds
|
|
224
|
-
}
|
|
225
|
-
}
|
|
226
|
-
});
|
|
227
|
-
return updatedAssets.map((asset) => ({
|
|
228
|
-
id: asset.id,
|
|
229
|
-
contract_address: asset.contractAddress,
|
|
230
|
-
wallet_address: asset.ownerAddress,
|
|
231
|
-
asset_id: asset.assetId,
|
|
232
|
-
metadata: asset.metadata ? JSON.parse(asset.metadata) : null,
|
|
233
|
-
owner_address: asset.ownerAddress,
|
|
234
|
-
tried_count: asset.triedCount,
|
|
235
|
-
amount: asset.amount || null,
|
|
236
|
-
token_id: asset.tokenId || null
|
|
237
|
-
}));
|
|
238
|
-
},
|
|
239
|
-
updateMintingStatusToSubmitted: async (ids) => {
|
|
240
|
-
await client.imAssets.updateMany({
|
|
241
|
-
where: {
|
|
242
|
-
id: {
|
|
243
|
-
in: ids
|
|
244
|
-
}
|
|
245
|
-
},
|
|
246
|
-
data: {
|
|
247
|
-
mintingStatus: "submitted"
|
|
248
|
-
}
|
|
249
|
-
});
|
|
250
|
-
},
|
|
251
|
-
syncMintingStatus: async (submittedMintRequest) => {
|
|
252
|
-
const existingAsset = await client.imAssets.findUnique({
|
|
253
|
-
where: {
|
|
254
|
-
im_assets_uindex: {
|
|
255
|
-
assetId: submittedMintRequest.assetId,
|
|
256
|
-
contractAddress: submittedMintRequest.contractAddress
|
|
257
|
-
}
|
|
258
|
-
}
|
|
259
|
-
});
|
|
260
|
-
if (existingAsset && (existingAsset.lastImtblZkevmMintRequestUpdatedId === null || existingAsset.lastImtblZkevmMintRequestUpdatedId < submittedMintRequest.imtblZkevmMintRequestUpdatedId)) {
|
|
261
|
-
await client.imAssets.update({
|
|
262
|
-
where: {
|
|
263
|
-
im_assets_uindex: {
|
|
264
|
-
assetId: submittedMintRequest.assetId,
|
|
265
|
-
contractAddress: submittedMintRequest.contractAddress
|
|
266
|
-
}
|
|
267
|
-
},
|
|
268
|
-
data: {
|
|
269
|
-
ownerAddress: submittedMintRequest.ownerAddress,
|
|
270
|
-
tokenId: submittedMintRequest.tokenId,
|
|
271
|
-
mintingStatus: submittedMintRequest.status,
|
|
272
|
-
metadataId: submittedMintRequest.metadataId,
|
|
273
|
-
lastImtblZkevmMintRequestUpdatedId: submittedMintRequest.imtblZkevmMintRequestUpdatedId,
|
|
274
|
-
error: submittedMintRequest.error,
|
|
275
|
-
amount: submittedMintRequest.amount || null
|
|
276
|
-
}
|
|
277
|
-
});
|
|
278
|
-
} else if (!existingAsset) {
|
|
279
|
-
await client.imAssets.create({
|
|
280
|
-
data: {
|
|
281
|
-
assetId: submittedMintRequest.assetId,
|
|
282
|
-
contractAddress: submittedMintRequest.contractAddress,
|
|
283
|
-
ownerAddress: submittedMintRequest.ownerAddress,
|
|
284
|
-
tokenId: submittedMintRequest.tokenId,
|
|
285
|
-
mintingStatus: submittedMintRequest.status,
|
|
286
|
-
metadataId: submittedMintRequest.metadataId,
|
|
287
|
-
lastImtblZkevmMintRequestUpdatedId: submittedMintRequest.imtblZkevmMintRequestUpdatedId,
|
|
288
|
-
error: submittedMintRequest.error,
|
|
289
|
-
amount: submittedMintRequest.amount || null
|
|
290
|
-
}
|
|
291
|
-
});
|
|
292
|
-
}
|
|
293
|
-
},
|
|
294
|
-
updateMintingStatusToSubmissionFailed: async (ids) => {
|
|
295
|
-
await client.imAssets.updateMany({
|
|
296
|
-
where: {
|
|
297
|
-
id: {
|
|
298
|
-
in: ids
|
|
299
|
-
}
|
|
300
|
-
},
|
|
301
|
-
data: {
|
|
302
|
-
mintingStatus: "submission_failed"
|
|
303
|
-
}
|
|
304
|
-
});
|
|
305
|
-
},
|
|
306
|
-
markAsConflict: async (assetIds, contractAddress) => {
|
|
307
|
-
await client.imAssets.updateMany({
|
|
308
|
-
where: {
|
|
309
|
-
assetId: {
|
|
310
|
-
in: assetIds
|
|
311
|
-
// Targets assets where assetId is in the provided list
|
|
312
|
-
},
|
|
313
|
-
contractAddress
|
|
314
|
-
// Additional condition for contract address
|
|
315
|
-
},
|
|
316
|
-
data: {
|
|
317
|
-
mintingStatus: "conflicting"
|
|
318
|
-
// Set the new status
|
|
319
|
-
}
|
|
320
|
-
});
|
|
321
|
-
},
|
|
322
|
-
resetMintingStatus: async (ids) => {
|
|
323
|
-
await client.imAssets.updateMany({
|
|
324
|
-
where: {
|
|
325
|
-
id: {
|
|
326
|
-
in: ids
|
|
327
|
-
// Condition to match ids
|
|
328
|
-
}
|
|
329
|
-
},
|
|
330
|
-
data: {
|
|
331
|
-
mintingStatus: null
|
|
332
|
-
// Setting minting_status to null
|
|
333
|
-
}
|
|
334
|
-
});
|
|
335
|
-
},
|
|
336
|
-
// this method is not concurrency safe
|
|
337
|
-
markForRetry: async (ids) => {
|
|
338
|
-
const assets = await client.imAssets.findMany({
|
|
339
|
-
where: {
|
|
340
|
-
id: {
|
|
341
|
-
in: ids
|
|
342
|
-
}
|
|
343
|
-
},
|
|
344
|
-
select: {
|
|
345
|
-
id: true,
|
|
346
|
-
triedCount: true
|
|
347
|
-
// Assuming the field is named triedCount
|
|
348
|
-
}
|
|
349
|
-
});
|
|
350
|
-
for (const asset of assets) {
|
|
351
|
-
await client.imAssets.update({
|
|
352
|
-
where: {
|
|
353
|
-
id: asset.id
|
|
354
|
-
},
|
|
355
|
-
data: {
|
|
356
|
-
mintingStatus: null,
|
|
357
|
-
triedCount: asset.triedCount + 1
|
|
358
|
-
}
|
|
359
|
-
});
|
|
360
|
-
}
|
|
361
|
-
},
|
|
362
|
-
getMintingRequest: async (contractAddress, referenceId) => {
|
|
363
|
-
const asset = await client.imAssets.findFirst({
|
|
364
|
-
where: {
|
|
365
|
-
contractAddress,
|
|
366
|
-
assetId: referenceId
|
|
367
|
-
}
|
|
368
|
-
});
|
|
369
|
-
if (!asset) {
|
|
370
|
-
return null;
|
|
371
|
-
}
|
|
372
|
-
return {
|
|
373
|
-
asset_id: asset.assetId,
|
|
374
|
-
contract_address: asset.contractAddress,
|
|
375
|
-
id: asset.id,
|
|
376
|
-
metadata: asset.metadata ? JSON.parse(asset.metadata) : null,
|
|
377
|
-
owner_address: asset.ownerAddress,
|
|
378
|
-
tried_count: asset.triedCount,
|
|
379
|
-
wallet_address: asset.ownerAddress,
|
|
380
|
-
amount: asset.amount || null
|
|
381
|
-
};
|
|
382
|
-
}
|
|
383
|
-
};
|
|
384
|
-
};
|
|
385
|
-
|
|
386
|
-
// src/minting.ts
|
|
387
|
-
var recordMint = async (mintingPersistence3, mintRequest) => {
|
|
388
|
-
trackRecordMint();
|
|
389
|
-
mintingPersistence3.recordMint(mintRequest);
|
|
390
|
-
};
|
|
391
|
-
var defaultMintingDelay = 1e3;
|
|
392
|
-
var submitMintingRequests = async (mintingPersistence3, blockchainDataSDKClient, {
|
|
393
|
-
defaultBatchSize = 1e3,
|
|
394
|
-
chainName = "imtbl-zkevm-testnet",
|
|
395
|
-
maxNumberOfTries = 3
|
|
396
|
-
}, logger = console, maxLoops = Infinity) => {
|
|
397
|
-
trackSubmitMintingRequests();
|
|
398
|
-
let mintingResponse;
|
|
399
|
-
let numberOfLoops = 0;
|
|
400
|
-
while (numberOfLoops++ < maxLoops) {
|
|
401
|
-
await new Promise((resolve) => {
|
|
402
|
-
setTimeout(resolve, defaultMintingDelay);
|
|
403
|
-
});
|
|
404
|
-
let batchSize = Math.min(
|
|
405
|
-
_optionalChain([mintingResponse, 'optionalAccess', _ => _.imx_remaining_mint_requests]) ? parseInt(mintingResponse.imx_remaining_mint_requests, 10) : defaultBatchSize,
|
|
406
|
-
defaultBatchSize
|
|
407
|
-
);
|
|
408
|
-
if (batchSize === 0 && mintingResponse && new Date(mintingResponse.imx_mint_requests_limit_reset) > /* @__PURE__ */ new Date()) {
|
|
409
|
-
logger.info(
|
|
410
|
-
`minting limit reached, waiting for reset at ${_optionalChain([mintingResponse, 'optionalAccess', _2 => _2.imx_mint_requests_limit_reset])}`
|
|
411
|
-
);
|
|
412
|
-
continue;
|
|
413
|
-
}
|
|
414
|
-
if (batchSize === 0) {
|
|
415
|
-
logger.info(
|
|
416
|
-
`minting limit has been reset, use default batch size: ${defaultBatchSize}`
|
|
417
|
-
);
|
|
418
|
-
mintingResponse = void 0;
|
|
419
|
-
batchSize = defaultBatchSize;
|
|
420
|
-
}
|
|
421
|
-
const pendingMints = await mintingPersistence3.getNextBatchForSubmission(
|
|
422
|
-
batchSize
|
|
423
|
-
);
|
|
424
|
-
if (pendingMints.length === 0) {
|
|
425
|
-
logger.info("no assets to mint");
|
|
426
|
-
continue;
|
|
427
|
-
}
|
|
428
|
-
const chunkedAssets = pendingMints.sort(
|
|
429
|
-
(a, b) => a.contract_address > b.contract_address ? 1 : -1
|
|
430
|
-
).reduce((acc, row) => {
|
|
431
|
-
if (acc.length === 0) {
|
|
432
|
-
return [{ contractAddress: row.contract_address, assets: [row] }];
|
|
433
|
-
}
|
|
434
|
-
const lastBatch = acc[acc.length - 1];
|
|
435
|
-
if (lastBatch.contractAddress === row.contract_address && lastBatch.assets.length < 100) {
|
|
436
|
-
return [...acc.slice(0, -1), { ...lastBatch, assets: [...lastBatch.assets, row] }];
|
|
437
|
-
}
|
|
438
|
-
return [...acc, { contractAddress: row.contract_address, assets: [row] }];
|
|
439
|
-
}, []);
|
|
440
|
-
const mintingResults = await Promise.allSettled(
|
|
441
|
-
chunkedAssets.map(
|
|
442
|
-
async ({ contractAddress, assets }) => {
|
|
443
|
-
const mintingRequest = {
|
|
444
|
-
chainName,
|
|
445
|
-
contractAddress,
|
|
446
|
-
createMintRequestRequest: {
|
|
447
|
-
assets: assets.map((row) => ({
|
|
448
|
-
reference_id: row.asset_id,
|
|
449
|
-
owner_address: row.owner_address,
|
|
450
|
-
metadata: row.metadata,
|
|
451
|
-
token_id: row.token_id,
|
|
452
|
-
amount: row.amount ? `${row.amount}` : null
|
|
453
|
-
}))
|
|
454
|
-
}
|
|
455
|
-
};
|
|
456
|
-
try {
|
|
457
|
-
const response = await blockchainDataSDKClient.createMintRequest(
|
|
458
|
-
mintingRequest
|
|
459
|
-
);
|
|
460
|
-
logger.info(
|
|
461
|
-
`mintingResponse: ${JSON.stringify(response, null, 2)}`
|
|
462
|
-
);
|
|
463
|
-
await mintingPersistence3.updateMintingStatusToSubmitted(
|
|
464
|
-
assets.map(({ id }) => id)
|
|
465
|
-
);
|
|
466
|
-
return response;
|
|
467
|
-
} catch (e) {
|
|
468
|
-
logger.error(e);
|
|
469
|
-
trackError(e);
|
|
470
|
-
if (e.code === "CONFLICT_ERROR" && _optionalChain([e, 'access', _3 => _3.details, 'optionalAccess', _4 => _4.id]) === "reference_id") {
|
|
471
|
-
try {
|
|
472
|
-
await mintingPersistence3.markAsConflict(
|
|
473
|
-
e.details.values,
|
|
474
|
-
contractAddress
|
|
475
|
-
);
|
|
476
|
-
await mintingPersistence3.resetMintingStatus(
|
|
477
|
-
assets.map(({ id }) => id).filter((id) => !e.details.values.includes(id))
|
|
478
|
-
);
|
|
479
|
-
} catch (e2) {
|
|
480
|
-
logger.error(e2);
|
|
481
|
-
trackError(e);
|
|
482
|
-
}
|
|
483
|
-
} else {
|
|
484
|
-
const { assetsToRetry, assetsExceededMaxNumberOfTries } = assets.reduce(
|
|
485
|
-
(acc, { tried_count = 0, id }) => {
|
|
486
|
-
if (tried_count < maxNumberOfTries) {
|
|
487
|
-
acc.assetsToRetry.push(id);
|
|
488
|
-
} else {
|
|
489
|
-
acc.assetsExceededMaxNumberOfTries.push(id);
|
|
490
|
-
}
|
|
491
|
-
return acc;
|
|
492
|
-
},
|
|
493
|
-
{
|
|
494
|
-
assetsToRetry: [],
|
|
495
|
-
assetsExceededMaxNumberOfTries: []
|
|
496
|
-
}
|
|
497
|
-
);
|
|
498
|
-
await mintingPersistence3.markForRetry(
|
|
499
|
-
assetsToRetry
|
|
500
|
-
);
|
|
501
|
-
await mintingPersistence3.updateMintingStatusToSubmissionFailed(
|
|
502
|
-
assetsExceededMaxNumberOfTries
|
|
503
|
-
);
|
|
504
|
-
}
|
|
505
|
-
return e;
|
|
506
|
-
}
|
|
507
|
-
}
|
|
508
|
-
)
|
|
509
|
-
);
|
|
510
|
-
mintingResponse = _optionalChain([mintingResults, 'access', _5 => _5.reverse, 'call', _6 => _6(), 'access', _7 => _7.find, 'call', _8 => _8(
|
|
511
|
-
(r) => r.status === "fulfilled"
|
|
512
|
-
), 'optionalAccess', _9 => _9.value]);
|
|
513
|
-
}
|
|
514
|
-
};
|
|
515
|
-
var processMint = async (mintingPersistence3, event, logger = console) => {
|
|
516
|
-
trackProcessMint();
|
|
517
|
-
if (event.event_name !== "imtbl_zkevm_mint_request_updated") {
|
|
518
|
-
logger.info(
|
|
519
|
-
`${event.event_name} is not imtbl_zkevm_mint_request_updated, skip.`
|
|
520
|
-
);
|
|
521
|
-
return;
|
|
522
|
-
}
|
|
523
|
-
const referenceId = event.data.reference_id;
|
|
524
|
-
if (!referenceId) {
|
|
525
|
-
throw new Error("reference_id not found in webhook event");
|
|
526
|
-
}
|
|
527
|
-
const contractAddress = event.data.contract_address;
|
|
528
|
-
if (!contractAddress) {
|
|
529
|
-
throw new Error("contract_address not found in webhook event");
|
|
530
|
-
}
|
|
531
|
-
if (event.data.status === "failed") {
|
|
532
|
-
logger.error(`mint failed: ${JSON.stringify(event.data, null, 2)}`);
|
|
533
|
-
}
|
|
534
|
-
const mintReq = await mintingPersistence3.getMintingRequest(
|
|
535
|
-
contractAddress,
|
|
536
|
-
referenceId
|
|
537
|
-
);
|
|
538
|
-
if (!mintReq) {
|
|
539
|
-
logger.info(
|
|
540
|
-
`minting request not found in the database, ${JSON.stringify(event.data)}`
|
|
541
|
-
);
|
|
542
|
-
}
|
|
543
|
-
const ownerAddress = _optionalChain([mintReq, 'optionalAccess', _10 => _10.wallet_address]) || event.data.owner_address;
|
|
544
|
-
if (!ownerAddress) {
|
|
545
|
-
logger.error("owner_address missing");
|
|
546
|
-
throw new Error("owner_address missing");
|
|
547
|
-
}
|
|
548
|
-
await mintingPersistence3.syncMintingStatus({
|
|
549
|
-
tokenId: event.data.token_id,
|
|
550
|
-
status: event.data.status,
|
|
551
|
-
assetId: referenceId,
|
|
552
|
-
contractAddress,
|
|
553
|
-
ownerAddress,
|
|
554
|
-
metadataId: event.data.metadata_id,
|
|
555
|
-
imtblZkevmMintRequestUpdatedId: event.event_id,
|
|
556
|
-
error: event.data.error ? JSON.stringify(event.data.error) : null,
|
|
557
|
-
amount: event.data.amount || null
|
|
558
|
-
});
|
|
559
|
-
};
|
|
560
|
-
|
|
561
|
-
// src/index.ts
|
|
562
|
-
var noopHandlers = {
|
|
563
|
-
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
564
|
-
zkevmMintRequestUpdated: async (event) => {
|
|
565
|
-
}
|
|
566
|
-
};
|
|
567
|
-
var MintingBackendModule = class {
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
constructor(config) {
|
|
573
|
-
this.baseConfig = config.baseConfig;
|
|
574
|
-
this.persistence = config.persistence;
|
|
575
|
-
this.logger = config.logger || console;
|
|
576
|
-
this.blockchainDataClient = new (0, _blockchaindata.BlockchainData)({
|
|
577
|
-
baseConfig: config.baseConfig
|
|
578
|
-
});
|
|
579
|
-
_metrics.setEnvironment.call(void 0, this.baseConfig.environment);
|
|
580
|
-
if (this.baseConfig.publishableKey) {
|
|
581
|
-
_metrics.setPublishableApiKey.call(void 0, this.baseConfig.publishableKey);
|
|
582
|
-
}
|
|
583
|
-
}
|
|
584
|
-
async recordMint(mintRequest) {
|
|
585
|
-
await recordMint(this.persistence, mintRequest);
|
|
586
|
-
}
|
|
587
|
-
async submitMintingRequests(config) {
|
|
588
|
-
await submitMintingRequests(
|
|
589
|
-
this.persistence,
|
|
590
|
-
this.blockchainDataClient,
|
|
591
|
-
config
|
|
592
|
-
);
|
|
593
|
-
}
|
|
594
|
-
async processMint(body, otherHandlers = noopHandlers) {
|
|
595
|
-
await _webhook.handle.call(void 0, body, this.baseConfig.environment, {
|
|
596
|
-
zkevmMintRequestUpdated: async (event) => {
|
|
597
|
-
await processMint(this.persistence, event, this.logger);
|
|
598
|
-
if (otherHandlers.zkevmMintRequestUpdated) {
|
|
599
|
-
otherHandlers.zkevmMintRequestUpdated(event);
|
|
600
|
-
}
|
|
601
|
-
}
|
|
602
|
-
});
|
|
603
|
-
}
|
|
604
|
-
};
|
|
605
|
-
if (typeof process !== "undefined" && process.on) {
|
|
606
|
-
try {
|
|
607
|
-
process.on("uncaughtExceptionMonitor", trackUncaughtException);
|
|
608
|
-
} catch (e10) {
|
|
609
|
-
}
|
|
610
|
-
}
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
exports.MintingBackendModule = MintingBackendModule; exports.mintingPersistencePg = mintingPersistence; exports.mintingPersistencePrismaSqlite = mintingPersistence2; exports.processMint = processMint; exports.recordMint = recordMint; exports.submitMintingRequests = submitMintingRequests;
|
|
56
|
+
`,[t,s])).rows[0]||null});var U=e=>(h(),{recordMint:async t=>{if(!await e.imAssets.upsert({where:{im_assets_uindex:{assetId:t.asset_id,contractAddress:t.contract_address}},update:{},create:{assetId:t.asset_id,contractAddress:t.contract_address,ownerAddress:t.owner_address,metadata:JSON.stringify(t.metadata),amount:t.amount||null,tokenId:t.token_id||null}}))throw new Error("Duplicated mint")},getNextBatchForSubmission:async t=>{let a=(await e.imAssets.findMany({where:{mintingStatus:null},take:t})).map(n=>n.id);return await e.imAssets.updateMany({where:{id:{in:a}},data:{mintingStatus:"submitting"}}),(await e.imAssets.findMany({where:{id:{in:a}}})).map(n=>({id:n.id,contract_address:n.contractAddress,wallet_address:n.ownerAddress,asset_id:n.assetId,metadata:n.metadata?JSON.parse(n.metadata):null,owner_address:n.ownerAddress,tried_count:n.triedCount,amount:n.amount||null,token_id:n.tokenId||null}))},updateMintingStatusToSubmitted:async t=>{await e.imAssets.updateMany({where:{id:{in:t}},data:{mintingStatus:"submitted"}})},syncMintingStatus:async t=>{let s=await e.imAssets.findUnique({where:{im_assets_uindex:{assetId:t.assetId,contractAddress:t.contractAddress}}});s&&(s.lastImtblZkevmMintRequestUpdatedId===null||s.lastImtblZkevmMintRequestUpdatedId<t.imtblZkevmMintRequestUpdatedId)?await e.imAssets.update({where:{im_assets_uindex:{assetId:t.assetId,contractAddress:t.contractAddress}},data:{ownerAddress:t.ownerAddress,tokenId:t.tokenId,mintingStatus:t.status,metadataId:t.metadataId,lastImtblZkevmMintRequestUpdatedId:t.imtblZkevmMintRequestUpdatedId,error:t.error,amount:t.amount||null}}):s||await e.imAssets.create({data:{assetId:t.assetId,contractAddress:t.contractAddress,ownerAddress:t.ownerAddress,tokenId:t.tokenId,mintingStatus:t.status,metadataId:t.metadataId,lastImtblZkevmMintRequestUpdatedId:t.imtblZkevmMintRequestUpdatedId,error:t.error,amount:t.amount||null}})},updateMintingStatusToSubmissionFailed:async t=>{await e.imAssets.updateMany({where:{id:{in:t}},data:{mintingStatus:"submission_failed"}})},markAsConflict:async(t,s)=>{await e.imAssets.updateMany({where:{assetId:{in:t},contractAddress:s},data:{mintingStatus:"conflicting"}})},resetMintingStatus:async t=>{await e.imAssets.updateMany({where:{id:{in:t}},data:{mintingStatus:null}})},markForRetry:async t=>{let s=await e.imAssets.findMany({where:{id:{in:t}},select:{id:!0,triedCount:!0}});for(let a of s)await e.imAssets.update({where:{id:a.id},data:{mintingStatus:null,triedCount:a.triedCount+1}})},getMintingRequest:async(t,s)=>{let a=await e.imAssets.findFirst({where:{contractAddress:t,assetId:s}});return a?{asset_id:a.assetId,contract_address:a.contractAddress,id:a.id,metadata:a.metadata?JSON.parse(a.metadata):null,owner_address:a.ownerAddress,tried_count:a.triedCount,wallet_address:a.ownerAddress,amount:a.amount||null}:null}});var R=async(e,t)=>{S(),e.recordMint(t)},O=1e3,b= exports.submitMintingRequests =async(e,t,{defaultBatchSize:s=1e3,chainName:a="imtbl-zkevm-testnet",maxNumberOfTries:l=3},n=console,g=1/0)=>{I();let m,P=0;for(;P++<g;){await new Promise(r=>{setTimeout(r,O)});let p=Math.min(_optionalChain([m, 'optionalAccess', _2 => _2.imx_remaining_mint_requests])?parseInt(m.imx_remaining_mint_requests,10):s,s);if(p===0&&m&&new Date(m.imx_mint_requests_limit_reset)>new Date){n.info(`minting limit reached, waiting for reset at ${_optionalChain([m, 'optionalAccess', _3 => _3.imx_mint_requests_limit_reset])}`);continue}p===0&&(n.info(`minting limit has been reset, use default batch size: ${s}`),m=void 0,p=s);let y=await e.getNextBatchForSubmission(p);if(y.length===0){n.info("no assets to mint");continue}let N=y.sort((r,d)=>r.contract_address>d.contract_address?1:-1).reduce((r,d)=>{if(r.length===0)return[{contractAddress:d.contract_address,assets:[d]}];let _=r[r.length-1];return _.contractAddress===d.contract_address&&_.assets.length<100?[...r.slice(0,-1),{..._,assets:[..._.assets,d]}]:[...r,{contractAddress:d.contract_address,assets:[d]}]},[]);m=await _asyncOptionalChain([(await Promise.allSettled(N.map(async({contractAddress:r,assets:d})=>{let _={chainName:a,contractAddress:r,createMintRequestRequest:{assets:d.map(i=>({reference_id:i.asset_id,owner_address:i.owner_address,metadata:i.metadata,token_id:i.token_id,amount:i.amount?`${i.amount}`:null}))}};try{let i=await t.createMintRequest(_);return n.info(`mintingResponse: ${JSON.stringify(i,null,2)}`),await e.updateMintingStatusToSubmitted(d.map(({id:o})=>o)),i}catch(i){if(n.error(i),w(i),i.code==="CONFLICT_ERROR"&&_optionalChain([i, 'access', _4 => _4.details, 'optionalAccess', _5 => _5.id])==="reference_id")try{await e.markAsConflict(i.details.values,r),await e.resetMintingStatus(d.map(({id:o})=>o).filter(o=>!i.details.values.includes(o)))}catch(o){n.error(o),w(i)}else{let{assetsToRetry:o,assetsExceededMaxNumberOfTries:x}=d.reduce((f,{tried_count:$=0,id:k})=>($<l?f.assetsToRetry.push(k):f.assetsExceededMaxNumberOfTries.push(k),f),{assetsToRetry:[],assetsExceededMaxNumberOfTries:[]});await e.markForRetry(o),await e.updateMintingStatusToSubmissionFailed(x)}return i}}))), 'access', async _6 => _6.reverse, 'call', async _7 => _7(), 'access', async _8 => _8.find, 'call', async _9 => _9(r=>r.status==="fulfilled"), 'optionalAccess', async _10 => _10.value])}},T= exports.processMint =async(e,t,s=console)=>{if(A(),t.event_name!=="imtbl_zkevm_mint_request_updated"){s.info(`${t.event_name} is not imtbl_zkevm_mint_request_updated, skip.`);return}let a=t.data.reference_id;if(!a)throw new Error("reference_id not found in webhook event");let l=t.data.contract_address;if(!l)throw new Error("contract_address not found in webhook event");t.data.status==="failed"&&s.error(`mint failed: ${JSON.stringify(t.data,null,2)}`);let n=await e.getMintingRequest(l,a);n||s.info(`minting request not found in the database, ${JSON.stringify(t.data)}`);let g=_optionalChain([n, 'optionalAccess', _11 => _11.wallet_address])||t.data.owner_address;if(!g)throw s.error("owner_address missing"),new Error("owner_address missing");await e.syncMintingStatus({tokenId:t.data.token_id,status:t.data.status,assetId:a,contractAddress:l,ownerAddress:g,metadataId:t.data.metadata_id,imtblZkevmMintRequestUpdatedId:t.event_id,error:t.data.error?JSON.stringify(t.data.error):null,amount:t.data.amount||null})};var z={zkevmMintRequestUpdated:async e=>{}},C= exports.MintingBackendModule =class{constructor(t){this.baseConfig=t.baseConfig,this.persistence=t.persistence,this.logger=t.logger||console,this.blockchainDataClient=new (0, _blockchaindata.BlockchainData)({baseConfig:t.baseConfig}),_metrics.setEnvironment.call(void 0, this.baseConfig.environment),this.baseConfig.publishableKey&&_metrics.setPublishableApiKey.call(void 0, this.baseConfig.publishableKey)}async recordMint(t){await R(this.persistence,t)}async submitMintingRequests(t){await b(this.persistence,this.blockchainDataClient,t)}async processMint(t,s=z){await _webhook.handle.call(void 0, t,this.baseConfig.environment,{zkevmMintRequestUpdated:async a=>{await T(this.persistence,a,this.logger),s.zkevmMintRequestUpdated&&s.zkevmMintRequestUpdated(a)}})}};if(typeof process<"u"&&process.on)try{process.on("uncaughtExceptionMonitor",E)}catch (e9){}exports.MintingBackendModule = C; exports.mintingPersistencePg = q; exports.mintingPersistencePrismaSqlite = U; exports.processMint = T; exports.recordMint = R; exports.submitMintingRequests = b;
|
package/dist/index.js
CHANGED
|
@@ -1,86 +1,7 @@
|
|
|
1
|
-
|
|
2
|
-
import { BlockchainData } from "@imtbl/blockchain-data";
|
|
3
|
-
import { handle } from "@imtbl/webhook";
|
|
4
|
-
import { setEnvironment, setPublishableApiKey } from "@imtbl/metrics";
|
|
5
|
-
|
|
6
|
-
// src/analytics/index.ts
|
|
7
|
-
import { track } from "@imtbl/metrics";
|
|
8
|
-
var moduleName = "minting_backend_sdk";
|
|
9
|
-
var trackInitializePersistencePG = () => {
|
|
10
|
-
try {
|
|
11
|
-
track(moduleName, "initializePersistencePG");
|
|
12
|
-
} catch {
|
|
13
|
-
}
|
|
14
|
-
};
|
|
15
|
-
var trackInitializePersistencePrismaSqlite = () => {
|
|
16
|
-
try {
|
|
17
|
-
track(moduleName, "initializePersistencePrismaSqlite");
|
|
18
|
-
} catch {
|
|
19
|
-
}
|
|
20
|
-
};
|
|
21
|
-
var trackSubmitMintingRequests = () => {
|
|
22
|
-
try {
|
|
23
|
-
track(moduleName, "submitMintingRequests");
|
|
24
|
-
} catch {
|
|
25
|
-
}
|
|
26
|
-
};
|
|
27
|
-
var trackProcessMint = () => {
|
|
28
|
-
try {
|
|
29
|
-
track(moduleName, "processMint");
|
|
30
|
-
} catch {
|
|
31
|
-
}
|
|
32
|
-
};
|
|
33
|
-
var trackRecordMint = () => {
|
|
34
|
-
try {
|
|
35
|
-
track(moduleName, "recordMint");
|
|
36
|
-
} catch {
|
|
37
|
-
}
|
|
38
|
-
};
|
|
39
|
-
var trackError = (error) => {
|
|
40
|
-
try {
|
|
41
|
-
track(moduleName, "error", {
|
|
42
|
-
name: error.name,
|
|
43
|
-
message: error.message
|
|
44
|
-
});
|
|
45
|
-
} catch {
|
|
46
|
-
}
|
|
47
|
-
};
|
|
48
|
-
var trackUncaughtException = (error, origin) => {
|
|
49
|
-
try {
|
|
50
|
-
track(moduleName, "error", {
|
|
51
|
-
name: error.name,
|
|
52
|
-
message: error.message,
|
|
53
|
-
origin
|
|
54
|
-
});
|
|
55
|
-
} catch {
|
|
56
|
-
}
|
|
57
|
-
};
|
|
58
|
-
|
|
59
|
-
// src/persistence/pg/postgres.ts
|
|
60
|
-
var mintingPersistence = (client) => {
|
|
61
|
-
trackInitializePersistencePG();
|
|
62
|
-
return {
|
|
63
|
-
recordMint: async (request) => {
|
|
64
|
-
const r = await client.query(
|
|
65
|
-
`
|
|
1
|
+
import{BlockchainData as v}from"@imtbl/blockchain-data";import{handle as D}from"@imtbl/webhook";import{setEnvironment as L,setPublishableApiKey as F}from"@imtbl/metrics";import{track as c}from"@imtbl/metrics";var u="minting_backend_sdk",M=()=>{try{c(u,"initializePersistencePG")}catch{}},h=()=>{try{c(u,"initializePersistencePrismaSqlite")}catch{}},I=()=>{try{c(u,"submitMintingRequests")}catch{}},A=()=>{try{c(u,"processMint")}catch{}},S=()=>{try{c(u,"recordMint")}catch{}},w=e=>{try{c(u,"error",{name:e.name,message:e.message})}catch{}},E=(e,t)=>{try{c(u,"error",{name:e.name,message:e.message,origin:t})}catch{}};var q=e=>(M(),{recordMint:async t=>{if((await e.query(`
|
|
66
2
|
INSERT INTO im_assets (asset_id, contract_address, owner_address, metadata, amount, token_id)
|
|
67
3
|
VALUES ($1, $2, $3, $4, $5, $6) ON CONFLICT (asset_id, contract_address) DO NOTHING;
|
|
68
|
-
`,
|
|
69
|
-
[
|
|
70
|
-
request.asset_id,
|
|
71
|
-
request.contract_address,
|
|
72
|
-
request.owner_address,
|
|
73
|
-
request.metadata,
|
|
74
|
-
request.amount,
|
|
75
|
-
request.token_id
|
|
76
|
-
]
|
|
77
|
-
);
|
|
78
|
-
if (r.rowCount === 0) {
|
|
79
|
-
throw new Error("Duplicated mint");
|
|
80
|
-
}
|
|
81
|
-
},
|
|
82
|
-
getNextBatchForSubmission: async (limit) => {
|
|
83
|
-
const res = await client.query(`
|
|
4
|
+
`,[t.asset_id,t.contract_address,t.owner_address,t.metadata,t.amount,t.token_id])).rowCount===0)throw new Error("Duplicated mint")},getNextBatchForSubmission:async t=>(await e.query(`
|
|
84
5
|
WITH limited_assets AS (
|
|
85
6
|
SELECT id
|
|
86
7
|
FROM im_assets
|
|
@@ -93,16 +14,9 @@ var mintingPersistence = (client) => {
|
|
|
93
14
|
WHERE minting_status IS NULL
|
|
94
15
|
AND id IN (SELECT id FROM limited_assets)
|
|
95
16
|
RETURNING *;
|
|
96
|
-
`,
|
|
97
|
-
return res.rows;
|
|
98
|
-
},
|
|
99
|
-
updateMintingStatusToSubmitted: async (ids) => {
|
|
100
|
-
await client.query(`
|
|
17
|
+
`,[t])).rows,updateMintingStatusToSubmitted:async t=>{await e.query(`
|
|
101
18
|
UPDATE im_assets SET minting_status = $2 WHERE id = ANY($1);
|
|
102
|
-
`,
|
|
103
|
-
},
|
|
104
|
-
syncMintingStatus: async (submittedMintRequest) => {
|
|
105
|
-
await client.query(`
|
|
19
|
+
`,[t,"submitted"])},syncMintingStatus:async t=>{await e.query(`
|
|
106
20
|
INSERT INTO im_assets (
|
|
107
21
|
asset_id,
|
|
108
22
|
contract_address,
|
|
@@ -125,494 +39,18 @@ var mintingPersistence = (client) => {
|
|
|
125
39
|
im_assets.last_imtbl_zkevm_mint_request_updated_id < $7 OR
|
|
126
40
|
im_assets.last_imtbl_zkevm_mint_request_updated_id is null
|
|
127
41
|
);
|
|
128
|
-
`,
|
|
129
|
-
submittedMintRequest.assetId,
|
|
130
|
-
submittedMintRequest.contractAddress,
|
|
131
|
-
submittedMintRequest.ownerAddress,
|
|
132
|
-
submittedMintRequest.tokenId,
|
|
133
|
-
submittedMintRequest.status,
|
|
134
|
-
submittedMintRequest.metadataId,
|
|
135
|
-
submittedMintRequest.imtblZkevmMintRequestUpdatedId,
|
|
136
|
-
submittedMintRequest.error,
|
|
137
|
-
submittedMintRequest.amount
|
|
138
|
-
]);
|
|
139
|
-
},
|
|
140
|
-
markAsConflict: async (assetIds, contractAddress) => {
|
|
141
|
-
await client.query(`
|
|
42
|
+
`,[t.assetId,t.contractAddress,t.ownerAddress,t.tokenId,t.status,t.metadataId,t.imtblZkevmMintRequestUpdatedId,t.error,t.amount])},markAsConflict:async(t,s)=>{await e.query(`
|
|
142
43
|
UPDATE im_assets
|
|
143
44
|
SET minting_status = 'conflicting'
|
|
144
45
|
WHERE asset_id = ANY($1)
|
|
145
46
|
AND contract_address = $2;
|
|
146
|
-
`,
|
|
147
|
-
},
|
|
148
|
-
resetMintingStatus: async (ids) => {
|
|
149
|
-
await client.query(`
|
|
47
|
+
`,[t,s])},resetMintingStatus:async t=>{await e.query(`
|
|
150
48
|
UPDATE im_assets SET minting_status = null WHERE id = ANY($1);
|
|
151
|
-
`,
|
|
152
|
-
},
|
|
153
|
-
markForRetry: async (ids) => {
|
|
154
|
-
await client.query(`
|
|
49
|
+
`,[t])},markForRetry:async t=>{await e.query(`
|
|
155
50
|
UPDATE im_assets
|
|
156
51
|
SET minting_status = null, tried_count = tried_count + 1 WHERE id = ANY($1);
|
|
157
|
-
`,
|
|
158
|
-
},
|
|
159
|
-
updateMintingStatusToSubmissionFailed: async (ids) => {
|
|
160
|
-
await client.query(`
|
|
52
|
+
`,[t])},updateMintingStatusToSubmissionFailed:async t=>{await e.query(`
|
|
161
53
|
UPDATE im_assets SET minting_status = 'submission_failed' WHERE id = ANY($1);
|
|
162
|
-
`,
|
|
163
|
-
},
|
|
164
|
-
getMintingRequest: async (contractAddress, referenceId) => {
|
|
165
|
-
const res = await client.query(`
|
|
54
|
+
`,[t])},getMintingRequest:async(t,s)=>(await e.query(`
|
|
166
55
|
SELECT * FROM im_assets WHERE contract_address = $1 and asset_id = $2;
|
|
167
|
-
`, [contractAddress,
|
|
168
|
-
return res.rows[0] || null;
|
|
169
|
-
}
|
|
170
|
-
};
|
|
171
|
-
};
|
|
172
|
-
|
|
173
|
-
// src/persistence/prismaSqlite/sqlite.ts
|
|
174
|
-
var mintingPersistence2 = (client) => {
|
|
175
|
-
trackInitializePersistencePrismaSqlite();
|
|
176
|
-
return {
|
|
177
|
-
recordMint: async (request) => {
|
|
178
|
-
const result = await client.imAssets.upsert({
|
|
179
|
-
where: {
|
|
180
|
-
im_assets_uindex: {
|
|
181
|
-
assetId: request.asset_id,
|
|
182
|
-
contractAddress: request.contract_address
|
|
183
|
-
}
|
|
184
|
-
},
|
|
185
|
-
update: {},
|
|
186
|
-
// Do nothing on conflict
|
|
187
|
-
create: {
|
|
188
|
-
assetId: request.asset_id,
|
|
189
|
-
contractAddress: request.contract_address,
|
|
190
|
-
ownerAddress: request.owner_address,
|
|
191
|
-
metadata: JSON.stringify(request.metadata),
|
|
192
|
-
// Serialize JSON metadata
|
|
193
|
-
amount: request.amount || null,
|
|
194
|
-
tokenId: request.token_id || null
|
|
195
|
-
}
|
|
196
|
-
});
|
|
197
|
-
if (!result) {
|
|
198
|
-
throw new Error("Duplicated mint");
|
|
199
|
-
}
|
|
200
|
-
},
|
|
201
|
-
// WARNING: this is NOT concurrency safe. Please only call this method one at a time.
|
|
202
|
-
getNextBatchForSubmission: async (limit) => {
|
|
203
|
-
const assets = await client.imAssets.findMany({
|
|
204
|
-
where: {
|
|
205
|
-
mintingStatus: null
|
|
206
|
-
},
|
|
207
|
-
take: limit
|
|
208
|
-
});
|
|
209
|
-
const assetIds = assets.map((asset) => asset.id);
|
|
210
|
-
await client.imAssets.updateMany({
|
|
211
|
-
where: {
|
|
212
|
-
id: {
|
|
213
|
-
in: assetIds
|
|
214
|
-
}
|
|
215
|
-
},
|
|
216
|
-
data: {
|
|
217
|
-
mintingStatus: "submitting"
|
|
218
|
-
}
|
|
219
|
-
});
|
|
220
|
-
const updatedAssets = await client.imAssets.findMany({
|
|
221
|
-
where: {
|
|
222
|
-
id: {
|
|
223
|
-
in: assetIds
|
|
224
|
-
}
|
|
225
|
-
}
|
|
226
|
-
});
|
|
227
|
-
return updatedAssets.map((asset) => ({
|
|
228
|
-
id: asset.id,
|
|
229
|
-
contract_address: asset.contractAddress,
|
|
230
|
-
wallet_address: asset.ownerAddress,
|
|
231
|
-
asset_id: asset.assetId,
|
|
232
|
-
metadata: asset.metadata ? JSON.parse(asset.metadata) : null,
|
|
233
|
-
owner_address: asset.ownerAddress,
|
|
234
|
-
tried_count: asset.triedCount,
|
|
235
|
-
amount: asset.amount || null,
|
|
236
|
-
token_id: asset.tokenId || null
|
|
237
|
-
}));
|
|
238
|
-
},
|
|
239
|
-
updateMintingStatusToSubmitted: async (ids) => {
|
|
240
|
-
await client.imAssets.updateMany({
|
|
241
|
-
where: {
|
|
242
|
-
id: {
|
|
243
|
-
in: ids
|
|
244
|
-
}
|
|
245
|
-
},
|
|
246
|
-
data: {
|
|
247
|
-
mintingStatus: "submitted"
|
|
248
|
-
}
|
|
249
|
-
});
|
|
250
|
-
},
|
|
251
|
-
syncMintingStatus: async (submittedMintRequest) => {
|
|
252
|
-
const existingAsset = await client.imAssets.findUnique({
|
|
253
|
-
where: {
|
|
254
|
-
im_assets_uindex: {
|
|
255
|
-
assetId: submittedMintRequest.assetId,
|
|
256
|
-
contractAddress: submittedMintRequest.contractAddress
|
|
257
|
-
}
|
|
258
|
-
}
|
|
259
|
-
});
|
|
260
|
-
if (existingAsset && (existingAsset.lastImtblZkevmMintRequestUpdatedId === null || existingAsset.lastImtblZkevmMintRequestUpdatedId < submittedMintRequest.imtblZkevmMintRequestUpdatedId)) {
|
|
261
|
-
await client.imAssets.update({
|
|
262
|
-
where: {
|
|
263
|
-
im_assets_uindex: {
|
|
264
|
-
assetId: submittedMintRequest.assetId,
|
|
265
|
-
contractAddress: submittedMintRequest.contractAddress
|
|
266
|
-
}
|
|
267
|
-
},
|
|
268
|
-
data: {
|
|
269
|
-
ownerAddress: submittedMintRequest.ownerAddress,
|
|
270
|
-
tokenId: submittedMintRequest.tokenId,
|
|
271
|
-
mintingStatus: submittedMintRequest.status,
|
|
272
|
-
metadataId: submittedMintRequest.metadataId,
|
|
273
|
-
lastImtblZkevmMintRequestUpdatedId: submittedMintRequest.imtblZkevmMintRequestUpdatedId,
|
|
274
|
-
error: submittedMintRequest.error,
|
|
275
|
-
amount: submittedMintRequest.amount || null
|
|
276
|
-
}
|
|
277
|
-
});
|
|
278
|
-
} else if (!existingAsset) {
|
|
279
|
-
await client.imAssets.create({
|
|
280
|
-
data: {
|
|
281
|
-
assetId: submittedMintRequest.assetId,
|
|
282
|
-
contractAddress: submittedMintRequest.contractAddress,
|
|
283
|
-
ownerAddress: submittedMintRequest.ownerAddress,
|
|
284
|
-
tokenId: submittedMintRequest.tokenId,
|
|
285
|
-
mintingStatus: submittedMintRequest.status,
|
|
286
|
-
metadataId: submittedMintRequest.metadataId,
|
|
287
|
-
lastImtblZkevmMintRequestUpdatedId: submittedMintRequest.imtblZkevmMintRequestUpdatedId,
|
|
288
|
-
error: submittedMintRequest.error,
|
|
289
|
-
amount: submittedMintRequest.amount || null
|
|
290
|
-
}
|
|
291
|
-
});
|
|
292
|
-
}
|
|
293
|
-
},
|
|
294
|
-
updateMintingStatusToSubmissionFailed: async (ids) => {
|
|
295
|
-
await client.imAssets.updateMany({
|
|
296
|
-
where: {
|
|
297
|
-
id: {
|
|
298
|
-
in: ids
|
|
299
|
-
}
|
|
300
|
-
},
|
|
301
|
-
data: {
|
|
302
|
-
mintingStatus: "submission_failed"
|
|
303
|
-
}
|
|
304
|
-
});
|
|
305
|
-
},
|
|
306
|
-
markAsConflict: async (assetIds, contractAddress) => {
|
|
307
|
-
await client.imAssets.updateMany({
|
|
308
|
-
where: {
|
|
309
|
-
assetId: {
|
|
310
|
-
in: assetIds
|
|
311
|
-
// Targets assets where assetId is in the provided list
|
|
312
|
-
},
|
|
313
|
-
contractAddress
|
|
314
|
-
// Additional condition for contract address
|
|
315
|
-
},
|
|
316
|
-
data: {
|
|
317
|
-
mintingStatus: "conflicting"
|
|
318
|
-
// Set the new status
|
|
319
|
-
}
|
|
320
|
-
});
|
|
321
|
-
},
|
|
322
|
-
resetMintingStatus: async (ids) => {
|
|
323
|
-
await client.imAssets.updateMany({
|
|
324
|
-
where: {
|
|
325
|
-
id: {
|
|
326
|
-
in: ids
|
|
327
|
-
// Condition to match ids
|
|
328
|
-
}
|
|
329
|
-
},
|
|
330
|
-
data: {
|
|
331
|
-
mintingStatus: null
|
|
332
|
-
// Setting minting_status to null
|
|
333
|
-
}
|
|
334
|
-
});
|
|
335
|
-
},
|
|
336
|
-
// this method is not concurrency safe
|
|
337
|
-
markForRetry: async (ids) => {
|
|
338
|
-
const assets = await client.imAssets.findMany({
|
|
339
|
-
where: {
|
|
340
|
-
id: {
|
|
341
|
-
in: ids
|
|
342
|
-
}
|
|
343
|
-
},
|
|
344
|
-
select: {
|
|
345
|
-
id: true,
|
|
346
|
-
triedCount: true
|
|
347
|
-
// Assuming the field is named triedCount
|
|
348
|
-
}
|
|
349
|
-
});
|
|
350
|
-
for (const asset of assets) {
|
|
351
|
-
await client.imAssets.update({
|
|
352
|
-
where: {
|
|
353
|
-
id: asset.id
|
|
354
|
-
},
|
|
355
|
-
data: {
|
|
356
|
-
mintingStatus: null,
|
|
357
|
-
triedCount: asset.triedCount + 1
|
|
358
|
-
}
|
|
359
|
-
});
|
|
360
|
-
}
|
|
361
|
-
},
|
|
362
|
-
getMintingRequest: async (contractAddress, referenceId) => {
|
|
363
|
-
const asset = await client.imAssets.findFirst({
|
|
364
|
-
where: {
|
|
365
|
-
contractAddress,
|
|
366
|
-
assetId: referenceId
|
|
367
|
-
}
|
|
368
|
-
});
|
|
369
|
-
if (!asset) {
|
|
370
|
-
return null;
|
|
371
|
-
}
|
|
372
|
-
return {
|
|
373
|
-
asset_id: asset.assetId,
|
|
374
|
-
contract_address: asset.contractAddress,
|
|
375
|
-
id: asset.id,
|
|
376
|
-
metadata: asset.metadata ? JSON.parse(asset.metadata) : null,
|
|
377
|
-
owner_address: asset.ownerAddress,
|
|
378
|
-
tried_count: asset.triedCount,
|
|
379
|
-
wallet_address: asset.ownerAddress,
|
|
380
|
-
amount: asset.amount || null
|
|
381
|
-
};
|
|
382
|
-
}
|
|
383
|
-
};
|
|
384
|
-
};
|
|
385
|
-
|
|
386
|
-
// src/minting.ts
|
|
387
|
-
var recordMint = async (mintingPersistence3, mintRequest) => {
|
|
388
|
-
trackRecordMint();
|
|
389
|
-
mintingPersistence3.recordMint(mintRequest);
|
|
390
|
-
};
|
|
391
|
-
var defaultMintingDelay = 1e3;
|
|
392
|
-
var submitMintingRequests = async (mintingPersistence3, blockchainDataSDKClient, {
|
|
393
|
-
defaultBatchSize = 1e3,
|
|
394
|
-
chainName = "imtbl-zkevm-testnet",
|
|
395
|
-
maxNumberOfTries = 3
|
|
396
|
-
}, logger = console, maxLoops = Infinity) => {
|
|
397
|
-
trackSubmitMintingRequests();
|
|
398
|
-
let mintingResponse;
|
|
399
|
-
let numberOfLoops = 0;
|
|
400
|
-
while (numberOfLoops++ < maxLoops) {
|
|
401
|
-
await new Promise((resolve) => {
|
|
402
|
-
setTimeout(resolve, defaultMintingDelay);
|
|
403
|
-
});
|
|
404
|
-
let batchSize = Math.min(
|
|
405
|
-
mintingResponse?.imx_remaining_mint_requests ? parseInt(mintingResponse.imx_remaining_mint_requests, 10) : defaultBatchSize,
|
|
406
|
-
defaultBatchSize
|
|
407
|
-
);
|
|
408
|
-
if (batchSize === 0 && mintingResponse && new Date(mintingResponse.imx_mint_requests_limit_reset) > /* @__PURE__ */ new Date()) {
|
|
409
|
-
logger.info(
|
|
410
|
-
`minting limit reached, waiting for reset at ${mintingResponse?.imx_mint_requests_limit_reset}`
|
|
411
|
-
);
|
|
412
|
-
continue;
|
|
413
|
-
}
|
|
414
|
-
if (batchSize === 0) {
|
|
415
|
-
logger.info(
|
|
416
|
-
`minting limit has been reset, use default batch size: ${defaultBatchSize}`
|
|
417
|
-
);
|
|
418
|
-
mintingResponse = void 0;
|
|
419
|
-
batchSize = defaultBatchSize;
|
|
420
|
-
}
|
|
421
|
-
const pendingMints = await mintingPersistence3.getNextBatchForSubmission(
|
|
422
|
-
batchSize
|
|
423
|
-
);
|
|
424
|
-
if (pendingMints.length === 0) {
|
|
425
|
-
logger.info("no assets to mint");
|
|
426
|
-
continue;
|
|
427
|
-
}
|
|
428
|
-
const chunkedAssets = pendingMints.sort(
|
|
429
|
-
(a, b) => a.contract_address > b.contract_address ? 1 : -1
|
|
430
|
-
).reduce((acc, row) => {
|
|
431
|
-
if (acc.length === 0) {
|
|
432
|
-
return [{ contractAddress: row.contract_address, assets: [row] }];
|
|
433
|
-
}
|
|
434
|
-
const lastBatch = acc[acc.length - 1];
|
|
435
|
-
if (lastBatch.contractAddress === row.contract_address && lastBatch.assets.length < 100) {
|
|
436
|
-
return [...acc.slice(0, -1), { ...lastBatch, assets: [...lastBatch.assets, row] }];
|
|
437
|
-
}
|
|
438
|
-
return [...acc, { contractAddress: row.contract_address, assets: [row] }];
|
|
439
|
-
}, []);
|
|
440
|
-
const mintingResults = await Promise.allSettled(
|
|
441
|
-
chunkedAssets.map(
|
|
442
|
-
async ({ contractAddress, assets }) => {
|
|
443
|
-
const mintingRequest = {
|
|
444
|
-
chainName,
|
|
445
|
-
contractAddress,
|
|
446
|
-
createMintRequestRequest: {
|
|
447
|
-
assets: assets.map((row) => ({
|
|
448
|
-
reference_id: row.asset_id,
|
|
449
|
-
owner_address: row.owner_address,
|
|
450
|
-
metadata: row.metadata,
|
|
451
|
-
token_id: row.token_id,
|
|
452
|
-
amount: row.amount ? `${row.amount}` : null
|
|
453
|
-
}))
|
|
454
|
-
}
|
|
455
|
-
};
|
|
456
|
-
try {
|
|
457
|
-
const response = await blockchainDataSDKClient.createMintRequest(
|
|
458
|
-
mintingRequest
|
|
459
|
-
);
|
|
460
|
-
logger.info(
|
|
461
|
-
`mintingResponse: ${JSON.stringify(response, null, 2)}`
|
|
462
|
-
);
|
|
463
|
-
await mintingPersistence3.updateMintingStatusToSubmitted(
|
|
464
|
-
assets.map(({ id }) => id)
|
|
465
|
-
);
|
|
466
|
-
return response;
|
|
467
|
-
} catch (e) {
|
|
468
|
-
logger.error(e);
|
|
469
|
-
trackError(e);
|
|
470
|
-
if (e.code === "CONFLICT_ERROR" && e.details?.id === "reference_id") {
|
|
471
|
-
try {
|
|
472
|
-
await mintingPersistence3.markAsConflict(
|
|
473
|
-
e.details.values,
|
|
474
|
-
contractAddress
|
|
475
|
-
);
|
|
476
|
-
await mintingPersistence3.resetMintingStatus(
|
|
477
|
-
assets.map(({ id }) => id).filter((id) => !e.details.values.includes(id))
|
|
478
|
-
);
|
|
479
|
-
} catch (e2) {
|
|
480
|
-
logger.error(e2);
|
|
481
|
-
trackError(e);
|
|
482
|
-
}
|
|
483
|
-
} else {
|
|
484
|
-
const { assetsToRetry, assetsExceededMaxNumberOfTries } = assets.reduce(
|
|
485
|
-
(acc, { tried_count = 0, id }) => {
|
|
486
|
-
if (tried_count < maxNumberOfTries) {
|
|
487
|
-
acc.assetsToRetry.push(id);
|
|
488
|
-
} else {
|
|
489
|
-
acc.assetsExceededMaxNumberOfTries.push(id);
|
|
490
|
-
}
|
|
491
|
-
return acc;
|
|
492
|
-
},
|
|
493
|
-
{
|
|
494
|
-
assetsToRetry: [],
|
|
495
|
-
assetsExceededMaxNumberOfTries: []
|
|
496
|
-
}
|
|
497
|
-
);
|
|
498
|
-
await mintingPersistence3.markForRetry(
|
|
499
|
-
assetsToRetry
|
|
500
|
-
);
|
|
501
|
-
await mintingPersistence3.updateMintingStatusToSubmissionFailed(
|
|
502
|
-
assetsExceededMaxNumberOfTries
|
|
503
|
-
);
|
|
504
|
-
}
|
|
505
|
-
return e;
|
|
506
|
-
}
|
|
507
|
-
}
|
|
508
|
-
)
|
|
509
|
-
);
|
|
510
|
-
mintingResponse = mintingResults.reverse().find(
|
|
511
|
-
(r) => r.status === "fulfilled"
|
|
512
|
-
)?.value;
|
|
513
|
-
}
|
|
514
|
-
};
|
|
515
|
-
var processMint = async (mintingPersistence3, event, logger = console) => {
|
|
516
|
-
trackProcessMint();
|
|
517
|
-
if (event.event_name !== "imtbl_zkevm_mint_request_updated") {
|
|
518
|
-
logger.info(
|
|
519
|
-
`${event.event_name} is not imtbl_zkevm_mint_request_updated, skip.`
|
|
520
|
-
);
|
|
521
|
-
return;
|
|
522
|
-
}
|
|
523
|
-
const referenceId = event.data.reference_id;
|
|
524
|
-
if (!referenceId) {
|
|
525
|
-
throw new Error("reference_id not found in webhook event");
|
|
526
|
-
}
|
|
527
|
-
const contractAddress = event.data.contract_address;
|
|
528
|
-
if (!contractAddress) {
|
|
529
|
-
throw new Error("contract_address not found in webhook event");
|
|
530
|
-
}
|
|
531
|
-
if (event.data.status === "failed") {
|
|
532
|
-
logger.error(`mint failed: ${JSON.stringify(event.data, null, 2)}`);
|
|
533
|
-
}
|
|
534
|
-
const mintReq = await mintingPersistence3.getMintingRequest(
|
|
535
|
-
contractAddress,
|
|
536
|
-
referenceId
|
|
537
|
-
);
|
|
538
|
-
if (!mintReq) {
|
|
539
|
-
logger.info(
|
|
540
|
-
`minting request not found in the database, ${JSON.stringify(event.data)}`
|
|
541
|
-
);
|
|
542
|
-
}
|
|
543
|
-
const ownerAddress = mintReq?.wallet_address || event.data.owner_address;
|
|
544
|
-
if (!ownerAddress) {
|
|
545
|
-
logger.error("owner_address missing");
|
|
546
|
-
throw new Error("owner_address missing");
|
|
547
|
-
}
|
|
548
|
-
await mintingPersistence3.syncMintingStatus({
|
|
549
|
-
tokenId: event.data.token_id,
|
|
550
|
-
status: event.data.status,
|
|
551
|
-
assetId: referenceId,
|
|
552
|
-
contractAddress,
|
|
553
|
-
ownerAddress,
|
|
554
|
-
metadataId: event.data.metadata_id,
|
|
555
|
-
imtblZkevmMintRequestUpdatedId: event.event_id,
|
|
556
|
-
error: event.data.error ? JSON.stringify(event.data.error) : null,
|
|
557
|
-
amount: event.data.amount || null
|
|
558
|
-
});
|
|
559
|
-
};
|
|
560
|
-
|
|
561
|
-
// src/index.ts
|
|
562
|
-
var noopHandlers = {
|
|
563
|
-
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
564
|
-
zkevmMintRequestUpdated: async (event) => {
|
|
565
|
-
}
|
|
566
|
-
};
|
|
567
|
-
var MintingBackendModule = class {
|
|
568
|
-
baseConfig;
|
|
569
|
-
persistence;
|
|
570
|
-
blockchainDataClient;
|
|
571
|
-
logger;
|
|
572
|
-
constructor(config) {
|
|
573
|
-
this.baseConfig = config.baseConfig;
|
|
574
|
-
this.persistence = config.persistence;
|
|
575
|
-
this.logger = config.logger || console;
|
|
576
|
-
this.blockchainDataClient = new BlockchainData({
|
|
577
|
-
baseConfig: config.baseConfig
|
|
578
|
-
});
|
|
579
|
-
setEnvironment(this.baseConfig.environment);
|
|
580
|
-
if (this.baseConfig.publishableKey) {
|
|
581
|
-
setPublishableApiKey(this.baseConfig.publishableKey);
|
|
582
|
-
}
|
|
583
|
-
}
|
|
584
|
-
async recordMint(mintRequest) {
|
|
585
|
-
await recordMint(this.persistence, mintRequest);
|
|
586
|
-
}
|
|
587
|
-
async submitMintingRequests(config) {
|
|
588
|
-
await submitMintingRequests(
|
|
589
|
-
this.persistence,
|
|
590
|
-
this.blockchainDataClient,
|
|
591
|
-
config
|
|
592
|
-
);
|
|
593
|
-
}
|
|
594
|
-
async processMint(body, otherHandlers = noopHandlers) {
|
|
595
|
-
await handle(body, this.baseConfig.environment, {
|
|
596
|
-
zkevmMintRequestUpdated: async (event) => {
|
|
597
|
-
await processMint(this.persistence, event, this.logger);
|
|
598
|
-
if (otherHandlers.zkevmMintRequestUpdated) {
|
|
599
|
-
otherHandlers.zkevmMintRequestUpdated(event);
|
|
600
|
-
}
|
|
601
|
-
}
|
|
602
|
-
});
|
|
603
|
-
}
|
|
604
|
-
};
|
|
605
|
-
if (typeof process !== "undefined" && process.on) {
|
|
606
|
-
try {
|
|
607
|
-
process.on("uncaughtExceptionMonitor", trackUncaughtException);
|
|
608
|
-
} catch {
|
|
609
|
-
}
|
|
610
|
-
}
|
|
611
|
-
export {
|
|
612
|
-
MintingBackendModule,
|
|
613
|
-
mintingPersistence as mintingPersistencePg,
|
|
614
|
-
mintingPersistence2 as mintingPersistencePrismaSqlite,
|
|
615
|
-
processMint,
|
|
616
|
-
recordMint,
|
|
617
|
-
submitMintingRequests
|
|
618
|
-
};
|
|
56
|
+
`,[t,s])).rows[0]||null});var U=e=>(h(),{recordMint:async t=>{if(!await e.imAssets.upsert({where:{im_assets_uindex:{assetId:t.asset_id,contractAddress:t.contract_address}},update:{},create:{assetId:t.asset_id,contractAddress:t.contract_address,ownerAddress:t.owner_address,metadata:JSON.stringify(t.metadata),amount:t.amount||null,tokenId:t.token_id||null}}))throw new Error("Duplicated mint")},getNextBatchForSubmission:async t=>{let a=(await e.imAssets.findMany({where:{mintingStatus:null},take:t})).map(n=>n.id);return await e.imAssets.updateMany({where:{id:{in:a}},data:{mintingStatus:"submitting"}}),(await e.imAssets.findMany({where:{id:{in:a}}})).map(n=>({id:n.id,contract_address:n.contractAddress,wallet_address:n.ownerAddress,asset_id:n.assetId,metadata:n.metadata?JSON.parse(n.metadata):null,owner_address:n.ownerAddress,tried_count:n.triedCount,amount:n.amount||null,token_id:n.tokenId||null}))},updateMintingStatusToSubmitted:async t=>{await e.imAssets.updateMany({where:{id:{in:t}},data:{mintingStatus:"submitted"}})},syncMintingStatus:async t=>{let s=await e.imAssets.findUnique({where:{im_assets_uindex:{assetId:t.assetId,contractAddress:t.contractAddress}}});s&&(s.lastImtblZkevmMintRequestUpdatedId===null||s.lastImtblZkevmMintRequestUpdatedId<t.imtblZkevmMintRequestUpdatedId)?await e.imAssets.update({where:{im_assets_uindex:{assetId:t.assetId,contractAddress:t.contractAddress}},data:{ownerAddress:t.ownerAddress,tokenId:t.tokenId,mintingStatus:t.status,metadataId:t.metadataId,lastImtblZkevmMintRequestUpdatedId:t.imtblZkevmMintRequestUpdatedId,error:t.error,amount:t.amount||null}}):s||await e.imAssets.create({data:{assetId:t.assetId,contractAddress:t.contractAddress,ownerAddress:t.ownerAddress,tokenId:t.tokenId,mintingStatus:t.status,metadataId:t.metadataId,lastImtblZkevmMintRequestUpdatedId:t.imtblZkevmMintRequestUpdatedId,error:t.error,amount:t.amount||null}})},updateMintingStatusToSubmissionFailed:async t=>{await e.imAssets.updateMany({where:{id:{in:t}},data:{mintingStatus:"submission_failed"}})},markAsConflict:async(t,s)=>{await e.imAssets.updateMany({where:{assetId:{in:t},contractAddress:s},data:{mintingStatus:"conflicting"}})},resetMintingStatus:async t=>{await e.imAssets.updateMany({where:{id:{in:t}},data:{mintingStatus:null}})},markForRetry:async t=>{let s=await e.imAssets.findMany({where:{id:{in:t}},select:{id:!0,triedCount:!0}});for(let a of s)await e.imAssets.update({where:{id:a.id},data:{mintingStatus:null,triedCount:a.triedCount+1}})},getMintingRequest:async(t,s)=>{let a=await e.imAssets.findFirst({where:{contractAddress:t,assetId:s}});return a?{asset_id:a.assetId,contract_address:a.contractAddress,id:a.id,metadata:a.metadata?JSON.parse(a.metadata):null,owner_address:a.ownerAddress,tried_count:a.triedCount,wallet_address:a.ownerAddress,amount:a.amount||null}:null}});var R=async(e,t)=>{S(),e.recordMint(t)},O=1e3,b=async(e,t,{defaultBatchSize:s=1e3,chainName:a="imtbl-zkevm-testnet",maxNumberOfTries:l=3},n=console,g=1/0)=>{I();let m,P=0;for(;P++<g;){await new Promise(r=>{setTimeout(r,O)});let p=Math.min(m?.imx_remaining_mint_requests?parseInt(m.imx_remaining_mint_requests,10):s,s);if(p===0&&m&&new Date(m.imx_mint_requests_limit_reset)>new Date){n.info(`minting limit reached, waiting for reset at ${m?.imx_mint_requests_limit_reset}`);continue}p===0&&(n.info(`minting limit has been reset, use default batch size: ${s}`),m=void 0,p=s);let y=await e.getNextBatchForSubmission(p);if(y.length===0){n.info("no assets to mint");continue}let N=y.sort((r,d)=>r.contract_address>d.contract_address?1:-1).reduce((r,d)=>{if(r.length===0)return[{contractAddress:d.contract_address,assets:[d]}];let _=r[r.length-1];return _.contractAddress===d.contract_address&&_.assets.length<100?[...r.slice(0,-1),{..._,assets:[..._.assets,d]}]:[...r,{contractAddress:d.contract_address,assets:[d]}]},[]);m=(await Promise.allSettled(N.map(async({contractAddress:r,assets:d})=>{let _={chainName:a,contractAddress:r,createMintRequestRequest:{assets:d.map(i=>({reference_id:i.asset_id,owner_address:i.owner_address,metadata:i.metadata,token_id:i.token_id,amount:i.amount?`${i.amount}`:null}))}};try{let i=await t.createMintRequest(_);return n.info(`mintingResponse: ${JSON.stringify(i,null,2)}`),await e.updateMintingStatusToSubmitted(d.map(({id:o})=>o)),i}catch(i){if(n.error(i),w(i),i.code==="CONFLICT_ERROR"&&i.details?.id==="reference_id")try{await e.markAsConflict(i.details.values,r),await e.resetMintingStatus(d.map(({id:o})=>o).filter(o=>!i.details.values.includes(o)))}catch(o){n.error(o),w(i)}else{let{assetsToRetry:o,assetsExceededMaxNumberOfTries:x}=d.reduce((f,{tried_count:$=0,id:k})=>($<l?f.assetsToRetry.push(k):f.assetsExceededMaxNumberOfTries.push(k),f),{assetsToRetry:[],assetsExceededMaxNumberOfTries:[]});await e.markForRetry(o),await e.updateMintingStatusToSubmissionFailed(x)}return i}}))).reverse().find(r=>r.status==="fulfilled")?.value}},T=async(e,t,s=console)=>{if(A(),t.event_name!=="imtbl_zkevm_mint_request_updated"){s.info(`${t.event_name} is not imtbl_zkevm_mint_request_updated, skip.`);return}let a=t.data.reference_id;if(!a)throw new Error("reference_id not found in webhook event");let l=t.data.contract_address;if(!l)throw new Error("contract_address not found in webhook event");t.data.status==="failed"&&s.error(`mint failed: ${JSON.stringify(t.data,null,2)}`);let n=await e.getMintingRequest(l,a);n||s.info(`minting request not found in the database, ${JSON.stringify(t.data)}`);let g=n?.wallet_address||t.data.owner_address;if(!g)throw s.error("owner_address missing"),new Error("owner_address missing");await e.syncMintingStatus({tokenId:t.data.token_id,status:t.data.status,assetId:a,contractAddress:l,ownerAddress:g,metadataId:t.data.metadata_id,imtblZkevmMintRequestUpdatedId:t.event_id,error:t.data.error?JSON.stringify(t.data.error):null,amount:t.data.amount||null})};var z={zkevmMintRequestUpdated:async e=>{}},C=class{baseConfig;persistence;blockchainDataClient;logger;constructor(t){this.baseConfig=t.baseConfig,this.persistence=t.persistence,this.logger=t.logger||console,this.blockchainDataClient=new v({baseConfig:t.baseConfig}),L(this.baseConfig.environment),this.baseConfig.publishableKey&&F(this.baseConfig.publishableKey)}async recordMint(t){await R(this.persistence,t)}async submitMintingRequests(t){await b(this.persistence,this.blockchainDataClient,t)}async processMint(t,s=z){await D(t,this.baseConfig.environment,{zkevmMintRequestUpdated:async a=>{await T(this.persistence,a,this.logger),s.zkevmMintRequestUpdated&&s.zkevmMintRequestUpdated(a)}})}};if(typeof process<"u"&&process.on)try{process.on("uncaughtExceptionMonitor",E)}catch{}export{C as MintingBackendModule,q as mintingPersistencePg,U as mintingPersistencePrismaSqlite,T as processMint,R as recordMint,b as submitMintingRequests};
|
package/package.json
CHANGED
|
@@ -1,15 +1,15 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@imtbl/minting-backend",
|
|
3
3
|
"description": "minting backend utilising Immutable Minting API",
|
|
4
|
-
"version": "2.0.0-alpha.
|
|
4
|
+
"version": "2.0.0-alpha.8",
|
|
5
5
|
"author": "Immutable",
|
|
6
6
|
"bugs": "https://github.com/immutable/ts-immutable-sdk/issues",
|
|
7
7
|
"dependencies": {
|
|
8
|
-
"@imtbl/blockchain-data": "2.0.0-alpha.
|
|
9
|
-
"@imtbl/config": "2.0.0-alpha.
|
|
10
|
-
"@imtbl/generated-clients": "2.0.0-alpha.
|
|
11
|
-
"@imtbl/metrics": "2.0.0-alpha.
|
|
12
|
-
"@imtbl/webhook": "2.0.0-alpha.
|
|
8
|
+
"@imtbl/blockchain-data": "2.0.0-alpha.8",
|
|
9
|
+
"@imtbl/config": "2.0.0-alpha.8",
|
|
10
|
+
"@imtbl/generated-clients": "2.0.0-alpha.8",
|
|
11
|
+
"@imtbl/metrics": "2.0.0-alpha.8",
|
|
12
|
+
"@imtbl/webhook": "2.0.0-alpha.8",
|
|
13
13
|
"uuid": "^8.3.2"
|
|
14
14
|
},
|
|
15
15
|
"devDependencies": {
|