Skip to content

Commit fc13db1

Browse files
f: agreement versioning WIP
1 parent ae910c4 commit fc13db1

File tree

9 files changed

+272
-90
lines changed

9 files changed

+272
-90
lines changed
Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
// SPDX-License-Identifier: GPL-3.0-or-later
2+
pragma solidity 0.8.27;
3+
4+
import { ISubgraphService } from "./interfaces/ISubgraphService.sol";
5+
6+
contract Decoder {
7+
function decodeCollectIndexingFeeData(
8+
bytes calldata data
9+
) external pure returns (ISubgraphService.IndexingAgreementKey memory, bytes memory) {
10+
return abi.decode(data, (ISubgraphService.IndexingAgreementKey, bytes));
11+
}
12+
13+
/**
14+
* @notice Decodes the indexing agreement metadata.
15+
*
16+
* @param data The data to decode. See {ISubgraphService.RCVIndexingAgreementMetadata}
17+
* @return The decoded data
18+
*/
19+
function decodeRCVMetadata(
20+
bytes calldata data
21+
) external pure returns (ISubgraphService.RCVIndexingAgreementMetadata memory) {
22+
return abi.decode(data, (ISubgraphService.RCVIndexingAgreementMetadata));
23+
}
24+
25+
function decodeCollectIndexingFeeDataV1(bytes memory data) external pure returns (uint256 entities, bytes32 poi) {
26+
return abi.decode(data, (uint256, bytes32));
27+
}
28+
29+
function decodeAcceptIndexingAgreementTermsV1(
30+
bytes memory data
31+
) external pure returns (ISubgraphService.IndexingAgreementTermsV1 memory) {
32+
return abi.decode(data, (ISubgraphService.IndexingAgreementTermsV1));
33+
}
34+
35+
function _decodeCollectIndexingFeeData(
36+
bytes memory _data
37+
) internal view returns (ISubgraphService.IndexingAgreementKey memory, bytes memory) {
38+
try this.decodeCollectIndexingFeeData(_data) returns (
39+
ISubgraphService.IndexingAgreementKey memory key,
40+
bytes memory data
41+
) {
42+
return (key, data);
43+
} catch {
44+
revert ISubgraphService.SubgraphServiceInvalidCollectIndexingFeeData(_data);
45+
}
46+
}
47+
48+
function _decodeRCVMetadata(
49+
bytes memory _data
50+
) internal view returns (ISubgraphService.RCVIndexingAgreementMetadata memory) {
51+
try this.decodeRCVMetadata(_data) returns (ISubgraphService.RCVIndexingAgreementMetadata memory metadata) {
52+
return metadata;
53+
} catch {
54+
revert ISubgraphService.SubgraphServiceInvalidRCVMetadata(_data);
55+
}
56+
}
57+
58+
function _decodeCollectIndexingFeeDataV1(bytes memory _data) internal view returns (uint256, bytes32) {
59+
try this.decodeCollectIndexingFeeDataV1(_data) returns (uint256 entities, bytes32 poi) {
60+
return (entities, poi);
61+
} catch {
62+
revert ISubgraphService.SubgraphServiceInvalidCollectIndexingFeeV1Data(_data);
63+
}
64+
}
65+
66+
function _decodeAcceptIndexingAgreementTermsV1(
67+
bytes memory _data
68+
) internal view returns (ISubgraphService.IndexingAgreementTermsV1 memory) {
69+
try this.decodeAcceptIndexingAgreementTermsV1(_data) returns (
70+
ISubgraphService.IndexingAgreementTermsV1 memory terms
71+
) {
72+
return terms;
73+
} catch {
74+
revert ISubgraphService.SubgraphServiceInvalidAcceptIndexingAgreementTermsV1(_data);
75+
}
76+
}
77+
}

packages/subgraph-service/contracts/DisputeManager.sol

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -130,7 +130,7 @@ contract DisputeManager is
130130
}
131131

