Skip to content

feat: indexing fees / dips (wip) #1091

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 7 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
27 changes: 27 additions & 0 deletions packages/indexer-agent/src/commands/start.ts
Original file line number Diff line number Diff line change
Expand Up @@ -302,6 +302,26 @@ export const start = {
default: 1,
group: 'Indexer Infrastructure',
})
.option('enable-dips', {
description: 'Whether to enable Indexing Fees (DIPs)',
type: 'boolean',
default: false,
group: 'Indexing Fees ("DIPs")',
})
.option('dipper-endpoint', {
description: 'Gateway endpoint for DIPs receipts',
type: 'string',
array: false,
required: false,
group: 'Indexing Fees ("DIPs")',
})
.option('dips-allocation-amount', {
description: 'Amount of GRT to allocate for DIPs',
type: 'number',
default: 1,
required: false,
group: 'Indexing Fees ("DIPs")',
})
.check(argv => {
if (
!argv['network-subgraph-endpoint'] &&
Expand Down Expand Up @@ -329,6 +349,9 @@ export const start = {
) {
return 'Invalid --rebate-claim-max-batch-size provided. Must be > 0 and an integer.'
}
if (argv['enable-dips'] && !argv['dipper-endpoint']) {
return 'Invalid --dipper-endpoint provided. Must be provided when --enable-dips is true.'
}
return true
})
},
Expand Down Expand Up @@ -364,6 +387,10 @@ export async function createNetworkSpecification(
allocateOnNetworkSubgraph: argv.allocateOnNetworkSubgraph,
register: argv.register,
finalityTime: argv.chainFinalizeTime,
enableDips: argv.enableDips,
dipperEndpoint: argv.dipperEndpoint,
dipsAllocationAmount: argv.dipsAllocationAmount,
dipsEpochsMargin: argv.dipsEpochsMargin,
}

const transactionMonitoring = {
Expand Down
3 changes: 3 additions & 0 deletions packages/indexer-common/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,11 @@
"clean": "rm -rf ./node_modules ./dist ./tsconfig.tsbuildinfo"
},
"dependencies": {
"@bufbuild/protobuf": "2.2.3",
"@graphprotocol/common-ts": "2.0.11",
"@graphprotocol/cost-model": "0.1.18",
"@graphprotocol/dips-proto": "0.2.1",
"@grpc/grpc-js": "^1.12.6",
"@semiotic-labs/tap-contracts-bindings": "^1.2.1",
"@thi.ng/heaps": "1.2.38",
"@types/lodash.clonedeep": "^4.5.7",
Expand Down
31 changes: 31 additions & 0 deletions packages/indexer-common/src/allocations/escrow-accounts.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,14 @@ export type EscrowAccountResponse = {
}[]
}

export type EscrowSenderResponse = {
signer: {
sender: {
id: string
}
}
}

export class EscrowAccounts {
constructor(private sendersBalances: Map<Address, U256>) {}

Expand Down Expand Up @@ -65,3 +73,26 @@ export const getEscrowAccounts = async (
}
return EscrowAccounts.fromResponse(result.data)
}

export const getEscrowSenderForSigner = async (
tapSubgraph: SubgraphClient,
signer: Address,
): Promise<Address> => {
const signerLower = signer.toLowerCase()
const result = await tapSubgraph.query<EscrowSenderResponse>(
gql`
query EscrowAccountQuery($signer: ID!) {
signer(id: $signer) {
sender {
id
}
}
}
`,
{ signer: signerLower },
)
if (!result.data) {
throw `There was an error while querying Tap Subgraph. Errors: ${result.error}`
}
return toAddress(result.data.signer.sender.id)
}
1 change: 1 addition & 0 deletions packages/indexer-common/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ export * from './allocations'
export * from './async-cache'
export * from './errors'
export * from './indexer-management'
export * from './indexing-fees'
export * from './graph-node'
export * from './operator'
export * from './network'
Expand Down
39 changes: 38 additions & 1 deletion packages/indexer-common/src/indexer-management/allocations.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import {
AllocationStatus,
CloseAllocationResult,
CreateAllocationResult,
DipsManager,
fetchIndexingRules,
GraphNode,
indexerError,
Expand Down Expand Up @@ -98,12 +99,23 @@ export type TransactionResult =
| ActionFailure[]

export class AllocationManager {
private dipsManager: DipsManager | null = null
constructor(
private logger: Logger,
private models: IndexerManagementModels,
private graphNode: GraphNode,
private network: Network,
) {}
) {
if (this.network.specification.indexerOptions.dipperEndpoint) {
this.dipsManager = new DipsManager(
this.logger,
this.models,
this.graphNode,
this.network,
this,
)
}
}

async executeBatch(actions: Action[]): Promise<AllocationResult[]> {
const logger = this.logger.child({ function: 'executeBatch' })
Expand Down Expand Up @@ -511,6 +523,14 @@ export class AllocationManager {
await upsertIndexingRule(logger, this.models, indexingRule)
}

if (this.dipsManager) {
await this.dipsManager.tryUpdateAgreementAllocation(
deployment,
null,
createAllocationEventLogs.allocationID,
)
}

return {
actionID,
type: 'allocate',
Expand Down Expand Up @@ -667,6 +687,15 @@ export class AllocationManager {

await upsertIndexingRule(logger, this.models, neverIndexingRule)

if (this.dipsManager) {
await this.dipsManager.tryCancelAgreement(allocationID)
await this.dipsManager.tryUpdateAgreementAllocation(
allocation.subgraphDeployment.id.toString(),
allocationID,
null,
)
}

return {
actionID,
type: 'unallocate',
Expand Down Expand Up @@ -966,6 +995,14 @@ export class AllocationManager {
await upsertIndexingRule(logger, this.models, indexingRule)
}

if (this.dipsManager) {
await this.dipsManager.tryUpdateAgreementAllocation(
subgraphDeploymentID.toString(),
allocationID,
createAllocationEventLogs.allocationID,
)
}

return {
actionID,
type: 'reallocate',
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import { IndexingRuleModels, defineIndexingRuleModels } from './indexing-rule'
import { CostModelModels, defineCostModelModels } from './cost-model'
import { POIDisputeModels, definePOIDisputeModels } from './poi-dispute'
import { ActionModels, defineActionModels } from './action'
import { defineIndexingFeesModels, IndexingFeesModels } from './indexing-agreement'

export * from './cost-model'
export * from './indexing-rule'
Expand All @@ -13,7 +14,8 @@ export * from './action'
export type IndexerManagementModels = IndexingRuleModels &
CostModelModels &
POIDisputeModels &
ActionModels
ActionModels &
IndexingFeesModels

export const defineIndexerManagementModels = (
sequelize: Sequelize,
Expand All @@ -24,4 +26,5 @@ export const defineIndexerManagementModels = (
defineIndexingRuleModels(sequelize),
definePOIDisputeModels(sequelize),
defineActionModels(sequelize),
defineIndexingFeesModels(sequelize),
)
Original file line number Diff line number Diff line change
@@ -0,0 +1,156 @@
import {
DataTypes,
Sequelize,
Model,
CreationOptional,
InferAttributes,
InferCreationAttributes,
} from 'sequelize'

// Indexing Fees AKA "DIPs"

export class IndexingAgreement extends Model<
InferAttributes<IndexingAgreement>,
InferCreationAttributes<IndexingAgreement>
> {
declare id: CreationOptional<string>
declare signature: Buffer
declare signed_payload: Buffer
declare protocol_network: string
declare chain_id: string
declare base_price_per_epoch: string
declare price_per_entity: string
declare subgraph_deployment_id: string
declare service: string
declare payee: string
declare payer: string
declare deadline: Date
declare duration_epochs: bigint
declare max_initial_amount: string
declare max_ongoing_amount_per_epoch: string
declare min_epochs_per_collection: bigint
declare max_epochs_per_collection: bigint
declare created_at: Date
declare updated_at: Date
declare cancelled_at: Date | null
declare signed_cancellation_payload: Buffer | null
declare current_allocation_id: string | null
declare last_allocation_id: string | null
declare last_payment_collected_at: Date | null
}

export interface IndexingFeesModels {
IndexingAgreement: typeof IndexingAgreement
}

export const defineIndexingFeesModels = (sequelize: Sequelize): IndexingFeesModels => {
IndexingAgreement.init(
{
id: {
type: DataTypes.UUID,
primaryKey: true,
},
signature: {
type: DataTypes.BLOB,
allowNull: false,
unique: true,
},
signed_payload: {
type: DataTypes.BLOB,
allowNull: false,
},
protocol_network: {
type: DataTypes.STRING(255),
allowNull: false,
},
chain_id: {
type: DataTypes.STRING(255),
allowNull: false,
},
base_price_per_epoch: {
type: DataTypes.DECIMAL(39),
allowNull: false,
},
price_per_entity: {
type: DataTypes.DECIMAL(39),
allowNull: false,
},
subgraph_deployment_id: {
type: DataTypes.STRING(255),
allowNull: false,
},
service: {
type: DataTypes.CHAR(40),
allowNull: false,
},
payee: {
type: DataTypes.CHAR(40),
allowNull: false,
},
payer: {
type: DataTypes.CHAR(40),
allowNull: false,
},
deadline: {
type: DataTypes.DATE,
allowNull: false,
},
duration_epochs: {
type: DataTypes.BIGINT,
allowNull: false,
},
max_initial_amount: {
type: DataTypes.DECIMAL(39),
allowNull: false,
},
max_ongoing_amount_per_epoch: {
type: DataTypes.DECIMAL(39),
allowNull: false,
},
min_epochs_per_collection: {
type: DataTypes.BIGINT,
allowNull: false,
},
max_epochs_per_collection: {
type: DataTypes.BIGINT,
allowNull: false,
},
created_at: {
type: DataTypes.DATE,
allowNull: false,
},
updated_at: {
type: DataTypes.DATE,
allowNull: false,
},
cancelled_at: {
type: DataTypes.DATE,
allowNull: true,
},
signed_cancellation_payload: {
type: DataTypes.BLOB,
allowNull: true,
},
current_allocation_id: {
type: DataTypes.CHAR(40),
allowNull: true,
},
last_allocation_id: {
type: DataTypes.CHAR(40),
allowNull: true,
},
last_payment_collected_at: {
type: DataTypes.DATE,
allowNull: true,
},
},
{
modelName: 'IndexingAgreement',
sequelize,
},
)

return {
['IndexingAgreement']: IndexingAgreement,
}
}
Loading
Loading