mppx 0.4.10 → 0.4.12

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 (74) hide show
  1. package/CHANGELOG.md +23 -1
  2. package/dist/internal/env.d.ts +1 -1
  3. package/dist/internal/env.d.ts.map +1 -1
  4. package/dist/internal/env.js +2 -6
  5. package/dist/internal/env.js.map +1 -1
  6. package/dist/internal/types.d.ts +23 -0
  7. package/dist/internal/types.d.ts.map +1 -1
  8. package/dist/server/Mppx.d.ts +1 -1
  9. package/dist/server/Mppx.d.ts.map +1 -1
  10. package/dist/server/Mppx.js +49 -2
  11. package/dist/server/Mppx.js.map +1 -1
  12. package/dist/stripe/internal/types.d.ts +3 -0
  13. package/dist/stripe/internal/types.d.ts.map +1 -1
  14. package/dist/stripe/server/Charge.d.ts.map +1 -1
  15. package/dist/stripe/server/Charge.js +9 -2
  16. package/dist/stripe/server/Charge.js.map +1 -1
  17. package/dist/tempo/Methods.d.ts +15 -0
  18. package/dist/tempo/Methods.d.ts.map +1 -1
  19. package/dist/tempo/Methods.js +27 -3
  20. package/dist/tempo/Methods.js.map +1 -1
  21. package/dist/tempo/client/Charge.d.ts +21 -0
  22. package/dist/tempo/client/Charge.d.ts.map +1 -1
  23. package/dist/tempo/client/Charge.js +33 -7
  24. package/dist/tempo/client/Charge.js.map +1 -1
  25. package/dist/tempo/client/Methods.d.ts +15 -0
  26. package/dist/tempo/client/Methods.d.ts.map +1 -1
  27. package/dist/tempo/internal/account.d.ts +5 -11
  28. package/dist/tempo/internal/account.d.ts.map +1 -1
  29. package/dist/tempo/internal/charge.d.ts +20 -0
  30. package/dist/tempo/internal/charge.d.ts.map +1 -0
  31. package/dist/tempo/internal/charge.js +23 -0
  32. package/dist/tempo/internal/charge.js.map +1 -0
  33. package/dist/tempo/internal/fee-payer.d.ts.map +1 -1
  34. package/dist/tempo/internal/fee-payer.js +15 -3
  35. package/dist/tempo/internal/fee-payer.js.map +1 -1
  36. package/dist/tempo/server/Charge.d.ts +17 -2
  37. package/dist/tempo/server/Charge.d.ts.map +1 -1
  38. package/dist/tempo/server/Charge.js +148 -99
  39. package/dist/tempo/server/Charge.js.map +1 -1
  40. package/dist/tempo/server/Methods.d.ts +17 -2
  41. package/dist/tempo/server/Methods.d.ts.map +1 -1
  42. package/dist/tempo/server/Methods.js +4 -1
  43. package/dist/tempo/server/Methods.js.map +1 -1
  44. package/dist/tempo/server/Session.d.ts +9 -4
  45. package/dist/tempo/server/Session.d.ts.map +1 -1
  46. package/dist/tempo/server/Session.js +25 -6
  47. package/dist/tempo/server/Session.js.map +1 -1
  48. package/dist/tempo/session/Chain.d.ts +18 -2
  49. package/dist/tempo/session/Chain.d.ts.map +1 -1
  50. package/dist/tempo/session/Chain.js +18 -14
  51. package/dist/tempo/session/Chain.js.map +1 -1
  52. package/package.json +1 -1
  53. package/src/internal/env.test.ts +12 -12
  54. package/src/internal/env.ts +2 -6
  55. package/src/internal/types.ts +25 -0
  56. package/src/server/Mppx.test.ts +287 -0
  57. package/src/server/Mppx.ts +59 -5
  58. package/src/stripe/internal/types.ts +5 -1
  59. package/src/stripe/server/Charge.test.ts +52 -1
  60. package/src/stripe/server/Charge.ts +12 -4
  61. package/src/tempo/Methods.test.ts +79 -0
  62. package/src/tempo/Methods.ts +53 -17
  63. package/src/tempo/client/Charge.ts +41 -8
  64. package/src/tempo/internal/account.ts +7 -14
  65. package/src/tempo/internal/charge.ts +43 -0
  66. package/src/tempo/internal/fee-payer.test.ts +33 -14
  67. package/src/tempo/internal/fee-payer.ts +21 -6
  68. package/src/tempo/server/Charge.test.ts +231 -0
  69. package/src/tempo/server/Charge.ts +193 -124
  70. package/src/tempo/server/Methods.ts +4 -1
  71. package/src/tempo/server/Session.test.ts +57 -0
  72. package/src/tempo/server/Session.ts +33 -20
  73. package/src/tempo/session/Chain.test.ts +25 -5
  74. package/src/tempo/session/Chain.ts +30 -14
@@ -8,6 +8,7 @@ import * as Client from '../../viem/Client.js';
8
8
  import * as z from '../../zod.js';
9
9
  import * as Attribution from '../Attribution.js';
10
10
  import * as AutoSwap from '../internal/auto-swap.js';
11
+ import * as Charge_internal from '../internal/charge.js';
11
12
  import * as defaults from '../internal/defaults.js';
12
13
  import * as Methods from '../Methods.js';
