feat: enhance multi-product subscription support - #9866
Conversation
…hield ERC-20 transactions
…ts to 'money_account_plus'
…n previous subscriptions
… and add optional cryptoAuthMethod field
…port with new crypto auth methods and updated action types
…ment methods and token info, enhancing validation and structure
…intents and update documentation for clarity
…ate refresh and error handling
…tion methods and enhance tests for trial eligibility
| if (txMeta.type !== TransactionType.shieldSubscriptionApprove) { | ||
| return; | ||
| if ( | ||
| productType !== PRODUCT_TYPES.SHIELD || |
There was a problem hiding this comment.
Let's remove the productType from method params and this?
| this.state.lastSelectedPaymentMethod?.[request.products[0]]; | ||
| this.#assertIsPaymentMethodCrypto(selectedPaymentMethod); | ||
|
|
||
| const cryptoAuthMethod = |
There was a problem hiding this comment.
Looks like CRYPTO_AUTH_METHODS.ERC20_APPROVAL is being used by default, if last selected payment isn't available.
Then may I know where do we even use the CRYPTO_AUTH_METHODS.DELEGATION?
Or we don't need sponsorship for delegations?
There was a problem hiding this comment.
Yes, currently only ERC20_APPROVAL handle sponsorship, for DELEGATION we only receive the delegation hash here, no sponsorship handled
| * when omitted. Use `CRYPTO_AUTH_METHODS.DELEGATION` for products such as | ||
| * Money Account Plus. | ||
| */ | ||
| cryptoAuthMethod?: CryptoAuthMethod; |
| rawTransaction?: Hex; | ||
| /** | ||
| * Crypto authorization method. Defaults to `CRYPTO_AUTH_METHODS.ERC20_APPROVAL` | ||
| * when omitted. Use `CRYPTO_AUTH_METHODS.DELEGATION` for products such as |
There was a problem hiding this comment.
Can I check is CRYPTO_AUTH_METHODS.DELEGATION only for money account?
There was a problem hiding this comment.
If CRYPTO_AUTH_METHODS.DELEGATION only for money account, we should add some validation/assertions in startSubscriptionWithCrypto and reject the request when shield subscription comes with DELEGATION method.
…on and validation logic, adding tests for edge cases
…y in crypto subscription methods and corresponding tests
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes and found 1 potential issue.
❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, have a team admin enable autofix in the Cursor dashboard.
Reviewed by Cursor Bugbot for commit 48918a8. Configure here.
…pto subscription requests, adding new request types and enhancing validation logic
…equest objects for crypto approval and payment method caching, enhancing type safety and clarity
…ed on subscription state, enhancing tests for trial requests

Explanation
Generalizes @metamask/subscription-controller beyond Shield-only flows so clients can manage multiple subscription products (Shield + Money Account Plus) with product-scoped payment methods, crypto auth methods, and trial logic.
Current state
The subscription controller was built around Shield as the sole product. Messenger actions, crypto approval handling, payment-method lookup, and trial eligibility were all hardcoded to
PRODUCT_TYPES.SHIELD. The pricing API now supports multiple products with different crypto auth flows (ERC-20 approval vs. delegation), so the controller needed to be generalized.Solution
This PR extends the subscription controller and service to support multi-product subscriptions aligned with PR-141 pricing API changes:
New types and constants
PRODUCT_TYPES.MONEY_ACCOUNT_PLUS(money_account_plus)CRYPTO_AUTH_METHODS(erc20_approval,delegation)CryptoAuthMethodtype exported from the packagePricing model extensions
PricingPaymentMethodgains optionalproductsandcryptoAuthMethodfor product-scoped payment rowsChainPaymentInfogains optionaldelegateAddressfor delegation flowsTokenPaymentInfogains optionalisVaultShare,accountantAddress,sources, and makesconversionRateoptional (vault share tokens)StartCryptoSubscriptionRequestmakesrawTransactionoptional for delegation; addscryptoAuthMethodanddelegationHashCachedLastSelectedPaymentMethodtracks per-productcryptoAuthMethodController generalization
lastSelectedPaymentMethodis nowPartial<Record<ProductType, ...>>(per-product)#findCryptoPaymentMethod#getIsTrialRequested— derived fromtrialPeriodDaysandtrialedProducts, not a simple "has trialed" booleangetCryptoApproveTransactionParamsselects the ERC-20 approval payment method for the requested productsubmitSubscriptionCryptoApprovalacceptsproductTypeand works for any product (not Shield-only)lastSubscriptionis synced from the API but not used for active product lookupBreaking renames
SubscriptionController:startShieldSubscriptionWithCardSubscriptionController:startSubscriptionWithCardSubscriptionController:submitShieldSubscriptionCryptoApprovalSubscriptionController:submitSubscriptionCryptoApproval(+ requiredproductTypeas first arg)Migration for consumers
References
Checklist
Note
High Risk
Breaking messenger/API renames and payment/trial logic changes affect all subscription consumers; incorrect product-scoped crypto lookup or trial overrides could block checkout or grant trials wrongly.
Overview
Generalizes
@metamask/subscription-controllerbeyond Shield so clients can manage Shield and Money Account Plus in parallel, with product-scoped payment rows, crypto auth methods, and trial handling.New surface area:
PRODUCT_TYPES.MONEY_ACCOUNT_PLUS,CRYPTO_AUTH_METHODS(erc20_approval/delegation), and richer pricing types—card vs crypto payment methods, spot vs vault tokens (optionalconversionRate, requiredaccountantAddressfor vault shares), optionaldelegateAddresson chains, andStartCryptoSubscriptionRequestas a union of ERC-20 (rawTransaction) vs delegation (delegationHash).Runtime behavior changes: Card and crypto starts refresh subscriptions first, then override
isTrialRequestedfrom pricingtrialPeriodDaysandtrialedProducts(client-supplied trial flags are ignored). Crypto start refetches subscriptions after success. Crypto approve params, sponsorship, and cached payment methods resolve via product +cryptoAuthMethod, with legacy unscoped pricing rows defaulting to Shield + ERC-20 approval only when bothproductsandcryptoAuthMethodare omitted.Breaking renames / signatures:
startShieldSubscriptionWithCard→startSubscriptionWithCard;submitShieldSubscriptionCryptoApproval→submitSubscriptionCryptoApprovalwith a request object (still Shield /shieldSubscriptionApproveonly—delegation products usestartSubscriptionWithCrypto).cacheLastSelectedPaymentMethodtakes{ product, paymentMethod }.lastSelectedPaymentMethodisPartial<Record<ProductType, …>>. Consumers must narrow discriminated unions for pricing and token payment info.Service layer:
startSubscriptionWithCryptovalidates emptyproductsand exactly one auth combo before POST; pricing responses validated against the new structs.Reviewed by Cursor Bugbot for commit 6cbac54. Bugbot is set up for automated code reviews on this repo. Configure here.