@gvnrdao/dh-sdk 0.0.323 → 0.0.324

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.js CHANGED
@@ -1379,30 +1379,30 @@ var require_pkg_src = __commonJS({
1379
1379
  }
1380
1380
  },
1381
1381
  btcTransactionSigner: {
1382
- cid: "QmPncBUbxN9giWntJcvBMFW9GDAgA3DwgAkUAHxSsY67ic",
1382
+ cid: "QmakWzTce8NH1Jkgv1xwg83Bg9WmF2UG1Mq76pDYDSwwUp",
1383
1383
  authorizedCidHex: cidToHex(
1384
- "QmPncBUbxN9giWntJcvBMFW9GDAgA3DwgAkUAHxSsY67ic"
1384
+ "QmakWzTce8NH1Jkgv1xwg83Bg9WmF2UG1Mq76pDYDSwwUp"
1385
1385
  ),
1386
1386
  name: "Btc Transaction Signer",
1387
1387
  description: "Production Btc Transaction Signer",
1388
1388
  version: "1.1.1",
1389
1389
  deployed: true,
1390
- deployedAt: 1785226367707,
1391
- size: 66624,
1392
- hash: "9e0d9909519d5133bab03a9491566870b08d8b42c80e2d768bd24f02946cc781"
1390
+ deployedAt: 1786113907707,
1391
+ size: 67999,
1392
+ hash: "83f3644c68819215e05ba8db3225571354a009458fc1437f606df6cb9142d3f9"
1393
1393
  },