13
14
  /**
@@ -45,16 +46,33 @@ export function charge(parameters = {}) {
45
46
  const { request } = challenge;
46
47
  const { amount, methodDetails } = request;
47
48
  const currency = request.currency;
48
- const recipient = request.recipient;
49
+ if (parameters.expectedRecipients) {
50
+ const allowed = new Set(parameters.expectedRecipients.map((a) => a.toLowerCase()));
51
+ const splits = methodDetails?.splits;
52
+ if (splits) {
53
+ for (const split of splits) {
54
+ if (!allowed.has(split.recipient.toLowerCase()))
55
+ throw new Error(`Unexpected split recipient: ${split.recipient}`);
56
+ }
57
+ }
58
+ }
49
59
  const memo = methodDetails?.memo
50
60
  ? methodDetails.memo
51
61
  : Attribution.encode({ serverId: challenge.realm, clientId });
52
- const transferCall = Actions.token.transfer.call({
53
- amount: BigInt(amount),
54
- memo,
55
- to: recipient,
56
- token: currency,
62
+ const transfers = Charge_internal.getTransfers({
63
+ amount,
64
+ methodDetails: {
65
+ ...methodDetails,
66
+ memo,
67
+ },
68
+ recipient: request.recipient,
57
69
  });
70
+ const transferCalls = transfers.map((transfer) => Actions.token.transfer.call({
71
+ amount: BigInt(transfer.amount),
72
+ ...(transfer.memo && { memo: transfer.memo }),
73
+ to: transfer.recipient,
74
+ token: currency,
75
+ }));
58
76
  const autoSwap = AutoSwap.resolve(context?.autoSwap ?? parameters.autoSwap, AutoSwap.defaultCurrencies);
59
77
  const swapCalls = autoSwap
60
78
  ? await AutoSwap.findCalls(client, {
@@ -65,7 +83,14 @@ export function charge(parameters = {}) {
65
83
  slippage: autoSwap.slippage,
66
84
  })
67
85
  : undefined;
68
- const calls = [...(swapCalls ?? []), transferCall];
86
+ const calls = [...(swapCalls ?? []), ...transferCalls];
87
+ const validBefore = (() => {
88
+ const defaultExpiry = Math.floor(Date.now() / 1000) + 25;
89
+ if (!challenge.expires)
90
+ return defaultExpiry;
91
+ const challengeExpiry = Math.floor(new Date(challenge.expires).getTime() / 1000);
92
+ return Math.min(defaultExpiry, challengeExpiry);
93
+ })();
69
94
  if (mode === 'push') {
70
95
  const { receipts } = await sendCallsSync(client, {
71
96
  account,
@@ -86,6 +111,7 @@ export function charge(parameters = {}) {
86
111
  calls,
87
112
  ...(methodDetails?.feePayer && { feePayer: true }),
88
113
  nonceKey: 'expiring',
114
+ validBefore,
89
115
  });
90
116
  // FIXME: figure out gas estimation issue for fee payer tx
91
117
  prepared.gas = prepared.gas + 5000n;
@@ -1 +1 @@
1
- {"version":3,"file":"Charge.js","sourceRoot":"","sources":["../../../src/tempo/client/Charge.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"Charge.js","sourceRoot":"","sources":["../../../src/tempo/client/Charge.ts"],"names":[],"mappings":"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"}
@@ -36,8 +36,18 @@ export declare function tempo(parameters?: tempo.Parameters): readonly [import("
36
36
  feePayer: import("zod/mini").ZodMiniOptional<import("zod/mini").ZodMiniPipe<import("zod/mini").ZodMiniUnion<readonly [import("zod/mini").ZodMiniBoolean<boolean>, import("zod/mini").ZodMiniCustom<import("viem").Account, import("viem").Account>]>, import("zod/mini").ZodMiniTransform<boolean, boolean | import("viem").Account>>>;
37
37
  memo: import("zod/mini").ZodMiniOptional<import("zod/mini").ZodMiniString<string>>;
38
38
  recipient: import("zod/mini").ZodMiniOptional<import("zod/mini").ZodMiniString<string>>;
39
+ splits: import("zod/mini").ZodMiniOptional<import("zod/mini").ZodMiniArray<import("zod/mini").ZodMiniObject<{
40
+ amount: import("zod/mini").ZodMiniString<string>;
41
+ memo: import("zod/mini").ZodMiniOptional<import("zod/mini").ZodMiniString<string>>;
42
+ recipient: import("zod/mini").ZodMiniPipe<import("zod/mini").ZodMiniString<string>, import("zod/mini").ZodMiniTransform<`0x${string}`, string>>;
43
+ }, import("zod/v4/core").$strip>>>;
39
44
  }, import("zod/v4/core").$strip>, import("zod/mini").ZodMiniTransform<{
40
45
  methodDetails?: {
46
+ splits?: {
47
+ amount: string;
48
+ recipient: `0x${string}`;
49
+ memo?: string | undefined;
50
+ }[] | undefined;
41
51
  memo?: string | undefined;
42
52
  feePayer?: boolean | undefined;
43
53
  chainId?: number | undefined;
@@ -57,6 +67,11 @@ export declare function tempo(parameters?: tempo.Parameters): readonly [import("
57
67
  feePayer?: boolean | undefined;
58
68
  memo?: string | undefined;
59
69
  recipient?: string | undefined;
70
+ splits?: {
71
+ amount: string;
72
+ recipient: `0x${string}`;
73
+ memo?: string | undefined;
74
+ }[] | undefined;
60
75
  }>>;
61
76
  };
62
77
  }, import("zod/mini").ZodMiniObject<{
@@ -1 +1 @@
1
- {"version":3,"file":"Methods.d.ts","sourceRoot":"","sources":["../../../src/tempo/client/Methods.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,IAAI,OAAO,EAAE,MAAM,aAAa,CAAA;AAC/C,OAAO,EAAE,OAAO,IAAI,cAAc,EAAE,MAAM,cAAc,CAAA;AACxD,OAAO,EAAE,cAAc,IAAI,QAAQ,EAAE,MAAM,qBAAqB,CAAA;AAEhE;;;;;;;;;;;GAWG;AACH,wBAAgB,KAAK,CAAC,UAAU,GAAE,KAAK,CAAC,UAAe;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;mCAEtD;AAED,yBAAiB,KAAK,CAAC;IACrB,KAAY,UAAU,GAAG,OAAO,CAAC,UAAU,GAAG,cAAc,CAAC,UAAU,CAAA;IAEvE,kFAAkF;IAC3E,MAAM,MAAM,gBAAU,CAAA;IAC7B,6EAA6E;IACtE,MAAM,OAAO,iBAAW,CAAA;CAChC"}
1
+ {"version":3,"file":"Methods.d.ts","sourceRoot":"","sources":["../../../src/tempo/client/Methods.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,IAAI,OAAO,EAAE,MAAM,aAAa,CAAA;AAC/C,OAAO,EAAE,OAAO,IAAI,cAAc,EAAE,MAAM,cAAc,CAAA;AACxD,OAAO,EAAE,cAAc,IAAI,QAAQ,EAAE,MAAM,qBAAqB,CAAA;AAEhE;;;;;;;;;;;GAWG;AACH,wBAAgB,KAAK,CAAC,UAAU,GAAE,KAAK,CAAC,UAAe;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;mCAEtD;AAED,yBAAiB,KAAK,CAAC;IACrB,KAAY,UAAU,GAAG,OAAO,CAAC,UAAU,GAAG,cAAc,CAAC,UAAU,CAAA;IAEvE,kFAAkF;IAC3E,MAAM,MAAM,gBAAU,CAAA;IAC7B,6EAA6E;IACtE,MAAM,OAAO,iBAAW,CAAA;CAChC"}
@@ -19,16 +19,10 @@ export declare function resolve(parameters: resolve.Parameters): {
19
19
  export declare namespace resolve {
20
20
  type Parameters = {
21
21
  recipient?: Address | undefined;
22
- } & ({
23
- /** Account that performs payment operations. */
24
- account?: Account | undefined;
25
- /** When true, the account also sponsors (pays) transaction fees. */
26
- feePayer?: true | undefined;
27
- } | {
28
- /** Address that receives payment. */
29
- account?: Address | undefined;
30
- /** Optional fee payer account or fee payer URL for covering transaction fees. */
31
- feePayer?: Account | string | undefined;
32
- });
22
+ /** Account or address that performs payment operations / receives payment. */
23
+ account?: Account | Address | undefined;
24
+ /** When `true`, the account also sponsors fees. An `Account` object or URL string can also be provided as a dedicated fee payer. */
25
+ feePayer?: Account | string | true | undefined;
26
+ };
33
27
  }
34
28
  //# sourceMappingURL=account.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"account.d.ts","sourceRoot":"","sources":["../../../src/tempo/internal/account.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,OAAO,EAAE,MAAM,MAAM,CAAA;AAE5C;;;;;;;;;;GAUG;AACH,wBAAgB,OAAO,CAAC,UAAU,EAAE,OAAO,CAAC,UAAU;;;;eAkBa,OAAO,GAAG,SAAS;EACrF;AAED,MAAM,CAAC,OAAO,WAAW,OAAO,CAAC;IAC/B,KAAK,UAAU,GAAG;QAAE,SAAS,CAAC,EAAE,OAAO,GAAG,SAAS,CAAA;KAAE,GAAG,CACpD;QACE,gDAAgD;QAChD,OAAO,CAAC,EAAE,OAAO,GAAG,SAAS,CAAA;QAC7B,oEAAoE;QACpE,QAAQ,CAAC,EAAE,IAAI,GAAG,SAAS,CAAA;KAC5B,GACD;QACE,qCAAqC;QACrC,OAAO,CAAC,EAAE,OAAO,GAAG,SAAS,CAAA;QAC7B,iFAAiF;QACjF,QAAQ,CAAC,EAAE,OAAO,GAAG,MAAM,GAAG,SAAS,CAAA;KACxC,CACJ,CAAA;CACF"}
