@cmdoss/suipay 0.1.1-dev.7 → 0.1.1-dev.9

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (2) hide show
  1. package/dist/index.js +71 -4
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -1752,6 +1752,33 @@ function decodeSponsorGasPayment(encoded) {
1752
1752
  return { objectId: bits[0], version: bits[1], digest: bits[2] };
1753
1753
  });
1754
1754
  }
1755
+ var SPONSOR_GAS_ADDRESS_BALANCE = "address-balance";
1756
+ function decodeSponsorGasPin(encoded) {
1757
+ if (encoded === SPONSOR_GAS_ADDRESS_BALANCE)
1758
+ return [];
1759
+ return decodeSponsorGasPayment(encoded);
1760
+ }
1761
+ var ADDRESS_BALANCE_VALIDITY_EPOCHS = 1n;
1762
+ function addressBalanceGasExpiration(input) {
1763
+ const chain = input.chainIdentifier.trim();
1764
+ if (!chain)
1765
+ throw new Error("address-balance gas needs a chain identifier");
1766
+ if (input.epoch < 0n)
1767
+ throw new Error("address-balance gas needs a non-negative epoch");
1768
+ if (!Number.isInteger(input.nonce) || input.nonce < 0 || input.nonce > 4294967295) {
1769
+ throw new Error("address-balance gas nonce must be a u32");
1770
+ }
1771
+ return {
1772
+ ValidDuring: {
1773
+ minEpoch: String(input.epoch),
1774
+ maxEpoch: String(input.epoch + ADDRESS_BALANCE_VALIDITY_EPOCHS),
1775
+ minTimestamp: null,
1776
+ maxTimestamp: null,
1777
+ chain,
1778
+ nonce: input.nonce
1779
+ }
1780
+ };
1781
+ }
1755
1782
 
1756
1783
  // ../sdk/dist/protocol/mpp.js
1757
1784
  function offerToBase64Url(offer) {
@@ -4381,7 +4408,7 @@ function readX402GasPin(offer) {
4381
4408
  owner,
4382
4409
  budget,
4383
4410
  price,
4384
- payment: decodeSponsorGasPayment(offer.sponsorGasPayment ?? "")
4411
+ payment: decodeSponsorGasPin(offer.sponsorGasPayment ?? "")
4385
4412
  };
4386
4413
  } catch {
4387
4414
  return null;
@@ -4395,16 +4422,33 @@ async function buildSpendAccountX402PayTx(input) {
4395
4422
  tx.setGasBudget(input.gas.budget);
4396
4423
  tx.setGasPrice(input.gas.price);
4397
4424
  tx.setGasPayment(input.gas.payment);
4398
- tx.setExpiration({ Epoch: String(input.currentEpoch + X402_EXPIRATION_EPOCHS) });
4425
+ if (input.gas.payment.length === 0) {
4426
+ if (!input.chainIdentifier) {
4427
+ throw new Error("address-balance sponsor gas needs a chain identifier");
4428
+ }
4429
+ tx.setExpiration(addressBalanceGasExpiration({
4430
+ epoch: input.currentEpoch,
4431
+ chainIdentifier: input.chainIdentifier,
4432
+ nonce: input.nonce ?? randomU32()
4433
+ }));
4434
+ } else {
4435
+ tx.setExpiration({ Epoch: String(input.currentEpoch + X402_EXPIRATION_EPOCHS) });
4436
+ }
4399
4437
  const txBytes = toBase645(await tx.build());
4400
4438
  return { txBytes, kindBytes };
4401
4439
  }
4440
+ function randomU32() {
4441
+ return globalThis.crypto.getRandomValues(new Uint32Array(1))[0];
4442
+ }
4402
4443
  function currentEpochReader(client) {
4403
4444
  return async () => {
4404
4445
  const { systemState } = await client.core.getCurrentSystemState();
4405
4446
  return BigInt(systemState.epoch);
4406
4447
  };
4407
4448
  }
4449
+ function chainIdentifierReader(client) {
4450
+ return async () => (await client.core.getChainIdentifier()).chainIdentifier;
4451
+ }
4408
4452
  function assertPayTransaction(txBytes, expected) {
4409
4453
  let data;
4410
4454
  try {
@@ -4865,6 +4909,10 @@ async function payDelegatedSpendAccount(args) {
4865
4909
  return { status: "ok", paid: false, body: resolution.body };
4866
4910
  }
4867
4911
  if (resolution.status === "failed") {
4912
+ logInternal(logError, "resolve payment failed", {
4913
+ code: resolution.code,
4914
+ detail: resolution.detail
4915
+ });
4868
4916
  const mapped = mapPayOpErrorToDelegated(resolution.code, resolution.detail);
4869
4917
  return failed2(mapped.code, mapped.detail, {
4870
4918
  paymentId: resolution.paymentId
@@ -4989,7 +5037,8 @@ async function payDelegatedSpendAccount(args) {
4989
5037
  buildInput: {
4990
5038
  ...kindBuildInput,
4991
5039
  gas: x402Terms.gas,
4992
- currentEpoch: x402Terms.currentEpoch
5040
+ currentEpoch: x402Terms.currentEpoch,
5041
+ ...x402Terms.chainIdentifier !== void 0 ? { chainIdentifier: x402Terms.chainIdentifier } : {}
4993
5042
  },
4994
5043
  settlement: {
4995
5044
  status: "success",
@@ -5366,12 +5415,28 @@ async function x402Preflight(dialect, offer, deps, logError) {
5366
5415
  logInternal(logError, "x402 needs a current-epoch reader");
5367
5416
  return null;
5368
5417
  }
5418
+ let currentEpoch;
5369
5419
  try {
5370
- return { gas, currentEpoch: BigInt(await deps.getCurrentEpoch()) };
5420
+ currentEpoch = BigInt(await deps.getCurrentEpoch());
5371
5421
  } catch (err) {
5372
5422
  logInternal(logError, "read current epoch failed", err);
5373
5423
  return null;
5374
5424
  }
5425
+ if (gas.payment.length > 0)
5426
+ return { gas, currentEpoch };
5427
+ if (typeof deps.getChainIdentifier !== "function") {
5428
+ logInternal(logError, "address-balance x402 gas needs a chain-identifier reader");
5429
+ return null;
5430
+ }
5431
+ try {
5432
+ const chainIdentifier = await deps.getChainIdentifier();
5433
+ if (!chainIdentifier.trim())
5434
+ throw new Error("chain identifier is blank");
5435
+ return { gas, currentEpoch, chainIdentifier };
5436
+ } catch (err) {
5437
+ logInternal(logError, "read chain identifier failed", err);
5438
+ return null;
5439
+ }
5375
5440
  }
5376
5441
  function emitX402Progress(ctx, event) {
5377
5442
  if (!ctx.onProgress)
@@ -6453,6 +6518,8 @@ async function createPayer(options) {
6453
6518
  // x402 bounds the transaction's expiration by the current epoch, read from
6454
6519
  // the same client as every other chain read here.
6455
6520
  getCurrentEpoch: currentEpochReader(chain.client),
6521
+ // Address-balance gas (ADR-0055) binds the expiration to the chain.
6522
+ getChainIdentifier: chainIdentifierReader(chain.client),
6456
6523
  ...options.offerSecret ? { offerSecret: options.offerSecret } : {},
6457
6524
  ...options.fetchImpl ? { fetchImpl: options.fetchImpl } : {},
6458
6525
  ...options.logError ? { logError: options.logError } : {}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@cmdoss/suipay",
3
- "version": "0.1.1-dev.7",
3
+ "version": "0.1.1-dev.9",
4
4
  "private": false,
5
5
  "type": "module",
6
6
  "description": "SuiPay embeddable client — quote and pay a 402 from a spend-account grant.",