mppx 0.11.0 → 0.12.0
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/CHANGELOG.md +28 -0
- package/README.md +22 -1
- package/dist/cli/agent.d.ts +3 -0
- package/dist/cli/agent.js +20 -0
- package/dist/cli/cli.d.ts +1 -1
- package/dist/cli/cli.js +135 -135
- package/dist/cli/plugins/index.js +12 -12
- package/dist/cli/validate/payment.js +29 -12
- package/dist/evm/server/Methods.d.ts +164 -3
- package/dist/evm/server/Methods.js +50 -2
- package/dist/internal/version.d.ts +2 -2
- package/dist/internal/version.js +1 -1
- package/dist/server/Mppx.d.ts +5 -1
- package/dist/server/Mppx.js +120 -49
- package/dist/server/internal/html/compose.main.gen.d.ts +1 -1
- package/dist/server/internal/html/serviceWorker.gen.d.ts +1 -1
- package/dist/stripe/server/Methods.js +2 -4
- package/dist/stripe/server/internal/html.gen.d.ts +1 -1
- package/dist/tempo/internal/currencies.d.ts +19 -0
- package/dist/tempo/internal/currencies.js +41 -0
- package/dist/tempo/internal/defaults.d.ts +5 -3
- package/dist/tempo/internal/defaults.js +6 -2
- package/dist/tempo/internal/fee-payer.d.ts +5 -4
- package/dist/tempo/internal/fee-payer.js +7 -5
- package/dist/tempo/server/Charge.d.ts +12 -1
- package/dist/tempo/server/Charge.js +34 -32
- package/dist/tempo/server/Methods.d.ts +5003 -40
- package/dist/tempo/server/Methods.js +104 -13
- package/dist/tempo/server/internal/html.gen.d.ts +1 -1
- package/dist/tempo/server/internal/html.gen.js +1 -1
- package/dist/tempo/session/server/ChannelStore.d.ts +2 -0
- package/dist/tempo/session/server/ChannelStore.js +12 -3
- package/dist/tempo/session/server/CredentialVerification.d.ts +2 -0
- package/dist/tempo/session/server/CredentialVerification.js +22 -13
- package/dist/tempo/session/server/RequestState.d.ts +6 -0
- package/dist/tempo/session/server/RequestState.js +11 -4
- package/dist/tempo/session/server/Session.js +8 -1
- package/dist/tempo/session/server/Settlement.d.ts +2 -0
- package/dist/tempo/session/server/Settlement.js +13 -8
- package/dist/tempo/subscription/KeyAuthorization.d.ts +70 -8
- package/package.json +3 -3
|
@@ -33,7 +33,9 @@ import * as SponsorBudget from './SponsorBudget.js';
|
|
|
33
33
|
* ```
|
|
34
34
|
*/
|
|
35
35
|
export function charge(parameters = {}) {
|
|
36
|
-
const { machineTokenEnabled, amount, currency = defaults.resolveCurrency(parameters), decimals = defaults.decimals, description, externalId, feeToken: configuredFeeToken, feePayerPolicy, html, relay, sponsorBudget, splits, supportedModes, validateSender, waitForConfirmation = true, } = parameters;
|
|
36
|
+
const { machineTokenEnabled, allowedFeeTokens: configuredAllowedFeeTokens, amount, currency = defaults.resolveCurrency(parameters), decimals = defaults.decimals, description, externalId, feeToken: configuredFeeToken, feePayerPolicy, html, relay, sponsorBudget, splits, supportedModes, validateSender, waitForConfirmation = true, } = parameters;
|
|
37
|
+
if (configuredAllowedFeeTokens?.length === 0)
|
|
38
|
+
throw new Error('`allowedFeeTokens` must contain at least one token.');
|
|
37
39
|
const storeKeyPrefix = parameters.storeKeyPrefix ?? '';
|
|
38
40
|
const rawStore = (parameters.store ?? Store.memory());
|
|
39
41
|
const store = Store.from(rawStore, { keyPrefix: storeKeyPrefix });
|
|
@@ -92,7 +94,12 @@ export function charge(parameters = {}) {
|
|
|
92
94
|
Expires.assert(challenge.expires, challenge.id);
|
|
93
95
|
if (isZeroAmount && payload.type !== 'proof')
|
|
94
96
|
throw new MismatchError('Zero-amount challenges require a proof credential.', {});
|
|
97
|
+
// Request-level local sponsorship takes precedence over the hosted provider.
|
|
98
|
+
const localFeePayer = Account.is(request.feePayer) ? request.feePayer : feePayer;
|
|
99
|
+
const allowedFeeTokens = configuredAllowedFeeTokens ??
|
|
100
|
+
(localFeePayer || !remoteFeePayer ? FeePayer.defaultAllowedFeeTokens(chainId) : undefined);
|
|
95
101
|
return {
|
|
102
|
+
allowedFeeTokens,
|
|
96
103
|
amount,
|
|
97
104
|
machineTokenEnabled,
|
|
98
105
|
chainId,
|
|
@@ -208,7 +215,7 @@ export function charge(parameters = {}) {
|
|
|
208
215
|
if (isFeePayerTx) {
|
|
209
216
|
if (!machineTokenRoute)
|
|
210
217
|
FeePayer.validateCalls(transaction.calls, { amount, currency, recipient }, { currency, expectedTransfers: transfers });
|
|
211
|
-
FeePayer.assertAllowedFeeToken(transaction,
|
|
218
|
+
FeePayer.assertAllowedFeeToken(transaction, context.allowedFeeTokens);
|
|
212
219
|
}
|
|
213
220
|
else {
|
|
214
221
|
await viem_call(client, FeePayer.simulationTransaction(transaction, { feePayer: false }));
|
|
@@ -305,6 +312,8 @@ export function charge(parameters = {}) {
|
|
|
305
312
|
const chainId = await (async () => {
|
|
306
313
|
if (request.chainId)
|
|
307
314
|
return request.chainId;
|
|
315
|
+
if (parameters.chainId !== undefined)
|
|
316
|
+
return parameters.chainId;
|
|
308
317
|
if (parameters.testnet)
|
|
309
318
|
return defaults.chainId.testnet;
|
|
310
319
|
return (await getClient({})).chain?.id;
|
|
@@ -402,12 +411,10 @@ export function charge(parameters = {}) {
|
|
|
402
411
|
let finalHash;
|
|
403
412
|
let reservation;
|
|
404
413
|
try {
|
|
405
|
-
const allowedFeeTokens =
|
|
406
|
-
if (isFeePayerTx)
|
|
407
|
-
FeePayer.assertAllowedFeeToken(transaction, allowedFeeTokens);
|
|
408
|
-
const selectableFeeTokens = allowedFeeTokens;
|
|
414
|
+
const { allowedFeeTokens } = context;
|
|
409
415
|
const completedTransaction = await (async () => {
|
|
410
416
|
if (feePayerAccount && methodDetails?.feePayer !== false) {
|
|
417
|
+
const selectableFeeTokens = allowedFeeTokens ?? FeePayer.defaultAllowedFeeTokens(chainId);
|
|
411
418
|
const completed = await FeePayer.preflightSponsorship({
|
|
412
419
|
transaction,
|
|
413
420
|
simulate: (request) => viem_call(client, request),
|
|
@@ -422,7 +429,7 @@ export function charge(parameters = {}) {
|
|
|
422
429
|
}));
|
|
423
430
|
const sponsored = FeePayer.prepareSponsoredTransaction({
|
|
424
431
|
account: feePayerAccount,
|
|
425
|
-
allowedFeeTokens,
|
|
432
|
+
allowedFeeTokens: selectableFeeTokens,
|
|
426
433
|
challengeExpires: expires,
|
|
427
434
|
chainId: chainId ?? client.chain.id,
|
|
428
435
|
details: { amount, currency, recipient },
|
|
@@ -901,34 +908,29 @@ function toReceipt(receipt) {
|
|
|
901
908
|
reference: transactionHash,
|
|
902
909
|
};
|
|
903
910
|
}
|
|
904
|
-
/**
|
|
905
|
-
* Asserts that at least one of the matched payment logs carries a
|
|
906
|
-
* challenge-bound memo nonce (keccak256(challengeId)[0..6] in bytes 25–31).
|
|
907
|
-
* Only checks logs that were matched by `assertTransferLogs`, not the
|
|
908
|
-
* entire receipt — preventing unrelated dust transfers from satisfying
|
|
909
|
-
* the binding.
|
|
910
|
-
* @internal
|
|
911
|
-
*/
|
|
912
911
|
function assertChallengeBoundMemo(matchedLogs, parameters) {
|
|
913
|
-
|
|
914
|
-
if (log.kind !== 'memo')
|
|
915
|
-
return false;
|
|
916
|
-
if (!Attribution.verifyServer(log.args.memo, parameters.realm))
|
|
917
|
-
return false;
|
|
918
|
-
return Attribution.verifyChallengeBinding(log.args.memo, parameters.challengeId);
|
|
919
|
-
});
|
|
920
|
-
if (!bound)
|
|
921
|
-
throw new MismatchError('Payment verification failed: memo is not bound to this challenge.', {});
|
|
912
|
+
assertChallengeBoundMemos(matchedLogs.map((log) => (log.kind === 'memo' ? log.args.memo : undefined)), parameters);
|
|
922
913
|
}
|
|
923
914
|
function assertChallengeBoundCallMemo(matchedCalls, parameters) {
|
|
924
|
-
|
|
925
|
-
|
|
926
|
-
|
|
927
|
-
|
|
928
|
-
|
|
929
|
-
|
|
930
|
-
|
|
931
|
-
|
|
915
|
+
assertChallengeBoundMemos(matchedCalls.map((call) => call.memo), parameters);
|
|
916
|
+
}
|
|
917
|
+
/**
|
|
918
|
+
* Requires a challenge-bound attribution memo and rejects conflicting attribution
|
|
919
|
+
* on matched payment transfers. Otherwise, a split payment could authorize another
|
|
920
|
+
* challenge after the first challenge's replay marker expires. Unmatched transfers
|
|
921
|
+
* cannot establish the binding; plain transfers and non-MPP memos remain allowed.
|
|
922
|
+
* @internal
|
|
923
|
+
*/
|
|
924
|
+
function assertChallengeBoundMemos(memos, parameters) {
|
|
925
|
+
let bound = false;
|
|
926
|
+
for (const memo of memos) {
|
|
927
|
+
if (!memo || !Attribution.isMppMemo(memo))
|
|
928
|
+
continue;
|
|
929
|
+
if (!Attribution.verifyServer(memo, parameters.realm) ||
|
|
930
|
+
!Attribution.verifyChallengeBinding(memo, parameters.challengeId))
|
|
931
|
+
throw new MismatchError('Payment verification failed: memo is not bound to this challenge.', {});
|
|
932
|
+
bound = true;
|
|
933
|
+
}
|
|
932
934
|
if (!bound)
|
|
933
935
|
throw new MismatchError('Payment verification failed: memo is not bound to this challenge.', {});
|
|
934
936
|
}
|