Description
The payInvoicesBatch function contains a critical logic bug in the ERC20 payment path that causes all ERC20 transfers in a batch to be sent to the last invoice’s recipient only, regardless of which invoices are being paid.
This issue is independent of the already-reported batch payment race condition in #59.
Even if the Checks–Effects–Interactions ordering is fixed, this bug will still persist and cause incorrect fund transfers.
Problem Explanation
In payInvoicesBatch, invoice validation is done in an initial loop where an InvoiceDetails storage inv variable is declared.
Later, during the ERC20 transfer loop, the same inv variable is reused without being reassigned per iteration. As a result:
-
inv continues to reference the last invoice from the validation loop
-
All transferFrom calls use:
- the last invoice’s
from address
- the last invoice’s
amountDue
-
Other invoice issuers never receive their tokens
This happens deterministically on every ERC20 batch payment.
Expected Behavior
Each ERC20 transfer should:
- Use the current invoice’s
from address
- Use the current invoice’s
amountDue
Each invoice issuer should receive exactly the amount owed to them.
Current Behavior
- All ERC20 transfers in a batch go to the last invoice’s issuer only
- Other issuers receive nothing
- Funds are permanently misrouted
Impact
- Guaranteed fund loss / misrouting
- Affects all ERC20 batch payments
- Breaks trust in batch payment functionality
Description
The
payInvoicesBatchfunction contains a critical logic bug in the ERC20 payment path that causes all ERC20 transfers in a batch to be sent to the last invoice’s recipient only, regardless of which invoices are being paid.This issue is independent of the already-reported batch payment race condition in #59.
Even if the Checks–Effects–Interactions ordering is fixed, this bug will still persist and cause incorrect fund transfers.
Problem Explanation
In
payInvoicesBatch, invoice validation is done in an initial loop where anInvoiceDetails storage invvariable is declared.Later, during the ERC20 transfer loop, the same
invvariable is reused without being reassigned per iteration. As a result:invcontinues to reference the last invoice from the validation loopAll
transferFromcalls use:fromaddressamountDueOther invoice issuers never receive their tokens
This happens deterministically on every ERC20 batch payment.
Expected Behavior
Each ERC20 transfer should:
fromaddressamountDueEach invoice issuer should receive exactly the amount owed to them.
Current Behavior
Impact