Skip to content

feat: batch fundInvoice and approveInvoice (DEV-2408)#210

Open
GeraldBennyClawBot wants to merge 6 commits intomainfrom
gerald/dev-2408-batch-fund-approve
Open

feat: batch fundInvoice and approveInvoice (DEV-2408)#210
GeraldBennyClawBot wants to merge 6 commits intomainfrom
gerald/dev-2408-batch-fund-approve

Conversation

@GeraldBennyClawBot
Copy link
Contributor

Replace single approveInvoice/fundInvoice with batch versions. New ApproveInvoiceParams and FundInvoiceParams structs. receiverAddressIndex indexes into a separate receiverAddresses array per Ben's feedback. Builder patterns for test params. All 618 tests passing. Closes DEV-2408

Replace single approveInvoice/fundInvoice with batch versions:
- approveInvoices(ApproveInvoiceParams[] calldata)
- fundInvoices(FundInvoiceParams[] calldata, address[] calldata receiverAddresses)

Key changes:
- New ApproveInvoiceParams and FundInvoiceParams structs in IBullaFactoring
- receiverAddressIndex in FundInvoiceParams indexes into receiverAddresses array
- Single permission check and checkpoint per batch call
- Builder patterns (ApproveInvoiceParamsBuilder, FundInvoiceParamsBuilder) in tests
- All 618 tests passing

Closes DEV-2408

Co-Authored-By: Claude Opus 4.6 <[email protected]>
…transfers

Per review: _fundInvoice now returns fee/amount values instead of
updating aggregate state directly. fundInvoices accumulates into a
totals array, performs a single totalAssets() liquidity check, single
SSTORE per state variable, and batches ERC20 transfers by receiver.
All 618 tests passing.

Co-Authored-By: Claude Opus 4.6 <[email protected]>
…ressIndex

Per review feedback:
- Remove msg.sender fallback when receiverAddressIndex is invalid
- Revert with InvalidReceiverAddressIndex if index out of bounds or address is zero
- Remove extra +1 slot in receiverAmounts array
- Remove receiverSlot return from _fundInvoice (caller uses params[i].receiverAddressIndex)
- Update test helper to pass msg.sender when address(0) is provided

Co-Authored-By: Claude Opus 4.6 <[email protected]>
Gerald Bot and others added 2 commits March 13, 2026 14:57
Per review: only revert InvalidReceiverAddressIndex on out-of-bounds
index. address(0) in receiverAddresses is valid and maps to msg.sender.
Batch transfers accumulate all address(0) slots into one msg.sender
transfer.

Co-Authored-By: Claude Opus 4.6 <[email protected]>
`optimize` is not a valid Foundry key — changed to `optimizer`.
This fixes the Solc "Tag too large for reserved space" internal
compiler error by actually enabling the optimizer.

Co-Authored-By: Claude Opus 4.6 <[email protected]>
@GeraldBennyClawBot
Copy link
Contributor Author

Pushed two fixes: (1) address(0) is valid (9ed240d) - removed the address(0) revert, only reverts on out-of-bounds index now. address(0) resolves to msg.sender. (2) foundry.toml optimizer fix (9a1bc46) - changed optimize to optimizer, fixing the Solc Tag too large compiler error. All 614 tests pass.


// ============ Builder Patterns ============

library ApproveInvoiceParamsBuilder {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This should be put in its own file.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done in fdda85b — moved all three convenience helpers (_approveInvoice, _fundInvoice, _fundInvoiceExpectRevert) and both builder libraries to test/foundry/helpers/TestHelpers.sol. CommonSetup now inherits from BatchTestHelpers and implements _factoringContract().

}
}

library FundInvoiceParamsBuilder {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done in fdda85b — both builders moved to test/foundry/helpers/TestHelpers.sol.

});
}

function withInvoiceId(IBullaFactoringV2_2.FundInvoiceParams memory self, uint256 invoiceId) internal pure returns (IBullaFactoringV2_2.FundInvoiceParams memory) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Both of the builders added here are not actually following the builder pattern. The builder should contain all of the fields to create the constructor, and the constructor is only invoked on the builder. Right now, the builder has a create function that creates params and we're really not getting the benefit that we're looking for.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done in fdda85b — builders now use separate structs (ApproveInvoiceBuilder, FundInvoiceBuilder) with create() returning the builder, with*() methods setting fields on it, and build() constructing the actual params struct.

Move convenience helpers (_approveInvoice, _fundInvoice, _fundInvoiceExpectRevert)
and builder pattern libraries to test/foundry/helpers/TestHelpers.sol per review.
CommonSetup now inherits from BatchTestHelpers.

Co-Authored-By: Claude Opus 4.6 <[email protected]>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants