Skip to content

Commit

Permalink
Paro/rfq indexer updates suggs (#3243)
Browse files Browse the repository at this point in the history
* fixing terminology

* rfq-indexer-docs

* Update RFQ Indexer API Readme (#3221)

* adding dispute events to ponder and linting

* numbering typo

Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>

* small fixes

* sync with master

* API changes for disputes

* fixing pending txs missing proofs

* proof/dispute active & other tweaks/suggs

* dispute col rename originChain prefix

---------

Co-authored-by: defi-moses <[email protected]>
Co-authored-by: Moses <[email protected]>
Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
  • Loading branch information
4 people authored Oct 7, 2024
1 parent 5c3686c commit c63eb6e
Show file tree
Hide file tree
Showing 16 changed files with 346 additions and 32 deletions.
26 changes: 16 additions & 10 deletions packages/rfq-indexer/api/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,34 +6,40 @@ To make requests, use: https://triumphant-magic-production.up.railway.app , and

## API Calls

1. GET /api/hello
- Description: A simple hello world endpoint
- Example: `curl http://localhost:3001/api/hello`

2. GET /api/pending-transactions-missing-relay
All API calls can be viewed in Swagger:

[Swagger Documentation](http://localhost:3001/api-docs)

1. GET /api/pending-transactions-missing-relay
- Description: Retrieves pending transactions that are missing relay events
- Example:
```
curl http://localhost:3001/api/pending-transactions-missing-relay
curl http://localhost:3001/api/pending-transactions/missing-relay
```
3. GET /api/pending-transactions-missing-proof
2. GET /api/pending-transactions-missing-proof
- Description: Retrieves pending transactions that are missing proof events
- Example:
```
curl http://localhost:3001/api/pending-transactions-missing-proof
curl http://localhost:3001/api/pending-transactions/missing-proof
```
4. GET /api/pending-transactions-missing-claim
3. GET /api/pending-transactions-missing-claim
- Description: Retrieves pending transactions that are missing claim events
- Example:
```
curl http://localhost:3001/api/pending-transactions-missing-claim
curl http://localhost:3001/api/pending-transactions/missing-claim
```
5. GraphQL endpoint: /graphql
4. GraphQL endpoint: /graphql
- Description: Provides a GraphQL interface for querying indexed data, the user is surfaced an interface to query the data via GraphiQL
## Env Vars
- **NODE_ENV**: Set to `"development"` for localhost testing.
- **DATABASE_URL**: PostgreSQL connection URL for the ponder index.
## Important Scripts
- `yarn dev:local`: Runs the API in development mode using local environment variables
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ export const conflictingProofsController = async (
const query = db
.with('deposits', () => qDeposits())
.with('relays', () => qRelays())
.with('proofs', () => qProofs())
.with('proofs', () => qProofs({activeOnly: true}))
.with('combined', (qb) =>
qb
.selectFrom('deposits')
Expand Down Expand Up @@ -41,10 +41,10 @@ export const conflictingProofsController = async (
if (conflictingProofs && conflictingProofs.length > 0) {
res.json(conflictingProofs)
} else {
res.status(200).json({ message: 'No conflicting proofs found' })
res.status(200).json({ message: 'No active conflicting proofs found' })
}
} catch (error) {
console.error('Error fetching conflicting proofs:', error)
console.error('Error fetching active conflicting proofs:', error)
res.status(500).json({ message: 'Internal server error' })
}
}
27 changes: 27 additions & 0 deletions packages/rfq-indexer/api/src/controllers/disputesController.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
import { Request, Response } from 'express'

import { db } from '../db'
import { qDisputes } from '../queries'
import { nest_results } from '../utils/nestResults'

export const disputesController = async (req: Request, res: Response) => {
try {
const query = db
.with('disputes', () => qDisputes({activeOnly: true}))
.selectFrom('disputes')
.selectAll()
.orderBy('blockTimestamp_dispute', 'desc')

const results = await query.execute()
const disputes = nest_results(results)

if (disputes && disputes.length > 0) {
res.json(disputes)
} else {
res.status(200).json({ message: 'No active disputes found' })
}
} catch (error) {
console.error('Error fetching active disputes:', error)
res.status(500).json({ message: 'Internal server error' })
}
}
Original file line number Diff line number Diff line change
@@ -1,9 +1,18 @@
import { Request, Response } from 'express'

import { db } from '../db'
import { qDeposits, qRelays, qProofs, qClaims, qRefunds } from '../queries'
import {
qDeposits,
qRelays,
qProofs,
qClaims,
qRefunds,
qDisputes,
} from '../queries'
import { nest_results } from '../utils/nestResults'

const sevenDaysAgo = Math.floor(Date.now() / 1000) - 7 * 24 * 60 * 60

export const pendingTransactionsMissingClaimController = async (
req: Request,
res: Response
Expand All @@ -12,7 +21,7 @@ export const pendingTransactionsMissingClaimController = async (
const query = db
.with('deposits', () => qDeposits())
.with('relays', () => qRelays())
.with('proofs', () => qProofs())
.with('proofs', () => qProofs({activeOnly: true}))
.with('claims', () => qClaims())
.with('combined', (qb) =>
qb
Expand Down Expand Up @@ -45,7 +54,6 @@ export const pendingTransactionsMissingClaimController = async (
}
}


export const pendingTransactionsMissingProofController = async (
req: Request,
res: Response
Expand All @@ -54,7 +62,7 @@ export const pendingTransactionsMissingProofController = async (
const query = db
.with('deposits', () => qDeposits())
.with('relays', () => qRelays())
.with('proofs', () => qProofs())
.with('proofs', () => qProofs({activeOnly: true}))
.with('combined', (qb) =>
qb
.selectFrom('deposits')
Expand Down Expand Up @@ -111,6 +119,52 @@ export const pendingTransactionsMissingRelayController = async (
.selectFrom('combined')
.selectAll()
.orderBy('blockTimestamp_deposit', 'desc')
.where('blockTimestamp_deposit', '>', sevenDaysAgo)

const results = await query.execute()
const nestedResults = nest_results(results)

if (nestedResults && nestedResults.length > 0) {
res.json(nestedResults)
} else {
res
.status(404)
.json({ message: 'No pending transactions missing relay found' })
}
} catch (error) {
console.error('Error fetching pending transactions missing relay:', error)
res.status(500).json({ message: 'Internal server error' })
}
}

export const pendingTransactionsMissingRelayExceedDeadlineController = async (
req: Request,
res: Response
) => {
try {
const query = db
.with('deposits', () => qDeposits())
.with('relays', () => qRelays())
.with('refunds', () => qRefunds())
.with(
'combined',
(qb) =>
qb
.selectFrom('deposits')
.selectAll('deposits')
.leftJoin('relays', 'transactionId_deposit', 'transactionId_relay')
.leftJoin(
'refunds',
'transactionId_deposit',
'transactionId_refund'
)
.where('transactionId_relay', 'is', null) // is not relayed
.where('transactionId_refund', 'is', null) // is not refunded
)
.selectFrom('combined')
.selectAll()
.orderBy('blockTimestamp_deposit', 'desc')
.where('blockTimestamp_deposit', '<=', sevenDaysAgo)

const results = await query.execute()
const nestedResults = nest_results(results)
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { Request, Response } from 'express'

import { db } from '../db'
import { qDeposits, qRelays, qProofs, qClaims, qRefunds } from '../queries'
import { qDeposits, qRelays, qProofs, qClaims, qRefunds, qDisputes } from '../queries'
import { nest_results } from '../utils/nestResults'

export const getTransactionById = async (req: Request, res: Response) => {
Expand All @@ -13,19 +13,22 @@ export const getTransactionById = async (req: Request, res: Response) => {
qDeposits().where('transactionId', '=', transactionId as string)
)
.with('relays', () => qRelays())
.with('proofs', () => qProofs())
.with('proofs', () => qProofs({activeOnly: false})) // display proofs even if they have been invalidated/replaced by a dispute
.with('disputes', () => qDisputes({activeOnly: true})) // do not show disputes that have been invalidated/replaced by a proof
.with('claims', () => qClaims())
.with('refunds', () => qRefunds())
.with('combined', (qb) =>
qb
.selectFrom('deposits')
.leftJoin('relays', 'transactionId_deposit', 'transactionId_relay')
.leftJoin('proofs', 'transactionId_deposit', 'transactionId_proof')
.leftJoin('disputes', 'transactionId_deposit', 'transactionId_dispute')
.leftJoin('claims', 'transactionId_deposit', 'transactionId_claim')
.leftJoin('refunds', 'transactionId_deposit', 'transactionId_refund')
.selectAll('deposits')
.selectAll('relays')
.selectAll('proofs')
.selectAll('disputes')
.selectAll('claims')
.selectAll('refunds')
)
Expand Down
2 changes: 2 additions & 0 deletions packages/rfq-indexer/api/src/db/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import type {
BridgeProofProvidedEvents,
BridgeDepositRefundedEvents,
BridgeDepositClaimedEvents,
BridgeProofDisputedEvents,
} from '../types'

const { DATABASE_URL } = process.env
Expand All @@ -21,6 +22,7 @@ export interface Database {
BridgeProofProvidedEvents: BridgeProofProvidedEvents
BridgeDepositRefundedEvents: BridgeDepositRefundedEvents
BridgeDepositClaimedEvents: BridgeDepositClaimedEvents
BridgeProofDisputedEvents: BridgeProofDisputedEvents
}

export const db = new Kysely<Database>({ dialect })
7 changes: 7 additions & 0 deletions packages/rfq-indexer/api/src/graphql/queries/queries.graphql
Original file line number Diff line number Diff line change
Expand Up @@ -112,14 +112,21 @@ type ConflictingProof {
BridgeProof: Proof!
}

type DisputedRelay {
Bridge: Transaction!
BridgeProof: Proof!
}

type Query {
pendingTransactionsMissingRelay: [PendingTransactionMissingRelay!]!
pendingTransactionsMissingRelayExceedDeadline: [PendingTransactionMissingRelay!]!
pendingTransactionsMissingProof: [PendingTransactionMissingProof!]!
pendingTransactionsMissingClaim: [PendingTransactionMissingClaim!]!
transactionById(transactionId: String!): [CompleteTransaction!]!
recentInvalidRelays: [InvalidRelay!]!
refundedAndRelayedTransactions: [RefundedAndRelayedTransaction!]!
conflictingProofs: [ConflictingProof!]!
disputedRelays: [DisputedRelay!]!
}


50 changes: 50 additions & 0 deletions packages/rfq-indexer/api/src/graphql/resolvers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,20 @@ const qRefunds = () => {
])
}

// typical fields to return for a BridgeProofDisputed event when it is joined to a BridgeRequest
const qDisputes = () => {
return db
.selectFrom('BridgeProofDisputedEvents')
.select([
'BridgeProofDisputedEvents.transactionId as transactionId_dispute',
'BridgeProofDisputedEvents.blockNumber as blockNumber_dispute',
'BridgeProofDisputedEvents.blockTimestamp as blockTimestamp_dispute',
'BridgeProofDisputedEvents.transactionHash as transactionHash_dispute',
'BridgeProofDisputedEvents.originChainId as originChainId_dispute',
'BridgeProofDisputedEvents.originChain as originChain_dispute',
])
}

// using the suffix of a field, move it into a nested sub-object. This is a cleaner final resultset
// example: transactionHash_deposit:0xyz would get moved into BridgeRequest{transactionHash:0xyz}
//
Expand Down Expand Up @@ -220,6 +234,19 @@ const resolvers = {
'BridgeDepositClaimedEvents.originChain',
])
)
.unionAll(
db
.selectFrom('BridgeProofDisputedEvents')
.select([
'BridgeProofDisputedEvents.id',
'BridgeProofDisputedEvents.transactionId',
'BridgeProofDisputedEvents.blockNumber',
'BridgeProofDisputedEvents.blockTimestamp',
'BridgeProofDisputedEvents.transactionHash',
'BridgeProofDisputedEvents.originChainId',
'BridgeProofDisputedEvents.originChain',
])
)

if (filter) {
if (filter.transactionId) {
Expand Down Expand Up @@ -466,6 +493,29 @@ const resolvers = {

return nest_results(await query.execute())
},
disputedRelays: async () => {
const query = db
.with('deposits', () => qDeposits())
.with('relays', () => qRelays())
.with('proofs', () => qProofs())
.with('disputes', () => qDisputes())
.with('combined', (qb) =>
qb
.selectFrom('proofs')
.leftJoin(
'disputes',
'transactionId_proof',
'transactionId_dispute'
)
.selectAll('proofs')
.selectAll('disputes')
)
.selectFrom('combined')
.selectAll()
.orderBy('blockTimestamp_proof', 'desc')

return nest_results(await query.execute())
},
},
BridgeEvent: {
// eslint-disable-next-line prefer-arrow/prefer-arrow-functions
Expand Down
20 changes: 15 additions & 5 deletions packages/rfq-indexer/api/src/graphql/types/events.graphql
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ scalar BigInt
destChain: String!
sendChainGas: Boolean!
}

type BridgeRelayedEvent {
id: String!
transactionId: String!
Expand All @@ -39,7 +39,7 @@ scalar BigInt
destChainId: Int!
destChain: String!
}

type BridgeProofProvidedEvent {
id: String!
transactionId: String!
Expand All @@ -50,7 +50,7 @@ scalar BigInt
originChain: String!
relayer: String!
}

type BridgeDepositRefundedEvent {
id: String!
transactionId: String!
Expand All @@ -64,7 +64,7 @@ scalar BigInt
amount: BigInt!
amountFormatted: String!
}

type BridgeDepositClaimedEvent {
id: String!
transactionId: String!
Expand All @@ -78,4 +78,14 @@ scalar BigInt
token: String!
amount: BigInt!
amountFormatted: String!
}
}

type BridgeProofDisputedEvent {
id: String!
transactionId: String!
blockNumber: BigInt!
blockTimestamp: Int!
transactionHash: String!
originChainId: Int!
originChain: String!
}
Loading

0 comments on commit c63eb6e

Please sign in to comment.