Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit ae910c4

Browse files
f: add createIndexingFeeDispute to DisputeManager
1 parent a2fe023 commit ae910c4

File tree

6 files changed

+146
-1
lines changed

6 files changed

+146
-1
lines changed

‎IndexingPaymentsTodo.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
### Still pending
22

33
* Make `agreementId` unique globally so that we don't need the full tuple (`payer`+`indexer`+`agreementId`) as key?
4+
* Reverse name of `SubgraphServiceIndexingAgreementAlreadyAllocated`?
45
* Update `DisputeManager` and Arbitration Charter to support disputing Indexing Fees.
56
* Support indexing agreement upgadeability, so that there is a mechanism to adjust the rates without having to cancel and start over.
67
* Built-in upgrade path to indexing agreements v2. So that indexers can be paid per byte instead of per entity.

‎packages/subgraph-service/contracts/DisputeManager.sol

Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -129,6 +129,19 @@ contract DisputeManager is
129129
return _createIndexingDisputeWithAllocation(msg.sender, disputeDeposit, allocationId, poi);
130130
}
131131

132+
/// @inheritdoc IDisputeManager
133+
function createIndexingFeeDispute(
134+
ISubgraphService.IndexingAgreementKey calldata agreementKey,
135+
bytes32 poi,
136+
uint256 entities
137+
) external override returns (bytes32) {
138+
// Get funds from fisherman
139+
_graphToken().pullTokens(msg.sender, disputeDeposit);
140+
141+
// Create a dispute
142+
return _createIndexingFeeDisputeWithAgreement(msg.sender, disputeDeposit, agreementKey, poi, entities);
143+
}
144+
132145
/// @inheritdoc IDisputeManager
133146
function createQueryDispute(bytes calldata attestationData) external override returns (bytes32) {
134147
// Get funds from fisherman
@@ -450,6 +463,75 @@ contract DisputeManager is
450463
return disputeId;
451464
}
452465

466+
/**
467+
* @notice Create indexing fee dispute internal function.
468+
* @param _fisherman The fisherman creating the dispute
469+
* @param _deposit Amount of tokens staked as deposit
470+
* @param _key The indexing agreement key
471+
* @param _poi The POI being disputed
472+
* @param _entities The number of entities disputed
473+
* @return The dispute id
474+
*/
475+
function _createIndexingFeeDisputeWithAgreement(
476+
address _fisherman,
477+
uint256 _deposit,
478+
ISubgraphService.IndexingAgreementKey calldata _key,
479+
bytes32 _poi,
480+
uint256 _entities
481+
) private returns (bytes32) {
482+
// Create a disputeId
483+
bytes32 disputeId = keccak256(
484+
abi.encodePacked(
485+
"IndexingFeeDisputeWithAgreement",
486+
_key.agreementId,
487+
_key.indexer,
488+
_key.payer,
489+
_poi,
490+
_entities
491+
)
492+
);
493+
494+
// Only one dispute at a time
495+
require(!isDisputeCreated(disputeId), DisputeManagerDisputeAlreadyCreated(disputeId));
496+
497+
// Agreement must have been collected on
498+
ISubgraphService.IndexingAgreementData memory agreement = _getSubgraphService().getIndexingAgreement(_key);
499+
require(agreement.lastCollectionAt > 0, DisputeManagerIndexingAgreementNotDisputable(_key));
500+
501+
// The indexer must be disputable
502+
IHorizonStaking.Provision memory provision = _graphStaking().getProvision(
503+
_key.indexer,
504+
address(_getSubgraphService())
505+
);
506+
require(provision.tokens != 0, DisputeManagerZeroTokens());
507+
508+
uint256 stakeSnapshot = _getStakeSnapshot(_key.indexer, provision.tokens);
509+
disputes[disputeId] = Dispute(
510+
_key.indexer,
511+
_fisherman,
512+
_deposit,
513+
0, // no related dispute,
514+
DisputeType.IndexingFeeDispute,
515+
IDisputeManager.DisputeStatus.Pending,
516+
block.timestamp,
517+
stakeSnapshot
518+
);
519+
520+
emit IndexingFeeDisputeCreated(
521+
disputeId,
522+
_key.indexer,
523+
_fisherman,
524+
_deposit,
525+
_key.payer,
526+
_key.agreementId,
527+
_poi,
528+
_entities,
529+
stakeSnapshot
530+
);
531+
532+
return disputeId;
533+
}
534+
453535
/**
454536
* @notice Accept a dispute
455537
* @param _disputeId The id of the dispute

‎packages/subgraph-service/contracts/SubgraphService.sol

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -675,6 +675,12 @@ contract SubgraphService is
675675
emit IndexingAgreementCanceled(indexer, payer, agreementId, payer);
676676
}
677677

678+
function getIndexingAgreement(
679+
IndexingAgreementKey memory key
680+
) external view returns (IndexingAgreementData memory) {
681+
return indexingAgreements[key.indexer][key.payer][key.agreementId];
682+
}
683+
678684
/**
679685
* @notice Decodes the indexing agreement metadata.
680686
*

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

Lines changed: 54 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
pragma solidity 0.8.27;
44

55
import { Attestation } from "../libraries/Attestation.sol";
6+
import { ISubgraphService } from "./ISubgraphService.sol";
67

78
/**
89
* @title IDisputeManager
@@ -15,7 +16,8 @@ interface IDisputeManager {
1516
enum DisputeType {
1617
Null,
1718
IndexingDispute,
18-
QueryDispute
19+
QueryDispute,
20+
IndexingFeeDispute
1921
}
2022

2123
/// @notice Status of a dispute
@@ -108,6 +110,31 @@ interface IDisputeManager {
108110
uint256 stakeSnapshot
109111
);
110112

113+
/**
114+
* @dev Emitted when an indexing fee dispute is created for `agreementId` and `indexer`
115+
* by `fisherman`.
116+
* The event emits the amount of `tokens` deposited by the fisherman.
117+
* @param disputeId The dispute id
118+
* @param indexer The indexer address
119+
* @param fisherman The fisherman address
120+
* @param tokens The amount of tokens deposited by the fisherman
121+
* @param agreementId The agreement id
122+
* @param poi The POI disputed
123+
* @param entities The entities disputed
124+
* @param stakeSnapshot The stake snapshot of the indexer at the time of the dispute
125+
*/
126+
event IndexingFeeDisputeCreated(
127+
bytes32 indexed disputeId,
128+
address indexed indexer,
129+
address indexed fisherman,
130+
uint256 tokens,
131+
address payer,
132+
bytes16 agreementId,
133+
bytes32 poi,
134+
uint256 entities,
135+
uint256 stakeSnapshot
136+
);
137+
111138
/**
112139
* @dev Emitted when an indexing dispute is created for `allocationId` and `indexer`
113140
* by `fisherman`.
@@ -324,6 +351,11 @@ interface IDisputeManager {
324351
*/
325352
error DisputeManagerSubgraphServiceNotSet();
326353

