import { createRequire as __createRequire } from 'module'; import { fileURLToPath as __fileURLToPath } from 'url'; import { dirname as __pathDirname } from 'path'; const require = __createRequire(import.meta.url); const __filename = __fileURLToPath(import.meta.url); const __dirname = __pathDirname(__filename);
import {
  Transaction
} from "./chunk-TP3M7BAU.js";
import "./chunk-X6ON6NN5.js";
import {
  fromBase64,
  normalizeSuiAddress,
  toBase64,
  toHex
} from "./chunk-I2DCISQP.js";
import "./chunk-SVEVGZKZ.js";

// ../../node_modules/.pnpm/@suimpp+mpp@0.8.1_@modelcontextprotocol+sdk@1.28.0_zod@3.25.76__express@5.2.1_hono@4.12_f78e9d565196b7d48429724cce956455/node_modules/@suimpp/mpp/dist/x402.js
function parseAmountToRaw(amount, decimals) {
  const [whole = "0", frac = ""] = amount.split(".");
  const paddedFrac = frac.padEnd(decimals, "0").slice(0, decimals);
  return BigInt(whole + paddedFrac);
}
async function withRetry(fn, {
  attempts = 5,
  baseDelayMs = 1e3
} = {}) {
  let lastError;
  for (let i = 0; i < attempts; i++) {
    try {
      return await fn();
    } catch (err) {
      lastError = err;
      if (i < attempts - 1) {
        await new Promise((r) => setTimeout(r, baseDelayMs * (i + 1)));
      }
    }
  }
  throw lastError;
}
var X402_SCHEME = "exact";
var X402_VERSION = 1;
var X402_PAYMENT_HEADER = "X-PAYMENT";
var X402_PAYMENT_RESPONSE_HEADER = "X-PAYMENT-RESPONSE";
var FRAMEWORK_PACKAGE = normalizeSuiAddress("0x2");
var SEND_FUNDS_FNS = /* @__PURE__ */ new Set(["balance::send_funds", "coin::send_funds"]);
var ALLOWED_FNS = /* @__PURE__ */ new Set([
  ...SEND_FUNDS_FNS,
  "balance::redeem_funds",
  "coin::redeem_funds",
  "balance::withdrawal_split",
  "coin::into_balance"
]);
function challengeNonce(challengeId) {
  let hash = 2166136261;
  for (let i = 0; i < challengeId.length; i++) {
    hash ^= challengeId.charCodeAt(i);
    hash = Math.imul(hash, 16777619);
  }
  return hash >>> 0;
}
function x402Network(network) {
  return `sui:${network}`;
}
function createX402Requirements(options) {
  const amountRaw = parseAmountToRaw(options.amount, options.currency.decimals);
  const minEpoch = BigInt(options.currentEpoch);
  return {
    scheme: X402_SCHEME,
    network: x402Network(options.network),
    asset: options.currency.type,
    maxAmountRequired: amountRaw.toString(),
    payTo: options.recipient,
    resource: options.resource,
    maxTimeoutSeconds: options.maxTimeoutSeconds ?? 60,
    extra: {
      suimpp: {
        challengeId: options.challengeId,
        nonce: challengeNonce(options.challengeId),
        chain: options.chain,
        minEpoch: minEpoch.toString(),
        maxEpoch: (minEpoch + 1n).toString()
      }
    }
  };
}
async function buildX402SignedPayment(options) {
  const { requirements, signer } = options;
  const { suimpp } = requirements.extra;
  const sender = signer.toSuiAddress();
  const amountRaw = BigInt(requirements.maxAmountRequired);
  const tx = new Transaction();
  tx.setSender(sender);
  const [balance] = tx.moveCall({
    target: "0x2::balance::redeem_funds",
    typeArguments: [requirements.asset],
    arguments: [tx.withdrawal({ amount: amountRaw, type: requirements.asset })]
  });
  tx.moveCall({
    target: "0x2::balance::send_funds",
    typeArguments: [requirements.asset],
    arguments: [balance, tx.pure.address(requirements.payTo)]
  });
  tx.setGasPrice(0);
  tx.setGasBudget(0);
  tx.setGasPayment([]);
  tx.setExpiration({
    ValidDuring: {
      minEpoch: suimpp.minEpoch,
      maxEpoch: suimpp.maxEpoch,
      minTimestamp: null,
      maxTimestamp: null,
      chain: suimpp.chain,
      nonce: suimpp.nonce
    }
  });
  const bytes = options.client ? await tx.build({ client: options.client }) : await tx.build();
  const { signature } = await signer.signTransaction(bytes);
  const payment = {
    x402Version: X402_VERSION,
    scheme: X402_SCHEME,
    network: requirements.network,
    payload: {
      senderAddress: sender,
      txBytes: toBase64(bytes),
      senderSignature: signature,
      challengeId: suimpp.challengeId
    }
  };
  return { header: encodeX402Header(payment), payment };
}
function encodeX402Header(payment) {
  return toBase64(new TextEncoder().encode(JSON.stringify(payment)));
}
function parseX402Header(headerValue) {
  let parsed;
  try {
    parsed = JSON.parse(new TextDecoder().decode(fromBase64(headerValue)));
  } catch {
    throw new Error("[suimpp/x402] X-PAYMENT header is not base64 JSON");
  }
  if (parsed.scheme !== X402_SCHEME) {
    throw new Error(`[suimpp/x402] Unsupported scheme: ${parsed.scheme}`);
  }
  const p = parsed.payload;
  if (!p?.txBytes || !p?.senderSignature || !p?.challengeId || !p?.senderAddress) {
    throw new Error("[suimpp/x402] X-PAYMENT payload missing required fields");
  }
  return parsed;
}
function verifyX402Payment(options) {
  const { payment, expected } = options;
  if (payment.network !== x402Network(expected.network)) {
    throw new Error(`[suimpp/x402] Network mismatch: ${payment.network}`);
  }
  if (payment.payload.challengeId !== expected.challengeId) {
    throw new Error("[suimpp/x402] Payment is bound to a different challenge");
  }
  const txBytes = fromBase64(payment.payload.txBytes);
  const tx = Transaction.from(txBytes);
  const data = tx.getData();
  if (!data.sender || normalizeSuiAddress(data.sender) !== normalizeSuiAddress(payment.payload.senderAddress)) {
    throw new Error("[suimpp/x402] Transaction sender mismatch");
  }
  const gas = data.gasData;
  if (BigInt(gas.price ?? 1) !== 0n || (gas.payment?.length ?? 0) > 0) {
    throw new Error("[suimpp/x402] Transaction is not a gasless transfer");
  }
  const expiration = data.expiration;
  const validDuring = expiration && "ValidDuring" in expiration ? expiration.ValidDuring : null;
  if (!validDuring) {
    throw new Error(
      "[suimpp/x402] Transaction must use ValidDuring expiration"
    );
  }
  const expectedNonce = challengeNonce(expected.challengeId);
  if (Number(validDuring.nonce) !== expectedNonce) {
    throw new Error(
      "[suimpp/x402] ValidDuring nonce does not bind to the challenge"
    );
  }
  const normalizedRecipient = normalizeSuiAddress(expected.recipient);
  let paysRecipient = false;
  for (const command of data.commands) {
    if (!("MoveCall" in command) || !command.MoveCall) {
      throw new Error("[suimpp/x402] Only MoveCall commands are permitted");
    }
    const call = command.MoveCall;
    const fn = `${call.module}::${call.function}`;
    if (normalizeSuiAddress(call.package) !== FRAMEWORK_PACKAGE) {
      throw new Error(
        `[suimpp/x402] Non-framework package call: ${call.package}::${fn}`
      );
    }
    if (!ALLOWED_FNS.has(fn)) {
      throw new Error(`[suimpp/x402] Disallowed Move call: 0x2::${fn}`);
    }
    if (SEND_FUNDS_FNS.has(fn)) {
      const recipientArg = call.arguments[call.arguments.length - 1];
      if (recipientArg && typeof recipientArg === "object" && "Input" in recipientArg) {
        const input = data.inputs[recipientArg.Input];
        if (input && "Pure" in input && input.Pure?.bytes) {
          const addr = `0x${toHex(fromBase64(input.Pure.bytes))}`;
          if (normalizeSuiAddress(addr) === normalizedRecipient) {
            paysRecipient = true;
          }
        }
      }
    }
  }
  if (!paysRecipient) {
    throw new Error(
      "[suimpp/x402] Transaction does not pay the expected recipient"
    );
  }
  return { txBytes, nonce: expectedNonce };
}
async function settleX402Payment(options) {
  const { payment, client, store, expected } = options;
  const { txBytes } = verifyX402Payment({ payment, expected });
  const result = await withRetry(
    () => client.core.executeTransaction({
      transaction: txBytes,
      signatures: [payment.payload.senderSignature],
      include: { balanceChanges: true, transaction: true }
    }),
    { attempts: 3, baseDelayMs: 500 }
  );
  const resolved = result.Transaction ?? result.FailedTransaction;
  if (!resolved?.status.success) {
    throw new Error(
      `[suimpp/x402] Settlement failed on-chain: ${resolved?.status.error?.message ?? "unknown"}`
    );
  }
  const digest = resolved.digest;
  if (await store.has(digest)) {
    throw new Error(`[suimpp/x402] Digest already used: ${digest}`);
  }
  const normalizedRecipient = normalizeSuiAddress(expected.recipient);
  const paid = resolved.balanceChanges.find(
    (bc) => bc.coinType === expected.currency.type && normalizeSuiAddress(bc.address) === normalizedRecipient && BigInt(bc.amount) > 0n
  );
  const requestedRaw = parseAmountToRaw(
    expected.amount,
    expected.currency.decimals
  );
  if (!paid || BigInt(paid.amount) < requestedRaw) {
    throw new Error("[suimpp/x402] Settled amount does not satisfy the terms");
  }
  await store.set(digest);
  const report = {
    digest,
    sender: payment.payload.senderAddress,
    recipient: expected.recipient,
    amount: expected.amount,
    currency: expected.currency.type,
    network: expected.network
  };
  if (options.onPayment) {
    try {
      options.onPayment(report);
    } catch {
    }
  }
  return {
    success: true,
    network: payment.network,
    transaction: digest,
    payer: payment.payload.senderAddress
  };
}
function encodeX402Response(response) {
  return toBase64(new TextEncoder().encode(JSON.stringify(response)));
}
export {
  X402_PAYMENT_HEADER,
  X402_PAYMENT_RESPONSE_HEADER,
  X402_SCHEME,
  X402_VERSION,
  buildX402SignedPayment,
  challengeNonce,
  createX402Requirements,
  encodeX402Header,
  encodeX402Response,
  parseX402Header,
  settleX402Payment,
  verifyX402Payment,
  x402Network
};
//# sourceMappingURL=x402-UYN72OS3.js.map