Skip to content

Commit 47f8011

Browse files
committed
feat: strengthen net payable amount logic
1 parent d0efa5e commit 47f8011

2 files changed

Lines changed: 40 additions & 16 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: 28 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -138,11 +138,33 @@ 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;
142+
const minimumUnit = BigInt(1);
143+
144+
if (this.priceType === PriceType.PERCENTAGE) {
145+
const feeBasisPoints = BigInt(Math.round(this.priceValue * 10000));
146+
let feeAmount = (grossAmount * feeBasisPoints) / BigInt(10000);
147+
148+
if (feeBasisPoints > BigInt(0) && feeAmount === BigInt(0)) {
149+
feeAmount = minimumUnit;
150+
}
145151

152+
const netAmount = grossAmount - feeAmount;
153+
154+
const formattedNetAmount = formatUnits(netAmount, decimals);
155+
const netAmountNumber = parseFloat(formattedNetAmount);
156+
157+
if (!Number.isFinite(netAmountNumber)) {
158+
throw new AcpError(
159+
`Net payable amount overflow: ${formattedNetAmount} exceeds safe number range`
160+
);
161+
}
162+
163+
const factor = Math.pow(10, decimals);
164+
return Math.floor(netAmountNumber * factor) / factor;
165+
}
166+
167+
const formattedAmount = formatUnits(grossAmount, decimals);
146168
const payableAmount = parseFloat(formattedAmount);
147169

148170
if (!Number.isFinite(payableAmount)) {
@@ -157,17 +179,8 @@ class AcpJob {
157179
);
158180
}
159181

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;
168-
}
169-
170-
return payableAmount;
182+
const factor = Math.pow(10, decimals);
183+
return Math.floor(payableAmount * factor) / factor;
171184
}
172185

173186
async createRequirement(content: string) {

0 commit comments

Comments
 (0)