1
+ {"version":3,"file":"account.d.ts","sourceRoot":"","sources":["../../../src/tempo/internal/account.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,OAAO,EAAE,MAAM,MAAM,CAAA;AAE5C;;;;;;;;;;GAUG;AACH,wBAAgB,OAAO,CAAC,UAAU,EAAE,OAAO,CAAC,UAAU;;;;eAkBa,OAAO,GAAG,SAAS;EACrF;AAED,MAAM,CAAC,OAAO,WAAW,OAAO,CAAC;IAC/B,KAAK,UAAU,GAAG;QAChB,SAAS,CAAC,EAAE,OAAO,GAAG,SAAS,CAAA;QAC/B,8EAA8E;QAC9E,OAAO,CAAC,EAAE,OAAO,GAAG,OAAO,GAAG,SAAS,CAAA;QACvC,oIAAoI;QACpI,QAAQ,CAAC,EAAE,OAAO,GAAG,MAAM,GAAG,IAAI,GAAG,SAAS,CAAA;KAC/C,CAAA;CACF"}
@@ -0,0 +1,20 @@
1
+ import type { Address } from 'viem';
2
+ export type Split = {
3
+ amount: string;
4
+ memo?: string | undefined;
5
+ recipient: Address;
6
+ };
7
+ export type Transfer = {
8
+ amount: string;
9
+ memo?: string | undefined;
10
+ recipient: Address;
11
+ };
12
+ export declare function getTransfers(request: {
13
+ amount: string;
14
+ methodDetails?: {
15
+ memo?: string | undefined;
16
+ splits?: readonly Split[] | undefined;
17
+ };
18
+ recipient: Address;
19
+ }): Transfer[];
20
+ //# sourceMappingURL=charge.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"charge.d.ts","sourceRoot":"","sources":["../../../src/tempo/internal/charge.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,MAAM,CAAA;AAEnC,MAAM,MAAM,KAAK,GAAG;IAClB,MAAM,EAAE,MAAM,CAAA;IACd,IAAI,CAAC,EAAE,MAAM,GAAG,SAAS,CAAA;IACzB,SAAS,EAAE,OAAO,CAAA;CACnB,CAAA;AAED,MAAM,MAAM,QAAQ,GAAG;IACrB,MAAM,EAAE,MAAM,CAAA;IACd,IAAI,CAAC,EAAE,MAAM,GAAG,SAAS,CAAA;IACzB,SAAS,EAAE,OAAO,CAAA;CACnB,CAAA;AAED,wBAAgB,YAAY,CAAC,OAAO,EAAE;IACpC,MAAM,EAAE,MAAM,CAAA;IACd,aAAa,CAAC,EAAE;QAAE,IAAI,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;QAAC,MAAM,CAAC,EAAE,SAAS,KAAK,EAAE,GAAG,SAAS,CAAA;KAAE,CAAA;IACpF,SAAS,EAAE,OAAO,CAAA;CACnB,GAAG,QAAQ,EAAE,CAwBb"}
@@ -0,0 +1,23 @@
1
+ export function getTransfers(request) {
2
+ const totalAmount = BigInt(request.amount);
3
+ const splits = request.methodDetails?.splits ?? [];
4
+ const splitTotal = splits.reduce((sum, split) => sum + BigInt(split.amount), 0n);
5
+ if (splitTotal >= totalAmount)
6
+ throw new Error('Invalid charge request: split total must be less than total amount.');
7
+ const primaryAmount = totalAmount - splitTotal;
8
+ if (primaryAmount <= 0n)
9
+ throw new Error('Invalid charge request: primary transfer amount must be positive.');
10
+ return [
11
+ {
12
+ amount: primaryAmount.toString(),
13
+ memo: request.methodDetails?.memo,
14
+ recipient: request.recipient,
15
+ },
16
+ ...splits.map((split) => ({
17
+ amount: split.amount,
18
+ memo: split.memo,
19
+ recipient: split.recipient,
20
+ })),
21
+ ];
22
+ }
23
+ //# sourceMappingURL=charge.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"charge.js","sourceRoot":"","sources":["../../../src/tempo/internal/charge.ts"],"names":[],"mappings":"AAcA,MAAM,UAAU,YAAY,CAAC,OAI5B;IACC,MAAM,WAAW,GAAG,MAAM,CAAC,OAAO,CAAC,MAAM,CAAC,CAAA;IAC1C,MAAM,MAAM,GAAG,OAAO,CAAC,aAAa,EAAE,MAAM,IAAI,EAAE,CAAA;IAElD,MAAM,UAAU,GAAG,MAAM,CAAC,MAAM,CAAC,CAAC,GAAG,EAAE,KAAK,EAAE,EAAE,CAAC,GAAG,GAAG,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,EAAE,EAAE,CAAC,CAAA;IAChF,IAAI,UAAU,IAAI,WAAW;QAC3B,MAAM,IAAI,KAAK,CAAC,qEAAqE,CAAC,CAAA;IAExF,MAAM,aAAa,GAAG,WAAW,GAAG,UAAU,CAAA;IAC9C,IAAI,aAAa,IAAI,EAAE;QACrB,MAAM,IAAI,KAAK,CAAC,mEAAmE,CAAC,CAAA;IAEtF,OAAO;QACL;YACE,MAAM,EAAE,aAAa,CAAC,QAAQ,EAAE;YAChC,IAAI,EAAE,OAAO,CAAC,aAAa,EAAE,IAAI;YACjC,SAAS,EAAE,OAAO,CAAC,SAAS;SAC7B;QACD,GAAG,MAAM,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC;YACxB,MAAM,EAAE,KAAK,CAAC,MAAM;YACpB,IAAI,EAAE,KAAK,CAAC,IAAI;YAChB,SAAS,EAAE,KAAK,CAAC,SAAS;SAC3B,CAAC,CAAC;KACJ,CAAA;AACH,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"fee-payer.d.ts","sourceRoot":"","sources":["../../../src/tempo/internal/fee-payer.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,UAAU,CAAA;AAQ5C,8EAA8E;AAC9E,wBAAgB,kBAAkB,CAAC,UAAU,EAAE,MAAM,GAAG,SAAS,GAAG,OAAO,CAK1E;AAED;;;GAGG;AACH,eAAO,MAAM,UAAU,mBAKtB,CAAA;AAED,sFAAsF;AACtF,wBAAgB,aAAa,CAC3B,KAAK,EAAE,SAAS;IAAE,IAAI,CAAC,EAAE,KAAK,MAAM,EAAE,GAAG,SAAS,CAAC;IAAC,EAAE,CAAC,EAAE,YAAY,CAAC,OAAO,GAAG,SAAS,CAAA;CAAE,EAAE,EAC7F,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,QAwBhC;AAED,qBAAa,uBAAwB,SAAQ,KAAK;IAChD,SAAkB,IAAI,6BAA4B;gBAEtC,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC;CAQ5D"}
1
+ {"version":3,"file":"fee-payer.d.ts","sourceRoot":"","sources":["../../../src/tempo/internal/fee-payer.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,UAAU,CAAA;AAQ5C,8EAA8E;AAC9E,wBAAgB,kBAAkB,CAAC,UAAU,EAAE,MAAM,GAAG,SAAS,GAAG,OAAO,CAK1E;AAED;;;GAGG;AACH,eAAO,MAAM,UAAU,mBAKtB,CAAA;AAED,sFAAsF;AACtF,wBAAgB,aAAa,CAC3B,KAAK,EAAE,SAAS;IAAE,IAAI,CAAC,EAAE,KAAK,MAAM,EAAE,GAAG,SAAS,CAAC;IAAC,EAAE,CAAC,EAAE,YAAY,CAAC,OAAO,GAAG,SAAS,CAAA;CAAE,EAAE,EAC7F,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,QAuChC;AAED,qBAAa,uBAAwB,SAAQ,KAAK;IAChD,SAAkB,IAAI,6BAA4B;gBAEtC,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC;CAQ5D"}
@@ -20,11 +20,23 @@ export const callScopes = [
20
20
  ];
21
21
  /** Validates that a set of transaction calls matches an allowed fee-payer pattern. */
22
22
  export function validateCalls(calls, details) {
23
+ if (calls.length === 0)
24
+ throw new FeePayerValidationError('disallowed call pattern in fee-payer transaction', details);
23
25
  const callSelectors = calls.map((c) => c.data?.slice(0, 10));
24
- const allowed = callScopes.some((pattern) => pattern.length === callSelectors.length &&
25
- pattern.every((sel, i) => sel === callSelectors[i]));
26
- if (!allowed)
26
+ const hasSwapPrefix = callSelectors[0] === Selectors.approve;
27
+ if (hasSwapPrefix) {
28
+ if (callSelectors[1] !== Selectors.swapExactAmountOut)
29
+ throw new FeePayerValidationError('disallowed call pattern in fee-payer transaction', details);
30
+ }
31
+ else if (callSelectors[0] === Selectors.swapExactAmountOut) {
27
32
  throw new FeePayerValidationError('disallowed call pattern in fee-payer transaction', details);
33
+ }
34
+ const transferSelectors = callSelectors.slice(hasSwapPrefix ? 2 : 0);
35
+ if (transferSelectors.length === 0 ||
36
+ transferSelectors.length > 11 ||
37
+ transferSelectors.some((selector) => selector !== Selectors.transfer && selector !== Selectors.transferWithMemo)) {
38
+ throw new FeePayerValidationError('disallowed call pattern in fee-payer transaction', details);
39
+ }
28
40
  // Validate approve spender and buy target are the DEX.
29
41
  const approveCall = calls.find((c) => c.data?.slice(0, 10) === Selectors.approve);
30
42
  if (approveCall) {
@@ -1 +1 @@
1
- {"version":3,"file":"fee-payer.js","sourceRoot":"","sources":["../../../src/tempo/internal/fee-payer.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"fee-payer.js","sourceRoot":"","sources":["../../../src/tempo/internal/fee-payer.ts"],"names":[],"mappings":"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"}
@@ -1,4 +1,4 @@
1
- import type { LooseOmit } from '../../internal/types.js';
1
+ import type { LooseOmit, NoExtraKeys } from '../../internal/types.js';
2
2
  import * as Method from '../../Method.js';
3
3
  import * as Store from '../../Store.js';
4
4
  import * as Client from '../../viem/Client.js';
@@ -15,7 +15,7 @@ import * as Methods from '../Methods.js';
15
15
  * const charge = tempo.charge()
16
16
  * ```
17
17
  */
18
- export declare function charge<const parameters extends charge.Parameters>(parameters?: parameters): Method.Server<{
18
+ export declare function charge<const parameters extends charge.Parameters>(parameters?: NoExtraKeys<parameters, charge.Parameters>): Method.Server<{
19
19
  readonly name: "tempo";
20
20
  readonly intent: "charge";
21
21
  readonly schema: {
@@ -38,8 +38,18 @@ export declare function charge<const parameters extends charge.Parameters>(param
38
38
  feePayer: import("zod/mini").ZodMiniOptional<import("zod/mini").ZodMiniPipe<import("zod/mini").ZodMiniUnion<readonly [import("zod/mini").ZodMiniBoolean<boolean>, import("zod/mini").ZodMiniCustom<import("viem").Account, import("viem").Account>]>, import("zod/mini").ZodMiniTransform<boolean, boolean | import("viem").Account>>>;
39
39
  memo: import("zod/mini").ZodMiniOptional<import("zod/mini").ZodMiniString<string>>;
40
40
  recipient: import("zod/mini").ZodMiniOptional<import("zod/mini").ZodMiniString<string>>;
41
+ splits: import("zod/mini").ZodMiniOptional<import("zod/mini").ZodMiniArray<import("zod/mini").ZodMiniObject<{
42
+ amount: import("zod/mini").ZodMiniString<string>;
43
+ memo: import("zod/mini").ZodMiniOptional<import("zod/mini").ZodMiniString<string>>;
44
+ recipient: import("zod/mini").ZodMiniPipe<import("zod/mini").ZodMiniString<string>, import("zod/mini").ZodMiniTransform<`0x${string}`, string>>;
45
+ }, import("zod/v4/core").$strip>>>;
41
46
  }, import("zod/v4/core").$strip>, import("zod/mini").ZodMiniTransform<{
42
47
  methodDetails?: {
48
+ splits?: {
49
+ amount: string;
50
+ recipient: `0x${string}`;
51
+ memo?: string | undefined;
52
+ }[] | undefined;
43
53
  memo?: string | undefined;
44
54
  feePayer?: boolean | undefined;
45
55
  chainId?: number | undefined;
@@ -59,6 +69,11 @@ export declare function charge<const parameters extends charge.Parameters>(param
59
69
  feePayer?: boolean | undefined;
60
70
  memo?: string | undefined;
61
71
  recipient?: string | undefined;
72
+ splits?: {
73
+ amount: string;
74
+ recipient: `0x${string}`;
75
+ memo?: string | undefined;
76
+ }[] | undefined;
62
77
  }>>;
63
78
  };
64
79
  }, charge.DeriveDefaults<parameters>, undefined>;
@@ -1 +1 @@
1
- {"version":3,"file":"Charge.d.ts","sourceRoot":"","sources":["../../../src/tempo/server/Charge.ts"],"names":[],"mappings":"AAaA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,yBAAyB,CAAA;AACxD,OAAO,KAAK,MAAM,MAAM,iBAAiB,CAAA;AACzC,OAAO,KAAK,KAAK,MAAM,gBAAgB,CAAA;AACvC,OAAO,KAAK,MAAM,MAAM,sBAAsB,CAAA;AAC9C,OAAO,KAAK,OAAO,MAAM,wBAAwB,CAAA;AAKjD,OAAO,KAAK,KAAK,KAAK,MAAM,sBAAsB,CAAA;AAClD,OAAO,KAAK,OAAO,MAAM,eAAe,CAAA;AAExC;;;;;;;;;GASG;AACH,wBAAgB,MAAM,CAAC,KAAK,CAAC,UAAU,SAAS,MAAM,CAAC,UAAU,EAC/D,UAAU,GAAE,UAA6B;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;iDAwP1C;AAED,MAAM,CAAC,OAAO,WAAW,MAAM,CAAC;IAC9B,KAAK,YAAY,GAAG;QAAE,CAAC,GAAG,EAAE,eAAe,MAAM,EAAE,GAAG,MAAM,CAAA;KAAE,CAAA;IAE9D,KAAK,QAAQ,GAAG,SAAS,CAAC,MAAM,CAAC,eAAe,CAAC,OAAO,OAAO,CAAC,MAAM,CAAC,EAAE,UAAU,GAAG,WAAW,CAAC,CAAA;IAElG,KAAK,UAAU,GAAG;QAChB,oBAAoB;QACpB,OAAO,CAAC,EAAE,OAAO,GAAG,SAAS,CAAA;QAC7B;;;;;WAKG;QACH,KAAK,CAAC,EAAE,KAAK,CAAC,KAAK,GAAG,SAAS,CAAA;QAC/B;;;;;;;;;;WAUG;QACH,mBAAmB,CAAC,EAAE,OAAO,GAAG,SAAS,CAAA;KAC1C,GAAG,MAAM,CAAC,WAAW,CAAC,UAAU,GAC/B,OAAO,CAAC,OAAO,CAAC,UAAU,GAC1B,QAAQ,CAAA;IAEV,KAAK,cAAc,CAAC,UAAU,SAAS,UAAU,IAAI,KAAK,CAAC,cAAc,CACvE,UAAU,EACV,QAAQ,CACT,GAAG;QACF,QAAQ,EAAE,MAAM,CAAA;KACjB,CAAA;CACF"}
1
+ {"version":3,"file":"Charge.d.ts","sourceRoot":"","sources":["../../../src/tempo/server/Charge.ts"],"names":[],"mappings":"AAYA,OAAO,KAAK,EAAE,SAAS,EAAE,WAAW,EAAE,MAAM,yBAAyB,CAAA;AACrE,OAAO,KAAK,MAAM,MAAM,iBAAiB,CAAA;AACzC,OAAO,KAAK,KAAK,MAAM,gBAAgB,CAAA;AACvC,OAAO,KAAK,MAAM,MAAM,sBAAsB,CAAA;AAC9C,OAAO,KAAK,OAAO,MAAM,wBAAwB,CAAA;AAMjD,OAAO,KAAK,KAAK,KAAK,MAAM,sBAAsB,CAAA;AAClD,OAAO,KAAK,OAAO,MAAM,eAAe,CAAA;AAExC;;;;;;;;;GASG;AACH,wBAAgB,MAAM,CAAC,KAAK,CAAC,UAAU,SAAS,MAAM,CAAC,UAAU,EAC/D,UAAU,GAAE,WAAW,CAAC,UAAU,EAAE,MAAM,CAAC,UAAU,CAGpD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;iDAuMF;AAED,MAAM,CAAC,OAAO,WAAW,MAAM,CAAC;IAC9B,KAAK,YAAY,GAAG;QAAE,CAAC,GAAG,EAAE,eAAe,MAAM,EAAE,GAAG,MAAM,CAAA;KAAE,CAAA;IAE9D,KAAK,QAAQ,GAAG,SAAS,CAAC,MAAM,CAAC,eAAe,CAAC,OAAO,OAAO,CAAC,MAAM,CAAC,EAAE,UAAU,GAAG,WAAW,CAAC,CAAA;IAElG,KAAK,UAAU,GAAG;QAChB,oBAAoB;QACpB,OAAO,CAAC,EAAE,OAAO,GAAG,SAAS,CAAA;QAC7B;;;;;WAKG;QACH,KAAK,CAAC,EAAE,KAAK,CAAC,KAAK,GAAG,SAAS,CAAA;QAC/B;;;;;;;;;;WAUG;QACH,mBAAmB,CAAC,EAAE,OAAO,GAAG,SAAS,CAAA;KAC1C,GAAG,MAAM,CAAC,WAAW,CAAC,UAAU,GAC/B,OAAO,CAAC,OAAO,CAAC,UAAU,GAC1B,QAAQ,CAAA;IAEV,KAAK,cAAc,CAAC,UAAU,SAAS,UAAU,IAAI,KAAK,CAAC,cAAc,CACvE,UAAU,EACV,QAAQ,CACT,GAAG;QACF,QAAQ,EAAE,MAAM,CAAA;KACjB,CAAA;CACF"}
@@ -8,6 +8,7 @@ import * as Store from '../../Store.js';
8
8
  import * as Client from '../../viem/Client.js';
9
9
  import * as Account from '../internal/account.js';
10
10
  import * as TempoAddress from '../internal/address.js';
11
+ import * as Charge_internal from '../internal/charge.js';
11
12
  import * as defaults from '../internal/defaults.js';
12
13
  import * as FeePayer from '../internal/fee-payer.js';
13
14
  import * as Selectors from '../internal/selectors.js';
@@ -94,15 +95,12 @@ export function charge(parameters = {}) {
94
95
  case 'hash': {
95
96
  const hash = payload.hash;
96
97
  await assertHashUnused(store, hash);
97
- const receipt = await getTransactionReceipt(client, {
98
- hash,
99
- });
100
- assertTransferLog(receipt, {
101
- amount,
98
+ const expectedTransfers = getExpectedTransfers({ amount, memo, methodDetails, recipient });
99
+ const receipt = await getTransactionReceipt(client, { hash });
100
+ assertTransferLogs(receipt, {
102
101
  currency,
103
- from: receipt.from,
104
- memo,
105
- recipient,
102
+ sender: receipt.from,
103
+ transfers: expectedTransfers,
106
104
  });
107
105
  await markHashUsed(store, hash);
108
106
  return toReceipt(receipt);
@@ -118,55 +116,11 @@ export function charge(parameters = {}) {
118
116
  const transaction = Transaction.deserialize(serializedTransaction);
119
117
  if (!transaction.signature || !transaction.from)
120
118
  throw new MismatchError('Transaction must be signed by the sender before fee payer co-signing.', {});
121
- const call = transaction.calls.find((call) => {
122
- if (!call.to || !TempoAddress.isEqual(call.to, currency))
123
- return false;
124
- if (!call.data)
125
- return false;
126
- const selector = call.data.slice(0, 10);
127
- if (memo) {
128
- if (selector !== Selectors.transferWithMemo)
129
- return false;
130
- try {
131
- const { args } = decodeFunctionData({ abi: Abis.tip20, data: call.data });
132
- const [to, amount_, memo_] = args;
133
- return (TempoAddress.isEqual(to, recipient) &&
134
- amount_.toString() === amount &&
135
- memo_.toLowerCase() === memo.toLowerCase());
136
- }
137
- catch {
138
- return false;
139
- }
140
- }
141
- if (selector === Selectors.transfer) {
142
- try {
143
- const { args } = decodeFunctionData({ abi: Abis.tip20, data: call.data });
144
- const [to, amount_] = args;
145
- return TempoAddress.isEqual(to, recipient) && amount_.toString() === amount;
146
- }
147
- catch {
148
- return false;
149
- }
150
- }
151
- if (selector === Selectors.transferWithMemo) {
152
- try {
153
- const { args } = decodeFunctionData({ abi: Abis.tip20, data: call.data });
154
- const [to, amount_] = args;
155
- return TempoAddress.isEqual(to, recipient) && amount_.toString() === amount;
156
- }
157
- catch {
158
- return false;
159
- }
160
- }
161
- return false;
162
- });
163
- if (!call)
164
- throw new MismatchError('Invalid transaction: no matching payment call found', {
165
- amount,
166
- currency,
167
- recipient,
168
- });
169
- if ((feePayer || feePayerUrl) && methodDetails?.feePayer !== false)
119
+ const calls = (transaction.calls ?? []);
120
+ const transfers = getExpectedTransfers({ amount, memo, methodDetails, recipient });
121
+ const isFeePayerTx = !!(feePayer || feePayerUrl) && methodDetails?.feePayer !== false;
122
+ assertTransferCalls(calls, { currency, exactCount: isFeePayerTx, transfers });
123
+ if (isFeePayerTx)
170
124
  FeePayer.validateCalls(transaction.calls, { amount, currency, recipient });
171
125
  const resolvedFeeToken = transaction.feeToken ?? defaults.currency[chainId];
172
126
  const serializedTransaction_final = await (async () => {
@@ -184,12 +138,10 @@ export function charge(parameters = {}) {
184
138
  const receipt = await sendRawTransactionSync(client, {
185
139
  serializedTransaction: serializedTransaction_final,
186
140
  });
187
- assertTransferLog(receipt, {
188
- amount,
141
+ assertTransferLogs(receipt, {
189
142
  currency,
190
- from: transaction.from,
191
- memo,
192
- recipient,
143
+ sender: transaction.from,
144
+ transfers,
193
145
  });
194
146
  // Post-broadcast dedup: catch malleable input variants
195
147
  // (different serialized bytes, same underlying tx) that
@@ -233,49 +185,146 @@ export function charge(parameters = {}) {
233
185
  },
234
186
  });
235
187
  }
236
- /** @internal */
237
- function assertTransferLog(receipt, parameters) {
238
- const { amount, currency, from, memo, recipient } = parameters;
239
- if (memo) {
240
- const memoLogs = parseEventLogs({
241
- abi: Abis.tip20,
242
- eventName: 'TransferWithMemo',
243
- logs: receipt.logs,
188
+ function getExpectedTransfers(parameters) {
189
+ return Charge_internal.getTransfers({
190
+ amount: parameters.amount,
191
+ methodDetails: {
192
+ memo: parameters.memo,
193
+ splits: parameters.methodDetails?.splits,
194
+ },
195
+ recipient: parameters.recipient,
196
+ }).map((transfer) => ({
197
+ ...transfer,
198
+ ...(!transfer.memo ? { allowAnyMemo: true } : {}),
199
+ }));
200
+ }
201
+ function assertTransferCalls(calls, parameters) {
202
+ const transferCalls = getTransferCalls(calls);
203
+ if (parameters.exactCount && transferCalls.length !== parameters.transfers.length)
204
+ throw new MismatchError('Invalid transaction: no matching payment call found', {
205
+ expectedCalls: String(parameters.transfers.length),
206
+ actualCalls: String(transferCalls.length),
207
+ });
208
+ const used = new Set();
209
+ // Match memo-specific transfers before wildcards to avoid greedy
210
+ // consumption of memo-bearing calls by allowAnyMemo entries.
211
+ const sorted = [...parameters.transfers].sort((a, b) => {
212
+ if (a.memo && !b.memo)
213
+ return -1;
214
+ if (!a.memo && b.memo)
215
+ return 1;
216
+ return 0;
217
+ });
218
+ for (const expected of sorted) {
219
+ const matchIndex = transferCalls.findIndex((call, index) => {
220
+ if (used.has(index))
221
+ return false;
222
+ const decoded = decodeTransferCall(call, parameters.currency);
223
+ if (!decoded)
224
+ return false;
225
+ if (!TempoAddress.isEqual(decoded.recipient, expected.recipient))
226
+ return false;
227
+ if (decoded.amount !== expected.amount)
228
+ return false;
229
+ if (expected.memo) {
230
+ return decoded.memo?.toLowerCase() === expected.memo.toLowerCase();
231
+ }
232
+ if (expected.allowAnyMemo)
233
+ return true;
234
+ return decoded.memo === undefined;
244
235
  });
245
- const match = memoLogs.find((log) => TempoAddress.isEqual(log.address, currency) &&
246
- TempoAddress.isEqual(log.args.from, from) &&
247
- TempoAddress.isEqual(log.args.to, recipient) &&
248
- log.args.amount.toString() === amount &&
249
- log.args.memo.toLowerCase() === memo.toLowerCase());
250
- if (!match)
251
- throw new MismatchError('Payment verification failed: no matching transfer with memo found.', {
252
- amount,
253
- currency,
254
- memo,
255
- recipient,
236
+ if (matchIndex === -1) {
237
+ throw new MismatchError('Invalid transaction: no matching payment call found', {
238
+ amount: expected.amount,
239
+ currency: parameters.currency,
240
+ recipient: expected.recipient,
256
241
  });
242
+ }
243
+ used.add(matchIndex);
257
244
  }
258
- else {
259
- const transferLogs = parseEventLogs({
260
- abi: Abis.tip20,
261
- eventName: 'Transfer',
262
- logs: receipt.logs,
263
- });
264
- const memoLogs = parseEventLogs({
265
- abi: Abis.tip20,
266
- eventName: 'TransferWithMemo',
267
- logs: receipt.logs,
245
+ }
246
+ function getTransferCalls(calls) {
247
+ const selectors = calls.map((call) => call.data?.slice(0, 10));
248
+ const offset = selectors[0] === Selectors.approve && selectors[1] === Selectors.swapExactAmountOut ? 2 : 0;
249
+ const transferCalls = calls.slice(offset);
250
+ if (transferCalls.length === 0 ||
251
+ selectors
252
+ .slice(offset)
253
+ .some((selector) => selector !== Selectors.transfer && selector !== Selectors.transferWithMemo)) {
254
+ throw new MismatchError('Invalid transaction: no matching payment call found', {});
255
+ }
256
+ return transferCalls;
257
+ }
258
+ function decodeTransferCall(call, currency) {
259
+ if (!call.to || !TempoAddress.isEqual(call.to, currency) || !call.data)
260
+ return null;
261
+ try {
262
+ const selector = call.data.slice(0, 10);
263
+ if (selector === Selectors.transfer) {
264
+ const { args } = decodeFunctionData({ abi: Abis.tip20, data: call.data });
265
+ const [recipient, amount] = args;
266
+ return { amount: amount.toString(), recipient };
267
+ }
268
+ if (selector === Selectors.transferWithMemo) {
269
+ const { args } = decodeFunctionData({ abi: Abis.tip20, data: call.data });
270
+ const [recipient, amount, memo] = args;
271
+ return { amount: amount.toString(), memo, recipient };
272
+ }
273
+ }
274
+ catch {
275
+ return null;
276
+ }
277
+ return null;
278
+ }
279
+ function assertTransferLogs(receipt, parameters) {
280
+ const transferLogs = parseEventLogs({
281
+ abi: Abis.tip20,
282
+ eventName: 'Transfer',
283
+ logs: receipt.logs,
284
+ }).map((log) => ({ ...log, kind: 'transfer' }));
285
+ const memoLogs = parseEventLogs({
286
+ abi: Abis.tip20,
287
+ eventName: 'TransferWithMemo',
288
+ logs: receipt.logs,
289
+ }).map((log) => ({ ...log, kind: 'memo' }));
290
+ const logs = [...transferLogs, ...memoLogs];
291
+ const used = new Set();
292
+ // Match memo-specific transfers before wildcards to avoid greedy
293
+ // consumption of memo-bearing logs by allowAnyMemo entries.
294
+ const sorted = [...parameters.transfers].sort((a, b) => {
295
+ if (a.memo && !b.memo)
296
+ return -1;
297
+ if (!a.memo && b.memo)
298
+ return 1;
299
+ return 0;
300
+ });
301
+ for (const transfer of sorted) {
302
+ const matchIndex = logs.findIndex((log, index) => {
303
+ if (used.has(index))
304
+ return false;
305
+ if (!TempoAddress.isEqual(log.address, parameters.currency))
306
+ return false;
307
+ if (!TempoAddress.isEqual(log.args.from, parameters.sender))
308
+ return false;
309
+ if (!TempoAddress.isEqual(log.args.to, transfer.recipient))
310
+ return false;
311
+ if (log.args.amount.toString() !== transfer.amount)
312
+ return false;
313
+ if (transfer.memo) {
314
+ return log.kind === 'memo' && log.args.memo.toLowerCase() === transfer.memo.toLowerCase();
315
+ }
316
+ if (transfer.allowAnyMemo)
317
+ return log.kind === 'transfer' || log.kind === 'memo';
318
+ return log.kind === 'transfer';
268
319
  });
269
- const match = [...transferLogs, ...memoLogs].find((log) => TempoAddress.isEqual(log.address, currency) &&
270
- TempoAddress.isEqual(log.args.from, from) &&
271
- TempoAddress.isEqual(log.args.to, recipient) &&
272
- log.args.amount.toString() === amount);
273
- if (!match)
320
+ if (matchIndex === -1) {
274
321
  throw new MismatchError('Payment verification failed: no matching transfer found.', {
275
- amount,
276
- currency,
277
- recipient,
322
+ amount: transfer.amount,
323
+ currency: parameters.currency,
324
+ recipient: transfer.recipient,
278
325
  });
326
+ }
327
+ used.add(matchIndex);
279
328
  }
280
329
  }
281
330
  /** @internal */