132132
/// @inheritdoc IDisputeManager
133-
function createIndexingFeeDispute(
133+
function createIndexingFeeDisputeV1(
134134
ISubgraphService.IndexingAgreementKey calldata agreementKey,
135135
bytes32 poi,
136136
uint256 entities
@@ -139,7 +139,7 @@ contract DisputeManager is
139139
_graphToken().pullTokens(msg.sender, disputeDeposit);
140140

141141
// Create a dispute
142-
return _createIndexingFeeDisputeWithAgreement(msg.sender, disputeDeposit, agreementKey, poi, entities);
142+
return _createIndexingFeeDisputeV1(msg.sender, disputeDeposit, agreementKey, poi, entities);
143143
}
144144

145145
/// @inheritdoc IDisputeManager
@@ -464,15 +464,15 @@ contract DisputeManager is
464464
}
465465

466466
/**
467-
* @notice Create indexing fee dispute internal function.
467+
* @notice Create indexing fee (version 1) dispute internal function.
468468
* @param _fisherman The fisherman creating the dispute
469469
* @param _deposit Amount of tokens staked as deposit
470470
* @param _key The indexing agreement key
471471
* @param _poi The POI being disputed
472472
* @param _entities The number of entities disputed
473473
* @return The dispute id
474474
*/
475-
function _createIndexingFeeDisputeWithAgreement(
475+
function _createIndexingFeeDisputeV1(
476476
address _fisherman,
477477
uint256 _deposit,
478478
ISubgraphService.IndexingAgreementKey calldata _key,
@@ -494,9 +494,13 @@ contract DisputeManager is
494494
// Only one dispute at a time
495495
require(!isDisputeCreated(disputeId), DisputeManagerDisputeAlreadyCreated(disputeId));
496496

497-
// Agreement must have been collected on
497+
// Agreement must have been collected on and be a version 1
498498
ISubgraphService.IndexingAgreementData memory agreement = _getSubgraphService().getIndexingAgreement(_key);
499499
require(agreement.lastCollectionAt > 0, DisputeManagerIndexingAgreementNotDisputable(_key));
500+
require(
501+
agreement.version == ISubgraphService.IndexingAgreementVersion.V1,
502+
DisputeManagerIndexingAgreementInvalidVersion(agreement.version)
503+
);
500504

501505
// The indexer must be disputable
502506
IHorizonStaking.Provision memory provision = _graphStaking().getProvision(

packages/subgraph-service/contracts/SubgraphService.sol

Lines changed: 57 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ import { DataServiceFees } from "@graphprotocol/horizon/contracts/data-service/e
1717
import { Directory } from "./utilities/Directory.sol";
1818
import { AllocationManager } from "./utilities/AllocationManager.sol";
1919
import { SubgraphServiceV1Storage } from "./SubgraphServiceStorage.sol";
20+
import { Decoder } from "./Decoder.sol";
2021

2122
import { TokenUtils } from "@graphprotocol/contracts/contracts/utils/TokenUtils.sol";
2223
import { PPMMath } from "@graphprotocol/horizon/contracts/libraries/PPMMath.sol";
@@ -40,6 +41,7 @@ contract SubgraphService is
4041
Directory,
4142
AllocationManager,
4243
SubgraphServiceV1Storage,
44+
Decoder,
4345
IRewardsIssuer,
4446
ISubgraphService
4547
{
@@ -288,11 +290,9 @@ contract SubgraphService is
288290
);
289291
paymentCollected = _collectIndexingRewards(allocationId, poi, _delegationRatio);
290292
} else if (paymentType == IGraphPayments.PaymentTypes.IndexingFee) {
291-
(IndexingAgreementKey memory key, uint256 entities, bytes32 poi) = abi.decode(
292-
data,
293-
(IndexingAgreementKey, uint256, bytes32)
294-
);
295-
paymentCollected = _collectIndexingFees(key, entities, poi);
293+
(IndexingAgreementKey memory key, bytes memory iaCollectionData) = _decodeCollectIndexingFeeData(data);
294+
295+
paymentCollected = _collectIndexingFees(key, iaCollectionData);
296296
} else {
297297
revert SubgraphServiceInvalidPaymentType(paymentType);
298298
}
@@ -555,6 +555,10 @@ contract SubgraphService is
555555
mapping(address indexer => mapping(address payer => mapping(bytes16 agreementId => IndexingAgreementData data)))
556556
public indexingAgreements;
557557

558+
/// @notice Tracks indexing agreements parameters (V1)
559+
mapping(address indexer => mapping(address payer => mapping(bytes16 agreementId => IndexingAgreementTermsV1 data)))
560+
public indexingAgreementTermsV1;
561+
558562
/// @notice Lookup agreement key by allocation ID
559563
mapping(address allocationId => IndexingAgreementKey key) public allocationToActiveAgreementKey;
560564

@@ -572,7 +576,7 @@ contract SubgraphService is
572576
* - Agreement must not have been accepted before
573577
* - Allocation must not have an agreement already
574578
*
575-
* @dev signedRCV.rcv.metadata is an encoding of {ISubgraphService.RCVMetadata}
579+
* @dev signedRCV.rcv.metadata is an encoding of {ISubgraphService.RCVIndexingAgreementMetadata}
576580
*
577581
* Emits {IndexingAgreementAccepted} event
578582
*
@@ -594,22 +598,17 @@ contract SubgraphService is
594598
SubgraphServiceIndexingAgreementDataServiceMismatch(signedRCV.rcv.dataService)
595599
);
596600

597-
RCVMetadata memory metadata;
598-
try this.decodeRCVMetadata(signedRCV.rcv.metadata) returns (RCVMetadata memory decoded) {
599-
metadata = decoded;
600-
_acceptIndexingAgreement(allocationId, signedRCV, decoded);
601-
} catch {
602-
revert SubgraphServiceInvalidRCVMetadata(signedRCV.rcv.metadata);
603-
}
601+
RCVIndexingAgreementMetadata memory metadata = _decodeRCVMetadata(signedRCV.rcv.metadata);
602+
_acceptIndexingAgreement(allocationId, signedRCV, metadata);
604603

605604
emit IndexingAgreementAccepted(
606605
signedRCV.rcv.serviceProvider,
607606
signedRCV.rcv.payer,
608607
signedRCV.rcv.agreementId,
609608
allocationId,
610609
metadata.subgraphDeploymentId,
611-
metadata.tokensPerSecond,
612-
metadata.tokensPerEntityPerSecond
610+
metadata.version,
611+
metadata.terms
613612
);
614613
}
615614

@@ -681,16 +680,6 @@ contract SubgraphService is
681680
return indexingAgreements[key.indexer][key.payer][key.agreementId];
682681
}
683682

684-
/**
685-
* @notice Decodes the indexing agreement metadata.
686-
*
687-
* @param metadata The metadata to decode. See {ISubgraphService.RCVMetadata}
688-
* @return The decoded metadata
689-
*/
690-
function decodeRCVMetadata(bytes calldata metadata) public pure returns (RCVMetadata memory) {
691-
return abi.decode(metadata, (RCVMetadata));
692-
}
693-
694683
/**
695684
* @notice Collect Indexing fees
696685
* Stake equal to the amount being collected times the `stakeToFeesRatio` is locked into a stake claim.
@@ -709,53 +698,54 @@ contract SubgraphService is
709698
*
710699
* Emits a {StakeClaimsReleased} event, and a {StakeClaimReleased} event for each claim released.
711700
* Emits a {StakeClaimLocked} event.
712-
* Emits a {IndexingFeesCollected} event.
701+
* Emits a {IndexingFeesCollectedV1} event.
713702
*
714703
* @param _key The indexing agreement key
715-
* @param _entities The number of entities indexed
716-
* @param _poi The proof of indexing
704+
* @param _data The indexing agreement collection data
717705
* @return The amount of fees collected
718706
*/
719-
function _collectIndexingFees(
720-
IndexingAgreementKey memory _key,
721-
uint256 _entities,
722-
bytes32 _poi
723-
) private returns (uint256) {
707+
function _collectIndexingFees(IndexingAgreementKey memory _key, bytes memory _data) private returns (uint256) {
724708
IndexingAgreementData memory agreement = _requireActiveIndexingAgreement(_key);
725709
Allocation.State memory allocation = _requireValidAllocation(agreement.allocationId, _key.indexer);
726710

711+
require(
712+
agreement.version == IndexingAgreementVersion.V1,
713+
SubgraphServiceInvalidIndexingAgreementVersion(agreement.version)
714+
);
715+
(uint256 entities, bytes32 poi) = _decodeCollectIndexingFeeDataV1(_data);
716+
727717
uint256 tokensCollected = _indexingAgreementCollect(
728718
_key,
729719
bytes32(uint256(uint160(agreement.allocationId))),
730-
_indexingAgreementTokensToCollect(_key, _entities)
720+
_indexingAgreementTokensToCollect(_key, entities)
731721
);
732722

733723
_releaseAndLockStake(_key.indexer, tokensCollected);
734724

735-
emit IndexingFeesCollected(
725+
emit IndexingFeesCollectedV1(
736726
_key.indexer,
737727
_key.payer,
738728
_key.agreementId,
739729
agreement.allocationId,
740730
allocation.subgraphDeploymentId,
741731
_graphEpochManager().currentEpoch(),
742732
tokensCollected,
743-
_entities,
744-
_poi
733+
entities,
734+
poi
745735
);
746736
return tokensCollected;
747737
}
748738

749739
function _acceptIndexingAgreement(
750740
address _allocationId,
751741
IRecurringCollector.SignedRCV calldata _signedRCV,
752-
RCVMetadata memory _metadata
742+
RCVIndexingAgreementMetadata memory _agreementMetadata
753743
) private {
754744
Allocation.State memory allocation = _requireValidAllocation(_allocationId, _signedRCV.rcv.serviceProvider);
755745
require(
756-
allocation.subgraphDeploymentId == _metadata.subgraphDeploymentId,
746+
allocation.subgraphDeploymentId == _agreementMetadata.subgraphDeploymentId,
757747
SubgraphServiceIndexingAgreementDeploymentIdMismatch(
758-
_metadata.subgraphDeploymentId,
748+
_agreementMetadata.subgraphDeploymentId,
759749
_allocationId,
760750
allocation.subgraphDeploymentId
761751
)
@@ -776,25 +766,37 @@ contract SubgraphService is
776766
allocationToActiveAgreementKey[_allocationId] = key;
777767

778768
agreement.allocationId = _allocationId;
779-
agreement.tokensPerSecond = _metadata.tokensPerSecond;
780-
agreement.tokensPerEntityPerSecond = _metadata.tokensPerEntityPerSecond;
781769
agreement.acceptedAt = block.timestamp;
782770

771+
require(
772+
_agreementMetadata.version == IndexingAgreementVersion.V1,
773+
SubgraphServiceInvalidIndexingAgreementVersion(_agreementMetadata.version)
774+
);
775+
_acceptIndexingAgreementTermsV1(key, _agreementMetadata.terms);
776+
783777
_recurringCollector().accept(_signedRCV);
784778
}
785779

780+
function _acceptIndexingAgreementTermsV1(IndexingAgreementKey memory _key, bytes memory _data) private {
781+
IndexingAgreementTermsV1 memory agreementTermsV1 = _decodeAcceptIndexingAgreementTermsV1(_data);
782+
IndexingAgreementTermsV1 storage termsV1 = _getForUpdateIndexingAgreementTermsV1(_key);
783+
termsV1.tokensPerSecond = agreementTermsV1.tokensPerSecond;
784+
termsV1.tokensPerEntityPerSecond = agreementTermsV1.tokensPerEntityPerSecond;
785+
}
786+
786787
function _indexingAgreementTokensToCollect(
787788
IndexingAgreementKey memory _key,
788789
uint256 _entities
789790
) private returns (uint256) {
790791
IndexingAgreementData storage agreement = _getForUpdateIndexingAgreement(_key);
792+
IndexingAgreementTermsV1 memory termsV1 = _getIndexingAgreementTermsV1(_key);
791793

792794
uint256 collectionSeconds = block.timestamp;
793795
collectionSeconds -= agreement.lastCollectionAt > 0 ? agreement.lastCollectionAt : agreement.acceptedAt;
794796
agreement.lastCollectionAt = block.timestamp;
795797

796798
// FIX-ME: this is bad because it encourages people to collect at max seconds allowed to maximize collection.
797-
return collectionSeconds * (agreement.tokensPerSecond + agreement.tokensPerEntityPerSecond * _entities);
799+
return collectionSeconds * (termsV1.tokensPerSecond + termsV1.tokensPerEntityPerSecond * _entities);
798800
}
799801

800802
function _indexingAgreementCollect(
@@ -851,6 +853,18 @@ contract SubgraphService is
851853
return indexingAgreements[_key.indexer][_key.payer][_key.agreementId];
852854
}
853855

856+
function _getForUpdateIndexingAgreementTermsV1(
857+
IndexingAgreementKey memory _key
858+
) private view returns (IndexingAgreementTermsV1 storage) {
859+
return indexingAgreementTermsV1[_key.indexer][_key.payer][_key.agreementId];
860+
}
861+
862+
function _getIndexingAgreementTermsV1(
863+
IndexingAgreementKey memory _key
864+
) private view returns (IndexingAgreementTermsV1 memory) {
865+
return indexingAgreementTermsV1[_key.indexer][_key.payer][_key.agreementId];
866+
}
867+
854868
function _requireValidAllocation(
855869
address _allocationId,
856870
address _indexer

packages/subgraph-service/contracts/interfaces/IDisputeManager.sol

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -353,9 +353,16 @@ interface IDisputeManager {
353353

354354
/**
355355
* @notice Thrown when the Indexing Agreement is not disputable
356+
* @param agreementKey The indexing agreement key
356357
*/
357358
error DisputeManagerIndexingAgreementNotDisputable(ISubgraphService.IndexingAgreementKey agreementKey);
358359

360+
/**
361+
* @notice Thrown when the Indexing Agreement is not disputable
362+
* @param version The indexing agreement version
363+
*/
364+
error DisputeManagerIndexingAgreementInvalidVersion(ISubgraphService.IndexingAgreementVersion version);
365+
359366
/**
360367
* @notice Initialize this contract.
361368
* @param owner The owner of the contract
@@ -469,8 +476,8 @@ interface IDisputeManager {
469476
function createIndexingDispute(address allocationId, bytes32 poi) external returns (bytes32);
470477

471478
/**
472-
* @notice Create an indexing fee dispute for the arbitrator to resolve.
473-
* The disputes are created in reference to an indexing agreement and specifically
479+
* @notice Create an indexing fee (version 1) dispute for the arbitrator to resolve.
480+
* The disputes are created in reference to a version 1 indexing agreement and specifically
474481
* a POI and entities provided when collecting that agreement.
475482
* This function is called by a fisherman and it will pull `disputeDeposit` GRT tokens.
476483
*
@@ -483,7 +490,7 @@ interface IDisputeManager {
483490
* @param entities The number of entities disputed
484491
* @return The dispute id
485492
*/
486-
function createIndexingFeeDispute(
493+
function createIndexingFeeDisputeV1(
487494
ISubgraphService.IndexingAgreementKey calldata agreementKey,
488495
bytes32 poi,
489496
uint256 entities

0 commit comments

Comments
 (0)