@cmdoss/suipay-mcp 0.2.2-dev.17 → 0.2.2-dev.19

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/README.md CHANGED
@@ -5,7 +5,7 @@ buyer-funded spend account. The buyer owns the account. The agent holds the
5
5
  delegate key and can spend only under the on-chain grant (recipient bind,
6
6
  per-payment cap, budget).
7
7
 
8
- Pin `@cmdoss/suipay-mcp@0.2.2-dev.17` in MCP config for the `latest` dist-tag.
8
+ Pin `@cmdoss/suipay-mcp@0.2.2-dev.19` in MCP config for the `latest` dist-tag.
9
9
  `npx -y @cmdoss/suipay-mcp@dev` tracks the `dev` prerelease line.
10
10
  `1.0.1` remains on the registry as a historical release; do not install it
11
11
  for new agents.
@@ -13,7 +13,7 @@ for new agents.
13
13
  ## Install
14
14
 
15
15
  ```bash
16
- claude mcp add --scope user suipay -- npx -y @cmdoss/suipay-mcp@0.2.2-dev.17
16
+ claude mcp add --scope user suipay -- npx -y @cmdoss/suipay-mcp@0.2.2-dev.19
17
17
  ```
18
18
 
19
19
  `@dev` installs the Railway-dev gateway/console defaults. A workspace
@@ -118,10 +118,10 @@ Default is Railway **suipay-dev**. `--local` / `target: "local"` is laptop-only.
118
118
 
119
119
  ```bash
120
120
  # Railway suipay-dev (default)
121
- npx @cmdoss/suipay-mcp@0.2.2-dev.17
121
+ npx @cmdoss/suipay-mcp@0.2.2-dev.19
122
122
 
123
123
  # Laptop stack
124
- npx @cmdoss/suipay-mcp@0.2.2-dev.17 --local
124
+ npx @cmdoss/suipay-mcp@0.2.2-dev.19 --local
125
125
  ```
126
126
 
127
127
  `SUIPAY_MCP_TARGET=local|dev` selects the same preset. Explicit
@@ -1,8 +1,8 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
3
  main
4
- } from "../chunk-6GJ7IGYM.js";
5
- import "../chunk-WRN7FRUI.js";
4
+ } from "../chunk-IBRMIXCG.js";
5
+ import "../chunk-6VFKI2BY.js";
6
6
 
7
7
  // src/bin/suipay.ts
8
8
  main().catch((err) => {
@@ -1812,6 +1812,33 @@ function decodeSponsorGasPayment(encoded) {
1812
1812
  return { objectId: bits[0], version: bits[1], digest: bits[2] };
1813
1813
  });
1814
1814
  }
1815
+ var SPONSOR_GAS_ADDRESS_BALANCE = "address-balance";
1816
+ function decodeSponsorGasPin(encoded) {
1817
+ if (encoded === SPONSOR_GAS_ADDRESS_BALANCE)
1818
+ return [];
1819
+ return decodeSponsorGasPayment(encoded);
1820
+ }
1821
+ var ADDRESS_BALANCE_VALIDITY_EPOCHS = 1n;
1822
+ function addressBalanceGasExpiration(input) {
1823
+ const chain = input.chainIdentifier.trim();
1824
+ if (!chain)
1825
+ throw new Error("address-balance gas needs a chain identifier");
1826
+ if (input.epoch < 0n)
1827
+ throw new Error("address-balance gas needs a non-negative epoch");
1828
+ if (!Number.isInteger(input.nonce) || input.nonce < 0 || input.nonce > 4294967295) {
1829
+ throw new Error("address-balance gas nonce must be a u32");
1830
+ }
1831
+ return {
1832
+ ValidDuring: {
1833
+ minEpoch: String(input.epoch),
1834
+ maxEpoch: String(input.epoch + ADDRESS_BALANCE_VALIDITY_EPOCHS),
1835
+ minTimestamp: null,
1836
+ maxTimestamp: null,
1837
+ chain,
1838
+ nonce: input.nonce
1839
+ }
1840
+ };
1841
+ }
1815
1842
 
1816
1843
  // ../sdk/dist/protocol/mpp.js
1817
1844
  function offerToBase64Url(offer) {
@@ -4125,7 +4152,7 @@ function readX402GasPin(offer) {
4125
4152
  owner,
4126
4153
  budget,
4127
4154
  price,
4128
- payment: decodeSponsorGasPayment(offer.sponsorGasPayment ?? "")
4155
+ payment: decodeSponsorGasPin(offer.sponsorGasPayment ?? "")
4129
4156
  };
4130
4157
  } catch {
4131
4158
  return null;
@@ -4139,16 +4166,33 @@ async function buildSpendAccountX402PayTx(input) {
4139
4166
  tx.setGasBudget(input.gas.budget);
4140
4167
  tx.setGasPrice(input.gas.price);
4141
4168
  tx.setGasPayment(input.gas.payment);
4142
- tx.setExpiration({ Epoch: String(input.currentEpoch + X402_EXPIRATION_EPOCHS) });
4169
+ if (input.gas.payment.length === 0) {
4170
+ if (!input.chainIdentifier) {
4171
+ throw new Error("address-balance sponsor gas needs a chain identifier");
4172
+ }
4173
+ tx.setExpiration(addressBalanceGasExpiration({
4174
+ epoch: input.currentEpoch,
4175
+ chainIdentifier: input.chainIdentifier,
4176
+ nonce: input.nonce ?? randomU32()
4177
+ }));
4178
+ } else {
4179
+ tx.setExpiration({ Epoch: String(input.currentEpoch + X402_EXPIRATION_EPOCHS) });
4180
+ }
4143
4181
  const txBytes = toBase645(await tx.build());
4144
4182
  return { txBytes, kindBytes };
4145
4183
  }
4184
+ function randomU32() {
4185
+ return globalThis.crypto.getRandomValues(new Uint32Array(1))[0];
4186
+ }
4146
4187
  function currentEpochReader(client) {
4147
4188
  return async () => {
4148
4189
  const { systemState } = await client.core.getCurrentSystemState();
4149
4190
  return BigInt(systemState.epoch);
4150
4191
  };
4151
4192
  }
4193
+ function chainIdentifierReader(client) {
4194
+ return async () => (await client.core.getChainIdentifier()).chainIdentifier;
4195
+ }
4152
4196
  function assertPayTransaction(txBytes, expected) {
4153
4197
  let data;
4154
4198
  try {
@@ -4609,6 +4653,10 @@ async function payDelegatedSpendAccount(args) {
4609
4653
  return { status: "ok", paid: false, body: resolution.body };
4610
4654
  }
4611
4655
  if (resolution.status === "failed") {
4656
+ logInternal(logError, "resolve payment failed", {
4657
+ code: resolution.code,
4658
+ detail: resolution.detail
4659
+ });
4612
4660
  const mapped = mapPayOpErrorToDelegated(resolution.code, resolution.detail);
4613
4661
  return failed2(mapped.code, mapped.detail, {
4614
4662
  paymentId: resolution.paymentId
@@ -4733,7 +4781,8 @@ async function payDelegatedSpendAccount(args) {
4733
4781
  buildInput: {
4734
4782
  ...kindBuildInput,
4735
4783
  gas: x402Terms.gas,
4736
- currentEpoch: x402Terms.currentEpoch
4784
+ currentEpoch: x402Terms.currentEpoch,
4785
+ ...x402Terms.chainIdentifier !== void 0 ? { chainIdentifier: x402Terms.chainIdentifier } : {}
4737
4786
  },
4738
4787
  settlement: {
4739
4788
  status: "success",
@@ -5110,12 +5159,28 @@ async function x402Preflight(dialect, offer, deps, logError) {
5110
5159
  logInternal(logError, "x402 needs a current-epoch reader");
5111
5160
  return null;
5112
5161
  }
5162
+ let currentEpoch;
5113
5163
  try {
5114
- return { gas, currentEpoch: BigInt(await deps.getCurrentEpoch()) };
5164
+ currentEpoch = BigInt(await deps.getCurrentEpoch());
5115
5165
  } catch (err) {
5116
5166
  logInternal(logError, "read current epoch failed", err);
5117
5167
  return null;
5118
5168
  }
5169
+ if (gas.payment.length > 0)
5170
+ return { gas, currentEpoch };
5171
+ if (typeof deps.getChainIdentifier !== "function") {
5172
+ logInternal(logError, "address-balance x402 gas needs a chain-identifier reader");
5173
+ return null;
5174
+ }
5175
+ try {
5176
+ const chainIdentifier = await deps.getChainIdentifier();
5177
+ if (!chainIdentifier.trim())
5178
+ throw new Error("chain identifier is blank");
5179
+ return { gas, currentEpoch, chainIdentifier };
5180
+ } catch (err) {
5181
+ logInternal(logError, "read chain identifier failed", err);
5182
+ return null;
5183
+ }
5119
5184
  }
5120
5185
  function emitX402Progress(ctx, event) {
5121
5186
  if (!ctx.onProgress)
@@ -7422,6 +7487,8 @@ async function createPayer(options) {
7422
7487
  // x402 bounds the transaction's expiration by the current epoch, read from
7423
7488
  // the same client as every other chain read here.
7424
7489
  getCurrentEpoch: currentEpochReader(chain.client),
7490
+ // Address-balance gas (ADR-0055) binds the expiration to the chain.
7491
+ getChainIdentifier: chainIdentifierReader(chain.client),
7425
7492
  ...options.offerSecret ? { offerSecret: options.offerSecret } : {},
7426
7493
  ...options.fetchImpl ? { fetchImpl: options.fetchImpl } : {},
7427
7494
  ...options.logError ? { logError: options.logError } : {}
@@ -4,7 +4,7 @@ import {
4
4
  loadLocalSigningKeyRecord,
5
5
  loadMcpConfig,
6
6
  loadPaymentProfile
7
- } from "./chunk-WRN7FRUI.js";
7
+ } from "./chunk-6VFKI2BY.js";
8
8
 
9
9
  // src/index.ts
10
10
  import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
package/dist/http.js CHANGED
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  handleSuipayMcpHttpRequest
3
- } from "./chunk-WRN7FRUI.js";
3
+ } from "./chunk-6VFKI2BY.js";
4
4
  export {
5
5
  handleSuipayMcpHttpRequest
6
6
  };
package/dist/index.js CHANGED
@@ -1,7 +1,7 @@
1
1
  import {
2
2
  loadBootProfile,
3
3
  main
4
- } from "./chunk-6GJ7IGYM.js";
4
+ } from "./chunk-IBRMIXCG.js";
5
5
  import {
6
6
  MCP_TARGET_PRESETS,
7
7
  PACKAGE_NAME,
@@ -26,7 +26,7 @@ import {
26
26
  settlePreparedMcpPayment,
27
27
  traceMcpHttpRequest,
28
28
  verifySpendAccountPayReconstructs
29
- } from "./chunk-WRN7FRUI.js";
29
+ } from "./chunk-6VFKI2BY.js";
30
30
  export {
31
31
  MCP_TARGET_PRESETS,
32
32
  PACKAGE_NAME,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@cmdoss/suipay-mcp",
3
- "version": "0.2.2-dev.17",
3
+ "version": "0.2.2-dev.19",
4
4
  "type": "module",
5
5
  "description": "SuiPay MCP — pay MPP-gated APIs from a spend-account grant with an agent-held delegate key.",
6
6
  "main": "./dist/index.js",