mppx 0.8.3 → 0.8.5

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 (78) hide show
  1. package/CHANGELOG.md +14 -0
  2. package/dist/cli/cli.d.ts.map +1 -1
  3. package/dist/cli/cli.js +2 -0
  4. package/dist/cli/cli.js.map +1 -1
  5. package/dist/cli/plugins/stripe.d.ts.map +1 -1
  6. package/dist/cli/plugins/stripe.js +32 -12
  7. package/dist/cli/plugins/stripe.js.map +1 -1
  8. package/dist/cli/utils.d.ts.map +1 -1
  9. package/dist/cli/utils.js +1 -1
  10. package/dist/cli/utils.js.map +1 -1
  11. package/dist/cli/validate/challenge.d.ts +14 -0
  12. package/dist/cli/validate/challenge.d.ts.map +1 -0
  13. package/dist/cli/validate/challenge.js +211 -0
  14. package/dist/cli/validate/challenge.js.map +1 -0
  15. package/dist/cli/validate/discovery.d.ts +10 -0
  16. package/dist/cli/validate/discovery.d.ts.map +1 -0
  17. package/dist/cli/validate/discovery.js +128 -0
  18. package/dist/cli/validate/discovery.js.map +1 -0
  19. package/dist/cli/validate/helpers.d.ts +33 -0
  20. package/dist/cli/validate/helpers.d.ts.map +1 -0
  21. package/dist/cli/validate/helpers.js +136 -0
  22. package/dist/cli/validate/helpers.js.map +1 -0
  23. package/dist/cli/validate/index.d.ts +17 -0
  24. package/dist/cli/validate/index.d.ts.map +1 -0
  25. package/dist/cli/validate/index.js +224 -0
  26. package/dist/cli/validate/index.js.map +1 -0
  27. package/dist/cli/validate/payment.d.ts +7 -0
  28. package/dist/cli/validate/payment.d.ts.map +1 -0
  29. package/dist/cli/validate/payment.js +381 -0
  30. package/dist/cli/validate/payment.js.map +1 -0
  31. package/dist/evm/client/Charge.d.ts +2 -2
  32. package/dist/evm/client/Charge.d.ts.map +1 -1
  33. package/dist/evm/client/Charge.js +11 -17
  34. package/dist/evm/client/Charge.js.map +1 -1
  35. package/dist/evm/server/Charge.d.ts +5 -5
  36. package/dist/evm/server/Charge.d.ts.map +1 -1
  37. package/dist/evm/server/Charge.js +15 -7
  38. package/dist/evm/server/Charge.js.map +1 -1
  39. package/dist/tempo/internal/auto-swap.d.ts.map +1 -1
  40. package/dist/tempo/internal/auto-swap.js +6 -1
  41. package/dist/tempo/internal/auto-swap.js.map +1 -1
  42. package/dist/tempo/server/internal/html.gen.d.ts +1 -1
  43. package/dist/tempo/server/internal/html.gen.d.ts.map +1 -1
  44. package/dist/tempo/server/internal/html.gen.js +1 -1
  45. package/dist/tempo/server/internal/html.gen.js.map +1 -1
  46. package/dist/x402/Assets.d.ts +40 -0
  47. package/dist/x402/Assets.d.ts.map +1 -1
  48. package/dist/x402/Assets.js +73 -0
  49. package/dist/x402/Assets.js.map +1 -1
  50. package/dist/x402/client/Exact.d.ts +2 -2
  51. package/dist/x402/client/Exact.d.ts.map +1 -1
  52. package/dist/x402/client/Exact.js +6 -13
  53. package/dist/x402/client/Exact.js.map +1 -1
  54. package/package.json +1 -1
  55. package/src/cli/cli.test.ts +134 -29
  56. package/src/cli/cli.ts +2 -0
  57. package/src/cli/mcp.test.ts +1 -0
  58. package/src/cli/plugins/stripe.ts +31 -12
  59. package/src/cli/utils.test.ts +36 -2
  60. package/src/cli/utils.ts +2 -1
  61. package/src/cli/validate/challenge.ts +335 -0
  62. package/src/cli/validate/discovery.ts +120 -0
  63. package/src/cli/validate/helpers.ts +154 -0
  64. package/src/cli/validate/index.ts +348 -0
  65. package/src/cli/validate/payment.ts +488 -0
  66. package/src/cli/validate.test.ts +539 -0
  67. package/src/evm/PublicInterface.test-d.ts +15 -2
  68. package/src/evm/client/Charge.test.ts +248 -0
  69. package/src/evm/client/Charge.ts +12 -23
  70. package/src/evm/server/Charge.test.ts +140 -0
  71. package/src/evm/server/Charge.ts +19 -12
  72. package/src/tempo/internal/auto-swap.test.ts +26 -9
  73. package/src/tempo/internal/auto-swap.ts +15 -2
  74. package/src/tempo/server/internal/html.gen.ts +1 -1
  75. package/src/x402/Assets.test.ts +211 -0
  76. package/src/x402/Assets.ts +116 -0
  77. package/src/x402/client/Exact.test.ts +129 -0
  78. package/src/x402/client/Exact.ts +7 -19
@@ -1 +1 @@
1
- {"version":3,"file":"html.gen.js","sourceRoot":"","sources":["../../../../src/tempo/server/internal/html.gen.ts"],"names":[],"mappings":"AAAA,2BAA2B;AAC3B,MAAM,CAAC,MAAM,IAAI,GAAG,2srpBAA2srpB,CAAA"}
1
+ {"version":3,"file":"html.gen.js","sourceRoot":"","sources":["../../../../src/tempo/server/internal/html.gen.ts"],"names":[],"mappings":"AAAA,2BAA2B;AAC3B,MAAM,CAAC,MAAM,IAAI,GAAG,swrpBAAswrpB,CAAA"}
@@ -1,3 +1,4 @@
1
+ import type { Token } from 'viem/tokens';
1
2
  import type { Asset, EvmNetwork, ExactTransfer } from './Types.js';
2
3
  declare const knownAsset: unique symbol;
3
4
  /** Known x402 asset metadata. */
@@ -5,6 +6,10 @@ export type KnownAsset = Asset & {
5
6
  readonly [knownAsset]: true;
6
7
  network: EvmNetwork;
7
8
  };
9
+ /** Viem token metadata from `viem/tokens`. */
10
+ export type ViemToken = Token;
11
+ /** Currency metadata accepted by EVM and x402 payment config. */
12
+ export type Currency = `0x${string}` | KnownAsset | ViemToken;
8
13
  /** Creates typed x402 asset metadata for custom tokens. */
9
14
  export declare function define(parameters: define.Parameters): KnownAsset;
10
15
  export declare namespace define {
@@ -15,6 +20,21 @@ export declare namespace define {
15
20
  transfer: ExactTransfer;
16
21
  };
17
22
  }
23
+ /** Creates x402 asset metadata from a `viem/tokens` token definition. */
24
+ export declare function fromToken(token: ViemToken, parameters: fromToken.Parameters): KnownAsset;
25
+ export declare namespace fromToken {
26
+ type Parameters = {
27
+ chainId: number;
28
+ transfer: Transfer;
29
+ };
30
+ type Transfer = (Omit<Extract<ExactTransfer, {
31
+ type: 'eip3009';
32
+ }>, 'name'> & {
33
+ name?: string | undefined;
34
+ }) | Extract<ExactTransfer, {
35
+ type: 'permit2';
36
+ }>;
37
+ }
18
38
  /** Base network known assets. */
