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
Recorders Overview Compare recording strategies.
Custom Conditions Build custom condition contracts.