1394
1394
  ucdMintValidator: {
1395
- cid: "QmPRLCfseSWCAS4PpvQWt9aEd6rXqWYG4JyGTn26KYk6xc",
1395
+ cid: "Qmd8jgKRceLvf5aoTtwdXG2JqMoBK5cRJwrvEtQkgvbFbx",
1396
1396
  authorizedCidHex: cidToHex(
1397
- "QmPRLCfseSWCAS4PpvQWt9aEd6rXqWYG4JyGTn26KYk6xc"
1397
+ "Qmd8jgKRceLvf5aoTtwdXG2JqMoBK5cRJwrvEtQkgvbFbx"
1398
1398
  ),
1399
1399
  name: "Ucd Mint Validator",
1400
1400
  description: "Production Ucd Mint Validator",
1401
1401
  version: "1.2.1",
1402
1402
  deployed: true,
1403
- deployedAt: 1785226381631,
1404
- size: 81658,
1405
- hash: "d8ea21622885c3d26fdb64e2ba9d2f9460753a5cd7934b2928858899537443eb",
1403
+ deployedAt: 1786113908489,
1404
+ size: 82739,
1405
+ hash: "2bdd9aebdaad58a43a4731d5b7284f2531b7a9caaf8caf5719d891c4ed33cb2e",
1406
1406
  validatorWalletAddress: "0x82DB9F515957aA380B596C6eA2Bd30CEF181f236",
1407
1407
  pkp: {
1408
1408
  publicKey: "0x041ab17cd91fc5c0b761eea6092d032807561b621b82c488826776e04a9158d61ba64d809a4729f0501289d980732cb06d8dfd06999dd9c8efd2f495dad78b31bb",
@@ -1410,17 +1410,17 @@ var require_pkg_src = __commonJS({
1410
1410
  }
1411
1411
  },
1412
1412
  processPaymentValidator: {
1413
- cid: "QmNUzmHQHsaKThGkfZiD3xZrN64qZfn4P6J4MqWgvkeEsX",
1413
+ cid: "QmNXVdysXDhCaQ1uNE2Vgjbuzy6yUEnnVgHzmDfNKXMU6z",
1414
1414
  authorizedCidHex: cidToHex(
1415
- "QmNUzmHQHsaKThGkfZiD3xZrN64qZfn4P6J4MqWgvkeEsX"
1415
+ "QmNXVdysXDhCaQ1uNE2Vgjbuzy6yUEnnVgHzmDfNKXMU6z"
1416
1416
  ),
1417
1417
  name: "Process Payment Validator",
1418
1418
  description: "Production Process Payment Validator",
1419
1419
  version: "1.2.1",
1420
1420
  deployed: true,
1421
- deployedAt: 1785226385509,
1422
- size: 77655,
1423
- hash: "3c2af3c3e62e8e606d35f81fd7e6f4943f8516a9bef74f4150c8c1767cbd316f",
1421
+ deployedAt: 1786113909138,
1422
+ size: 78736,
1423
+ hash: "17191ecc9c009e0fa5ab52c876330beb2a9a75d30cccb92e7c0c04f169df088b",
1424
1424
  validatorWalletAddress: "0x82DB9F515957aA380B596C6eA2Bd30CEF181f236",
1425
1425
  pkp: {
1426
1426
  publicKey: "0x04cfccb9b6c7addc79469c0e9fafebef4c70801302c62cdb26b610723a9b8527d23f98a40158c7340d83fd0e62d02b5ec74c12f7a86d98e8c6973b4811110f19ad",
@@ -1428,17 +1428,17 @@ var require_pkg_src = __commonJS({
1428
1428
  }
1429
1429
  },
1430
1430
  extendPositionValidator: {
1431
- cid: "QmY2t41w1maaoDmdRPx6wTfciHPQAydSpLSKwKVFSS2DPM",
1431
+ cid: "QmYwBsyrhGfHWyRKx549G4tKHxsBLAuRUHcecigeUCkFav",
1432
1432
  authorizedCidHex: cidToHex(
1433
- "QmY2t41w1maaoDmdRPx6wTfciHPQAydSpLSKwKVFSS2DPM"
1433
+ "QmYwBsyrhGfHWyRKx549G4tKHxsBLAuRUHcecigeUCkFav"
1434
1434
  ),
1435
1435
  name: "Extend Position Validator",
1436
1436
  description: "Production Extend Position Validator",
1437
1437
  version: "1.2.1",
1438
1438
  deployed: true,
1439
- deployedAt: 1785226398291,
1440
- size: 75434,
1441
- hash: "ba55532fbeaf6e65d180b869fd69ee06393d574daa0ace524a9e831d846539a5",
1439
+ deployedAt: 1786113909872,
1440
+ size: 76515,
1441
+ hash: "1d4e085335af80f194a663a577876902c83015177e95906a0b461fa93bd5da08",
1442
1442
  validatorWalletAddress: "0x82DB9F515957aA380B596C6eA2Bd30CEF181f236",
1443
1443
  pkp: {
1444
1444
  publicKey: "0x04e52338f6a0c3362800f1a94c4c8f08be5030dde0fa217388c53d1c1a4790f4443c9f2886b2d2d8f4b75a9a156e9b028011b1a1cf7648da0e556aa980ec692836",
@@ -1446,9 +1446,9 @@ var require_pkg_src = __commonJS({
1446
1446
  }
1447
1447
  },
1448
1448
  btcWithdrawal: {
1449
- cid: "QmcBg8vPXsCmiKDk28bJVTqDpTrwCzSYAGu5V6ABVVPuK5",
1449
+ cid: "QmZuR3qSBajutXfRd91ffpyFrRMgmaMh7fDEHRiQQF8Ljp",
1450
1450
  authorizedCidHex: cidToHex(
1451
- "QmcBg8vPXsCmiKDk28bJVTqDpTrwCzSYAGu5V6ABVVPuK5"
1451
+ "QmZuR3qSBajutXfRd91ffpyFrRMgmaMh7fDEHRiQQF8Ljp"
1452
1452
  ),
1453
1453
  name: "Btc Withdrawal",
1454
1454
  description: "Production Btc Withdrawal",
@@ -1458,9 +1458,9 @@ var require_pkg_src = __commonJS({
1458
1458
  // than the one it replaced, which a rotation ceremony would treat as a rollback.
1459
1459
  version: "1.2.4",
1460
1460
  deployed: true,
1461
- deployedAt: 1785226412397,
1462
- size: 92754,
1463
- hash: "d3a8ec62e0b1e6d0566a154a884bf7ee4e25ef6dc2dd84fde98211d25c1dede5",
1461
+ deployedAt: 1786113910531,
1462
+ size: 95313,
1463
+ hash: "ce12f11e3b5469953bc919586e4f3b8b5d594224b58b799dd9a3b60e3749559c",
1464
1464
  validatorWalletAddress: "0x82DB9F515957aA380B596C6eA2Bd30CEF181f236",
1465
1465
  pkp: {
1466
1466
  publicKey: "0x043616787c5432415c24378c4ef48de2bcd6bb7b575b837e3cff09171802662da7105d79586c7659677a0ecbaddac4cce06cb2a11f69a16fa0c4d7002ac7d51a4d",
@@ -1571,6 +1571,21 @@ var require_pkg_src = __commonJS({
1571
1571
  size: 1046,
1572
1572
  hash: "03ee5be239c91c735d2c95db89a0d1b77e602cfc18af8eb64b3281fddcd90a72"
1573
1573
  },
1574
+ agentModuleExecutor: {
1575
+ // Bound to the isolated Sepolia agent group 7 ("DH-Agent-Sepolia"), which
1576
+ // holds this action and no PKPs until an agent is minted into it. NOT yet
1577
+ // bound on mainnet — the Base `DH-Agent-Mainnet` group is created at rollout.
1578
+ cid: "QmVgjGXUuxoGf8XyddW8a7btaazT9yEotpKoBgb65oPvcF",
1579
+ authorizedCidHex: cidToHex(
1580
+ "QmVgjGXUuxoGf8XyddW8a7btaazT9yEotpKoBgb65oPvcF"
1581
+ ),
1582
+ name: "Agent Module Executor",
1583
+ description: "Capability gate for multi-sig Safe agent delegation: binds the agent PKP to the AgentDelegationRegistry record before signing (authorize | execute modes)",
1584
+ version: "1.0.0",
1585
+ deployed: true,
1586
+ size: 11785,
1587
+ hash: "fa294e164273c2158f9ef11a0ccfd735c343c0e3759fcb4b37e0f8a5d1ab0d29"
1588
+ },
1574
1589
  staleSpendRecoveryValidator: {
1575
1590
  cid: "QmXQWT8V4wjuvH8BbC7xrkYxsVu5AKfvfWcS7jnYfrexYm",
1576
1591
  authorizedCidHex: cidToHex(
@@ -1590,17 +1605,17 @@ var require_pkg_src = __commonJS({
1590
1605
  }
1591
1606
  },
1592
1607
  btcUtxoInvalidator: {
1593
- cid: "QmZE422cZsEjYN8pE6AmpkgFoZCK4UAfdDuzoVRRsMJbwm",
1608
+ cid: "Qmf4Ze8yhnQhHbnX5RPgJrC7Jw1aA3gbpfpd52kFg7fd1m",
1594
1609
  authorizedCidHex: cidToHex(
1595
- "QmZE422cZsEjYN8pE6AmpkgFoZCK4UAfdDuzoVRRsMJbwm"
1610
+ "Qmf4Ze8yhnQhHbnX5RPgJrC7Jw1aA3gbpfpd52kFg7fd1m"
1596
1611
  ),
1597
1612
  name: "Btc Utxo Invalidator",
1598
1613
  description: "Production Btc Utxo Invalidator",
1599
1614
  version: "1.0.0",
1600
1615
  deployed: true,
1601
- deployedAt: 1785226423791,
1602
- size: 61472,
1603
- hash: "75eca528d8ac30ae8f21caaae206ccab162a83a048d622868e60f645f0c475e2"
1616
+ deployedAt: 1786113911948,
1617
+ size: 62553,
1618
+ hash: "1dcea2b49e545c423195be22e072dc5e3039ed1c95a8490b23505956029f5b33"
1604
1619
  }
1605
1620
  };
1606
1621
  function getDeploymentsForNetwork(network) {
@@ -6253,7 +6268,10 @@ var import_ethers2 = require("ethers");
6253
6268
  // src/utils/quantum-timing.ts
6254
6269
  var QUANTUM_WINDOW_SECONDS = 60;
6255
6270
  var DEAD_ZONE_SECONDS = 8;
6256
- var INCLUSION_LATENCY_BUDGET = 16;
6271
+ var SLOT_SECONDS = 12;
6272
+ var INCLUSION_SLOT_TOLERANCE = 3;
6273
+ var INCLUSION_LATENCY_BUDGET = SLOT_SECONDS * INCLUSION_SLOT_TOLERANCE;
6274
+ var MAX_GATE_POLLS = 12;
6257
6275
  var POST_BOUNDARY_SKEW_MARGIN = 3;
6258
6276
  function calculateNextQuantumTimestamp() {
6259
6277
  const now = Math.floor(Date.now() / 1e3);
@@ -6286,8 +6304,17 @@ function validateQuantumTiming(signedTimestamp, _bufferSeconds = 30) {
6286
6304
  async function awaitSafeSubmissionWindow(quantumTimestamp, opts = {}) {
6287
6305
  const now = opts.now ?? (() => Math.floor(Date.now() / 1e3));
6288
6306
  const sleep = opts.sleep ?? ((ms) => new Promise((r) => setTimeout(r, ms)));
6289
- const nowSec = now();
6290
6307
  const signatureQuantum = Math.floor(quantumTimestamp / QUANTUM_WINDOW_SECONDS) * QUANTUM_WINDOW_SECONDS;
6308
+ if (opts.chainNow) {
6309
+ const chainResult = await awaitSafeSubmissionWindowOnChain(
6310
+ signatureQuantum,
6311
+ opts.chainNow,
6312
+ sleep
6313
+ );
6314
+ if (chainResult)
6315
+ return chainResult;
6316
+ }
6317
+ const nowSec = now();
6291
6318
  const currentQuantum = Math.floor(nowSec / QUANTUM_WINDOW_SECONDS) * QUANTUM_WINDOW_SECONDS;
6292
6319
  const secsToBoundary = QUANTUM_WINDOW_SECONDS - nowSec % QUANTUM_WINDOW_SECONDS;
6293
6320
  const isNextQuantumSig = signatureQuantum === currentQuantum + QUANTUM_WINDOW_SECONDS;
@@ -6304,6 +6331,44 @@ async function awaitSafeSubmissionWindow(quantumTimestamp, opts = {}) {
6304
6331
  }
6305
6332
  return { waited: false, waitedSeconds: 0 };
6306
6333
  }
6334
+ async function awaitSafeSubmissionWindowOnChain(signatureQuantum, chainNow, sleep) {
6335
+ let waitedSeconds = 0;
6336
+ for (let poll = 0; poll < MAX_GATE_POLLS; poll++) {
6337
+ let head;
6338
+ try {
6339
+ head = await chainNow();
6340
+ } catch {
6341
+ head = null;
6342
+ }
6343
+ if (head === null || !Number.isFinite(head)) {
6344
+ return waitedSeconds > 0 ? { waited: true, waitedSeconds } : null;
6345
+ }
6346
+ const chainQuantum = Math.floor(head / QUANTUM_WINDOW_SECONDS) * QUANTUM_WINDOW_SECONDS;
6347
+ if (signatureQuantum <= chainQuantum) {
6348
+ return { waited: waitedSeconds > 0, waitedSeconds };
6349
+ }
6350
+ const earliestMine = head + SLOT_SECONDS;
6351
+ const latestMine = head + SLOT_SECONDS * INCLUSION_SLOT_TOLERANCE;
6352
+ const safeBeforeDeadZone = latestMine < signatureQuantum - DEAD_ZONE_SECONDS;
6353
+ const safeAfterBoundary = earliestMine >= signatureQuantum;
6354
+ if (safeBeforeDeadZone || safeAfterBoundary) {
6355
+ return { waited: waitedSeconds > 0, waitedSeconds };
6356
+ }
6357
+ const sleepSeconds = Math.max(
6358
+ 1,
6359
+ Math.min(SLOT_SECONDS, signatureQuantum - head)
6360
+ );
6361
+ log.debug(
6362
+ `[Quantum Timing] \u23F3 Deferring send ${sleepSeconds}s to clear the quantum dead zone (sig quantum ${signatureQuantum}, chain head ${head}, insured mine window [${earliestMine}, ${latestMine}])`
6363
+ );
6364
+ await sleep(sleepSeconds * 1e3);
6365
+ waitedSeconds += sleepSeconds;
6366
+ }
6367
+ log.debug(
6368
+ `[Quantum Timing] \u26A0\uFE0F Dead-zone gate exhausted ${MAX_GATE_POLLS} chain polls (sig quantum ${signatureQuantum}) \u2014 proceeding`
6369
+ );
6370
+ return { waited: waitedSeconds > 0, waitedSeconds };
6371
+ }
6307
6372
 
6308
6373
  // src/utils/mint-authorization.utils.ts
6309
6374
  var PKP_NFT_ABI = [
@@ -7260,6 +7325,20 @@ function decodeQuantumRevert(e) {
7260
7325
  }
7261
7326
  return { data, selector, name };
7262
7327
  }
7328
+ var RETRYABLE_QUANTUM_ERROR_NAMES = [
7329
+ "DeadZoneViolation",
7330
+ "QuantumOutsideWindow",
7331
+ "QuantumAlreadyUsed",
7332
+ "QuantumExpired"
7333
+ ];
7334
+ function isRetryableQuantumFailure(message) {
7335
+ if (!message)
7336
+ return false;
7337
+ if (message.includes("Transaction timeout") || message.includes("Transaction confirmation failed") || message.includes("Transaction receipt not found")) {
7338
+ return false;
7339
+ }
7340
+ return RETRYABLE_QUANTUM_ERROR_NAMES.some((name) => message.includes(name)) || message.includes("Transaction reverted");
7341
+ }
7263
7342
 
7264
7343
  // src/utils/quantum-submission.utils.ts
7265
7344
  var MAX_DEADZONE_RESIMULATIONS = 3;
@@ -7281,9 +7360,14 @@ async function assertSafeQuantumSubmission(opts) {
7281
7360
  const now = opts.now ?? (() => Math.floor(Date.now() / 1e3));
7282
7361
  const onDebug = opts.onDebug ?? (() => {
7283
7362
  });
7363
+ const chainNow = opts.chainNow ?? (typeof provider.getBlock === "function" ? async () => {
7364
+ const block = await provider.getBlock("latest");
7365
+ return typeof block?.timestamp === "number" ? block.timestamp : null;
7366
+ } : void 0);
7284
7367
  const gateOpts = {
7285
7368
  now,
7286
- ...opts.sleep ? { sleep: opts.sleep } : {}
7369
+ ...opts.sleep ? { sleep: opts.sleep } : {},
7370
+ ...chainNow ? { chainNow } : {}
7287
7371
  };
7288
7372
  await awaitSafeSubmissionWindow(quantumTimestamp, gateOpts);
7289
7373
  const SAME_BLOCK_INTERACTION_SELECTOR = "0x3b53d1db";
@@ -22293,10 +22377,7 @@ Message: ${causeMessage}${quantumContext}${mintDebtDiagnostics}`
22293
22377
  isRetryablePaymentQuantumFailure(result) {
22294
22378
  if (result.success || !result.error)
22295
22379
  return false;
22296
- const e = result.error;
22297
- if (e.includes("Transaction timeout"))
22298
- return false;
22299
- return e.includes("DeadZoneViolation") || e.includes("QuantumOutsideWindow") || e.includes("QuantumAlreadyUsed") || e.includes("QuantumExpired") || e === "Transaction reverted";
22380
+ return isRetryableQuantumFailure(result.error);
22300
22381
  }
22301
22382
  /**
22302
22383
  * One payment attempt: user auth → Lit Action authorization → dead-zone gate →
@@ -22935,6 +23016,37 @@ Message: ${causeMessage}${quantumContext}${mintDebtDiagnostics}`
22935
23016
  }
22936
23017
  return this.withdrawalAddressModule.getEntries(target);
22937
23018
  }
23019
+ /**
23020
+ * Recover the revert reason of an already-mined, already-reverted transaction.
23021
+ *
23022
+ * A status-0 receipt carries no revert data, and ethers does not re-fetch it, so
23023
+ * the reason has to be recovered by replaying the exact calldata as an `eth_call`
23024
+ * pinned to the block that mined it — the only block whose `block.timestamp`
23025
+ * reproduces a timing-dependent revert such as `DeadZoneViolation()`.
23026
+ *
23027
+ * Caveat: the replay runs against end-of-block state rather than the state at the
23028
+ * transaction's own index, so for a state-dependent revert the recovered name is
23029
+ * diagnostic, not proof. Timing reverts (the case this exists for) are unaffected —
23030
+ * they depend only on the block timestamp.
23031
+ *
23032
+ * @returns the decoded error name, its raw selector if unknown, or `null` when the
23033
+ * replay yields no revert data at all (never throws — a failed diagnosis
23034
+ * must not mask the underlying failure).
23035
+ */
23036
+ async decodeMinedRevert(params) {
23037
+ try {
23038
+ await this.getProviderOrThrow().call({
23039
+ to: params.to,
23040
+ from: params.from,
23041
+ data: params.data,
23042
+ blockTag: params.blockNumber
23043
+ });
23044
+ return null;
23045
+ } catch (replayError) {
23046
+ const decoded = decodeQuantumRevert(replayError);
23047
+ return decoded.name ?? decoded.selector ?? null;
23048
+ }
23049
+ }
22938
23050
  /**
22939
23051
  * Withdraw Bitcoin from a position
22940
23052
  *
@@ -23508,9 +23620,23 @@ Message: ${causeMessage}${quantumContext}${mintDebtDiagnostics}`
23508
23620
  txHash: tx.hash
23509
23621
  });
23510
23622
  }
23623
+ const withdrawProvider = this.getProviderOrThrow();
23624
+ const withdrawTimeoutMs = this.config.transactionTimeoutMs || 3e5;
23511
23625
  let receipt;
23512
23626
  try {
23513
- receipt = await tx.wait();
23627
+ receipt = await Promise.race([
23628
+ withdrawProvider.waitForTransaction(tx.hash, 1),
23629
+ new Promise(
23630
+ (_, reject) => setTimeout(
23631
+ () => reject(
23632
+ new Error(
23633
+ `Transaction timeout after ${withdrawTimeoutMs}ms. Hash: ${tx.hash}`
23634
+ )
23635
+ ),
23636
+ withdrawTimeoutMs
23637
+ )
23638
+ )
23639
+ ]);
23514
23640
  } catch (waitError) {
23515
23641
  const waitErrorMsg = waitError instanceof Error ? waitError.message : String(waitError);
23516
23642
  if (this.config.debug) {
@@ -23527,7 +23653,26 @@ Message: ${causeMessage}${quantumContext}${mintDebtDiagnostics}`
23527
23653
  if (!receipt) {
23528
23654
  return {
23529
23655
  success: false,
23530
- error: `Transaction confirmation returned no receipt. Hash: ${tx.hash}`
23656
+ error: `Transaction receipt not found for hash: ${tx.hash}`
23657
+ };
23658
+ }
23659
+ if (receipt.status === 0) {
23660
+ const revertName = await this.decodeMinedRevert({
23661
+ to: positionManagerAddress,
23662
+ from: await withdrawSigner.getAddress(),
23663
+ data: withdrawCalldata,
23664
+ blockNumber: receipt.blockNumber
23665
+ });
23666
+ if (this.config.debug) {
23667
+ log.error("\u274C withdrawBTC reverted on-chain", {
23668
+ txHash: receipt.hash,
23669
+ blockNumber: receipt.blockNumber,
23670
+ revert: revertName ?? "undecodable"
23671
+ });
23672
+ }
23673
+ return {
23674
+ success: false,
23675
+ error: `Transaction reverted: ${revertName ?? "unknown reason"} (tx: ${receipt.hash})`
23531
23676
  };
23532
23677
  }
23533
23678
  if (this.config.debug) {
@@ -24655,13 +24800,11 @@ Message: ${causeMessage}${quantumContext}${mintDebtDiagnostics}`
24655
24800
  if (authResult.success) {
24656
24801
  break;
24657
24802
  }
24658
- const isQuantumError = authResult.error?.includes(
24659
- "QuantumOutsideWindow"
24660
- );
24803
+ const isQuantumError = isRetryableQuantumFailure(authResult.error);
24661
24804
  if (isQuantumError && wAttempt < MAX_WITHDRAWAL_QUANTUM_RETRIES) {
24662
24805
  if (this.config.debug) {
24663
24806
  log.warn(
24664
- `\u26A0\uFE0F Phase 1 QuantumOutsideWindow (attempt ${wAttempt}/${MAX_WITHDRAWAL_QUANTUM_RETRIES}). LIT action took too long. Retrying with fresh quantum...`
24807
+ `\u26A0\uFE0F Phase 1 quantum-timing failure (attempt ${wAttempt}/${MAX_WITHDRAWAL_QUANTUM_RETRIES}): ${authResult.error}. Retrying with a fresh quantum...`
24665
24808
  );
24666
24809
  }
24667
24810
  await new Promise((resolve) => setTimeout(resolve, 2e3));