Skip to content

Commit 7f59360

Browse files
committed
feat: strengthen net payable amount logic
1 parent d0efa5e commit 7f59360

2 files changed

Lines changed: 35 additions & 21 deletions

File tree

src/acpFare.ts

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,18 @@ class Fare {
1313
constructor(public contractAddress: Address, public decimals: number) {}
1414

1515
formatAmount(amount: number) {
16-
return parseUnits(amount.toString(), this.decimals);
16+
if (!Number.isFinite(amount) || amount < 0) {
17+
throw new AcpError(
18+
`Invalid amount: ${amount}. Amount must be a finite, non-negative number.`
19+
);
20+
}
21+
22+
const numStr = amount.toString();
23+
const amountStr = numStr.includes('e')
24+
? amount.toFixed(this.decimals)
25+
: numStr;
26+
27+
return parseUnits(amountStr, this.decimals);
1728
}
1829

1930
static async fromContractAddress(

src/acpJob.ts

Lines changed: 23 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -138,36 +138,39 @@ class AcpJob {
138138
? this.baseFare.decimals
139139
: 18;
140140

141-
const formattedAmount = formatUnits(
142-
payableMemo.payableDetails.amount,
143-
decimals
144-
);
141+
const grossAmount = payableMemo.payableDetails.amount;
145142

146-
const payableAmount = parseFloat(formattedAmount);
143+
let netAmount: bigint;
144+
if (this.priceType === PriceType.PERCENTAGE) {
145+
const feeBasisPoints = BigInt(Math.round(this.priceValue * 10000));
146+
let feeAmount = (grossAmount * feeBasisPoints) / BigInt(10000);
147147

148-
if (!Number.isFinite(payableAmount)) {
149-
throw new AcpError(
150-
`Payable amount overflow: ${formattedAmount} exceeds safe number range`
151-
);
148+
if (feeBasisPoints > BigInt(0) && feeAmount === BigInt(0)) {
149+
feeAmount = BigInt(1);
150+
}
151+
152+
netAmount = grossAmount - feeAmount;
153+
} else {
154+
netAmount = grossAmount;
152155
}
153156

154-
if (payableAmount > Number.MAX_SAFE_INTEGER) {
157+
const formattedAmount = formatUnits(netAmount, decimals);
158+
const amountNumber = parseFloat(formattedAmount);
159+
160+
if (!Number.isFinite(amountNumber)) {
155161
throw new AcpError(
156-
`Payable amount ${formattedAmount} exceeds MAX_SAFE_INTEGER (${Number.MAX_SAFE_INTEGER}). Precision may be lost.`
162+
`Net payable amount overflow: ${formattedAmount} exceeds safe number range`
157163
);
158164
}
159165

160-
if (this.priceType === PriceType.PERCENTAGE) {
161-
const netAmount = payableAmount * (1 - this.priceValue);
162-
if (!Number.isFinite(netAmount)) {
163-
throw new AcpError(
164-
`Net payable amount calculation overflow for percentage pricing`
165-
);
166-
}
167-
return netAmount;
166+
if (amountNumber > Number.MAX_SAFE_INTEGER) {
167+
throw new AcpError(
168+
`Net payable amount ${formattedAmount} exceeds MAX_SAFE_INTEGER (${Number.MAX_SAFE_INTEGER}). Precision may be lost.`
169+
);
168170
}
169171

170-
return payableAmount;
172+
const factor = Math.pow(10, decimals);
173+
return Math.floor(amountNumber * factor) / factor;
171174
}
172175

173176
async createRequirement(content: string) {

0 commit comments

Comments
 (0)