Skip to content

Feat/shield create subscription crypto#6456

Merged
chaitanyapotti merged 29 commits intomainfrom
feat/shield-create-subscription-crypto
Sep 9, 2025
Merged

Feat/shield create subscription crypto#6456
chaitanyapotti merged 29 commits intomainfrom
feat/shield-create-subscription-crypto

Conversation

@tuna1207
Copy link
Copy Markdown
Member

@tuna1207 tuna1207 commented Sep 4, 2025

Explanation

  • Add getCryptoApproveTransactionParams which handle validating and prepare params to create crypto approve transaction for user to sign then submit to subscription service
  • Add startSubscriptionWithCrypto which register submitted crypto transaction with subscription service to start subscription

References

Checklist

  • I've updated the test suite for new or updated code as appropriate
  • I've updated documentation (JSDoc, Markdown, etc.) for new or updated code as appropriate
  • I've communicated my changes to consumers by updating changelogs for packages I've changed, highlighting breaking changes as necessary
  • I've prepared draft pull requests for clients and consumer packages to resolve any breaking changes

Comment thread packages/subscription-controller/src/SubscriptionController.ts Outdated
Comment thread packages/subscription-controller/src/SubscriptionController.ts Outdated
@tuna1207 tuna1207 marked this pull request as ready for review September 6, 2025 07:05
@tuna1207 tuna1207 requested review from a team as code owners September 6, 2025 07:05
cursor[bot]

This comment was marked as outdated.

cursor[bot]

This comment was marked as outdated.

chaitanyapotti
chaitanyapotti previously approved these changes Sep 8, 2025
@chaitanyapotti chaitanyapotti enabled auto-merge (squash) September 8, 2025 04:54
Comment thread packages/subscription-controller/CHANGELOG.md Outdated
Comment thread packages/subscription-controller/src/SubscriptionService.ts Outdated
Comment thread packages/subscription-controller/src/SubscriptionService.ts
Comment thread packages/subscription-controller/src/constants.test.ts Outdated
Comment thread packages/subscription-controller/src/types.ts
Comment thread packages/subscription-controller/src/SubscriptionController.ts Outdated
Comment thread packages/subscription-controller/src/SubscriptionController.ts
Comment thread packages/subscription-controller/src/SubscriptionController.ts
Comment on lines +347 to +366
// conversion rate is a float string e.g: "1.0"
// We need to handle float conversion rates with integer math for BigInt.
// We'll scale the conversion rate to an integer by multiplying by 10^4.
// conversionRate is in usd decimal. In most currencies, we only care about 2 decimals (cents)
// So, scale must be max of 10 ** 4 (most exchanges trade with max 4 decimals of usd)
// This allows us to avoid floating point math and keep precision.
const CONVERSION_RATE_SCALE = 10n ** 4n;
const conversionRateScaled = BigInt(
Number(conversionRate) * Number(CONVERSION_RATE_SCALE),
);
const priceAmount = this.#getSubscriptionPriceAmount(price);
const priceAmountScaled = BigInt(
priceAmount * Number(CONVERSION_RATE_SCALE),
);

const amount =
((priceAmountScaled / CONVERSION_RATE_SCALE) *
BigInt(10) ** BigInt(tokenPaymentInfo.decimals) *
CONVERSION_RATE_SCALE) /
conversionRateScaled;
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we should be able to do that computation without relying on floating point arithmetic.

Does the following work?

tokenApproveAmount = priceInUSD * tokenPerUSD
= (priceAmount / priceDecimals) * (tokenAmount / tokenDecimals)
= (priceAmount * tokenAmount) / (priceDecimals * tokenDecimals)

Comment thread packages/subscription-controller/src/SubscriptionController.ts Outdated
cursor[bot]

This comment was marked as outdated.

Co-authored-by: matthiasgeihs <62935430+matthiasgeihs@users.noreply.github.com>
cursor[bot]

This comment was marked as outdated.

cursor[bot]

This comment was marked as outdated.

cursor[bot]

This comment was marked as outdated.

BigInt(10) ** BigInt(tokenPaymentInfo.decimals) *
CONVERSION_RATE_SCALE) /
conversionRateScaled;
return amount;
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Bug: Token Approval Bug Causes Precision Loss

The token approve amount calculation in #getTokenApproveAmount has a precision loss bug. The BigInt integer division (priceAmountScaled / CONVERSION_RATE_SCALE) truncates the result, especially for small or fractional subscription prices. This can lead to an incorrect or zero token approval amount, causing transaction failures.

Fix in Cursor Fix in Web

@chaitanyapotti chaitanyapotti removed the request for review from lwin-kyaw September 9, 2025 09:09
@@ -1,5 +1,4 @@
import { handleFetch } from '@metamask/controller-utils';
import nock, { cleanAll, isDone } from 'nock';
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why did you remove the usage of nock here?
Remember that we should keep changes minimal within the context of the PR, if possible.

@@ -1,3 +1,5 @@
import { handleFetch } from '@metamask/controller-utils';
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

need to move @metamask/controller-utils to main dependencies now

const tokenAmount =
(priceAmountScaled * tokenDecimal) / conversionRateScaled;
return tokenAmount;
}
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Bug: Token Amount Calculation Precision Error

The #getTokenApproveAmount method's BigInt scaling logic immediately divides scaled values by SCALE using integer division. This truncates decimal precision, leading to incorrect token amount calculations for crypto subscriptions.

Fix in Cursor Fix in Web

matthiasgeihs
matthiasgeihs previously approved these changes Sep 9, 2025
const tokenAmount =
(priceAmountScaled * tokenDecimal) / conversionRateScaled;
return tokenAmount;
}
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Bug: BigInt Scaling Logic Fails

The BigInt scaling logic in #getTokenApproveAmount loses precision. Values are scaled up by SCALE and then immediately divided by SCALE using integer division, which truncates decimal values. This defeats the purpose of scaling, resulting in incorrect conversionRateScaled and priceAmountScaled values, and ultimately wrong token approval amounts for crypto payments.

Fix in Cursor Fix in Web

@matthiasgeihs matthiasgeihs dismissed himanshuchawla009’s stale review September 9, 2025 10:34

as far as i can see comments have been addressed.
dismissing so we can move forward with other features.
(if issues persist, we still have some time to address them before we release the first version of the controller.)


const tokenAmount =
(priceAmountScaled * tokenDecimal) / conversionRateScaled;
return tokenAmount;
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Bug: Token Approval Precision Loss

The scaling logic in #getTokenApproveAmount is flawed. conversionRateScaled and priceAmountScaled are scaled up by SCALE then immediately divided by SCALE using BigInt integer division. This truncates fractional parts, causing precision loss and incorrect token approval amounts. It also risks division by zero if conversionRateScaled becomes 0n.

Fix in Cursor Fix in Web

@chaitanyapotti chaitanyapotti merged commit e09ffed into main Sep 9, 2025
239 checks passed
@chaitanyapotti chaitanyapotti deleted the feat/shield-create-subscription-crypto branch September 9, 2025 10:47
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants