Skip to content

Commit

Permalink
Merge pull request #1097 from graphprotocol/mde/add-unique-id-to-coll…
Browse files Browse the repository at this point in the history
…ector-tracking
  • Loading branch information
tmigone authored Feb 10, 2025
2 parents 8f922a1 + 2af2e68 commit 3dc3140
Show file tree
Hide file tree
Showing 9 changed files with 428 additions and 260 deletions.
4 changes: 3 additions & 1 deletion packages/horizon/contracts/interfaces/IPaymentsCollector.sol
Original file line number Diff line number Diff line change
Expand Up @@ -17,13 +17,15 @@ interface IPaymentsCollector {
/**
* @notice Emitted when a payment is collected
* @param paymentType The payment type collected as defined by {IGraphPayments}
* @param collectionId The id for the collection. Can be used at the discretion of the collector to group multiple payments.
* @param payer The address of the payer
* @param receiver The address of the receiver
* @param dataService The address of the data service
* @param tokens The amount of tokens being collected
*/
event PaymentCollected(
IGraphPayments.PaymentTypes indexed paymentType,
IGraphPayments.PaymentTypes paymentType,
bytes32 indexed collectionId,
address indexed payer,
address receiver,
address indexed dataService,
Expand Down
6 changes: 5 additions & 1 deletion packages/horizon/contracts/interfaces/ITAPCollector.sol
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,8 @@ interface ITAPCollector is IPaymentsCollector {

/// @notice The Receipt Aggregate Voucher (RAV) struct
struct ReceiptAggregateVoucher {
// The ID of the collection "bucket" the RAV belongs to. Note that multiple RAVs can be collected for the same collection id.
bytes32 collectionId;
// The address of the payer the RAV was issued by
address payer;
// The address of the data service the RAV was issued to
Expand Down Expand Up @@ -80,6 +82,7 @@ interface ITAPCollector is IPaymentsCollector {

/**
* @notice Emitted when a RAV is collected
* @param collectionId The ID of the collection "bucket" the RAV belongs to.
* @param payer The address of the payer
* @param dataService The address of the data service
* @param serviceProvider The address of the service provider
Expand All @@ -89,9 +92,10 @@ interface ITAPCollector is IPaymentsCollector {
* @param signature The signature of the RAV
*/
event RAVCollected(
bytes32 indexed collectionId,
address indexed payer,
address serviceProvider,
address indexed dataService,
address indexed serviceProvider,
uint64 timestampNs,
uint128 valueAggregate,
bytes metadata,
Expand Down
19 changes: 13 additions & 6 deletions packages/horizon/contracts/payments/collectors/TAPCollector.sol
Original file line number Diff line number Diff line change
Expand Up @@ -35,8 +35,10 @@ contract TAPCollector is EIP712, GraphDirectory, ITAPCollector {
/// @notice Authorization details for payer-signer pairs
mapping(address signer => PayerAuthorization authorizedSigner) public authorizedSigners;

/// @notice Tracks the amount of tokens already collected by a data service from a payer to a receiver
mapping(address dataService => mapping(address receiver => mapping(address payer => uint256 tokens)))
/// @notice Tracks the amount of tokens already collected by a data service from a payer to a receiver.
/// @dev The collectionId provides a secondary key for grouping payment tracking if needed. Data services that do not require
/// grouping can use the same collectionId for all payments (0x00 or some other default value).
mapping(address dataService => mapping(bytes32 collectionId => mapping(address receiver => mapping(address payer => uint256 tokens))))
public tokensCollected;

/// @notice The duration (in seconds) in which a signer is thawing before they can be revoked
Expand Down Expand Up @@ -182,6 +184,7 @@ contract TAPCollector is EIP712, GraphDirectory, ITAPCollector {
address payer = authorizedSigners[signer].payer;
require(signedRAV.rav.payer == payer, TAPCollectorInvalidRAVPayer(payer, signedRAV.rav.payer));

bytes32 collectionId = signedRAV.rav.collectionId;
address dataService = signedRAV.rav.dataService;
address receiver = signedRAV.rav.serviceProvider;

Expand All @@ -199,7 +202,7 @@ contract TAPCollector is EIP712, GraphDirectory, ITAPCollector {
uint256 tokensToCollect = 0;
{
uint256 tokensRAV = signedRAV.rav.valueAggregate;
uint256 tokensAlreadyCollected = tokensCollected[dataService][receiver][payer];
uint256 tokensAlreadyCollected = tokensCollected[dataService][collectionId][receiver][payer];
require(
tokensRAV > tokensAlreadyCollected,
TAPCollectorInconsistentRAVTokens(tokensRAV, tokensAlreadyCollected)
Expand All @@ -217,20 +220,24 @@ contract TAPCollector is EIP712, GraphDirectory, ITAPCollector {
}

if (tokensToCollect > 0) {
tokensCollected[dataService][receiver][payer] += tokensToCollect;
tokensCollected[dataService][collectionId][receiver][payer] += tokensToCollect;
_graphPaymentsEscrow().collect(_paymentType, payer, receiver, tokensToCollect, dataService, dataServiceCut);
}

emit PaymentCollected(_paymentType, payer, receiver, dataService, tokensToCollect);
emit PaymentCollected(_paymentType, collectionId, payer, receiver, dataService, tokensToCollect);

// This event is emitted to allow reconstructing RAV history with onchain data.
emit RAVCollected(
collectionId,
payer,
dataService,
receiver,
dataService,
signedRAV.rav.timestampNs,
signedRAV.rav.valueAggregate,
signedRAV.rav.metadata,
signedRAV.signature
);

return tokensToCollect;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -142,6 +142,7 @@ contract TAPCollectorTest is HorizonStakingSharedTest, PaymentsEscrowSharedTest
(address _payer, , ) = tapCollector.authorizedSigners(_signer);
uint256 tokensAlreadyCollected = tapCollector.tokensCollected(
signedRAV.rav.dataService,
signedRAV.rav.collectionId,
signedRAV.rav.serviceProvider,
_payer
);
Expand All @@ -152,16 +153,18 @@ contract TAPCollectorTest is HorizonStakingSharedTest, PaymentsEscrowSharedTest
vm.expectEmit(address(tapCollector));
emit IPaymentsCollector.PaymentCollected(
_paymentType,
signedRAV.rav.collectionId,
_payer,
signedRAV.rav.serviceProvider,
signedRAV.rav.dataService,
tokensToCollect
);
vm.expectEmit(address(tapCollector));
emit ITAPCollector.RAVCollected(
signedRAV.rav.collectionId,
_payer,
signedRAV.rav.dataService,
signedRAV.rav.serviceProvider,
signedRAV.rav.dataService,
signedRAV.rav.timestampNs,
signedRAV.rav.valueAggregate,
signedRAV.rav.metadata,
Expand All @@ -173,6 +176,7 @@ contract TAPCollectorTest is HorizonStakingSharedTest, PaymentsEscrowSharedTest

uint256 tokensCollectedAfter = tapCollector.tokensCollected(
signedRAV.rav.dataService,
signedRAV.rav.collectionId,
signedRAV.rav.serviceProvider,
_payer
);
Expand Down
Loading

0 comments on commit 3dc3140

Please sign in to comment.