@gvnrdao/dh-sdk 0.0.339 → 0.0.340

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
@@ -2351,7 +2351,7 @@ ${errorReport}`);
2351
2351
  }
2352
2352
  init_debug_logger();
2353
2353
  init_session_signature_cache();
2354
- var import_ethers19 = require("ethers");
2354
+ var import_ethers23 = require("ethers");
2355
2355
  var EXPIRED_LOAN_MIN_LIQUIDATION_THRESHOLD_BPS = 11e3;
2356
2356
  var GRACE_PERIOD_DAYS = 30;
2357
2357
  var SATOSHIS_PER_BITCOIN = 100000000n;
@@ -5279,12 +5279,12 @@ ${auth.clientId}`;
5279
5279
  }
5280
5280
  async function executeVaultSnapshot(params) {
5281
5281
  global.ethers = {
5282
- ...import_ethers19.ethers,
5282
+ ...import_ethers23.ethers,
5283
5283
  providers: {
5284
- StaticJsonRpcProvider: import_ethers19.ethers.JsonRpcProvider
5284
+ StaticJsonRpcProvider: import_ethers23.ethers.JsonRpcProvider
5285
5285
  },
5286
- Contract: import_ethers19.ethers.Contract,
5287
- utils: import_ethers19.ethers
5286
+ Contract: import_ethers23.ethers.Contract,
5287
+ utils: import_ethers23.ethers
5288
5288
  // v6 moved utils to top level
5289
5289
  };
5290
5290
  global.Lit = {
@@ -5540,8 +5540,8 @@ function getSepoliaConfig() {
5540
5540
  positionManagerCore: SEPOLIA_CONTRACTS.PositionManagerCoreModule || "",
5541
5541
  positionManagerViews: SEPOLIA_CONTRACTS.PositionManagerViews || "",
5542
5542
  simplePsmV2: SEPOLIA_CONTRACTS.SimplePSMV2 || "",
5543
- mockUsdcToken: SEPOLIA_CONTRACTS["MockUSDC"] || "",
5544
- mockUsdtToken: SEPOLIA_CONTRACTS["MockUSDT"] || "",
5543
+ mockUsdcToken: SEPOLIA_CONTRACTS.mockUsdcToken || "",
5544
+ mockUsdtToken: SEPOLIA_CONTRACTS.mockUsdtToken || "",
5545
5545
  loanOperationsManager: SEPOLIA_CONTRACTS.LoanOperationsManagerModule || "",
5546
5546
  termManager: SEPOLIA_CONTRACTS.TermManagerModule || "",
5547
5547
  circuitBreaker: SEPOLIA_CONTRACTS.CircuitBreakerModule || "",
@@ -5617,14 +5617,17 @@ function getMainnetConfig() {
5617
5617
  agentModuleFactory: MAINNET_CONTRACTS.AgentModuleFactory || ""
5618
5618
  },
5619
5619
  subgraphs: {
5620
- // KNOWN-WRONG placeholder (see GOAL-PLAN step 2 / dogfood F-CLI-4): this is a
5621
- // SEPOLIA subgraph id in a mainnet (chainId 1) config, and this gateway host
5622
- // needs an Authorization key the SDK does not (and must not) hold so the
5623
- // URL is doubly unusable. The `CCTPsd…` path segment is the subgraph's
5624
- // PUBLIC ID, not a credential. The fix is a chain-correct SERVER-side proxy
5625
- // (see mcp/docs/SUBGRAPH-PROXY-PLAN.md) — same rule as rpcUrls above:
5626
- // never ship an API-keyed URL in a client config.
5627
- diamondHandsUrl: "https://gateway-arbitrum.network.thegraph.com/api/subgraphs/id/CCTPsdYqco2jChDLLBQTbdJWwoukVoMt1cXeR9ti6r9A"
5620
+ // The MAINNET subgraph on The Graph's decentralized network the same id
5621
+ // lit-ops-server's ETHEREUM_SUBGRAPH_URL points at (infra/terraform). The path segment is
5622
+ // the subgraph's PUBLIC ID, not a credential. This used to be a SEPOLIA id under a
5623
+ // chainId-1 config: unusable as shipped, but a caller who added their own key would have
5624
+ // read Sepolia data as mainnet.
5625
+ //
5626
+ // The gateway needs an `Authorization: Bearer <query key>` the SDK does not (and must
5627
+ // not) hold, so this URL only works for a standalone caller supplying their own key.
5628
+ // Service mode never uses it — queries go through the lit-ops-server proxy, which adds
5629
+ // the key server-side. Same rule as rpcUrls above: never ship a keyed URL in a client config.
5630
+ diamondHandsUrl: "https://gateway.thegraph.com/api/subgraphs/id/8Gt9zaSCgkxxSiLMGaKVj7qU3ds1heGVGxgWcXXpwbPd"
5628
5631
  },
5629
5632
  litNetwork: "chipotle",
5630
5633
  debug: false
@@ -5863,7 +5866,7 @@ __export(src_exports, {
5863
5866
  module.exports = __toCommonJS(src_exports);
5864
5867
 
5865
5868
  // src/modules/diamond-hands-sdk.ts
5866
- var import_ethers17 = require("ethers");
5869
+ var import_ethers21 = require("ethers");
5867
5870
 
5868
5871
  // src/types/result.ts
5869
5872
  function success(value) {
@@ -6862,6 +6865,41 @@ async function resolveAuthorizationInput(provider, signer, ctx) {
6862
6865
  return { timestamp: result.timestamp, signature: result.signature };
6863
6866
  }
6864
6867
 
6868
+ // src/utils/loan-helpers.utils.ts
6869
+ function baseMintFeeWei(mintAmountWei, originationFeeBps) {
6870
+ if (mintAmountWei < 0n)
6871
+ throw new Error("baseMintFeeWei: mintAmountWei cannot be negative");
6872
+ if (!Number.isInteger(originationFeeBps) || originationFeeBps < 0 || originationFeeBps > 1e4) {
6873
+ throw new Error(
6874
+ `baseMintFeeWei: originationFeeBps must be an integer in [0, 10000] (got ${String(originationFeeBps)})`
6875
+ );
6876
+ }
6877
+ return mintAmountWei * BigInt(originationFeeBps) / 10000n;
6878
+ }
6879
+ function debtAfterMintExceedsLoanCap(params) {
6880
+ const { currentDebtWei, mintAmountWei, mintFeeWei, maxLoanWei } = params;
6881
+ for (const [name, v] of Object.entries(params)) {
6882
+ if (v < 0n)
6883
+ throw new Error(`debtAfterMintExceedsLoanCap: ${name} cannot be negative`);
6884
+ }
6885
+ return currentDebtWei + mintAmountWei + mintFeeWei > maxLoanWei;
6886
+ }
6887
+ function maxPrincipalWithinLoanCap(params) {
6888
+ const { maxLoanWei, currentDebtWei, originationFeeBps } = params;
6889
+ if (maxLoanWei < 0n || currentDebtWei < 0n) {
6890
+ throw new Error("maxPrincipalWithinLoanCap: amounts cannot be negative");
6891
+ }
6892
+ if (!Number.isInteger(originationFeeBps) || originationFeeBps < 0 || originationFeeBps > 1e4) {
6893
+ throw new Error(
6894
+ `maxPrincipalWithinLoanCap: originationFeeBps must be an integer in [0, 10000] (got ${String(originationFeeBps)})`
6895
+ );
6896
+ }
6897
+ const room = maxLoanWei - currentDebtWei;
6898
+ if (room <= 0n)
6899
+ return 0n;
6900
+ return room * 10000n / (10000n + BigInt(originationFeeBps));
6901
+ }
6902
+
6865
6903
  // src/utils/eip712-login.ts
6866
6904
  var import_ethers4 = require("ethers");
6867
6905
  function buildLoginDomain(chainId) {
@@ -8305,23 +8343,37 @@ var BitcoinUtils = class {
8305
8343
  };
8306
8344
 
8307
8345
  // src/utils/address-conversion.utils.ts
8308
- function safeValidateBitcoinAddress(address, network = "regtest") {
8346
+ function networksOfValidAddress(address) {
8347
+ const lower2 = address.toLowerCase();
8348
+ if (lower2.startsWith("bcrt1"))
8349
+ return ["regtest"];
8350
+ if (lower2.startsWith("bc1"))
8351
+ return ["mainnet"];
8352
+ if (lower2.startsWith("tb1"))
8353
+ return ["testnet"];
8354
+ if (address.startsWith("1") || address.startsWith("3"))
8355
+ return ["mainnet"];
8356
+ return ["testnet", "regtest"];
8357
+ }
8358
+ function safeValidateBitcoinAddress(address, network) {
8309
8359
  if (!address || typeof address !== "string") {
8310
8360
  throw new Error(`Invalid Bitcoin address: must be a non-empty string`);
8311
8361
  }
8312
- const base58Pattern = /^[123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz]+$/;
8313
- const bech32Pattern = /^(bc1|tb1|bcrt1)[a-z0-9]+$/;
8314
- if (!base58Pattern.test(address) && !bech32Pattern.test(address)) {
8315
- throw new Error(`Invalid Bitcoin address format: ${address}`);
8362
+ if (network !== "mainnet" && network !== "testnet" && network !== "regtest") {
8363
+ throw new Error(
8364
+ `Bitcoin network is required to validate an address (got ${JSON.stringify(network)})`
8365
+ );
8316
8366
  }
8317
- if (network === "regtest" || network === "testnet") {
8318
- if (!address.startsWith("m") && !address.startsWith("n") && !address.startsWith("2") && !address.startsWith("tb1") && !address.startsWith("bcrt1")) {
8319
- throw new Error(`Invalid ${network} Bitcoin address: ${address} (must start with m, n, 2, tb1, or bcrt1)`);
8320
- }
8321
- } else if (network === "mainnet") {
8322
- if (!address.startsWith("1") && !address.startsWith("3") && !address.startsWith("bc1")) {
8323
- throw new Error(`Invalid mainnet Bitcoin address: ${address} (must start with 1, 3, or bc1)`);
8324
- }
8367
+ if (!BitcoinUtils.validateAddress(address)) {
8368
+ throw new Error(
8369
+ `Invalid Bitcoin address: ${address} (malformed or failed its checksum \u2014 check for a typo)`
8370
+ );
8371
+ }
8372
+ const belongsTo = networksOfValidAddress(address);
8373
+ if (!belongsTo.includes(network)) {
8374
+ throw new Error(
8375
+ `Bitcoin address ${address} is not a ${network} address \u2014 it is a ${belongsTo.join("/")} address. Sending across networks would lose the funds.`
8376
+ );
8325
8377
  }
8326
8378
  return address;
8327
8379
  }
@@ -19139,6 +19191,625 @@ async function mintAgentPkp(params) {
19139
19191
  clearTimeout(timeout);
19140
19192
  }
19141
19193
  }
19194
+ var AGENT_STATUS = { None: 0, Active: 1, Revoked: 2 };
19195
+ function planAgentBinding(params) {
19196
+ const { isActive, record, nowSeconds } = params;
19197
+ if (isActive)
19198
+ return { kind: "reuse", agent: record.agent };
19199
+ const status = Number(record.status);
19200
+ if (status === AGENT_STATUS.None || status === AGENT_STATUS.Revoked) {
19201
+ return { kind: "register" };
19202
+ }
19203
+ if (status !== AGENT_STATUS.Active) {
19204
+ throw new Error(`Unknown agent status ${status} in AgentDelegationRegistry`);
19205
+ }
19206
+ if (Number(record.validUntil) > nowSeconds) {
19207
+ throw new Error(
19208
+ "AgentDelegationRegistry reports an unexpired agent as inactive \u2014 the registry is paused. Agent delegation cannot be changed until it is unpaused."
19209
+ );
19210
+ }
19211
+ return { kind: "rotate" };
19212
+ }
19213
+
19214
+ // src/utils/assert-provider-chain.ts
19215
+ async function describeProviderChainMismatch(provider, chainId) {
19216
+ const actual = Number((await provider.getNetwork()).chainId);
19217
+ if (actual === chainId)
19218
+ return null;
19219
+ return `Network mismatch: the SDK was configured for chainId ${chainId}, but the provider is connected to chainId ${actual}. Switch the wallet/RPC to chainId ${chainId}, or configure the SDK for chainId ${actual}. Nothing was signed.`;
19220
+ }
19221
+
19222
+ // src/utils/sign-guard/psm-exchange.ts
19223
+ var import_ethers20 = require("ethers");
19224
+
19225
+ // src/utils/sign-guard/errors.ts
19226
+ var TxValidationError = class extends Error {
19227
+ /**
19228
+ * @param subject What is being refused. Defaults to the server-returned transaction the
19229
+ * validator exists for; client-built flows (the PSM exchange) name themselves instead.
19230
+ */
19231
+ constructor(msg, subject = "server-returned transaction") {
19232
+ super(`Refusing to sign ${subject}: ${msg}`);
19233
+ this.name = "TxValidationError";
19234
+ }
19235
+ };
19236
+
19237
+ // src/utils/sign-guard/signable-functions.ts
19238
+ var import_ethers17 = require("ethers");
19239
+ var SIGNABLE_FUNCTIONS = [
19240
+ "function mintUCD(bytes32 positionId, uint256 mintAmount, uint256 mintFee, uint256 newDebt, uint256 newCollateral, uint256 btcPrice, bytes32 authorizedSpendsHash, bytes32 ucdDebtHash, bytes32 contractHash, uint256 quantumTimestamp, bytes calldata mintValidatorSignature) external returns (bool)",
19241
+ // `makePayment` is the ONLY repayment entry point. A `repayPosition` entry
19242
+ // used to sit here; it is not a function on any deployed contract — the
19243
+ // compiled PositionManager ABI has no `repay*` function at all, and the name
19244
+ // survives only in `archive/` prototypes. Nothing in lit-ops-server, the
19245
+ // lit-actions, or the SDK ever emitted it, and AgentModule never whitelisted
19246
+ // it. A signable-function whitelist should not carry calldata shapes the
19247
+ // protocol cannot execute.
19248
+ "function makePayment(bytes32 positionId, uint256 paymentAmount, uint256 quantumTimestamp, uint256 btcPrice, bytes calldata paymentValidatorSignature) external returns (bool)",
19249
+ "function extendPosition(bytes32 positionId, uint256 selectedTerm, uint256 quantumTimestamp, uint256 btcPrice, uint256 availableBTCBalance, uint256 proRataRenewalFee, bytes calldata extensionValidatorSignature) external returns (bool)",
19250
+ "function extendPosition(bytes32 positionId, uint256 selectedTerm, uint256 quantumTimestamp, uint256 btcPrice, uint256 availableBTCBalance, bytes calldata extensionValidatorSignature) external returns (bool)",
19251
+ // Struct-version: matches the actual on-chain function signature and the
19252
+ // SDK's calldata builder. An earlier 3-arg declaration was stale and would
19253
+ // silently fail to decode real `withdrawBTC` calldata. networkFee is NOT a
19254
+ // contract param — it is an off-chain Phase-2 BTC tx fee, validated elsewhere.
19255
+ "function withdrawBTC((bytes32 positionId, bytes32 actionHash, bytes32 authorizedSpendsHash, bytes32 ucdDebtHash, bytes32 contractBundleHash, string withdrawalAddress, uint256 totalDeduction, uint256 newCollateral, uint256 quantumTimestamp, uint256 btcPrice, string utxoTxid, uint32 utxoVout) params, bytes withdrawalValidatorSignature, bytes btcSpendAuthSignature) external returns (bool)",
19256
+ // `cancelStaleSpendByOwner` removed in audit #62210 follow-up — the on-chain
19257
+ // function reverts permanently. The trustless replacement
19258
+ // (`cancelStaleSpendWithProof` on BTCSpendAuthorizer) lands via a separate
19259
+ // entry when its LIT Action ships.
19260
+ "function approve(address spender, uint256 amount) external returns (bool)",
19261
+ "function setPositionDelegate(bytes32 positionId, address newDelegate) external",
19262
+ // Position creation. Signed opaquely by the SDK (like withdrawBTC), so
19263
+ // without an entry here it decoded as "<unparseable>" and the CLI's
19264
+ // WithdrawGuard waved it through — the flow that locks the user's BTC
19265
+ // collateral had no client-side pin at all.
19266
+ "function createPosition(bytes32 pkpId, bytes calldata validatorSignature, string mainnetVaultAddress, string regtestVaultAddress, uint256 selectedTermMonths, uint256 validatorVersion, bytes calldata pkpPublicKey) external returns (bytes32 positionId)",
19267
+ // SimplePSMV2 — the PSM exchange pair. Direct EOA calls, never routed through
19268
+ // AgentModule; the parity test documents them as client-only.
19269
+ "function swap(address stablecoin, uint256 amountIn, uint256 minUcdOut) external returns (uint256)",
19270
+ "function redeem(address stablecoin, uint256 ucdAmount, uint256 minStablecoinOut) external returns (uint256)",
19271
+ // BitcoinWithdrawalAddressRegistry — `msg.sender` must be the borrower, so
19272
+ // this too is client-only and never module-whitelisted.
19273
+ "function addAddress(string btcAddress) external"
19274
+ ];
19275
+ var IFACE = new import_ethers17.ethers.Interface(SIGNABLE_FUNCTIONS);
19276
+ function encodeSignable(fn, args) {
19277
+ return IFACE.encodeFunctionData(fn, args);
19278
+ }
19279
+ function decodeSignable(data) {
19280
+ try {
19281
+ const parsed = IFACE.parseTransaction({ data });
19282
+ if (!parsed) {
19283
+ throw new TxValidationError(
19284
+ `unsignedTx.data does not decode against the signable-function whitelist`
19285
+ );
19286
+ }
19287
+ return { name: parsed.name, args: parsed.args };
19288
+ } catch (e) {
19289
+ if (e instanceof TxValidationError)
19290
+ throw e;
19291
+ throw new TxValidationError(
19292
+ `unsignedTx.data does not decode against the signable-function whitelist: ${e.message}`
19293
+ );
19294
+ }
19295
+ }
19296
+
19297
+ // src/utils/sign-guard/tx-validator.ts
19298
+ var import_ethers19 = require("ethers");
19299
+
19300
+ // src/utils/sign-guard/fee-ceiling.ts
19301
+ var import_ethers18 = require("ethers");
19302
+ var MAX_GAS_LIMIT = 5000000n;
19303
+ var MAX_FEE_PER_GAS_WEI = 2000000000000n;
19304
+ var DEFAULT_MAX_TX_FEE_WEI = 250000000000000000n;
19305
+ var DEFAULT_FEE_CEILING = {
19306
+ maxGasLimit: MAX_GAS_LIMIT,
19307
+ maxFeePerGasWei: MAX_FEE_PER_GAS_WEI,
19308
+ maxTxFeeWei: DEFAULT_MAX_TX_FEE_WEI
19309
+ };
19310
+ function fmtEth(wei) {
19311
+ return `${import_ethers18.ethers.formatEther(wei)} ETH`;
19312
+ }
19313
+ function fmtGwei(wei) {
19314
+ return `${import_ethers18.ethers.formatUnits(wei, "gwei")} gwei`;
19315
+ }
19316
+ function worstCaseFeeWei(gasLimit, maxFeePerGas) {
19317
+ if (gasLimit == null || maxFeePerGas == null)
19318
+ return null;
19319
+ return gasLimit * maxFeePerGas;
19320
+ }
19321
+ function assertFeeCeiling(gasLimit, maxFeePerGas, raise, ceiling = DEFAULT_FEE_CEILING) {
19322
+ if (gasLimit != null && gasLimit > ceiling.maxGasLimit) {
19323
+ raise(`gasLimit ${gasLimit} exceeds the signing ceiling of ${ceiling.maxGasLimit}`);
19324
+ }
19325
+ if (maxFeePerGas != null && maxFeePerGas > ceiling.maxFeePerGasWei) {
19326
+ raise(
19327
+ `maxFeePerGas ${fmtGwei(maxFeePerGas)} exceeds the signing ceiling of ${fmtGwei(ceiling.maxFeePerGasWei)}`
19328
+ );
19329
+ }
19330
+ const worst = worstCaseFeeWei(gasLimit, maxFeePerGas);
19331
+ if (worst != null && worst > ceiling.maxTxFeeWei) {
19332
+ raise(
19333
+ `worst-case transaction fee ${fmtEth(worst)} (gasLimit ${gasLimit} \xD7 ${fmtGwei(maxFeePerGas)}) exceeds the signing ceiling of ${fmtEth(ceiling.maxTxFeeWei)}.${ceiling.raiseHint ? ` ${ceiling.raiseHint}` : ""}`
19334
+ );
19335
+ }
19336
+ }
19337
+
19338
+ // src/utils/sign-guard/tx-validator.ts
19339
+ function eqAddr(a, b) {
19340
+ if (!a || !b)
19341
+ return false;
19342
+ try {
19343
+ return import_ethers19.ethers.getAddress(a) === import_ethers19.ethers.getAddress(b);
19344
+ } catch {
19345
+ return false;
19346
+ }
19347
+ }
19348
+ function readToAddress(tx) {
19349
+ const to = tx["to"];
19350
+ if (typeof to !== "string") {
19351
+ throw new TxValidationError(`unsignedTx.to is missing or not a string`);
19352
+ }
19353
+ return to;
19354
+ }
19355
+ function readData(tx) {
19356
+ const data = tx["data"];
19357
+ if (typeof data !== "string" || !data.startsWith("0x")) {
19358
+ throw new TxValidationError(`unsignedTx.data missing or malformed`);
19359
+ }
19360
+ return data;
19361
+ }
19362
+ function readChainId(tx) {
19363
+ const c = tx["chainId"];
19364
+ if (c == null)
19365
+ return null;
19366
+ if (typeof c === "number")
19367
+ return c;
19368
+ if (typeof c === "string")
19369
+ return parseInt(c.startsWith("0x") ? c.slice(2) : c, c.startsWith("0x") ? 16 : 10);
19370
+ if (typeof c === "bigint")
19371
+ return Number(c);
19372
+ return null;
19373
+ }
19374
+ function readOptionalBigInt(tx, key) {
19375
+ const v = tx[key];
19376
+ if (v == null)
19377
+ return null;
19378
+ try {
19379
+ if (typeof v === "bigint")
19380
+ return v;
19381
+ if (typeof v === "number")
19382
+ return BigInt(v);
19383
+ if (typeof v === "string")
19384
+ return BigInt(v);
19385
+ return BigInt(v.toString());
19386
+ } catch {
19387
+ throw new TxValidationError(`unsignedTx.${key} is present but not a valid integer`);
19388
+ }
19389
+ }
19390
+ function readValue(tx) {
19391
+ const v = tx["value"];
19392
+ if (v == null)
19393
+ return 0n;
19394
+ if (typeof v === "string")
19395
+ return BigInt(v);
19396
+ if (typeof v === "number")
19397
+ return BigInt(v);
19398
+ if (typeof v === "bigint")
19399
+ return v;
19400
+ const maybe = v;
19401
+ if (typeof maybe.toBigInt === "function")
19402
+ return maybe.toBigInt();
19403
+ if (typeof maybe.toString === "function")
19404
+ return BigInt(maybe.toString());
19405
+ throw new TxValidationError(`unsignedTx.value has unrecognized type`);
19406
+ }
19407
+ function normalizePositionId(id) {
19408
+ const hex = id.startsWith("0x") ? id : `0x${id}`;
19409
+ return import_ethers19.ethers.zeroPadValue(hex, 32).toLowerCase();
19410
+ }
19411
+ function requirePositionId(actual, expected) {
19412
+ const txPositionId = String(actual).toLowerCase();
19413
+ if (txPositionId !== normalizePositionId(expected)) {
19414
+ throw new TxValidationError(
19415
+ `positionId mismatch \u2014 tx ${txPositionId}, expected ${normalizePositionId(expected)}`
19416
+ );
19417
+ }
19418
+ }
19419
+ function validateUnsignedTx(unsignedTx, expected, vctx) {
19420
+ const txChainId = readChainId(unsignedTx);
19421
+ if (txChainId == null) {
19422
+ throw new TxValidationError(
19423
+ `unsignedTx.chainId is missing \u2014 refusing to sign a transaction with no chain binding (client is on ${vctx.chainId})`
19424
+ );
19425
+ }
19426
+ if (txChainId !== vctx.chainId) {
19427
+ throw new TxValidationError(
19428
+ `chainId mismatch \u2014 tx says ${txChainId}, client is on ${vctx.chainId}`
19429
+ );
19430
+ }
19431
+ const value = readValue(unsignedTx);
19432
+ if (value !== 0n) {
19433
+ throw new TxValidationError(
19434
+ `unsignedTx.value is non-zero (${value}); none of the protocol functions accept ETH`
19435
+ );
19436
+ }
19437
+ assertFeeCeiling(
19438
+ readOptionalBigInt(unsignedTx, "gasLimit"),
19439
+ readOptionalBigInt(unsignedTx, "maxFeePerGas") ?? readOptionalBigInt(unsignedTx, "gasPrice"),
19440
+ (msg) => {
19441
+ throw new TxValidationError(msg);
19442
+ },
19443
+ vctx.feeCeiling
19444
+ );
19445
+ const to = readToAddress(unsignedTx);
19446
+ const data = readData(unsignedTx);
19447
+ const { name, args } = decodeSignable(data);
19448
+ const pm = vctx.contracts.PositionManager;
19449
+ switch (expected.kind) {
19450
+ case "mint": {
19451
+ if (name !== "mintUCD") {
19452
+ throw new TxValidationError(`expected mintUCD, server returned ${name}`);
19453
+ }
19454
+ if (!eqAddr(to, pm)) {
19455
+ throw new TxValidationError(`mintUCD must target PositionManager (${pm}), got ${to}`);
19456
+ }
19457
+ requirePositionId(args[0], expected.positionId);
19458
+ const txMintAmount = BigInt(String(args[1]));
19459
+ if (txMintAmount.toString() !== expected.amountWei) {
19460
+ throw new TxValidationError(`mintAmount mismatch \u2014 tx ${txMintAmount}, expected ${expected.amountWei}`);
19461
+ }
19462
+ const txMintFee = BigInt(String(args[2]));
19463
+ if (txMintFee.toString() !== expected.mintFeeWei) {
19464
+ throw new TxValidationError(`mintFee mismatch \u2014 tx ${txMintFee}, expected ${expected.mintFeeWei}`);
19465
+ }
19466
+ break;
19467
+ }
19468
+ case "repay": {
19469
+ if (name !== "makePayment") {
19470
+ throw new TxValidationError(`expected makePayment, server returned ${name}`);
19471
+ }
19472
+ if (!eqAddr(to, pm)) {
19473
+ throw new TxValidationError(`${name} must target PositionManager (${pm}), got ${to}`);
19474
+ }
19475
+ requirePositionId(args[0], expected.positionId);
19476
+ const txAmount = BigInt(String(args[1]));
19477
+ if (txAmount.toString() !== expected.amountWei) {
19478
+ throw new TxValidationError(`paymentAmount mismatch \u2014 tx ${txAmount}, expected ${expected.amountWei}`);
19479
+ }
19480
+ break;
19481
+ }
19482
+ case "extend": {
19483
+ if (name !== "extendPosition") {
19484
+ throw new TxValidationError(`expected extendPosition, server returned ${name}`);
19485
+ }
19486
+ if (!eqAddr(to, pm)) {
19487
+ throw new TxValidationError(`extendPosition must target PositionManager (${pm}), got ${to}`);
19488
+ }
19489
+ requirePositionId(args[0], expected.positionId);
19490
+ const txTerm = Number(args[1]);
19491
+ if (txTerm !== expected.selectedTerm) {
19492
+ throw new TxValidationError(`selectedTerm mismatch \u2014 tx ${txTerm}, expected ${expected.selectedTerm}`);
19493
+ }
19494
+ if (expected.upperBoundProRataFeeWei != null && args.length >= 7) {
19495
+ const txFee = BigInt(String(args[5]));
19496
+ const upper = BigInt(expected.upperBoundProRataFeeWei);
19497
+ if (txFee > upper) {
19498
+ throw new TxValidationError(
19499
+ `proRataRenewalFee=${txFee} exceeds upper bound=${upper}. A compromised validator could otherwise inflate the fee to drain UCD.`
19500
+ );
19501
+ }
19502
+ }
19503
+ break;
19504
+ }
19505
+ case "withdraw-btc": {
19506
+ if (name !== "withdrawBTC") {
19507
+ throw new TxValidationError(`expected withdrawBTC, server returned ${name}`);
19508
+ }
19509
+ if (!eqAddr(to, pm)) {
19510
+ throw new TxValidationError(`withdrawBTC must target PositionManager (${pm}), got ${to}`);
19511
+ }
19512
+ const paramsTuple = args[0];
19513
+ requirePositionId(paramsTuple[0], expected.positionId);
19514
+ const txWithdrawalAddress = String(paramsTuple[5]);
19515
+ if (txWithdrawalAddress !== expected.btcAddress) {
19516
+ throw new TxValidationError(`btcAddress mismatch \u2014 tx '${txWithdrawalAddress}', expected '${expected.btcAddress}'`);
19517
+ }
19518
+ if (expected.upperBoundTotalDeduction != null) {
19519
+ const txDeduction = BigInt(String(paramsTuple[6]));
19520
+ const upper = BigInt(expected.upperBoundTotalDeduction);
19521
+ if (txDeduction > upper) {
19522
+ throw new TxValidationError(
19523
+ `totalDeduction=${txDeduction} exceeds approved upper bound=${upper}. A compromised validator could otherwise drain collateral beyond the approved amount.`
19524
+ );
19525
+ }
19526
+ }
19527
+ break;
19528
+ }
19529
+ case "ucd-approve": {
19530
+ if (name !== "approve") {
19531
+ throw new TxValidationError(`expected ERC-20 approve, server returned ${name}`);
19532
+ }
19533
+ const ucd = vctx.contracts.UCDToken;
19534
+ if (!eqAddr(to, ucd)) {
19535
+ throw new TxValidationError(`approve must target UCDToken (${ucd}), got ${to}`);
19536
+ }
19537
+ const spender = String(args[0]);
19538
+ const ok = expected.spenderCandidates.some((s) => eqAddr(spender, s));
19539
+ if (!ok) {
19540
+ throw new TxValidationError(
19541
+ `approve spender ${spender} not in expected set ${expected.spenderCandidates.join(", ")}`
19542
+ );
19543
+ }
19544
+ const amt = BigInt(String(args[1]));
19545
+ const min = BigInt(expected.minAmountWei);
19546
+ if (amt < min) {
19547
+ throw new TxValidationError(`approve amount ${amt} is less than required ${min}`);
19548
+ }
19549
+ const SANITY_MAX = min * 1000n;
19550
+ if (amt > SANITY_MAX) {
19551
+ throw new TxValidationError(`approve amount ${amt} exceeds sanity cap ${SANITY_MAX} (1000x requested)`);
19552
+ }
19553
+ break;
19554
+ }
19555
+ case "create-position": {
19556
+ if (name !== "createPosition") {
19557
+ throw new TxValidationError(`expected createPosition, server returned ${name}`);
19558
+ }
19559
+ if (!eqAddr(to, pm)) {
19560
+ throw new TxValidationError(`createPosition must target PositionManager (${pm}), got ${to}`);
19561
+ }
19562
+ const txTerm = BigInt(String(args[4]));
19563
+ if (txTerm !== BigInt(expected.selectedTerm)) {
19564
+ throw new TxValidationError(`selectedTerm mismatch \u2014 tx ${txTerm}, expected ${expected.selectedTerm}`);
19565
+ }
19566
+ break;
19567
+ }
19568
+ case "set-position-delegate": {
19569
+ if (name !== "setPositionDelegate") {
19570
+ throw new TxValidationError(`expected setPositionDelegate, server returned ${name}`);
19571
+ }
19572
+ if (!eqAddr(to, expected.registryAddress)) {
19573
+ throw new TxValidationError(
19574
+ `setPositionDelegate must target PositionDelegateRegistry (${expected.registryAddress}), got ${to}`
19575
+ );
19576
+ }
19577
+ requirePositionId(args[0], expected.positionId);
19578
+ const txDelegate = String(args[1]);
19579
+ if (!eqAddr(txDelegate, expected.delegate)) {
19580
+ throw new TxValidationError(`delegate mismatch \u2014 tx ${txDelegate}, expected ${expected.delegate}`);
19581
+ }
19582
+ break;
19583
+ }
19584
+ case "bwar-add-address": {
19585
+ if (name !== "addAddress") {
19586
+ throw new TxValidationError(`expected addAddress, decoded ${name}`);
19587
+ }
19588
+ if (!eqAddr(to, expected.registryAddress)) {
19589
+ throw new TxValidationError(
19590
+ `addAddress must target the BitcoinWithdrawalAddressRegistry (${expected.registryAddress}), got ${to}`
19591
+ );
19592
+ }
19593
+ if (String(args[0]) !== expected.btcAddress) {
19594
+ throw new TxValidationError(
19595
+ `btcAddress mismatch \u2014 tx says '${String(args[0])}', user asked for '${expected.btcAddress}'`
19596
+ );
19597
+ }
19598
+ break;
19599
+ }
19600
+ case "stablecoin-approve": {
19601
+ if (name !== "approve") {
19602
+ throw new TxValidationError(`expected ERC-20 approve, server returned ${name}`);
19603
+ }
19604
+ if (!eqAddr(to, expected.tokenAddress)) {
19605
+ throw new TxValidationError(`approve must target the stablecoin token (${expected.tokenAddress}), got ${to}`);
19606
+ }
19607
+ if (!eqAddr(String(args[0]), expected.spender)) {
19608
+ throw new TxValidationError(`approve spender must be the PSM (${expected.spender}), got ${String(args[0])}`);
19609
+ }
19610
+ if (BigInt(String(args[1])).toString() !== expected.amountUnits) {
19611
+ throw new TxValidationError(
19612
+ `approve amount must be EXACTLY ${expected.amountUnits} (exact-amount rule), got ${BigInt(String(args[1]))}`
19613
+ );
19614
+ }
19615
+ break;
19616
+ }
19617
+ case "ucd-approve-controller": {
19618
+ if (name !== "approve") {
19619
+ throw new TxValidationError(`expected ERC-20 approve, server returned ${name}`);
19620
+ }
19621
+ if (!eqAddr(to, expected.ucdTokenAddress)) {
19622
+ throw new TxValidationError(`approve must target UCDToken (${expected.ucdTokenAddress}), got ${to}`);
19623
+ }
19624
+ if (!eqAddr(String(args[0]), expected.spender)) {
19625
+ throw new TxValidationError(`approve spender must be the UCDController (${expected.spender}), got ${String(args[0])}`);
19626
+ }
19627
+ if (BigInt(String(args[1])).toString() !== expected.amountWei) {
19628
+ throw new TxValidationError(
19629
+ `approve amount must be EXACTLY ${expected.amountWei} (exact-amount rule), got ${BigInt(String(args[1]))}`
19630
+ );
19631
+ }
19632
+ break;
19633
+ }
19634
+ case "psm-swap": {
19635
+ if (name !== "swap")
19636
+ throw new TxValidationError(`expected swap, server returned ${name}`);
19637
+ if (!eqAddr(to, expected.psmAddress)) {
19638
+ throw new TxValidationError(`swap must target the PSM (${expected.psmAddress}), got ${to}`);
19639
+ }
19640
+ if (!eqAddr(String(args[0]), expected.stablecoin))
19641
+ throw new TxValidationError(`swap stablecoin mismatch`);
19642
+ if (BigInt(String(args[1])).toString() !== expected.amountIn)
19643
+ throw new TxValidationError(`swap amountIn mismatch`);
19644
+ if (BigInt(String(args[2])).toString() !== expected.minOut)
19645
+ throw new TxValidationError(`swap minUcdOut mismatch`);
19646
+ if (BigInt(expected.minOut) === 0n) {
19647
+ throw new TxValidationError(`swap minUcdOut is 0 \u2014 a slippage floor is mandatory (SlippageProtectionRequired)`);
19648
+ }
19649
+ break;
19650
+ }
19651
+ case "psm-redeem": {
19652
+ if (name !== "redeem")
19653
+ throw new TxValidationError(`expected redeem, server returned ${name}`);
19654
+ if (!eqAddr(to, expected.psmAddress)) {
19655
+ throw new TxValidationError(`redeem must target the PSM (${expected.psmAddress}), got ${to}`);
19656
+ }
19657
+ if (!eqAddr(String(args[0]), expected.stablecoin))
19658
+ throw new TxValidationError(`redeem stablecoin mismatch`);
19659
+ if (BigInt(String(args[1])).toString() !== expected.amountUcdWei)
19660
+ throw new TxValidationError(`redeem ucdAmount mismatch`);
19661
+ if (BigInt(String(args[2])).toString() !== expected.minOut)
19662
+ throw new TxValidationError(`redeem minStablecoinOut mismatch`);
19663
+ if (BigInt(expected.minOut) === 0n) {
19664
+ throw new TxValidationError(`redeem minStablecoinOut is 0 \u2014 a slippage floor is mandatory (SlippageProtectionRequired)`);
19665
+ }
19666
+ break;
19667
+ }
19668
+ default: {
19669
+ const _exhaustive = expected;
19670
+ throw new TxValidationError(`unhandled expected action kind: ${JSON.stringify(_exhaustive)}`);
19671
+ }
19672
+ }
19673
+ }
19674
+
19675
+ // src/utils/sign-guard/psm-exchange.ts
19676
+ function buildPsmApproveTx(p) {
19677
+ return {
19678
+ to: p.token,
19679
+ data: encodeSignable("approve", [p.spender, p.amount]),
19680
+ value: "0x0",
19681
+ chainId: p.chainId
19682
+ };
19683
+ }
19684
+ function buildPsmSwapTx(p) {
19685
+ return {
19686
+ to: p.psm,
19687
+ data: encodeSignable("swap", [p.stablecoin, p.amountIn, p.minOut]),
19688
+ value: "0x0",
19689
+ chainId: p.chainId
19690
+ };
19691
+ }
19692
+ function buildPsmRedeemTx(p) {
19693
+ return {
19694
+ to: p.psm,
19695
+ data: encodeSignable("redeem", [p.stablecoin, p.ucdAmount, p.minOut]),
19696
+ value: "0x0",
19697
+ chainId: p.chainId
19698
+ };
19699
+ }
19700
+ var PSM_READS_ABI = ["function supportedStablecoins(address) view returns (bool)"];
19701
+ var ERC20_READS_ABI = ["function allowance(address owner, address spender) view returns (uint256)"];
19702
+ function psmExchangeReadsFromProvider(provider, psmAddress) {
19703
+ const psm = new import_ethers20.ethers.Contract(psmAddress, PSM_READS_ABI, provider);
19704
+ return {
19705
+ isStablecoinSupported: async (stablecoin) => await psm.getFunction("supportedStablecoins")(stablecoin),
19706
+ allowance: async (token, owner, spender) => await new import_ethers20.ethers.Contract(token, ERC20_READS_ABI, provider).getFunction("allowance")(owner, spender)
19707
+ };
19708
+ }
19709
+ var refuse = (direction, msg) => new TxValidationError(msg, `PSM ${direction}`);
19710
+ function requireAddress(direction, label, value) {
19711
+ if (!value || !import_ethers20.ethers.isAddress(value)) {
19712
+ throw refuse(direction, `${label} address is missing or invalid (${String(value)})`);
19713
+ }
19714
+ return import_ethers20.ethers.getAddress(value);
19715
+ }
19716
+ async function planPsmExchange(params) {
19717
+ const { direction, amountIn, minOut, vctx, reads } = params;
19718
+ const chainId = vctx.chainId;
19719
+ if (amountIn <= 0n) {
19720
+ throw refuse(direction, `amount must be greater than zero (got ${amountIn})`);
19721
+ }
19722
+ if (minOut <= 0n) {
19723
+ throw refuse(direction, `minimum-out floor must be greater than zero (got ${minOut}) \u2014 a zero floor is refused on-chain`);
19724
+ }
19725
+ const owner = requireAddress(direction, "owner", params.owner);
19726
+ const psm = requireAddress(direction, "SimplePSMV2", params.addresses.psm);
19727
+ const stablecoin = requireAddress(direction, "stablecoin", params.addresses.stablecoin);
19728
+ const isSwap = direction === "swap";
19729
+ const token = isSwap ? stablecoin : requireAddress(direction, "UCDToken", params.addresses.ucdToken);
19730
+ const spender = isSwap ? psm : requireAddress(direction, "UCDController", params.addresses.ucdController);
19731
+ if (!await reads.isStablecoinSupported(stablecoin)) {
19732
+ throw refuse(direction, `stablecoin ${stablecoin} is not supported by the PSM at ${psm}`);
19733
+ }
19734
+ const approveExpected = (amount) => isSwap ? { kind: "stablecoin-approve", tokenAddress: token, spender, amountUnits: amount.toString() } : { kind: "ucd-approve-controller", ucdTokenAddress: token, spender, amountWei: amount.toString() };
19735
+ const allowanceBefore = await reads.allowance(token, owner, spender);
19736
+ const approvals = [];
19737
+ if (allowanceBefore < amountIn) {
19738
+ if (allowanceBefore > 0n) {
19739
+ approvals.push({
19740
+ step: "reset-approve",
19741
+ tx: buildPsmApproveTx({ token, spender, amount: 0n, chainId }),
19742
+ expected: approveExpected(0n)
19743
+ });
19744
+ }
19745
+ approvals.push({
19746
+ step: "approve",
19747
+ tx: buildPsmApproveTx({ token, spender, amount: amountIn, chainId }),
19748
+ expected: approveExpected(amountIn)
19749
+ });
19750
+ }
19751
+ const exec = isSwap ? {
19752
+ step: "swap",
19753
+ tx: buildPsmSwapTx({ psm, stablecoin, amountIn, minOut, chainId }),
19754
+ expected: { kind: "psm-swap", psmAddress: psm, stablecoin, amountIn: amountIn.toString(), minOut: minOut.toString() }
19755
+ } : {
19756
+ step: "redeem",
19757
+ tx: buildPsmRedeemTx({ psm, stablecoin, ucdAmount: amountIn, minOut, chainId }),
19758
+ expected: {
19759
+ kind: "psm-redeem",
19760
+ psmAddress: psm,
19761
+ stablecoin,
19762
+ amountUcdWei: amountIn.toString(),
19763
+ minOut: minOut.toString()
19764
+ }
19765
+ };
19766
+ for (const leg of [...approvals, exec]) {
19767
+ validateUnsignedTx({ ...leg.tx }, leg.expected, vctx);
19768
+ }
19769
+ return { direction, owner, token, spender, amountIn, minOut, allowanceBefore, approvals, exec };
19770
+ }
19771
+ async function executePsmPlan(plan, signer, vctx) {
19772
+ const approvalHashes = [];
19773
+ const residual = () => approvalHashes.length === 0 ? "" : ` An approval already landed (tx ${approvalHashes[approvalHashes.length - 1]}): an allowance of exactly ${plan.amountIn} to ${plan.spender} stands. It authorizes only that amount; the next exchange uses or replaces it.`;
19774
+ const sendLeg = async (leg) => {
19775
+ const request = { to: leg.tx.to, data: leg.tx.data, value: 0n, chainId: leg.tx.chainId };
19776
+ validateUnsignedTx({ ...request }, leg.expected, vctx);
19777
+ const sent = await signer.sendTransaction(request);
19778
+ const receipt = await sent.wait();
19779
+ if (!receipt)
19780
+ throw new Error(`PSM ${leg.step} tx ${sent.hash} returned no receipt`);
19781
+ if (receipt.status !== 1)
19782
+ throw new Error(`PSM ${leg.step} tx ${sent.hash} reverted`);
19783
+ return { hash: sent.hash, blockNumber: receipt.blockNumber };
19784
+ };
19785
+ for (const leg of plan.approvals) {
19786
+ const landed = await sendLeg(leg).catch((e) => {
19787
+ throw new Error(`PSM ${leg.step} failed: ${e instanceof Error ? e.message : String(e)}.${residual()}`);
19788
+ });
19789
+ approvalHashes.push(landed.hash);
19790
+ }
19791
+ const exec = await sendLeg(plan.exec).catch((e) => {
19792
+ throw new Error(`PSM ${plan.exec.step} failed: ${e instanceof Error ? e.message : String(e)}.${residual()}`);
19793
+ });
19794
+ return { ...exec, approvalHashes };
19795
+ }
19796
+
19797
+ // src/utils/lit-action-chain-name.ts
19798
+ var LIT_ACTION_CHAIN_NAMES = Object.freeze({
19799
+ 1: "ethereum",
19800
+ 11155111: "sepolia",
19801
+ 1337: "hardhat",
19802
+ 31337: "hardhat"
19803
+ });
19804
+ function litActionChainNameForChainId(chainId) {
19805
+ const name = LIT_ACTION_CHAIN_NAMES[Number(chainId)];
19806
+ if (!name) {
19807
+ throw new Error(
19808
+ `Unsupported chainId ${String(chainId)} for a Lit Action (supported: ${Object.keys(LIT_ACTION_CHAIN_NAMES).join(", ")})`
19809
+ );
19810
+ }
19811
+ return name;
19812
+ }
19142
19813
 
19143
19814
  // src/modules/mock/mock-token-manager.module.ts
19144
19815
  var MockTokenManager = class {
@@ -19892,7 +20563,7 @@ var DiamondHandsSDK = class _DiamondHandsSDK {
19892
20563
  */
19893
20564
  constructor(config) {
19894
20565
  if (!config.provider && config.ethRpcUrl) {
19895
- config.provider = new import_ethers17.JsonRpcProvider(config.ethRpcUrl);
20566
+ config.provider = new import_ethers21.JsonRpcProvider(config.ethRpcUrl);
19896
20567
  }
19897
20568
  this.config = config;
19898
20569
  if (config.debug) {
@@ -20123,6 +20794,18 @@ var DiamondHandsSDK = class _DiamondHandsSDK {
20123
20794
  */
20124
20795
  static async create(config) {
20125
20796
  const userProvidedServiceEndpoint = config.serviceEndpoint;
20797
+ if (typeof config.chainId === "number" && config.provider) {
20798
+ const mismatch = await describeProviderChainMismatch(config.provider, config.chainId);
20799
+ if (mismatch) {
20800
+ return failure(
20801
+ new SDKError({
20802
+ message: mismatch,
20803
+ category: "CONFIGURATION" /* CONFIGURATION */,
20804
+ severity: "HIGH" /* HIGH */
20805
+ })
20806
+ );
20807
+ }
20808
+ }
20126
20809
  const enrichedConfig = await _DiamondHandsSDK.enrichConfigWithNetworkDefaults(config);
20127
20810
  if (userProvidedServiceEndpoint) {
20128
20811
  enrichedConfig.serviceEndpoint = userProvidedServiceEndpoint;
@@ -20172,7 +20855,7 @@ var DiamondHandsSDK = class _DiamondHandsSDK {
20172
20855
  const network = await config.provider.getNetwork();
20173
20856
  chainId = Number(network.chainId);
20174
20857
  } else if (config.ethRpcUrl) {
20175
- const tempProvider = new import_ethers17.JsonRpcProvider(
20858
+ const tempProvider = new import_ethers21.JsonRpcProvider(
20176
20859
  config.ethRpcUrl
20177
20860
  );
20178
20861
  const network = await tempProvider.getNetwork();
@@ -20708,7 +21391,7 @@ var DiamondHandsSDK = class _DiamondHandsSDK {
20708
21391
  }
20709
21392
  const loanOps = this.loanOps();
20710
21393
  const protocolConfig = await loanOps.getProtocolConfig();
20711
- const requestAmountWei = (0, import_ethers17.parseEther)(
21394
+ const requestAmountWei = (0, import_ethers21.parseEther)(
20712
21395
  request.amount.toString()
20713
21396
  );
20714
21397
  const minLoanValueWei = BigInt(protocolConfig.minimumLoanValueWei);
@@ -20763,6 +21446,53 @@ var DiamondHandsSDK = class _DiamondHandsSDK {
20763
21446
  if (this.config.debug) {
20764
21447
  log.info(` Position PKP ID: ${position2.pkpId}`);
20765
21448
  }
21449
+ const termsResult = await this.getTermsWithFees();
21450
+ if (!termsResult.success) {
21451
+ return {
21452
+ success: false,
21453
+ error: `Cannot verify the loan cap before minting: ${termsResult.error.message}`
21454
+ };
21455
+ }
21456
+ const positionTermMonths = Number(position2.selectedTerm);
21457
+ const positionTerm = termsResult.value.terms.find(
21458
+ (term) => term.termMonths === positionTermMonths
21459
+ );
21460
+ if (!positionTerm) {
21461
+ return {
21462
+ success: false,
21463
+ error: `Cannot verify the loan cap before minting: TermManager has no fee entry for the position's ${positionTermMonths}-month term`
21464
+ };
21465
+ }
21466
+ const currentDebtWei = BigInt(position2.ucdDebt);
21467
+ const baseFeeWei = baseMintFeeWei(
21468
+ requestAmountWei,
21469
+ positionTerm.originationFeeBps
21470
+ );
21471
+ if (debtAfterMintExceedsLoanCap({
21472
+ currentDebtWei,
21473
+ mintAmountWei: requestAmountWei,
21474
+ mintFeeWei: baseFeeWei,
21475
+ maxLoanWei: maxLoanValueWei
21476
+ })) {
21477
+ const debtAfterWei = currentDebtWei + requestAmountWei + baseFeeWei;
21478
+ const maxPrincipalUcd = Number(
21479
+ maxPrincipalWithinLoanCap({
21480
+ maxLoanWei: maxLoanValueWei,
21481
+ currentDebtWei,
21482
+ originationFeeBps: positionTerm.originationFeeBps
21483
+ }) / BigInt(10 ** 18)
21484
+ );
21485
+ return {
21486
+ success: false,
21487
+ error: `Amount ${request.amount} UCD plus the ${positionTerm.originationFeeBps / 100}% origination fee (${(0, import_ethers21.formatEther)(baseFeeWei)} UCD) would take this loan's debt to ${(0, import_ethers21.formatEther)(debtAfterWei)} UCD, above the protocol maximum of ${(0, import_ethers21.formatEther)(maxLoanValueWei)} UCD. The largest amount you can mint now is ${maxPrincipalUcd} UCD.`
21488
+ };
21489
+ }
21490
+ if (this.config.debug) {
21491
+ log.info(
21492
+ `\u2705 Fee-inclusive loan cap check passed: ${(0, import_ethers21.formatEther)(currentDebtWei + requestAmountWei + baseFeeWei)} UCD <= ${(0, import_ethers21.formatEther)(maxLoanValueWei)} UCD`,
21493
+ {}
21494
+ );
21495
+ }
20766
21496
  let pkpPublicKey;
20767
21497
  let pkpEthAddress;
20768
21498
  const pkpCache = this.cacheManager.getCache("pkp-data", {
@@ -20790,7 +21520,7 @@ var DiamondHandsSDK = class _DiamondHandsSDK {
20790
21520
  pkpNftAddress,
20791
21521
  this.getChipotlePublicKeyFallback()
20792
21522
  );
20793
- pkpEthAddress = (0, import_ethers17.computeAddress)(pkpPublicKey);
21523
+ pkpEthAddress = (0, import_ethers21.computeAddress)(pkpPublicKey);
20794
21524
  pkpCache.set(request.positionId, {
20795
21525
  publicKey: pkpPublicKey,
20796
21526
  ethAddress: pkpEthAddress,
@@ -20852,7 +21582,7 @@ var DiamondHandsSDK = class _DiamondHandsSDK {
20852
21582
  ` UCDController: ${contracts?.UCDController || "MISSING"}`
20853
21583
  );
20854
21584
  }
20855
- const chain = this.config.chain || (Number(network.chainId) === 1 ? "ethereum" : "sepolia");
21585
+ const chain = this.config.chain || litActionChainNameForChainId(network.chainId);
20856
21586
  const devBitcoinProviderUrl = request.customBitcoinRpcUrl || this.config.bitcoinProviders?.[0]?.url;
20857
21587
  if (this.config.debug) {
20858
21588
  log.info(` Network: ${chain} (chainId: ${network.chainId})`);
@@ -21133,8 +21863,8 @@ var DiamondHandsSDK = class _DiamondHandsSDK {
21133
21863
  throw new Error(`Position not found: ${request.positionId}`);
21134
21864
  }
21135
21865
  const currentDebt = position.ucdDebt.toString();
21136
- const ucdDebtHash = (0, import_ethers17.keccak256)(import_ethers17.AbiCoder.defaultAbiCoder().encode(["uint256"], [currentDebt]));
21137
- const contractHash = (0, import_ethers17.keccak256)(import_ethers17.AbiCoder.defaultAbiCoder().encode(
21866
+ const ucdDebtHash = (0, import_ethers21.keccak256)(import_ethers21.AbiCoder.defaultAbiCoder().encode(["uint256"], [currentDebt]));
21867
+ const contractHash = (0, import_ethers21.keccak256)(import_ethers21.AbiCoder.defaultAbiCoder().encode(
21138
21868
  ["address", "address", "address", "address"],
21139
21869
  [
21140
21870
  positionManagerAddress,
@@ -21203,7 +21933,7 @@ var DiamondHandsSDK = class _DiamondHandsSDK {
21203
21933
  const coreAbi = [
21204
21934
  "function getPositionDetails(bytes32) view returns (tuple(bytes32 positionId, bytes32 pkpId, uint256 ucdDebt, string vaultAddress, address borrower, uint40 createdAt, uint40 lastUpdated, uint16 selectedTerm, uint40 expiryAt, uint8 status, uint40 previousExpiryAt, uint16 totalTerm))"
21205
21935
  ];
21206
- const positionCore = new import_ethers17.Contract(
21936
+ const positionCore = new import_ethers21.Contract(
21207
21937
  coreAddress,
21208
21938
  coreAbi,
21209
21939
  this.getSignerOrThrow().provider
@@ -21211,8 +21941,8 @@ var DiamondHandsSDK = class _DiamondHandsSDK {
21211
21941
  const currentPosition = await positionCore["getPositionDetails"](
21212
21942
  positionIdBytes32
21213
21943
  );
21214
- const currentDebtHash = (0, import_ethers17.keccak256)(
21215
- import_ethers17.AbiCoder.defaultAbiCoder().encode(
21944
+ const currentDebtHash = (0, import_ethers21.keccak256)(
21945
+ import_ethers21.AbiCoder.defaultAbiCoder().encode(
21216
21946
  ["uint256"],
21217
21947
  [currentPosition.ucdDebt]
21218
21948
  )
@@ -21259,7 +21989,7 @@ var DiamondHandsSDK = class _DiamondHandsSDK {
21259
21989
  "function getCurrentQuantum() view returns (uint256)",
21260
21990
  "function isQuantumValid(bytes32,uint256) view returns (bool)"
21261
21991
  ];
21262
- const registry = new import_ethers17.Contract(
21992
+ const registry = new import_ethers21.Contract(
21263
21993
  registryAddress,
21264
21994
  registryAbi,
21265
21995
  this.getSignerOrThrow().provider
@@ -21375,7 +22105,7 @@ var DiamondHandsSDK = class _DiamondHandsSDK {
21375
22105
  });
21376
22106
  }
21377
22107
  const signatureHexMint = finalSignature.startsWith("0x") ? finalSignature : "0x" + finalSignature;
21378
- const mintIface = new import_ethers17.Interface(positionManagerAbi);
22108
+ const mintIface = new import_ethers21.Interface(positionManagerAbi);
21379
22109
  const mintCalldata = mintIface.encodeFunctionData("mintUCD", [
21380
22110
  positionIdBytes32,
21381
22111
  validationResponse.mintAmount,
@@ -21411,7 +22141,7 @@ var DiamondHandsSDK = class _DiamondHandsSDK {
21411
22141
  if (viewsAddress) {
21412
22142
  let diagnosis = null;
21413
22143
  try {
21414
- const views = new import_ethers17.Contract(
22144
+ const views = new import_ethers21.Contract(
21415
22145
  viewsAddress,
21416
22146
  [
21417
22147
  "function diagnoseMintUCD(bytes32,uint256,uint256,uint256,uint256,uint256,bytes32,bytes32,bytes32,uint256,bytes) view returns (string)"
@@ -21452,6 +22182,25 @@ Error data: none`
21452
22182
  }
21453
22183
  const selector = simError.selector;
21454
22184
  const errorName = simError.errorName ?? (selector ? `Unknown error ${selector}` : "unknown");
22185
+ const MINT_GUARD_CODES = {
22186
+ "1": "MINT_GUARD_LOAN_MAX_EXCEEDED \u2014 the position's total debt after this mint (existing debt + principal + fee) exceeds maximumLoanValueUcd",
22187
+ "2": "MINT_GUARD_CIRCUIT_BREAKER_EXCEEDED \u2014 exceeds CircuitBreaker maxSingleLoanValue",
22188
+ "3": "MINT_GUARD_PSM_DAILY_EXCEEDED \u2014 exceeds the PSM daily mint limit"
22189
+ };
22190
+ let loanCapDiagnostics = "";
22191
+ if (selector === "0xe6dd4d41") {
22192
+ const guardCode = BigInt(
22193
+ "0x" + String(simError.data).slice(10).padStart(64, "0")
22194
+ ).toString();
22195
+ const guardMeaning = MINT_GUARD_CODES[guardCode] ?? `unknown MintGuardFailed code ${guardCode}`;
22196
+ loanCapDiagnostics = `
22197
+
22198
+ MintGuardFailed(${guardCode}): ${guardMeaning}
22199
+ Lit mintAmount: ${validationResponse.mintAmount}
22200
+ Lit mintFee: ${validationResponse.mintFee}
22201
+ Lit newDebt: ${validationResponse.newDebt}
22202
+ Protocol maximum: ${(0, import_ethers21.formatEther)(maxLoanValueWei)} UCD (fee-inclusive)`;
22203
+ }
21455
22204
  const mintDebtDiagnostics = selector === "0xb9d419a7" || // DebtUpdateVerificationFailed()
21456
22205
  selector === "0xc7e20553" || // DebtUpdateVerificationFailedDetailed(...)
21457
22206
  selector === "0x0cfd2a97" || // MintVerificationMismatch(uint256,uint256)
@@ -21497,7 +22246,7 @@ Quantum Timing Analysis:
21497
22246
  Error selector: ${selector}
21498
22247
  Error data: ${simError.data}
21499
22248
  Call path: mintUCD -> mintUCDWithAuthorization -> increaseDebtFromMint -> finalizeMintDebtIncrease
21500
- Message: ${causeMessage}${quantumContext}${mintDebtDiagnostics}`
22249
+ Message: ${causeMessage}${quantumContext}${loanCapDiagnostics}${mintDebtDiagnostics}`
21501
22250
  );
21502
22251
  }
21503
22252
  const tx = await sendEip1559Transaction({
@@ -21522,7 +22271,7 @@ Message: ${causeMessage}${quantumContext}${mintDebtDiagnostics}`
21522
22271
  if (receipt.logs && receipt.logs.length > 0) {
21523
22272
  for (const receiptLog of receipt.logs) {
21524
22273
  if (receiptLog.topics && receiptLog.topics[0] === "0x08c379a0") {
21525
- const iface = new import_ethers17.Interface([
22274
+ const iface = new import_ethers21.Interface([
21526
22275
  "error Error(string)"
21527
22276
  ]);
21528
22277
  const decoded = iface.decodeErrorResult("Error", receiptLog.data);
@@ -21539,7 +22288,7 @@ Message: ${causeMessage}${quantumContext}${mintDebtDiagnostics}`
21539
22288
  const minimalAbi = [
21540
22289
  "event UCDMintedWithAuthorization(bytes32 indexed positionId, address indexed borrower, uint256 mintAmount, uint256 mintFee, uint256 newDebt, uint256 newCollateral, uint256 btcPrice, uint256 quantumTimestamp, bytes32 authorizedSpendsHash)"
21541
22290
  ];
21542
- const iface = new import_ethers17.Interface(minimalAbi);
22291
+ const iface = new import_ethers21.Interface(minimalAbi);
21543
22292
  for (const receiptLog of receipt.logs) {
21544
22293
  const parsed = (() => {
21545
22294
  const logIface = iface;
@@ -21726,7 +22475,7 @@ Message: ${causeMessage}${quantumContext}${mintDebtDiagnostics}`
21726
22475
  pkpNftAddress,
21727
22476
  this.getChipotlePublicKeyFallback()
21728
22477
  );
21729
- const pkpEthAddress = (0, import_ethers17.computeAddress)(pkpPublicKey);
22478
+ const pkpEthAddress = (0, import_ethers21.computeAddress)(pkpPublicKey);
21730
22479
  pkpData = {
21731
22480
  publicKey: pkpPublicKey,
21732
22481
  ethAddress: pkpEthAddress,
@@ -22128,7 +22877,7 @@ Message: ${causeMessage}${quantumContext}${mintDebtDiagnostics}`
22128
22877
  }
22129
22878
  const loanOpsForUcd = loanOpsForUcdResult.value;
22130
22879
  const ucdTokenAddress = await loanOpsForUcd.ucdToken();
22131
- const ucdToken = new import_ethers17.Contract(
22880
+ const ucdToken = new import_ethers21.Contract(
22132
22881
  ucdTokenAddress,
22133
22882
  [
22134
22883
  "function balanceOf(address) view returns (uint256)",
@@ -22144,9 +22893,9 @@ Message: ${causeMessage}${quantumContext}${mintDebtDiagnostics}`
22144
22893
  if (ucdBalance < debtWei) {
22145
22894
  return {
22146
22895
  success: false,
22147
- error: `Insufficient UCD balance for liquidation: ${(0, import_ethers17.formatEther)(
22896
+ error: `Insufficient UCD balance for liquidation: ${(0, import_ethers21.formatEther)(
22148
22897
  ucdBalance
22149
- )} UCD (need ${(0, import_ethers17.formatEther)(debtWei)} UCD)`,
22898
+ )} UCD (need ${(0, import_ethers21.formatEther)(debtWei)} UCD)`,
22150
22899
  positionId: request.positionId,
22151
22900
  wasLiquidated: false
22152
22901
  };
@@ -22155,7 +22904,7 @@ Message: ${causeMessage}${quantumContext}${mintDebtDiagnostics}`
22155
22904
  if (request.skipUcdApproval) {
22156
22905
  return {
22157
22906
  success: false,
22158
- error: `Insufficient UCD allowance for UCDController: need at least ${(0, import_ethers17.formatEther)(
22907
+ error: `Insufficient UCD allowance for UCDController: need at least ${(0, import_ethers21.formatEther)(
22159
22908
  debtWei
22160
22909
  )} UCD, or omit skipUcdApproval to let the SDK submit approve`,
22161
22910
  positionId: request.positionId,
@@ -22679,7 +23428,7 @@ Message: ${causeMessage}${quantumContext}${mintDebtDiagnostics}`
22679
23428
  if (typeof signatureBytes === "string" && signatureBytes.startsWith("{")) {
22680
23429
  try {
22681
23430
  const parsed = JSON.parse(signatureBytes);
22682
- signatureBytes = parsed.signature ?? (parsed.r && parsed.s && parsed.v ? import_ethers17.Signature.from({
23431
+ signatureBytes = parsed.signature ?? (parsed.r && parsed.s && parsed.v ? import_ethers21.Signature.from({
22683
23432
  r: parsed.r,
22684
23433
  s: parsed.s,
22685
23434
  v: parsed.v
@@ -22690,7 +23439,7 @@ Message: ${causeMessage}${quantumContext}${mintDebtDiagnostics}`
22690
23439
  if (!signatureBytes.startsWith("0x")) {
22691
23440
  signatureBytes = "0x" + signatureBytes;
22692
23441
  }
22693
- const extendIface = new import_ethers17.Interface([
23442
+ const extendIface = new import_ethers21.Interface([
22694
23443
  "function extendPosition(bytes32 positionId, uint256 selectedTerm, uint256 quantumTimestamp, uint256 btcPrice, uint256 availableBTCBalance, uint256 proRataRenewalFee, bytes calldata extensionValidatorSignature) external returns (bool)"
22695
23444
  ]);
22696
23445
  const extendCalldata = extendIface.encodeFunctionData("extendPosition", [
@@ -23239,7 +23988,7 @@ Message: ${causeMessage}${quantumContext}${mintDebtDiagnostics}`
23239
23988
  ` Converting payment amount: ${request.paymentAmount} (type: ${typeof request.paymentAmount})`
23240
23989
  );
23241
23990
  }
23242
- const paymentAmountWei = (0, import_ethers17.parseEther)(
23991
+ const paymentAmountWei = (0, import_ethers21.parseEther)(
23243
23992
  request.paymentAmount.toString()
23244
23993
  );
23245
23994
  if (this.config.debug) {
@@ -23306,7 +24055,7 @@ Message: ${causeMessage}${quantumContext}${mintDebtDiagnostics}`
23306
24055
  };
23307
24056
  }
23308
24057
  const ucdTokenAddress = await loanOps.ucdToken();
23309
- const ucdToken = new import_ethers17.Contract(
24058
+ const ucdToken = new import_ethers21.Contract(
23310
24059
  ucdTokenAddress,
23311
24060
  [
23312
24061
  "function balanceOf(address) view returns (uint256)",
@@ -23330,14 +24079,14 @@ Message: ${causeMessage}${quantumContext}${mintDebtDiagnostics}`
23330
24079
  ]);
23331
24080
  if (this.config.debug) {
23332
24081
  log.info(` UCD funds source: ${fundsSource}${isSelfRepay ? " (self)" : " (borrower; agent submitting)"}`);
23333
- log.info(` UCD Balance: ${(0, import_ethers17.formatEther)(balance)} UCD`);
23334
- log.info(` UCD Allowance: ${(0, import_ethers17.formatEther)(allowance)} UCD`);
24082
+ log.info(` UCD Balance: ${(0, import_ethers21.formatEther)(balance)} UCD`);
24083
+ log.info(` UCD Allowance: ${(0, import_ethers21.formatEther)(allowance)} UCD`);
23335
24084
  log.info(` Required: ${request.paymentAmount} UCD`);
23336
24085
  }
23337
24086
  if (balance < paymentAmountWei) {
23338
24087
  return {
23339
24088
  success: false,
23340
- error: `Insufficient UCD balance: ${(0, import_ethers17.formatEther)(
24089
+ error: `Insufficient UCD balance: ${(0, import_ethers21.formatEther)(
23341
24090
  balance
23342
24091
  )} UCD (need ${request.paymentAmount} UCD)${isSelfRepay ? "" : ` \u2014 borrower ${fundsSource} lacks funds`}`
23343
24092
  };
@@ -23346,7 +24095,7 @@ Message: ${causeMessage}${quantumContext}${mintDebtDiagnostics}`
23346
24095
  if (!isSelfRepay) {
23347
24096
  return {
23348
24097
  success: false,
23349
- error: `Borrower ${fundsSource} has insufficient UCD allowance to PositionManager (${(0, import_ethers17.formatEther)(allowance)} UCD, need ${request.paymentAmount}). The borrower must approve PositionManager before a delegated agent can repay.`
24098
+ error: `Borrower ${fundsSource} has insufficient UCD allowance to PositionManager (${(0, import_ethers21.formatEther)(allowance)} UCD, need ${request.paymentAmount}). The borrower must approve PositionManager before a delegated agent can repay.`
23350
24099
  };
23351
24100
  }
23352
24101
  if (this.config.debug) {
@@ -23615,7 +24364,7 @@ Message: ${causeMessage}${quantumContext}${mintDebtDiagnostics}`
23615
24364
  const paymentSigner = this.getSignerOrThrow();
23616
24365
  const paymentFrom = await paymentSigner.getAddress();
23617
24366
  const paymentProvider = contractManager.getProvider();
23618
- const paymentIface = new import_ethers17.Interface([
24367
+ const paymentIface = new import_ethers21.Interface([
23619
24368
  "function makePayment(bytes32 positionId, uint256 paymentAmount, uint256 quantumTimestamp, uint256 btcPrice, bytes calldata paymentValidatorSignature) external returns (bool)"
23620
24369
  ]);
23621
24370
  const paymentCalldata = paymentIface.encodeFunctionData("makePayment", [
@@ -23964,7 +24713,7 @@ Message: ${causeMessage}${quantumContext}${mintDebtDiagnostics}`
23964
24713
  const pkpId = position.pkpId;
23965
24714
  if (litValidatorAddr && pkpId) {
23966
24715
  try {
23967
- const litValidator = new import_ethers17.Contract(
24716
+ const litValidator = new import_ethers21.Contract(
23968
24717
  litValidatorAddr,
23969
24718
  ["function pkpOwners(bytes32) view returns (address)"],
23970
24719
  this.getProviderOrThrow()
@@ -23972,7 +24721,7 @@ Message: ${causeMessage}${quantumContext}${mintDebtDiagnostics}`
23972
24721
  const owner = await litValidator.pkpOwners(
23973
24722
  pkpId
23974
24723
  );
23975
- if (owner && owner !== import_ethers17.ZeroAddress) {
24724
+ if (owner && owner !== import_ethers21.ZeroAddress) {
23976
24725
  controller = owner;
23977
24726
  }
23978
24727
  } catch {
@@ -24024,7 +24773,7 @@ Message: ${causeMessage}${quantumContext}${mintDebtDiagnostics}`
24024
24773
  pkpNftAddress,
24025
24774
  this.getChipotlePublicKeyFallback()
24026
24775
  );
24027
- pkpEthAddress = (0, import_ethers17.computeAddress)(pkpPublicKey);
24776
+ pkpEthAddress = (0, import_ethers21.computeAddress)(pkpPublicKey);
24028
24777
  pkpCache.set(positionId, {
24029
24778
  publicKey: pkpPublicKey,
24030
24779
  ethAddress: pkpEthAddress,
@@ -24094,7 +24843,7 @@ Message: ${causeMessage}${quantumContext}${mintDebtDiagnostics}`
24094
24843
  ` BTCSpendAuthorizer: ${contracts.BTCSpendAuthorizer || "MISSING"}`
24095
24844
  );
24096
24845
  }
24097
- const chain = this.config.chain || (Number(network.chainId) === 1 ? "ethereum" : "sepolia");
24846
+ const chain = this.config.chain || litActionChainNameForChainId(network.chainId);
24098
24847
  const devBitcoinProviderUrl = this.config.bitcoinProviders?.[0]?.url;
24099
24848
  if (this.config.debug) {
24100
24849
  log.info(` Network: ${chain} (chainId: ${network.chainId})`);
@@ -24397,7 +25146,7 @@ Message: ${causeMessage}${quantumContext}${mintDebtDiagnostics}`
24397
25146
  utxoVout: withdrawalParams.utxoVout
24398
25147
  });
24399
25148
  }
24400
- const withdrawIface = new import_ethers17.Interface([
25149
+ const withdrawIface = new import_ethers21.Interface([
24401
25150
  "function withdrawBTC((bytes32 positionId, bytes32 actionHash, bytes32 authorizedSpendsHash, bytes32 ucdDebtHash, bytes32 contractBundleHash, string withdrawalAddress, uint256 totalDeduction, uint256 newCollateral, uint256 quantumTimestamp, uint256 btcPrice, string utxoTxid, uint32 utxoVout) params, bytes withdrawalValidatorSignature, bytes btcSpendAuthSignature) external returns (bool)"
24402
25151
  ]);
24403
25152
  const withdrawCalldata = withdrawIface.encodeFunctionData("withdrawBTC", [
@@ -24628,7 +25377,7 @@ Message: ${causeMessage}${quantumContext}${mintDebtDiagnostics}`
24628
25377
  }
24629
25378
  const pkpId = positionDetails.pkpId;
24630
25379
  const vaultAddress = positionDetails.vaultAddress;
24631
- if (!pkpId || pkpId === import_ethers17.ZeroHash) {
25380
+ if (!pkpId || pkpId === import_ethers21.ZeroHash) {
24632
25381
  return { success: false, error: "Position has no PKP" };
24633
25382
  }
24634
25383
  if (!vaultAddress) {
@@ -24648,14 +25397,8 @@ Message: ${causeMessage}${quantumContext}${mintDebtDiagnostics}`
24648
25397
  if (!publicKey) {
24649
25398
  return { success: false, error: "Failed to resolve PKP public key" };
24650
25399
  }
24651
- const chipotlePkpAddress = (0, import_ethers17.computeAddress)(publicKey);
24652
- const STANDALONE_CHAIN_NAMES = {
24653
- 1: "ethereum",
24654
- 11155111: "sepolia",
24655
- 1337: "hardhat",
24656
- 31337: "hardhat"
24657
- };
24658
- const chainName = STANDALONE_CHAIN_NAMES[chainId];
25400
+ const chipotlePkpAddress = (0, import_ethers21.computeAddress)(publicKey);
25401
+ const chainName = LIT_ACTION_CHAIN_NAMES[chainId];
24659
25402
  if (!chainName) {
24660
25403
  return {
24661
25404
  success: false,
@@ -25027,7 +25770,7 @@ Message: ${causeMessage}${quantumContext}${mintDebtDiagnostics}`
25027
25770
  const btcSpendAuthorizerAbi = [
25028
25771
  "function getAuthorizedSpends(bytes32) view returns (tuple(string txid, uint32 vout, uint256 satoshis, string targetAddress, uint256 targetAmount, uint256 authorizedAt)[])"
25029
25772
  ];
25030
- const btcSpendAuthorizer = new import_ethers17.Contract(
25773
+ const btcSpendAuthorizer = new import_ethers21.Contract(
25031
25774
  btcSpendAuthorizerAddress,
25032
25775
  btcSpendAuthorizerAbi,
25033
25776
  this.getProviderOrThrow()
@@ -25113,7 +25856,7 @@ Message: ${causeMessage}${quantumContext}${mintDebtDiagnostics}`
25113
25856
  const abi = [
25114
25857
  "function getAuthorizedSpends(bytes32) view returns (tuple(string txid, uint32 vout, uint256 satoshis, string targetAddress, uint256 targetAmount, uint256 authorizedAt)[])"
25115
25858
  ];
25116
- const contract = new import_ethers17.Contract(
25859
+ const contract = new import_ethers21.Contract(
25117
25860
  btcSpendAuthorizerAddress,
25118
25861
  abi,
25119
25862
  this.getProviderOrThrow()
@@ -25127,7 +25870,7 @@ Message: ${causeMessage}${quantumContext}${mintDebtDiagnostics}`
25127
25870
  targetAddress: spend.targetAddress,
25128
25871
  targetAmount: Number(spend.targetAmount),
25129
25872
  authorizedAt: Number(spend.authorizedAt),
25130
- utxoKey: (0, import_ethers17.solidityPackedKeccak256)(
25873
+ utxoKey: (0, import_ethers21.solidityPackedKeccak256)(
25131
25874
  ["string", "uint32"],
25132
25875
  [spend.txid, Number(spend.vout)]
25133
25876
  )
@@ -25333,7 +26076,7 @@ Message: ${causeMessage}${quantumContext}${mintDebtDiagnostics}`
25333
26076
  error: attRes.error ?? attRes.reason ?? `LIT recovery attestation rejected${attRes.failedStep ? ` at step ${attRes.failedStep}` : ""}`
25334
26077
  };
25335
26078
  }
25336
- const btcSpendAuthorizer = new import_ethers17.Contract(
26079
+ const btcSpendAuthorizer = new import_ethers21.Contract(
25337
26080
  btcSpendAuthorizerAddress,
25338
26081
  [
25339
26082
  "function cancelStaleSpendWithProof(bytes32 positionId, bytes32 utxoKey, uint256 authorizedAt, string calldata invalidatorTxid, uint256 attestationTimestamp, bytes calldata litSignature) external"
@@ -25430,7 +26173,7 @@ Message: ${causeMessage}${quantumContext}${mintDebtDiagnostics}`
25430
26173
  const positionDetails = await this.getPositionDetailsView(
25431
26174
  params.positionId
25432
26175
  );
25433
- if (!positionDetails?.pkpId || positionDetails.pkpId === import_ethers17.ZeroHash) {
26176
+ if (!positionDetails?.pkpId || positionDetails.pkpId === import_ethers21.ZeroHash) {
25434
26177
  return { success: false, error: "Position has no PKP" };
25435
26178
  }
25436
26179
  const pkpCache = this.cacheManager.getCache("pkp-data", {
@@ -25447,7 +26190,7 @@ Message: ${causeMessage}${quantumContext}${mintDebtDiagnostics}`
25447
26190
  if (!publicKey) {
25448
26191
  return { success: false, error: "Failed to resolve PKP public key" };
25449
26192
  }
25450
- const chipotlePkpAddress = (0, import_ethers17.computeAddress)(publicKey);
26193
+ const chipotlePkpAddress = (0, import_ethers21.computeAddress)(publicKey);
25451
26194
  const dc = this.config.contractAddresses || {};
25452
26195
  const chainName = chainId === 1 ? "ethereum" : chainId === 11155111 ? "sepolia" : chainId === 1337 || chainId === 31337 ? "hardhat" : void 0;
25453
26196
  if (!chainName) {
@@ -26014,11 +26757,12 @@ Message: ${causeMessage}${quantumContext}${mintDebtDiagnostics}`
26014
26757
  }
26015
26758
  /**
26016
26759
  * Execute a PSM stablecoin → UCD swap.
26017
- * Handles stablecoin approval to the PSM contract if the current allowance is insufficient.
26760
+ * Approves EXACTLY `amountWei` to the PSM when the current allowance is short (resetting a
26761
+ * partial allowance to zero first); every leg is validated by the sign-guard before it is sent.
26018
26762
  *
26019
26763
  * @param params.stablecoinAddress - ERC-20 address of the stablecoin to swap in
26020
26764
  * @param params.amountWei - Stablecoin amount in native decimals (bigint)
26021
- * @param params.minUcdOutWei - Minimum UCD to receive; reverts if below this (1% slippage guard)
26765
+ * @param params.minUcdOutWei - Minimum UCD to receive; must be > 0 (reverts on-chain if below)
26022
26766
  * @param params.signer - Connected signer for the approval and swap transactions
26023
26767
  */
26024
26768
  async psmSwap(params) {
@@ -26028,32 +26772,23 @@ Message: ${causeMessage}${quantumContext}${mintDebtDiagnostics}`
26028
26772
  "SimplePSMV2 address not configured \u2014 provide contractAddresses.simplePsmV2"
26029
26773
  );
26030
26774
  }
26031
- const signerAddress = await params.signer.getAddress();
26032
- const erc20Abi = [
26033
- "function allowance(address owner, address spender) view returns (uint256)",
26034
- "function approve(address spender, uint256 amount) returns (bool)"
26035
- ];
26036
- const stablecoin = new import_ethers17.Contract(params.stablecoinAddress, erc20Abi, params.signer);
26037
- const allowance = await stablecoin.allowance(signerAddress, psmAddress);
26038
- if (allowance < params.amountWei) {
26039
- const approveTx = await stablecoin.approve(psmAddress, import_ethers17.MaxUint256);
26040
- await approveTx.wait();
26041
- }
26042
- const psm = SimplePSMV2__factory.connect(psmAddress, params.signer);
26043
- const tx = await psm.swap(params.stablecoinAddress, params.amountWei, params.minUcdOutWei);
26044
- const receipt = await tx.wait();
26045
- if (!receipt)
26046
- throw new Error("PSM swap transaction receipt unavailable");
26047
- return { hash: tx.hash, blockNumber: receipt.blockNumber };
26775
+ return this.runPsmExchange({
26776
+ direction: "swap",
26777
+ signer: params.signer,
26778
+ addresses: { psm: psmAddress, stablecoin: params.stablecoinAddress },
26779
+ amountIn: params.amountWei,
26780
+ minOut: params.minUcdOutWei
26781
+ });
26048
26782
  }
26049
26783
  /**
26050
26784
  * Execute a PSM UCD → stablecoin redeem.
26051
- * Handles UCD approval to UCDController (not PSM) to satisfy the M-4 burn allowance guard:
26052
- * UCDToken.burn(from, amount) calls _spendAllowance(from, msg.sender=ucdController, amount).
26785
+ * Approves EXACTLY `ucdAmountWei` of UCD to the UCDController (not the PSM) to satisfy the
26786
+ * M-4 burn allowance guard: UCDToken.burn(from, amount) calls
26787
+ * _spendAllowance(from, msg.sender=ucdController, amount).
26053
26788
  *
26054
26789
  * @param params.stablecoinAddress - ERC-20 address of the stablecoin to receive
26055
26790
  * @param params.ucdAmountWei - UCD amount to redeem (18 decimals, bigint)
26056
- * @param params.minStablecoinOutWei - Minimum stablecoin to receive (slippage guard)
26791
+ * @param params.minStablecoinOutWei - Minimum stablecoin to receive; must be > 0
26057
26792
  * @param params.signer - Connected signer
26058
26793
  */
26059
26794
  async psmRedeem(params) {
@@ -26066,23 +26801,51 @@ Message: ${causeMessage}${quantumContext}${mintDebtDiagnostics}`
26066
26801
  throw new Error("UCDToken address not configured \u2014 provide contractAddresses.ucdToken");
26067
26802
  if (!ucdControllerAddress)
26068
26803
  throw new Error("UCDController address not configured \u2014 provide contractAddresses.ucdController");
26069
- const signerAddress = await params.signer.getAddress();
26070
- const erc20Abi = [
26071
- "function allowance(address owner, address spender) view returns (uint256)",
26072
- "function approve(address spender, uint256 amount) returns (bool)"
26073
- ];
26074
- const ucdToken = new import_ethers17.Contract(ucdAddress, erc20Abi, params.signer);
26075
- const allowance = await ucdToken.allowance(signerAddress, ucdControllerAddress);
26076
- if (allowance < params.ucdAmountWei) {
26077
- const approveTx = await ucdToken.approve(ucdControllerAddress, import_ethers17.MaxUint256);
26078
- await approveTx.wait();
26079
- }
26080
- const psm = SimplePSMV2__factory.connect(psmAddress, params.signer);
26081
- const tx = await psm.redeem(params.stablecoinAddress, params.ucdAmountWei, params.minStablecoinOutWei);
26082
- const receipt = await tx.wait();
26083
- if (!receipt)
26084
- throw new Error("PSM redeem transaction receipt unavailable");
26085
- return { hash: tx.hash, blockNumber: receipt.blockNumber };
26804
+ return this.runPsmExchange({
26805
+ direction: "redeem",
26806
+ signer: params.signer,
26807
+ addresses: {
26808
+ psm: psmAddress,
26809
+ stablecoin: params.stablecoinAddress,
26810
+ ucdToken: ucdAddress,
26811
+ ucdController: ucdControllerAddress
26812
+ },
26813
+ amountIn: params.ucdAmountWei,
26814
+ minOut: params.minStablecoinOutWei
26815
+ });
26816
+ }
26817
+ /**
26818
+ * Shared PSM path: plan + validate every leg against the chain the SIGNER is on, then send.
26819
+ * The signer's chain must match the SDK's configured chain — the addresses came from it.
26820
+ */
26821
+ async runPsmExchange(params) {
26822
+ const provider = params.signer.provider;
26823
+ if (!provider) {
26824
+ throw new Error(`PSM ${params.direction} needs a signer connected to a provider`);
26825
+ }
26826
+ const configuredChainId = this.config.chainId ?? this.config.networkOverride?.chainId;
26827
+ if (typeof configuredChainId !== "number") {
26828
+ throw new Error(`PSM ${params.direction} needs the SDK's chainId \u2014 configure chainId`);
26829
+ }
26830
+ const mismatch = await describeProviderChainMismatch(provider, configuredChainId);
26831
+ if (mismatch)
26832
+ throw new Error(mismatch);
26833
+ const vctx = {
26834
+ chainId: configuredChainId,
26835
+ network: String(configuredChainId),
26836
+ contracts: {}
26837
+ };
26838
+ const plan = await planPsmExchange({
26839
+ direction: params.direction,
26840
+ owner: await params.signer.getAddress(),
26841
+ addresses: params.addresses,
26842
+ amountIn: params.amountIn,
26843
+ minOut: params.minOut,
26844
+ vctx,
26845
+ reads: psmExchangeReadsFromProvider(provider, params.addresses.psm)
26846
+ });
26847
+ const { hash, blockNumber } = await executePsmPlan(plan, params.signer, vctx);
26848
+ return { hash, blockNumber };
26086
26849
  }
26087
26850
  /**
26088
26851
  * Wait for the subgraph to index up to (and including) the given block number.
@@ -26126,7 +26889,7 @@ Message: ${causeMessage}${quantumContext}${mintDebtDiagnostics}`
26126
26889
  *
26127
26890
  * Deliberately omits `minWithdrawRatioBps` — see {@link readLoanGrant}.
26128
26891
  */
26129
- static LOAN_GRANT_PREFIX_IFACE = new import_ethers17.Interface([
26892
+ static LOAN_GRANT_PREFIX_IFACE = new import_ethers21.Interface([
26130
26893
  "function getLoanGrant(bytes32 positionId) view returns (address borrower, uint32 scopeBits, uint32 minCollateralRatioBps)"
26131
26894
  ]);
26132
26895
  /**
@@ -26147,9 +26910,9 @@ Message: ${causeMessage}${quantumContext}${mintDebtDiagnostics}`
26147
26910
  to: registryAddress,
26148
26911
  data: iface.encodeFunctionData("getLoanGrant", [pid])
26149
26912
  });
26150
- if ((0, import_ethers17.getBytes)(data).length < 96) {
26913
+ if ((0, import_ethers21.getBytes)(data).length < 96) {
26151
26914
  throw new SDKError({
26152
- message: `AgentDelegationRegistry at ${registryAddress} returned ${(0, import_ethers17.getBytes)(data).length} bytes for getLoanGrant(bytes32) \u2014 expected at least 96. Wrong address, or a registry version this SDK does not support.`,
26915
+ message: `AgentDelegationRegistry at ${registryAddress} returned ${(0, import_ethers21.getBytes)(data).length} bytes for getLoanGrant(bytes32) \u2014 expected at least 96. Wrong address, or a registry version this SDK does not support.`,
26153
26916
  category: "CONTRACT" /* CONTRACT */,
26154
26917
  severity: "HIGH" /* HIGH */
26155
26918
  });
@@ -26158,10 +26921,10 @@ Message: ${causeMessage}${quantumContext}${mintDebtDiagnostics}`
26158
26921
  "getLoanGrant",
26159
26922
  data
26160
26923
  );
26161
- const raw = (0, import_ethers17.getBytes)(data);
26924
+ const raw = (0, import_ethers21.getBytes)(data);
26162
26925
  const withdrawScopeSupported = raw.length >= 128;
26163
26926
  const minWithdrawRatioBps = withdrawScopeSupported ? Number(
26164
- import_ethers17.AbiCoder.defaultAbiCoder().decode(["uint32"], raw.slice(96, 128))[0]
26927
+ import_ethers21.AbiCoder.defaultAbiCoder().decode(["uint32"], raw.slice(96, 128))[0]
26165
26928
  ) : 0;
26166
26929
  return {
26167
26930
  borrower,
@@ -26260,18 +27023,30 @@ Message: ${causeMessage}${quantumContext}${mintDebtDiagnostics}`
26260
27023
  const user = await signer.getAddress();
26261
27024
  const registry = AgentDelegationRegistry__factory.connect(addr, signer);
26262
27025
  let agentAddress;
26263
- const hasActiveAgent = await registry.isAgentActive(user);
26264
- if (hasActiveAgent) {
26265
- agentAddress = (await registry.agentOf(user)).agent;
27026
+ const [isActive, record, latestBlock] = await Promise.all([
27027
+ registry.isAgentActive(user),
27028
+ registry.agentOf(user),
27029
+ this.getProviderOrThrow().getBlock("latest")
27030
+ ]);
27031
+ if (!latestBlock) {
27032
+ throw new SDKError({
27033
+ message: "Could not read the latest block to check the agent registration's expiry",
27034
+ category: "NETWORK" /* NETWORK */,
27035
+ severity: "HIGH" /* HIGH */
27036
+ });
27037
+ }
27038
+ const plan = planAgentBinding({ isActive, record, nowSeconds: latestBlock.timestamp });
27039
+ if (plan.kind === "reuse") {
27040
+ agentAddress = plan.agent;
26266
27041
  } else {
26267
27042
  agentAddress = await mintAgentPkp({
26268
27043
  serviceEndpoint: this.config.serviceEndpoint,
26269
27044
  authHeader: this.serverSession ? () => this.serverSession.getAuthHeader() : void 0
26270
27045
  });
26271
27046
  const validitySeconds = options?.agentValiditySeconds ?? 90 * 24 * 60 * 60;
26272
- const validUntil = Math.floor(Date.now() / 1e3) + validitySeconds;
26273
- const regTx = await registry.registerAgent(user, agentAddress, validUntil);
26274
- await regTx.wait();
27047
+ const validUntil = latestBlock.timestamp + validitySeconds;
27048
+ const bindTx = plan.kind === "rotate" ? await registry.rotateAgent(user, agentAddress, validUntil) : await registry.registerAgent(user, agentAddress, validUntil);
27049
+ await bindTx.wait();
26275
27050
  }
26276
27051
  const currentDelegate = await getPositionDelegate(pid, signer, pdrAddr).catch(
26277
27052
  () => null
@@ -26310,7 +27085,7 @@ Message: ${causeMessage}${quantumContext}${mintDebtDiagnostics}`
26310
27085
  getPositionDelegate(pid, signer, pdrAddr),
26311
27086
  registry.agentOf(user).then((a) => a.agent)
26312
27087
  ]);
26313
- if (currentDelegate !== import_ethers17.ZeroAddress && currentDelegate.toLowerCase() === userAgent.toLowerCase()) {
27088
+ if (currentDelegate !== import_ethers21.ZeroAddress && currentDelegate.toLowerCase() === userAgent.toLowerCase()) {
26314
27089
  const clearTx = await setPositionDelegate(
26315
27090
  pid,
26316
27091
  "0x0000000000000000000000000000000000000000",
@@ -26702,7 +27477,7 @@ Message: ${causeMessage}${quantumContext}${mintDebtDiagnostics}`
26702
27477
  const maxUcdWhole = BigInt(result[3].toString());
26703
27478
  return success({
26704
27479
  liquidationThreshold: result[0].toString(),
26705
- minimumLoanValueUcd: (0, import_ethers17.formatUnits)(result[2], 18),
27480
+ minimumLoanValueUcd: (0, import_ethers21.formatUnits)(result[2], 18),
26706
27481
  minimumLoanValueWei: result[2].toString(),
26707
27482
  maxSingleLoanValueUcd: maxUcdWhole.toString(),
26708
27483
  maxSingleLoanValueWei: (maxUcdWhole * 10n ** 18n).toString()
@@ -26739,7 +27514,7 @@ Message: ${causeMessage}${quantumContext}${mintDebtDiagnostics}`
26739
27514
  const balanceWei = await provider.getBalance(address);
26740
27515
  return success({
26741
27516
  balanceWei: balanceWei.toString(),
26742
- balanceEth: (0, import_ethers17.formatEther)(balanceWei)
27517
+ balanceEth: (0, import_ethers21.formatEther)(balanceWei)
26743
27518
  });
26744
27519
  } catch (error) {
26745
27520
  return failure(new SDKError({
@@ -27148,7 +27923,7 @@ Message: ${causeMessage}${quantumContext}${mintDebtDiagnostics}`
27148
27923
  * Convert decimal position ID to bytes32 format
27149
27924
  */
27150
27925
  toBytes32(value) {
27151
- return (0, import_ethers17.zeroPadValue)((0, import_ethers17.toBeHex)(BigInt(value)), 32);
27926
+ return (0, import_ethers21.zeroPadValue)((0, import_ethers21.toBeHex)(BigInt(value)), 32);
27152
27927
  }
27153
27928
  /**
27154
27929
  * Check if an error indicates a technical failure vs business logic rejection
@@ -27189,7 +27964,7 @@ Message: ${causeMessage}${quantumContext}${mintDebtDiagnostics}`
27189
27964
  const coreModuleAbi = [
27190
27965
  "function getPositionDetails(bytes32) view returns (tuple(bytes32 positionId, bytes32 pkpId, uint256 ucdDebt, string vaultAddress, address borrower, uint40 createdAt, uint40 lastUpdated, uint16 selectedTerm, uint40 expiryAt, uint8 status, uint40 previousExpiryAt, uint16 totalTerm))"
27191
27966
  ];
27192
- const coreModule = new import_ethers17.Contract(
27967
+ const coreModule = new import_ethers21.Contract(
27193
27968
  coreModuleAddress,
27194
27969
  coreModuleAbi,
27195
27970
  provider
@@ -27256,7 +28031,7 @@ Message: ${causeMessage}${quantumContext}${mintDebtDiagnostics}`
27256
28031
  const corePositionAbi = [
27257
28032
  "function getPositionDetails(bytes32) view returns (tuple(bytes32 positionId, bytes32 pkpId, uint256 ucdDebt, string vaultAddress, address borrower, uint40 createdAt, uint40 lastUpdated, uint16 selectedTerm, uint40 expiryAt, uint8 status, uint40 previousExpiryAt, uint16 totalTerm))"
27258
28033
  ];
27259
- const corePositionContract = new import_ethers17.Contract(
28034
+ const corePositionContract = new import_ethers21.Contract(
27260
28035
  coreAddress,
27261
28036
  corePositionAbi,
27262
28037
  provider
@@ -27267,7 +28042,7 @@ Message: ${causeMessage}${quantumContext}${mintDebtDiagnostics}`
27267
28042
  positionIdBytes32
27268
28043
  );
27269
28044
  const positionIdFromCore = corePosition?.positionId || corePosition?.[0] || null;
27270
- if (positionIdFromCore && positionIdFromCore !== import_ethers17.ZeroHash && positionIdFromCore !== "0x0000000000000000000000000000000000000000000000000000000000000000") {
28045
+ if (positionIdFromCore && positionIdFromCore !== import_ethers21.ZeroHash && positionIdFromCore !== "0x0000000000000000000000000000000000000000000000000000000000000000") {
27271
28046
  if (this.config.debug) {
27272
28047
  log.info("Position exists in core contract", {
27273
28048
  positionId,
@@ -27335,7 +28110,7 @@ Message: ${causeMessage}${quantumContext}${mintDebtDiagnostics}`
27335
28110
  throw new Error("loanOperationsManager address not configured");
27336
28111
  }
27337
28112
  const runner = this.config.contractSigner || this.getProviderOrThrow();
27338
- const contract = new import_ethers17.Contract(
28113
+ const contract = new import_ethers21.Contract(
27339
28114
  addr.loanOperationsManager,
27340
28115
  [
27341
28116
  "function getProtocolConfig() external view returns (uint256 liquidationThreshold, uint256 minimumLoanValueUcd, uint256 minimumLoanValueWei, uint256 maxSingleLoanValueUcd)"
@@ -27348,7 +28123,7 @@ Message: ${causeMessage}${quantumContext}${mintDebtDiagnostics}`
27348
28123
  const maxUcdWhole = BigInt(result[3].toString());
27349
28124
  return {
27350
28125
  liquidationThreshold: result[0].toString(),
27351
- minimumLoanValueUcd: (0, import_ethers17.formatUnits)(result[2], 18),
28126
+ minimumLoanValueUcd: (0, import_ethers21.formatUnits)(result[2], 18),
27352
28127
  minimumLoanValueWei: result[2].toString(),
27353
28128
  maxSingleLoanValueUcd: maxUcdWhole.toString(),
27354
28129
  maxSingleLoanValueWei: (maxUcdWhole * 10n ** 18n).toString()
@@ -27366,8 +28141,8 @@ Message: ${causeMessage}${quantumContext}${mintDebtDiagnostics}`
27366
28141
  const MIN_REVEAL_DELAY = 60;
27367
28142
  const MAX_RANDOM_DELAY = 240;
27368
28143
  const entropyInput = positionId + quantumTimestamp.toString();
27369
- const hash = (0, import_ethers17.keccak256)(
27370
- (0, import_ethers17.toUtf8Bytes)(entropyInput)
28144
+ const hash = (0, import_ethers21.keccak256)(
28145
+ (0, import_ethers21.toUtf8Bytes)(entropyInput)
27371
28146
  );
27372
28147
  const randomValue = BigInt(hash);
27373
28148
  const randomDelay = Number(randomValue % BigInt(MAX_RANDOM_DELAY));
@@ -27392,12 +28167,12 @@ Message: ${causeMessage}${quantumContext}${mintDebtDiagnostics}`
27392
28167
  const rawPositionId = /^0x/i.test(params.positionId.trim()) ? params.positionId.trim().slice(2) : params.positionId.trim();
27393
28168
  const canonicalPositionId = "0x" + rawPositionId.padStart(64, "0").toLowerCase();
27394
28169
  const intentTimestamp = Math.floor(Date.now() / 1e3);
27395
- const intentActionHash = (0, import_ethers17.keccak256)((0, import_ethers17.toUtf8Bytes)("liquidate-position"));
27396
- const intentHash = (0, import_ethers17.solidityPackedKeccak256)(
28170
+ const intentActionHash = (0, import_ethers21.keccak256)((0, import_ethers21.toUtf8Bytes)("liquidate-position"));
28171
+ const intentHash = (0, import_ethers21.solidityPackedKeccak256)(
27397
28172
  ["bytes32", "uint256", "uint256", "address", "bytes32"],
27398
28173
  [canonicalPositionId, intentTimestamp, chainId, intentSigner, intentActionHash]
27399
28174
  );
27400
- const intentSignature = await signer.signMessage((0, import_ethers17.getBytes)(intentHash));
28175
+ const intentSignature = await signer.signMessage((0, import_ethers21.getBytes)(intentHash));
27401
28176
  const response = await fetch(endpoint, {
27402
28177
  method: "POST",
27403
28178
  headers: { "Content-Type": "application/json" },
@@ -27449,7 +28224,7 @@ Message: ${causeMessage}${quantumContext}${mintDebtDiagnostics}`
27449
28224
  const vrfSeedRaw = await lmResult.value["vrfSeeds"](positionId);
27450
28225
  const vrfSeed = BigInt(vrfSeedRaw.toString());
27451
28226
  if (vrfSeed !== 0n) {
27452
- const finalEntropy = (0, import_ethers17.solidityPackedKeccak256)(
28227
+ const finalEntropy = (0, import_ethers21.solidityPackedKeccak256)(
27453
28228
  ["uint256", "uint256", "bytes32"],
27454
28229
  [vrfSeed, BigInt(quantumTimestamp.toString()), positionId]
27455
28230
  );
@@ -27727,7 +28502,7 @@ var EventHelpers = {
27727
28502
  };
27728
28503
 
27729
28504
  // src/utils/safe-agent-delegation.utils.ts
27730
- var import_ethers18 = require("ethers");
28505
+ var import_ethers22 = require("ethers");
27731
28506
  init_deployment_addresses();
27732
28507
  var SAFE_ABI = [
27733
28508
  "function getModulesPaginated(address start, uint256 pageSize) view returns (address[] modules, address next)"
@@ -27745,7 +28520,7 @@ var MODULE_LIST_SENTINEL = "0x0000000000000000000000000000000000000001";
27745
28520
  var MODULE_PAGE_SIZE = 50;
27746
28521
  var lower = (v) => v.trim().toLowerCase();
27747
28522
  async function classifyModule(provider, moduleAddress, safeAddress, positionManager, factoryAddress) {
27748
- const module2 = new import_ethers18.Contract(moduleAddress, MODULE_ABI, provider);
28523
+ const module2 = new import_ethers22.Contract(moduleAddress, MODULE_ABI, provider);
27749
28524
  let boundSafe;
27750
28525
  try {
27751
28526
  boundSafe = await module2.safe();
@@ -27765,7 +28540,7 @@ async function classifyModule(provider, moduleAddress, safeAddress, positionMana
27765
28540
  if (!factoryAddress)
27766
28541
  return null;
27767
28542
  try {
27768
- const factory = new import_ethers18.Contract(factoryAddress, FACTORY_ABI, provider);
28543
+ const factory = new import_ethers22.Contract(factoryAddress, FACTORY_ABI, provider);
27769
28544
  return await factory.isFromFactory(moduleAddress) === true;
27770
28545
  } catch {
27771
28546
  return null;
@@ -27794,7 +28569,7 @@ async function getSafeAgentDelegation(params) {
27794
28569
  let modules;
27795
28570
  let next;
27796
28571
  try {
27797
- const safe = new import_ethers18.Contract(safeAddress, SAFE_ABI, provider);
28572
+ const safe = new import_ethers22.Contract(safeAddress, SAFE_ABI, provider);
27798
28573
  const page = await safe.getModulesPaginated(
27799
28574
  MODULE_LIST_SENTINEL,
27800
28575
  MODULE_PAGE_SIZE
@@ -27822,7 +28597,7 @@ async function getSafeAgentDelegation(params) {
27822
28597
  continue;
27823
28598
  let agentAddress = null;
27824
28599
  try {
27825
- agentAddress = await new import_ethers18.Contract(
28600
+ agentAddress = await new import_ethers22.Contract(
27826
28601
  moduleAddress,
27827
28602
  MODULE_ABI,
27828
28603
  provider
@@ -27836,7 +28611,7 @@ async function getSafeAgentDelegation(params) {
27836
28611
  let validUntil;
27837
28612
  let status;
27838
28613
  try {
27839
- const record = await new import_ethers18.Contract(
28614
+ const record = await new import_ethers22.Contract(
27840
28615
  registryAddress,
27841
28616
  REGISTRY_ABI,
27842
28617
  provider