Overview
You can create custom recorders for specialized tracking beyond what the built-in recorders provide. Implement the IRecorder interface and extend BaseRecorder for operator access control.
IRecorder Interface
interface IRecorder {
function record(
AuthCaptureEscrow.PaymentInfo calldata paymentInfo,
uint256 amount,
address caller
) external;
}
Extending BaseRecorder
Extend BaseRecorder to ensure only authorized operators can call record():
contract MyRecorder is BaseRecorder {
constructor(address _escrow) BaseRecorder(_escrow) {}
function record(
AuthCaptureEscrow.PaymentInfo calldata paymentInfo,
uint256 amount,
address caller
) external onlyAuthorizedOperator {
// Your recording logic here
}
}
Example: ReleaseCountRecorder
Tracks the number and total amount of releases per payment:
contract ReleaseCountRecorder is BaseRecorder {
mapping(bytes32 => uint256) public releaseCount;
mapping(bytes32 => uint256) public totalReleased;
constructor(address _escrow) BaseRecorder(_escrow) {}
function record(
PaymentInfo calldata payment,
uint256 amount,
address caller
) external onlyAuthorizedOperator {
bytes32 hash = escrow.getHash(payment);
releaseCount[hash]++;
totalReleased[hash] += amount;
}
// Enable tracking partial releases
function getStats(bytes32 paymentHash)
external view
returns (uint256 count, uint256 total)
{
return (releaseCount[paymentHash], totalReleased[paymentHash]);
}
}
Testing
Test custom recorders with Forge:
contract ReleaseCountRecorderTest is Test {
ReleaseCountRecorder recorder;
function setUp() public {
recorder = new ReleaseCountRecorder(address(escrow));
}
function test_incrementsOnRecord() public {
recorder.record(paymentInfo, 100e6, caller);
bytes32 hash = escrow.getHash(paymentInfo);
(uint256 count, uint256 total) = recorder.getStats(hash);
assertEq(count, 1);
assertEq(total, 100e6);
}
function test_tracksMultipleReleases() public {
recorder.record(paymentInfo, 50e6, caller);
recorder.record(paymentInfo, 30e6, caller);
bytes32 hash = escrow.getHash(paymentInfo);
(uint256 count, uint256 total) = recorder.getStats(hash);
assertEq(count, 2);
assertEq(total, 80e6);
}
}
Security Checklist
Unlike conditions, recorders do modify state. Ensure proper access control via BaseRecorder to prevent unauthorized writes.
Next Steps