diff --git a/modules/rcart/components/folk-payment-page.ts b/modules/rcart/components/folk-payment-page.ts index 8a6e974..8b20c64 100644 --- a/modules/rcart/components/folk-payment-page.ts +++ b/modules/rcart/components/folk-payment-page.ts @@ -216,7 +216,7 @@ class FolkPaymentPage extends HTMLElement { if (p.token === 'ETH') { // Native ETH transfer - const weiAmount = BigInt(Math.round(parseFloat(effectiveAmount) * 1e18)); + const weiAmount = this.parseTokenAmount(effectiveAmount, 18); txHash = await signer.sendTransaction({ from: this.walletAccount, to: p.recipientAddress, @@ -229,7 +229,7 @@ class FolkPaymentPage extends HTMLElement { if (!usdcAddress) throw new Error('USDC not supported on this chain'); const decimals = p.token === 'USDC' ? 6 : 18; - const rawAmount = BigInt(Math.round(parseFloat(effectiveAmount) * (10 ** decimals))); + const rawAmount = this.parseTokenAmount(effectiveAmount, decimals); // transfer(address to, uint256 amount) — selector: 0xa9059cbb const recipient = p.recipientAddress.slice(2).toLowerCase().padStart(64, '0'); @@ -303,7 +303,7 @@ class FolkPaymentPage extends HTMLElement { txHash = await client.sendTransaction({ account, to: p.recipientAddress as `0x${string}`, - value: BigInt(Math.round(parseFloat(effectiveAmount) * 1e18)), + value: this.parseTokenAmount(effectiveAmount, 18), chain, }); } else { @@ -312,7 +312,7 @@ class FolkPaymentPage extends HTMLElement { if (!usdcAddress) throw new Error('USDC not supported on this chain'); const decimals = p.token === 'USDC' ? 6 : 18; - const rawAmount = BigInt(Math.round(parseFloat(effectiveAmount) * (10 ** decimals))); + const rawAmount = this.parseTokenAmount(effectiveAmount, decimals); const recipient = p.recipientAddress.slice(2).toLowerCase().padStart(64, '0'); const amountHex = rawAmount.toString(16).padStart(64, '0'); @@ -347,6 +347,18 @@ class FolkPaymentPage extends HTMLElement { return this.customAmount || '0'; } + /** + * Parse a decimal amount string into a BigInt with the given decimals. + * Avoids floating-point precision loss for 18-decimal tokens. + * e.g. parseTokenAmount("1.5", 18) → 1500000000000000000n + */ + private parseTokenAmount(amount: string, decimals: number): bigint { + const parts = amount.split('.'); + const whole = parts[0] || '0'; + let frac = (parts[1] || '').slice(0, decimals).padEnd(decimals, '0'); + return BigInt(whole) * BigInt(10 ** decimals) + BigInt(frac); + } + // ── Status update ── private async updatePaymentStatus(status: string, method: string, txHash?: string | null, transakOrderId?: string | null) {