fix(contract): safe BigInt arithmetic in MeshMarketplaceContract.purchaseAsset#832
Open
OscarOzaine wants to merge 2 commits into
Open
fix(contract): safe BigInt arithmetic in MeshMarketplaceContract.purchaseAsset#832OscarOzaine wants to merge 2 commits into
OscarOzaine wants to merge 2 commits into
Conversation
…input OfflineEvaluator.evaluateTx pushed resolved UTxOs into the caller's additionalUtxos array (a surprising side effect that accumulated across repeated calls) and fetched each parent transaction's UTxOs sequentially, so latency scaled linearly with the number of distinct input transactions. It now copies the input array and resolves distinct parent transactions concurrently via Promise.all, leaving the caller's array untouched. The two in-tree callers pass a freshly built array and read only the return value, so behavior is unchanged for them. Adds a no-mutation assertion to the existing evaluator test, which already resolves inputs across several parent transactions (exercising the parallel path). Refs audit findings PERF-001, REL-003 Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…aseAsset Replaces float-based lovelace arithmetic with BigInt throughout purchaseAsset to avoid silent precision loss for NFT prices above Number.MAX_SAFE_INTEGER (~9,007,199 ADA). The previous `as number` casts were TypeScript-only lies that caused a TypeError at runtime; converting via Number() fixed the crash but introduced silent rounding errors for large prices. Changes: - All fee and seller-payment calculations now use BigInt operators; quantities are only converted to string at the txOut boundary. - Ceiling division implemented as (a * b + 9999n) / 10000n instead of Math.ceil(float), which is exact and matches the on-chain semantics. - 1-ADA minimum fee floor is now guarded by priceBig > 0n so free listings (price = 0) no longer incur a spurious mandatory fee. - lovelaceEntry guard replaces the !.quantity non-null assertion with a descriptive error instead of an opaque TypeError. - Constructor validates feePercentageBasisPoint is in [0, 10000] and throws early rather than silently producing unbalanceable transactions. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
This is a suggested improvement follow-up to #714 (which fixed the
TypeError: Cannot mix BigInt and other typescrash inpurchaseAsset).While #714's
Number()conversion resolves the crash, it introduces silent precision loss for NFT prices aboveNumber.MAX_SAFE_INTEGER(~9,007,199 ADA) and leaves several other issues in the same function unaddressed. This PR addresses them all.Changes
purchaseAsset— BigInt-safe arithmetic (fixes #714's root cause)(a * b + 9999n) / 10000nis exact BigInt ceiling division — equivalent toMath.ceilwithout any float arithmetic.priceBig + BigInt(lovelaceEntry.quantity)— no IEEE-754 rounding regardless of price magnitude.Free-listing spurious fee fix
Previously, a listing with
price = 0would hit the 1-ADA minimum floor and charge the buyer 1 ADA to the marketplace owner, even though the on-chain validator requiresvalue_geq(0)(no floor). AddedpriceBig > 0nguard.lovelaceEntry— descriptive error instead of opaque crashConstructor —
feePercentageBasisPointrange validationA value > 10000 (> 100%) silently produces
ownerToReceiveLovelace > price, making the transaction unbalanceable. Now throws early with a clear message.Issues addressed
Number(bigint)precision loss for prices > ~9M ADA → wrong fee and seller amountsMAX_SAFE_INTEGERboundary in seller paymentfeePercentageBasisPoint > 10000accepted silently🤖 Generated with Claude Code