Documentation Index
Fetch the complete documentation index at: https://docs.remlo.xyz/llms.txt
Use this file to discover all available pages before exploring further.
PayrollBatcher distributes a payroll batch to N recipients in one transaction. It pulls the exact total from PayrollTreasury, transfers to each employee, attaches a 32-byte ISO 20022 memo per item, and emits a single PaymentSent event indexed by employerId and runId.
Function signature
recipients: employee wallet addresses, one per payment.amounts: stablecoin amounts in atomic units (USDC.e has 6 decimals).memos: 32-byte ISO 20022 TIP-20 memos. Encoded bylib/memo.tswithmessageType(4 bytes),employerIdprefix (8 bytes),employeeIdprefix (8 bytes),payPeriod(4 bytes),costCenter(4 bytes),recordHash(4 bytes).employerId: keccak256 identifier of the employer inPayrollTreasury.
LengthMismatch if the three arrays don’t match. Reverts with EmptyBatch on zero recipients. Reverts with BatchTooLarge if recipients.length > 500 (audit fix M-3 caps batch size to bound gas usage).
Authorization
executeBatchPayroll is onlyAuthorizedAgent. Only the Remlo agent EOA (or the contract owner) can call it. The batcher itself does not check Privy JWTs or x402 payment headers; those checks happen at the API layer (/api/mpp/payroll/execute) before the agent broadcasts the on-chain call.
Optional employee validation (audit fix H-4)
IfBatcher.employeeRegistry is set to a non-zero address, the contract loops through recipients and reverts with RecipientNotEmployed(address) for any wallet not registered in EmployeeRegistry under the supplied employerId. This protects against a compromised agent broadcasting payments to wallets outside the employer’s verified team.
The flag is opt-in. During the v2 redeploy migration period (employees are still re-registering on the new EmployeeRegistry), the registry is set to 0x0 and validation is skipped. Re-wire after migration completes.
Settlement
The function pulls the exact total fromPayrollTreasury via safeTransferFrom (audit fix H-1: SafeTIP20 wrapper handles non-compliant TIP-20 return values). Each recipient transfer happens in the same transaction. If any single transfer fails, the whole batch reverts. Settlement on Tempo lands in the same block, typically under a second.
After successful execution, PaymentSent(employerId indexed, runId indexed, total, recipientCount) is emitted (audit fix M-6: employerId indexed for off-chain query efficiency). Off-chain indexers update payment_items.tx_hash and flip status to pending until the chain confirmation cron promotes them to confirmed.
Why atomic batches
A naive payroll loop of N individual transactions has N gas overheads, N nonce updates, and N opportunities for partial failure. The batcher gives:- One nonce, one fee. Constant overhead regardless of batch size.
- Atomicity. Either everyone gets paid, or no state changes. Partial-pay states are impossible.
- One indexed event for the whole run. Reputation and reporting cron jobs read one log entry instead of N.