19
39
  export declare const base: {
20
40
  readonly USDC: KnownAsset;
@@ -25,5 +45,25 @@ export declare const baseSepolia: {
25
45
  };
26
46
  /** Returns true when a value is known x402 asset metadata. */
27
47
  export declare function isAsset(value: unknown): value is KnownAsset;
48
+ /** Returns true when a value is a `viem/tokens` token definition. */
49
+ export declare function isToken(value: unknown): value is ViemToken;
50
+ /** Returns true when a currency is a raw address without chain metadata. */
51
+ export declare function isRawAddress(currency: Currency): currency is `0x${string}`;
52
+ /** Resolves currency metadata for an EVM network. */
53
+ export declare function resolve(currency: Currency, network: EvmNetwork): resolve.Result | undefined;
54
+ export declare namespace resolve {
55
+ type Result = {
56
+ address: `0x${string}`;
57
+ decimals?: number | undefined;
58
+ name?: string | undefined;
59
+ transfer?: ExactTransfer | undefined;
60
+ };
61
+ }
62
+ /** Returns true when a currency resolves to the accepted address on the network. */
63
+ export declare function matches(currency: Currency, acceptedCurrency: `0x${string}`, network: EvmNetwork): boolean;
64
+ /** Converts an EVM chain ID to a CAIP-2 network identifier. */
65
+ export declare function toNetwork(chainId: number): EvmNetwork;
66
+ /** Converts a CAIP-2 EVM network identifier to a chain ID. */
67
+ export declare function toChainId(network: EvmNetwork): number;
28
68
  export {};
29
69
  //# sourceMappingURL=Assets.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"Assets.d.ts","sourceRoot":"","sources":["../../src/x402/Assets.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,KAAK,EAAE,UAAU,EAAE,aAAa,EAAE,MAAM,YAAY,CAAA;AAElE,QAAA,MAAM,UAAU,eAA4B,CAAA;AAE5C,iCAAiC;AACjC,MAAM,MAAM,UAAU,GAAG,KAAK,GAAG;IAC/B,QAAQ,CAAC,CAAC,UAAU,CAAC,EAAE,IAAI,CAAA;IAC3B,OAAO,EAAE,UAAU,CAAA;CACpB,CAAA;AAED,2DAA2D;AAC3D,wBAAgB,MAAM,CAAC,UAAU,EAAE,MAAM,CAAC,UAAU,GAAG,UAAU,CAQhE;AAED,MAAM,CAAC,OAAO,WAAW,MAAM,CAAC;IAC9B,KAAK,UAAU,GAAG;QAChB,OAAO,EAAE,KAAK,MAAM,EAAE,CAAA;QACtB,QAAQ,EAAE,MAAM,CAAA;QAChB,OAAO,EAAE,UAAU,CAAA;QACnB,QAAQ,EAAE,aAAa,CAAA;KACxB,CAAA;CACF;AAED,iCAAiC;AACjC,eAAO,MAAM,IAAI;;CAYP,CAAA;AAEV,iCAAiC;AACjC,eAAO,MAAM,WAAW;;CAYd,CAAA;AAEV,8DAA8D;AAC9D,wBAAgB,OAAO,CAAC,KAAK,EAAE,OAAO,GAAG,KAAK,IAAI,UAAU,CAG3D"}
1
+ {"version":3,"file":"Assets.d.ts","sourceRoot":"","sources":["../../src/x402/Assets.ts"],"names":[],"mappings":"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"}
@@ -1,3 +1,4 @@
1
+ import { getAddress } from 'viem';
1
2
  const knownAsset = Symbol('mppx.x402.asset');
2
3
  /** Creates typed x402 asset metadata for custom tokens. */
3
4
  export function define(parameters) {
@@ -9,6 +10,16 @@ export function define(parameters) {
9
10
  transfer: parameters.transfer,
10
11
  };
11
12
  }
13
+ /** Creates x402 asset metadata from a `viem/tokens` token definition. */
14
+ export function fromToken(token, parameters) {
15
+ const resolved = token(parameters.chainId);
16
+ return define({
17
+ address: resolved.address,
18
+ decimals: resolved.decimals,
19
+ network: toNetwork(parameters.chainId),
20
+ transfer: withTokenDefaults(parameters.transfer, resolved),
21
+ });
22
+ }
12
23
  /** Base network known assets. */
13
24
  export const base = {
14
25
  USDC: define({
@@ -43,4 +54,66 @@ export function isAsset(value) {
43
54
  return false;
44
55
  return value[knownAsset] === true;
45
56
  }
57
+ /** Returns true when a value is a `viem/tokens` token definition. */
58
+ export function isToken(value) {
59
+ return (typeof value === 'function' &&
60
+ typeof value.addresses === 'object' &&
61
+ typeof value.decimals === 'number');
62
+ }
63
+ /** Returns true when a currency is a raw address without chain metadata. */
64
+ export function isRawAddress(currency) {
65
+ return typeof currency === 'string';
66
+ }
67
+ /** Resolves currency metadata for an EVM network. */
68
+ export function resolve(currency, network) {
69
+ if (isAsset(currency)) {
70
+ if (currency.network !== network)
71
+ return undefined;
72
+ return {
73
+ address: currency.address,
74
+ decimals: currency.decimals,
75
+ transfer: currency.transfer,
76
+ };
77
+ }
78
+ if (isToken(currency)) {
79
+ const address = currency.addresses[toChainId(network)];
80
+ if (!address)
81
+ return undefined;
82
+ return {
83
+ address,
84
+ decimals: currency.decimals,
85
+ name: currency.name,
86
+ };
87
+ }
88
+ return {
89
+ address: currency,
90
+ };
91
+ }
92
+ /** Returns true when a currency resolves to the accepted address on the network. */
93
+ export function matches(currency, acceptedCurrency, network) {
94
+ const resolved = resolve(currency, network);
95
+ if (!resolved)
96
+ return false;
97
+ return getAddress(resolved.address) === getAddress(acceptedCurrency);
98
+ }
99
+ /** Converts an EVM chain ID to a CAIP-2 network identifier. */
100
+ export function toNetwork(chainId) {
101
+ return `eip155:${chainId}`;
102
+ }
103
+ /** Converts a CAIP-2 EVM network identifier to a chain ID. */
104
+ export function toChainId(network) {
105
+ return Number(network.slice('eip155:'.length));
106
+ }
107
+ function withTokenDefaults(transfer, token) {
108
+ if (transfer.type !== 'eip3009')
109
+ return transfer;
110
+ if (transfer.name)
111
+ return { ...transfer, name: transfer.name };
112
+ if (!token.name)
113
+ throw new Error('EIP-3009 token assets require a token name.');
114
+ return {
115
+ ...transfer,
116
+ name: token.name,
117
+ };
118
+ }
46
119
  //# sourceMappingURL=Assets.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"Assets.js","sourceRoot":"","sources":["../../src/x402/Assets.ts"],"names":[],"mappings":"AAEA,MAAM,UAAU,GAAG,MAAM,CAAC,iBAAiB,CAAC,CAAA;AAQ5C,2DAA2D;AAC3D,MAAM,UAAU,MAAM,CAAC,UAA6B;IAClD,OAAO;QACL,CAAC,UAAU,CAAC,EAAE,IAAI;QAClB,OAAO,EAAE,UAAU,CAAC,OAAO;QAC3B,QAAQ,EAAE,UAAU,CAAC,QAAQ;QAC7B,OAAO,EAAE,UAAU,CAAC,OAAO;QAC3B,QAAQ,EAAE,UAAU,CAAC,QAAQ;KAC9B,CAAA;AACH,CAAC;AAWD,iCAAiC;AACjC,MAAM,CAAC,MAAM,IAAI,GAAG;IAClB,IAAI,EAAE,MAAM,CAAC;QACX,OAAO,EAAE,4CAA4C;QACrD,QAAQ,EAAE,CAAC;QACX,OAAO,EAAE,aAAa;QACtB,QAAQ,EAAE;YACR,oEAAoE;YACpE,IAAI,EAAE,UAAU;YAChB,IAAI,EAAE,SAAS;YACf,OAAO,EAAE,GAAG;SACb;KACF,CAAC;CACM,CAAA;AAEV,iCAAiC;AACjC,MAAM,CAAC,MAAM,WAAW,GAAG;IACzB,IAAI,EAAE,MAAM,CAAC;QACX,OAAO,EAAE,4CAA4C;QACrD,QAAQ,EAAE,CAAC;QACX,OAAO,EAAE,cAAc;QACvB,QAAQ,EAAE;YACR,qEAAqE;YACrE,IAAI,EAAE,MAAM;YACZ,IAAI,EAAE,SAAS;YACf,OAAO,EAAE,GAAG;SACb;KACF,CAAC;CACM,CAAA;AAEV,8DAA8D;AAC9D,MAAM,UAAU,OAAO,CAAC,KAAc;IACpC,IAAI,OAAO,KAAK,KAAK,QAAQ,IAAI,KAAK,KAAK,IAAI;QAAE,OAAO,KAAK,CAAA;IAC7D,OAAQ,KAA6B,CAAC,UAAU,CAAC,KAAK,IAAI,CAAA;AAC5D,CAAC"}
1
+ {"version":3,"file":"Assets.js","sourceRoot":"","sources":["../../src/x402/Assets.ts"],"names":[],"mappings":"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"}
@@ -31,8 +31,8 @@ export type Config = {
31
31
  /** Optional allowlist of supported EVM chain IDs. */
32
32
  networks?: readonly number[] | undefined;
33
33
  /** Optional allowlist of supported currencies. */
34
- currencies?: readonly (`0x${string}` | Assets.KnownAsset)[] | undefined;
34
+ currencies?: readonly Assets.Currency[] | undefined;
35
35
  /** Legacy alias for `currencies`. */
36
- assets?: readonly (`0x${string}` | Assets.KnownAsset)[] | undefined;
36
+ assets?: readonly Assets.Currency[] | undefined;
37
37
  };
38
38
  //# sourceMappingURL=Exact.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"Exact.d.ts","sourceRoot":"","sources":["../../../src/x402/client/Exact.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,MAAM,CAAA;AAGnC,OAAO,KAAK,KAAK,SAAS,MAAM,oBAAoB,CAAA;AACpD,OAAO,KAAK,MAAM,MAAM,cAAc,CAAA;AAGtC,OAAO,KAAK,KAAK,MAAM,aAAa,CAAA;AAEpC;;GAEG;AACH,wBAAsB,gBAAgB,CAAC,UAAU,EAAE,gBAAgB,CAAC,UAAU,GAAG,OAAO,CAAC,MAAM,CAAC,CA2D/F;AAED,MAAM,CAAC,OAAO,WAAW,gBAAgB,CAAC;IACxC,KAAK,UAAU,GAAG;QAChB,SAAS,EAAE,SAAS,CAAC,SAAS,CAAC,KAAK,CAAC,YAAY,CAAC,CAAA;QAClD,MAAM,EAAE,MAAM,CAAA;QACd,OAAO,CAAC,EAAE,OAAO,GAAG,SAAS,CAAA;KAC9B,CAAA;CACF;AAED,MAAM,MAAM,OAAO,GAAG;IACpB,OAAO,CAAC,EAAE,OAAO,GAAG,SAAS,CAAA;CAC9B,CAAA;AAED,MAAM,MAAM,MAAM,GAAG,OAAO,GAAG;IAC7B,aAAa,CAAC,EAAE,CAAC,UAAU,EAAE,GAAG,KAAK,OAAO,CAAC,KAAK,MAAM,EAAE,CAAC,CAAA;CAC5D,CAAA;AAED,MAAM,MAAM,MAAM,GAAG;IACnB,uDAAuD;IACvD,OAAO,EAAE,OAAO,CAAA;IAChB,gGAAgG;IAChG,QAAQ,CAAC,EAAE,MAAM,GAAG,SAAS,CAAA;IAC7B,yEAAyE;IACzE,SAAS,CAAC,EAAE,MAAM,GAAG,SAAS,CAAA;IAC9B,mEAAmE;IACnE,eAAe,CAAC,EAAE,MAAM,GAAG,SAAS,CAAA;IACpC,qDAAqD;IACrD,QAAQ,CAAC,EAAE,SAAS,MAAM,EAAE,GAAG,SAAS,CAAA;IACxC,kDAAkD;IAClD,UAAU,CAAC,EAAE,SAAS,CAAC,KAAK,MAAM,EAAE,GAAG,MAAM,CAAC,UAAU,CAAC,EAAE,GAAG,SAAS,CAAA;IACvE,qCAAqC;IACrC,MAAM,CAAC,EAAE,SAAS,CAAC,KAAK,MAAM,EAAE,GAAG,MAAM,CAAC,UAAU,CAAC,EAAE,GAAG,SAAS,CAAA;CACpE,CAAA"}
1
+ {"version":3,"file":"Exact.d.ts","sourceRoot":"","sources":["../../../src/x402/client/Exact.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,MAAM,CAAA;AAGnC,OAAO,KAAK,KAAK,SAAS,MAAM,oBAAoB,CAAA;AACpD,OAAO,KAAK,MAAM,MAAM,cAAc,CAAA;AAGtC,OAAO,KAAK,KAAK,MAAM,aAAa,CAAA;AAEpC;;GAEG;AACH,wBAAsB,gBAAgB,CAAC,UAAU,EAAE,gBAAgB,CAAC,UAAU,GAAG,OAAO,CAAC,MAAM,CAAC,CA2D/F;AAED,MAAM,CAAC,OAAO,WAAW,gBAAgB,CAAC;IACxC,KAAK,UAAU,GAAG;QAChB,SAAS,EAAE,SAAS,CAAC,SAAS,CAAC,KAAK,CAAC,YAAY,CAAC,CAAA;QAClD,MAAM,EAAE,MAAM,CAAA;QACd,OAAO,CAAC,EAAE,OAAO,GAAG,SAAS,CAAA;KAC9B,CAAA;CACF;AAED,MAAM,MAAM,OAAO,GAAG;IACpB,OAAO,CAAC,EAAE,OAAO,GAAG,SAAS,CAAA;CAC9B,CAAA;AAED,MAAM,MAAM,MAAM,GAAG,OAAO,GAAG;IAC7B,aAAa,CAAC,EAAE,CAAC,UAAU,EAAE,GAAG,KAAK,OAAO,CAAC,KAAK,MAAM,EAAE,CAAC,CAAA;CAC5D,CAAA;AAED,MAAM,MAAM,MAAM,GAAG;IACnB,uDAAuD;IACvD,OAAO,EAAE,OAAO,CAAA;IAChB,gGAAgG;IAChG,QAAQ,CAAC,EAAE,MAAM,GAAG,SAAS,CAAA;IAC7B,yEAAyE;IACzE,SAAS,CAAC,EAAE,MAAM,GAAG,SAAS,CAAA;IAC9B,mEAAmE;IACnE,eAAe,CAAC,EAAE,MAAM,GAAG,SAAS,CAAA;IACpC,qDAAqD;IACrD,QAAQ,CAAC,EAAE,SAAS,MAAM,EAAE,GAAG,SAAS,CAAA;IACxC,kDAAkD;IAClD,UAAU,CAAC,EAAE,SAAS,MAAM,CAAC,QAAQ,EAAE,GAAG,SAAS,CAAA;IACnD,qCAAqC;IACrC,MAAM,CAAC,EAAE,SAAS,MAAM,CAAC,QAAQ,EAAE,GAAG,SAAS,CAAA;CAChD,CAAA"}
@@ -81,11 +81,11 @@ function assertPolicy(parameters, accepted) {
81
81
  if (parameters.networks && !parameters.networks.includes(chainId))
82
82
  throw new Error(`x402 exact chain ID is not allowed: ${chainId}.`);
83
83
  const currencies = parameters.currencies ?? parameters.assets;
84
- if (currencies?.some((currency) => !Assets.isAsset(currency)) && !parameters.networks?.length)
84
+ if (currencies?.some((currency) => Assets.isRawAddress(currency)) && !parameters.networks?.length)
85
85
  throw new Error('x402 exact raw currency allowlists require networks.');
86
86
  if (currencies) {
87
87
  const acceptedCurrency = getAddress(accepted.asset);
88
- const allowed = currencies.some((currency) => currencyMatches(currency, acceptedCurrency, accepted.network));
88
+ const allowed = currencies.some((currency) => Assets.matches(currency, acceptedCurrency, accepted.network));
89
89
  if (!allowed)
90
90
  throw new Error(`x402 exact currency is not allowed: ${acceptedCurrency}.`);
91
91
  }
@@ -100,20 +100,13 @@ function assertPolicy(parameters, accepted) {
100
100
  throw new Error('x402 exact amount exceeds maxAmount.');
101
101
  }
102
102
  }
103
- function addressOf(currency) {
104
- return Assets.isAsset(currency) ? currency.address : currency;
105
- }
106
- function currencyMatches(currency, acceptedCurrency, network) {
107
- if (getAddress(addressOf(currency)) !== acceptedCurrency)
108
- return false;
109
- return !Assets.isAsset(currency) || currency.network === network;
110
- }
111
103
  function decimalsOfAcceptedCurrency(parameters, accepted) {
112
104
  const currencies = parameters.currencies ?? parameters.assets;
113
105
  const acceptedCurrency = getAddress(accepted.asset);
114
- const currency = currencies?.find((currency) => currencyMatches(currency, acceptedCurrency, accepted.network));
115
- if (currency && Assets.isAsset(currency))
116
- return currency.decimals;
106
+ const currency = currencies?.find((currency) => Assets.matches(currency, acceptedCurrency, accepted.network));
107
+ const resolved = currency ? Assets.resolve(currency, accepted.network) : undefined;
108
+ if (resolved?.decimals !== undefined)
109
+ return resolved.decimals;
117
110
  return parameters.decimals;
118
111
  }
119
112
  function withNonceSalt(extensions) {
@@ -1 +1 @@
1
- {"version":3,"file":"Exact.js","sourceRoot":"","sources":["../../../src/x402/client/Exact.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"Exact.js","sourceRoot":"","sources":["../../../src/x402/client/Exact.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "mppx",
3
3
  "type": "module",
4
- "version": "0.8.3",
4
+ "version": "0.8.5",
5
5
  "main": "./dist/index.js",
6
6
  "license": "MIT",
7
7
  "homepage": "https://github.com/wevm/mppx#readme",
@@ -20,6 +20,7 @@ import * as Receipt from '../Receipt.js'
20
20
  import * as Mppx_server from '../server/Mppx.js'
21
21
  import { toNodeListener } from '../server/Mppx.js'
22
22
  import * as Store from '../Store.js'
23
+ import { stripePreviewVersion } from '../stripe/internal/constants.js'
23
24
  import { stripe as stripe_server } from '../stripe/server/Methods.js'
24
25
  import { tempo } from '../tempo/server/Methods.js'
25
26
  import { escrowAbi } from '../tempo/session/precompile/escrow.abi.js'
@@ -1403,40 +1404,144 @@ describe('stripe charge', () => {
1403
1404
  }
1404
1405
  })
1405
1406
 
1406
- test('error: production key rejected', { timeout: 60_000 }, async () => {
1407
- const server = Mppx_server.create({
1408
- methods: [
1409
- stripe_server.charge({
1410
- secretKey: 'sk_test_mock',
1411
- networkId: 'internal',
1412
- paymentMethodTypes: ['card'],
1413
- }),
1414
- ],
1415
- realm: 'cli-test-stripe-live',
1416
- secretKey: 'cli-test-secret-cli-test-secret-32',
1417
- })
1407
+ test(
1408
+ 'happy path: live key uses production SPT endpoint and seller business profile',
1409
+ { timeout: 60_000 },
1410
+ async () => {
1411
+ const mockStripeClient = {
1412
+ paymentIntents: {
1413
+ create: async () => ({ id: 'pi_mock_cli_live_123', status: 'succeeded' }),
1414
+ },
1415
+ }
1418
1416
 
1419
- const appServer = await Http.createServer(async (req, res) => {
1420
- const result = await Mppx_server.toNodeListener(
1421
- server.charge({ amount: '1', currency: 'usd', decimals: 2 }),
1422
- )(req, res)
1423
- if (result.status === 402) return
1424
- res.end('paid')
1425
- })
1417
+ const server = Mppx_server.create({
1418
+ methods: [
1419
+ stripe_server.charge({
1420
+ client: mockStripeClient,
1421
+ networkId: 'profile_live_mock',
1422
+ paymentMethodTypes: ['card'],
1423
+ }),
1424
+ ],
1425
+ realm: 'cli-test-stripe-live',
1426
+ secretKey: 'cli-test-secret-cli-test-secret-32',
1427
+ })
1426
1428
 
1427
- try {
1428
- const { output, exitCode } = await serve(
1429
- [appServer.url, '-s', '-M', 'paymentMethod=pm_card_visa'],
1430
- { env: { MPPX_STRIPE_SECRET_KEY: 'sk_live_fake' } },
1429
+ const appServer = await Http.createServer(async (req, res) => {
1430
+ const result = await Mppx_server.toNodeListener(
1431
+ server.charge({ amount: '1', currency: 'usd', decimals: 2 }),
1432
+ )(req, res)
1433
+ if (result.status === 402) return
1434
+ res.end('paid')
1435
+ })
1436
+
1437
+ const { restore, stripeRequests } = mockSptFetch(
1438
+ 'https://api.stripe.com/v1/shared_payment/issued_tokens',
1431
1439
  )
1432
- expect(exitCode).toBe(2)
1433
- expect(output).toContain('test mode')
1434
- } finally {
1435
- appServer.close()
1436
- }
1437
- })
1440
+
1441
+ try {
1442
+ const { output } = await serve([appServer.url, '-s', '-M', 'paymentMethod=pm_card_visa'], {
1443
+ env: { MPPX_STRIPE_SECRET_KEY: 'sk_live_fake', MPPX_STRIPE_SPT_URL: undefined },
1444
+ })
1445
+ expect(output).toContain('paid')
1446
+ const stripeRequest = stripeRequests[0]
1447
+ expect(stripeRequest?.url).toBe('https://api.stripe.com/v1/shared_payment/issued_tokens')
1448
+ expect(stripeRequest?.body.get('seller_details[network_business_profile]')).toBe(
1449
+ 'profile_live_mock',
1450
+ )
1451
+ expect(stripeRequest?.body.has('seller_details[network_id]')).toBe(false)
1452
+ expect(stripeRequest?.headers['Stripe-Version']).toBe(stripePreviewVersion)
1453
+ } finally {
1454
+ restore()
1455
+ appServer.close()
1456
+ }
1457
+ },
1458
+ )
1459
+
1460
+ test(
1461
+ 'happy path: test key uses test-helper SPT endpoint and network ID',
1462
+ { timeout: 60_000 },
1463
+ async () => {
1464
+ const mockStripeClient = {
1465
+ paymentIntents: {
1466
+ create: async () => ({ id: 'pi_mock_cli_test_123', status: 'succeeded' }),
1467
+ },
1468
+ }
1469
+
1470
+ const server = Mppx_server.create({
1471
+ methods: [
1472
+ stripe_server.charge({
1473
+ client: mockStripeClient,
1474
+ networkId: 'internal',
1475
+ paymentMethodTypes: ['card'],
1476
+ }),
1477
+ ],
1478
+ realm: 'cli-test-stripe-testmode',
1479
+ secretKey: 'cli-test-secret-cli-test-secret-32',
1480
+ })
1481
+
1482
+ const appServer = await Http.createServer(async (req, res) => {
1483
+ const result = await Mppx_server.toNodeListener(
1484
+ server.charge({ amount: '1', currency: 'usd', decimals: 2 }),
1485
+ )(req, res)
1486
+ if (result.status === 402) return
1487
+ res.end('paid')
1488
+ })
1489
+
1490
+ const { restore, stripeRequests } = mockSptFetch(
1491
+ 'https://api.stripe.com/v1/test_helpers/shared_payment/granted_tokens',
1492
+ )
1493
+
1494
+ try {
1495
+ const { output } = await serve([appServer.url, '-s', '-M', 'paymentMethod=pm_card_visa'], {
1496
+ env: { MPPX_STRIPE_SECRET_KEY: 'sk_test_fake', MPPX_STRIPE_SPT_URL: undefined },
1497
+ })
1498
+ expect(output).toContain('paid')
1499
+ const stripeRequest = stripeRequests[0]
1500
+ expect(stripeRequest?.url).toBe(
1501
+ 'https://api.stripe.com/v1/test_helpers/shared_payment/granted_tokens',
1502
+ )
1503
+ expect(stripeRequest?.body.get('seller_details[network_id]')).toBe('internal')
1504
+ expect(stripeRequest?.body.has('seller_details[network_business_profile]')).toBe(false)
1505
+ expect(stripeRequest?.headers['Stripe-Version']).toBe(stripePreviewVersion)
1506
+ } finally {
1507
+ restore()
1508
+ appServer.close()
1509
+ }
1510
+ },
1511
+ )
1438
1512
  })
1439
1513
 
1514
+ /**
1515
+ * Intercepts `globalThis.fetch` calls to `sptUrl`, recording each request and
1516
+ * responding with a mock SPT. Returns the recorded requests and a `restore`
1517
+ * function that reinstates the original fetch.
1518
+ */
1519
+ function mockSptFetch(sptUrl: string) {
1520
+ const originalFetch = globalThis.fetch
1521
+ const stripeRequests: {
1522
+ body: URLSearchParams
1523
+ headers: Record<string, string>
1524
+ url: string
1525
+ }[] = []
1526
+ globalThis.fetch = (async (input, init) => {
1527
+ const url =
1528
+ typeof input === 'string' ? input : input instanceof URL ? input.toString() : input.url
1529
+ if (url === sptUrl) {
1530
+ stripeRequests.push({
1531
+ body: new URLSearchParams(init?.body as string),
1532
+ headers: (init?.headers ?? {}) as Record<string, string>,
1533
+ url,
1534
+ })
1535
+ return new Response(JSON.stringify({ id: 'spt_mock_cli_test' }), {
1536
+ headers: { 'Content-Type': 'application/json' },
1537
+ status: 200,
1538
+ })
1539
+ }
1540
+ return originalFetch(input, init)
1541
+ }) as typeof fetch
1542
+ return { restore: () => (globalThis.fetch = originalFetch), stripeRequests }
1543
+ }
1544
+
1440
1545
  // ---------------------------------------------------------------------------
1441
1546
  // account [action]
1442
1547
  // Keychain tests are opt-in because macOS/Linux keychain commands can block on
package/src/cli/cli.ts CHANGED
@@ -40,6 +40,7 @@ import {
40
40
  resolveFundingNetwork,
41
41
  resolveRpcUrl,
42
42
  } from './utils.js'
43
+ import validate from './validate/index.js'
43
44
 
44
45
  const packageJson = createRequire(import.meta.url)('../../package.json') as {
45
46
  name: string
@@ -1575,5 +1576,6 @@ cli.command(discover)
1575
1576
  cli.command(init)
1576
1577
  cli.command(services)
1577
1578
  cli.command(sign)
1579
+ cli.command(validate)
1578
1580
 
1579
1581
  export default cli
@@ -194,6 +194,7 @@ test('tools/list exposes mppx commands with input and output schemas', async ()
194
194
  'services_list',
195
195
  'services_show',
196
196
  'sign',
197
+ 'validate',
197
198
  ])
198
199
  expect(tools.find((tool: { name: string }) => tool.name === 'account_list').outputSchema).toEqual(
199
200
  expect.objectContaining({
@@ -1,6 +1,7 @@
1
1
  import { Errors, z } from 'incur'
2
2
 
3
3
  import { stripe as stripeMethods } from '../../stripe/client/index.js'
4
+ import { stripePreviewVersion } from '../../stripe/internal/constants.js'
4
5
  import { pc } from '../utils.js'
5
6
  import { createPlugin } from './plugin.js'
6
7
 
@@ -30,13 +31,6 @@ export function stripe() {
30
31
  message: 'MPPX_STRIPE_SECRET_KEY environment variable is required for Stripe payments.',
31
32
  exitCode: 2,
32
33
  })
33
- if (!stripeSecretKey.startsWith('sk_test_'))
34
- throw new Errors.IncurError({
35
- code: 'UNSUPPORTED_MODE',
36
- message:
37
- 'Stripe CLI payments are currently only supported in test mode (sk_test_... keys).',
38
- exitCode: 2,
39
- })
40
34
 
41
35
  return {
42
36
  tokenSymbol: currency?.toUpperCase() ?? '',
@@ -58,19 +52,35 @@ export function stripe() {
58
52
  'usage_limits[max_amount]': amount,
59
53
  'usage_limits[expires_at]': expiresAt.toString(),
60
54
  })
61
- if (networkId) body.set('seller_details[network_id]', networkId)
55
+ const testMode = isTestKey(stripeSecretKey)
56
+ const sptUrl = (() => {
57
+ // Allow tests and custom deployments to target a specific SPT endpoint.
58
+ if (process.env.MPPX_STRIPE_SPT_URL) return process.env.MPPX_STRIPE_SPT_URL
59
+ // Preserve test-key behavior against Stripe's test-helper SPT endpoint.
60
+ if (testMode)
61
+ return 'https://api.stripe.com/v1/test_helpers/shared_payment/granted_tokens'
62
+ // Live keys mint Shared Payment Tokens through the agent-side issued tokens API.
63
+ return 'https://api.stripe.com/v1/shared_payment/issued_tokens'
64
+ })()
65
+ if (networkId) {
66
+ // Live SPT issuance grants the token to the seller's Stripe business
67
+ // profile (`profile_...`); the test helper uses a plain network ID.
68
+ const sellerDetailsField = testMode
69
+ ? 'seller_details[network_id]'
70
+ : 'seller_details[network_business_profile]'
71
+ body.set(sellerDetailsField, networkId)
72
+ }
62
73
  if (metadata) {
63
74
  for (const [key, value] of Object.entries(metadata)) {
64
75
  body.set(`metadata[${key}]`, value)
65
76
  }
66
77
  }
67
78
 
68
- const sptUrl =
69
- process.env.MPPX_STRIPE_SPT_URL ??
70
- 'https://api.stripe.com/v1/test_helpers/shared_payment/granted_tokens'
71
79
  const sptHeaders = {
72
80
  Authorization: `Basic ${btoa(`${stripeSecretKey}:`)}`,
73
81
  'Content-Type': 'application/x-www-form-urlencoded',
82
+ // SPT endpoints are in preview and require an explicit preview API version.
83
+ 'Stripe-Version': stripePreviewVersion,
74
84
  }
75
85
 
76
86
  let response = await globalThis.fetch(sptUrl, {
@@ -80,7 +90,11 @@ export function stripe() {
80
90
  })
81
91
  if (!response.ok) {
82
92
  const errorBody = (await response.json()) as { error: { message: string } }
93
+ // Retry without optional parameters only in test mode: the live
94
+ // issued-tokens endpoint requires `seller_details`, so a retry
95
+ // without it can never succeed.
83
96
  if (
97
+ testMode &&
84
98
  (metadata || networkId) &&
85
99
  errorBody.error.message.includes('Received unknown parameter')
86
100
  ) {
@@ -122,7 +136,8 @@ export function stripe() {
122
136
 
123
137
  formatReceiptField(key, value) {
124
138
  if (key === 'reference' && typeof value === 'string' && value.startsWith('pi_')) {
125
- const isTest = process.env.MPPX_STRIPE_SECRET_KEY?.startsWith('sk_test_')
139
+ const secretKey = process.env.MPPX_STRIPE_SECRET_KEY
140
+ const isTest = secretKey !== undefined && isTestKey(secretKey)
126
141
  const url = `https://dashboard.stripe.com${isTest ? '/test' : ''}/payments/${value}`
127
142
  return pc.link(url, value, true)
128
143
  }
@@ -132,6 +147,10 @@ export function stripe() {
132
147
 
133
148
  // --- Helpers ---
134
149
 
150
+ function isTestKey(secretKey: string) {
151
+ return secretKey.startsWith('sk_test_') || secretKey.startsWith('rk_test_')
152
+ }
153
+
135
154
  function parseOptions<const schema extends z.ZodType>(
136
155
  schema: schema,
137
156
  rawOptions: unknown,
@@ -1,7 +1,13 @@
1
1
  import { tempo as tempoMainnet, tempoModerato } from 'viem/tempo/chains'
2
- import { afterEach, describe, expect, test } from 'vp/test'
2
+ import { afterEach, describe, expect, test, vi } from 'vp/test'
3
3
 
4
- import { networkRpcUrls, resolveChain, resolveFundingNetwork, resolveRpcUrl } from './utils.js'
4
+ import {
5
+ fetchTokenInfo,
6
+ networkRpcUrls,
7
+ resolveChain,
8
+ resolveFundingNetwork,
9
+ resolveRpcUrl,
10
+ } from './utils.js'
5
11
 
6
12
  describe('resolveRpcUrl', () => {
7
13
  afterEach(() => {
@@ -97,3 +103,31 @@ describe('resolveChain', () => {
97
103
  expect(chain.id).not.toBe(tempoModerato.id)
98
104
  })
99
105
  })
106
+
107
+ describe('fetchTokenInfo', () => {
108
+ afterEach(() => {
109
+ vi.doUnmock('viem/tempo')
110
+ })
111
+
112
+ test('uses 6 decimals when token metadata omits a numeric decimals value', async () => {
113
+ const token = '0x1111111111111111111111111111111111111111'
114
+ const account = '0x2222222222222222222222222222222222222222'
115
+ vi.doMock('viem/tempo', () => ({
116
+ Actions: {
117
+ token: {
118
+ getBalance: vi.fn(async () => ({ amount: 123n })),
119
+ getMetadata: vi.fn(async () => ({ decimals: undefined, symbol: 'TEST' })),
120
+ },
121
+ },
122
+ }))
123
+
124
+ const info = await fetchTokenInfo({} as never, token, account)
125
+
126
+ expect(info).toEqual({
127
+ balance: 123n,
128
+ decimals: 6,
129
+ symbol: 'TEST',
130
+ token,
131
+ })
132
+ })
133
+ })
package/src/cli/utils.ts CHANGED
@@ -318,7 +318,8 @@ export async function fetchTokenInfo(
318
318
  [usdc]: 'USDC',
319
319
  }
320
320
  const symbol = knownSymbols[token] ?? metadata.symbol
321
- const decimals = 'decimals' in metadata ? metadata.decimals : 6
321
+ const decimals =
322
+ 'decimals' in metadata && typeof metadata.decimals === 'number' ? metadata.decimals : 6
322
323
  return { balance, symbol, decimals, token }
323
324
  }
324
325