354+
/**
355+
* @notice Thrown when the Indexing Agreement is not disputable
356+
*/
357+
error DisputeManagerIndexingAgreementNotDisputable(ISubgraphService.IndexingAgreementKey agreementKey);
358+
327359
/**
328360
* @notice Initialize this contract.
329361
* @param owner The owner of the contract
@@ -436,6 +468,27 @@ interface IDisputeManager {
436468
*/
437469
function createIndexingDispute(address allocationId, bytes32 poi) external returns (bytes32);
438470

471+
/**
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
474+
* a POI and entities provided when collecting that agreement.
475+
* This function is called by a fisherman and it will pull `disputeDeposit` GRT tokens.
476+
*
477+
* Requirements:
478+
* - fisherman must have previously approved this contract to pull `disputeDeposit` amount
479+
* of tokens from their balance.
480+
*
481+
* @param agreementKey The indexing agreement key to dispute
482+
* @param poi The Proof of Indexing (POI) being disputed
483+
* @param entities The number of entities disputed
484+
* @return The dispute id
485+
*/
486+
function createIndexingFeeDispute(
487+
ISubgraphService.IndexingAgreementKey calldata agreementKey,
488+
bytes32 poi,
489+
uint256 entities
490+
) external returns (bytes32);
491+
439492
// -- Arbitrator --
440493

441494
/**

‎packages/subgraph-service/contracts/interfaces/ISubgraphService.sol

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -455,4 +455,6 @@ interface ISubgraphService is IDataServiceFees {
455455
* @notice Cancel an indexing agreement by payer / signer.
456456
*/
457457
function cancelIndexingAgreementByPayer(address indexer, address payer, bytes16 agreementId) external;
458+
459+
function getIndexingAgreement(IndexingAgreementKey memory key) external view returns (IndexingAgreementData memory);
458460
}

‎packages/subgraph-service/test/subgraphService/indexing-agreement/integration.t.sol

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,7 @@ contract SubgraphServiceIndexingAgreementCancelTest is SubgraphServiceIndexingAg
4848
TestIndexerParams memory params = _setupIndexer(fuzzyParams, expectedTokensLocked);
4949

5050
uint256 signerPrivateKey = boundKey(unboundedSignerPrivateKey);
51+
vm.assume(fuzzyRCV.payer != address(0));
5152
_setupPayerWithEscrow(fuzzyRCV.payer, signerPrivateKey, params.indexer, expectedTotalTokensCollected);
5253

5354
uint256 agreementTokensPerSecond = 1;

0 commit comments

Comments
(0)

AltStyle によって変換されたページ (->オリジナル) /