feat: add batch payment integration for settling multiple USDC invoices via Spraay#1730
feat: add batch payment integration for settling multiple USDC invoices via Spraay#1730plagtech wants to merge 3 commits into
Conversation
|
Hello @plagtech, thank you for submitting your first pull request to the requestNetwork repository. We value your contribution and encourage you to review our contribution guidelines to ensure your submission meets our standards. Please note that every merged PR is automatically enrolled in our Best PR Initiative, offering a chance to win $500 each quarter. Our team is available via GitHub Discussions or Discord if you have any questions. Welcome aboard! |
|
Thank you for your submission! As you prepare for the review process, please ensure that your PR title, description, and any linked issues fully comply with our contribution guidelines. A clear explanation of your changes and their context will help expedite the review process. Every merged PR is automatically entered into our Best PR Initiative, offering a chance to win $500 every quarter. We appreciate your attention to detail and look forward to reviewing your contribution! |
Greptile SummaryThis PR adds
Confidence Score: 3/5Not safe to merge without resolving the chainId/signer mismatch: passing a chainId override in BatchPaymentRequest routes all contract lookups to that chain's addresses while the signer's actual network is ignored, silently making RPC calls to the wrong contracts. The BatchPaymentRequest.chainId field lets callers override the chain used for contract address lookups, but payInvoices never validates that the signer's provider is actually on that chain. A signer connected to Base combined with chainId: 1 will query and transact against Ethereum contract addresses on Base — wrong decimals(), wrong balanceOf, and an approve/batchTransfer sent to whatever contract happens to live at those addresses on Base. Beyond that, the existing unaddressed thread comment about batchTransfer bypassing Request Network's payment-detection events means invoices will remain in 'created' state after payment, which is a fundamental correctness issue for the integration. packages/payment-processor/src/payment/spraay-batch-payer.ts — the chainId override in payInvoices and the batchTransfer payment-detection bypass Important Files Changed
Sequence DiagramsequenceDiagram
participant Caller
participant SpraayBatchPayer
participant ERC20_USDC
participant SpraayContract
Caller->>SpraayBatchPayer: payInvoices(request)
SpraayBatchPayer->>SpraayBatchPayer: validate chainId, addresses, invoice count
SpraayBatchPayer->>ERC20_USDC: decimals()
ERC20_USDC-->>SpraayBatchPayer: 6
SpraayBatchPayer->>SpraayBatchPayer: parse amounts, compute total
SpraayBatchPayer->>ERC20_USDC: balanceOf(sender)
ERC20_USDC-->>SpraayBatchPayer: balance
SpraayBatchPayer->>ERC20_USDC: allowance(sender, spraayContract)
ERC20_USDC-->>SpraayBatchPayer: allowance
alt "allowance < total"
SpraayBatchPayer->>ERC20_USDC: approve(spraayContract, total)
ERC20_USDC-->>SpraayBatchPayer: receipt (null check + status check)
end
SpraayBatchPayer->>SpraayContract: batchTransfer(token, recipients[], amounts[])
SpraayContract->>ERC20_USDC: transferFrom(sender, recipient_i, amount_i) x N
SpraayContract-->>SpraayBatchPayer: tx receipt (null check + status check)
SpraayBatchPayer-->>Caller: BatchPaymentResult
Reviews (3): Last reviewed commit: "fix: throw on reverted batch transfer in..." | Re-trigger Greptile |
…, scope USDC to active chain, type request client
| const chainId = request.chainId ?? this.chainId; | ||
| const batchContractAddr = SPRAAY_BATCH_CONTRACTS[chainId]; | ||
| const tokenAddr = request.tokenAddress ?? USDC_ADDRESSES[chainId]; |
There was a problem hiding this comment.
request.chainId override silently uses wrong chain's contracts
BatchPaymentRequest.chainId lets callers override the chain used to look up contract addresses, but the signer is never validated against that chain. If a caller constructs new SpraayBatchPayer(signer, 8453) with a Base-connected signer and then passes chainId: 1, every RPC call — token.decimals(), token.balanceOf(), token.allowance(), the approve, and batchTransfer — is sent through the Base signer to the Ethereum-chain contract addresses on the Base network. The decimals() call may return garbage or revert (the Ethereum USDC address is a different contract on Base), and if it happens to return a value, the approve and batch-transfer will go to the wrong address entirely. The chainId field in BatchPaymentRequest should either be removed (the signer's network is the authoritative source) or validated at the start of payInvoices via await this.signer.provider?.getNetwork() with an explicit mismatch error.
What
Adds batch payment support for settling multiple Request Network invoices in a single on-chain transaction, powered by Spraay Protocol's multi-recipient batch transfer contracts.
Related issue: #1729
Why
Businesses using Request Network for invoicing often need to pay multiple invoices at once — monthly vendor payments, contractor payroll, DAO grants, etc. Today this requires N separate transactions. Batch payment reduces this to 1 transaction with ~80% gas savings.
What's Included
New files:
packages/payment-processor/src/payment/spraay-batch-payer.ts— Core batch payment logicpackages/payment-processor/src/payment/spraay-utils.ts— Chain configs, contract addresses, helperspackages/payment-processor/test/spraay-batch-payer.test.ts— Unit testsdocs/integrations/spraay-batch-payments.md— Integration guideChanges:
packages/payment-processor/src/index.ts— Export new batch payment moduleREADME.md— Add Spraay batch payments to integrations sectionHow It Works
Usage
Supported Chains
Base, Ethereum, Arbitrum, Polygon, BNB Chain, Avalanche
Gas Comparison
(Base L2 gas estimates)
Testing
Checklist
payment-processorpatterns@requestnetwork/request-client.jsReferences