Skip to content

Commit

Permalink
History api from subsquid
Browse files Browse the repository at this point in the history
  • Loading branch information
yrong committed Jan 10, 2025
1 parent 875666c commit 5575e7b
Show file tree
Hide file tree
Showing 6 changed files with 395 additions and 116 deletions.
254 changes: 254 additions & 0 deletions web/packages/api/src/history_v2.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,254 @@
import {
fetchToPolkadotTransfers,
fetchToEthereumTransfers,
fetchBridgeHubOutboundMessageAccepted,
fetchEthereumInboundMessageDispatched,
fetchBridgeHubInboundMessageReceived,
fetchMessageProcessedOnPolkadot,
} from "./subsquid"
import { getEventIndex } from "./utils"

export enum TransferStatus {
Pending,
Complete,
Failed,
}

export type TransferInfo = {
when: Date
sourceAddress: string
beneficiaryAddress: string
tokenAddress: string
destinationParachain?: number
destinationFee?: string
amount: string
}

export type ToPolkadotTransferResult = {
id: string
status: TransferStatus
info: TransferInfo
submitted: {
blockHash: string
blockNumber: number
logIndex: number
transactionHash: string
transactionIndex: number
channelId: string
messageId: string
nonce: number
parentBeaconSlot?: number
}
beaconClientIncluded?: {
extrinsic_index: string
extrinsic_hash: string
event_index: string
block_timestamp: number
beaconSlot: number
beaconBlockHash: string
}
inboundMessageReceived?: {
extrinsic_index: string
extrinsic_hash: string
event_index: string
block_timestamp: number
messageId: string
channelId: string
nonce: number
}
assetHubMessageProcessed?: {
extrinsic_hash: string
event_index: string
block_timestamp: number
success: boolean
sibling: number
}
}

export type ToEthereumTransferResult = {
id: string
status: TransferStatus
info: TransferInfo
submitted: {
extrinsic_index: string
extrinsic_hash: string
block_hash: string
account_id: string
block_num: number
block_timestamp: number
messageId: string
bridgeHubMessageId: string
success: boolean
relayChain?: {
block_hash: string
block_num: number
}
}
bridgeHubXcmDelivered?: {
extrinsic_hash: string
event_index: string
block_timestamp: number
siblingParachain: number
success: boolean
}
bridgeHubChannelDelivered?: {
extrinsic_hash: string
event_index: string
block_timestamp: number
channelId: string
success: boolean
}
bridgeHubMessageQueued?: {
extrinsic_hash: string
event_index: string
block_timestamp: number
}
bridgeHubMessageAccepted?: {
extrinsic_hash: string
event_index: string
block_timestamp: number
nonce: number
}
ethereumBeefyIncluded?: {
blockNumber: number
blockHash: string
transactionHash: string
transactionIndex: number
logIndex: number
relayChainblockNumber: number
mmrRoot: string
}
ethereumMessageDispatched?: {
blockNumber: number
blockHash: string
transactionHash: string
transactionIndex: number
logIndex: number
messageId: string
channelId: string
nonce: number
success: boolean
}
}

export const toPolkadotHistory = async (): Promise<ToPolkadotTransferResult[]> => {
const ethOutboundMessages = await fetchToPolkadotTransfers()
const results: ToPolkadotTransferResult[] = []
for (const outboundMessage of ethOutboundMessages) {
const result: ToPolkadotTransferResult = {
id: outboundMessage.id,
status: TransferStatus.Pending,
info: {
when: new Date(outboundMessage.timestamp),
sourceAddress: outboundMessage.senderAddress,
beneficiaryAddress: outboundMessage.destinationAddress,
tokenAddress: outboundMessage.tokenAddress,
destinationParachain: outboundMessage.destinationParaId,
destinationFee: "",
amount: outboundMessage.amount,
},
submitted: {
blockHash: "",
blockNumber: outboundMessage.blockNumber,
logIndex: 0,
transactionHash: outboundMessage.txHash,
transactionIndex: 0,
channelId: outboundMessage.channelId,
messageId: outboundMessage.messageId,
nonce: outboundMessage.nonce,
},
}
let inboundMessageReceived = await fetchBridgeHubInboundMessageReceived(result.id)
if (inboundMessageReceived) {
result.inboundMessageReceived = {
extrinsic_index: "",
extrinsic_hash: "",
event_index: getEventIndex(inboundMessageReceived.id),
block_timestamp: inboundMessageReceived.timestamp,
messageId: inboundMessageReceived.messageId,
channelId: inboundMessageReceived.channelId,
nonce: inboundMessageReceived.nonce,
}
}

const assetHubMessageProcessed = await fetchMessageProcessedOnPolkadot(result.id)
if (assetHubMessageProcessed) {
result.assetHubMessageProcessed = {
extrinsic_hash: "",
event_index: getEventIndex(assetHubMessageProcessed.id),
block_timestamp: assetHubMessageProcessed.timestamp,
success: assetHubMessageProcessed.success,
sibling: 0,
}
if (!result.assetHubMessageProcessed.success) {
result.status = TransferStatus.Failed
continue
}

result.status = TransferStatus.Complete
}

results.push(result)
}
return results
}

export const toEthereumHistory = async (): Promise<ToEthereumTransferResult[]> => {
const allTransfers = await fetchToEthereumTransfers()
const results: ToEthereumTransferResult[] = []
for (const transfer of allTransfers) {
const result: ToEthereumTransferResult = {
id: transfer.id,
status: TransferStatus.Pending,
info: {
when: new Date(transfer.timestamp),
sourceAddress: transfer.senderAddress,
tokenAddress: transfer.tokenAddress,
beneficiaryAddress: transfer.destinationAddress,
amount: transfer.amount,
},
submitted: {
extrinsic_index: "",
extrinsic_hash: transfer.txHash,
block_hash: "",
account_id: transfer.senderAddress,
block_num: transfer.blockNumber,
block_timestamp: transfer.timestamp,
messageId: transfer.id,
bridgeHubMessageId: "",
success: true,
},
}

let outboundQueueAccepted = await fetchBridgeHubOutboundMessageAccepted(transfer.id)
if (outboundQueueAccepted) {
result.bridgeHubMessageQueued = {
block_timestamp: outboundQueueAccepted.timestamp,
event_index: getEventIndex(outboundQueueAccepted.id),
extrinsic_hash: "",
}
}

let ethereumMessageDispatched = await fetchEthereumInboundMessageDispatched(transfer.id)
if (ethereumMessageDispatched) {
result.ethereumMessageDispatched = {
blockNumber: ethereumMessageDispatched.blockNumber,
blockHash: "",
transactionHash: ethereumMessageDispatched.txHash,
transactionIndex: 0,
logIndex: 0,
messageId: ethereumMessageDispatched.messageId,
channelId: ethereumMessageDispatched.channelId,
nonce: ethereumMessageDispatched.nonce,
success: ethereumMessageDispatched.success,
}
if (!result.ethereumMessageDispatched.success) {
result.status = TransferStatus.Failed
continue
}
result.status = TransferStatus.Complete
}
results.push(result)
}
return results
}
2 changes: 2 additions & 0 deletions web/packages/api/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -175,3 +175,5 @@ export * as assets from "./assets"
export * as environment from "./environment"
export * as subscan from "./subscan"
export * as history from "./history"
export * as historyV2 from "./history_v2"
export * as subsquid from "./subsquid"
125 changes: 125 additions & 0 deletions web/packages/api/src/subsquid.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,125 @@
const graphqlApiUrl = process.env["GRAPHQL_API_URL"] || "https://data.snowbridge.network/graphql"
const graphqlQuerySize = process.env["GRAPHQL_QUERY_SIZE"] || "100"

export const fetchToPolkadotTransfers = async () => {
let query = `query { transferStatusToPolkadots(limit: ${graphqlQuerySize}, orderBy: blockNumber_DESC) {
id
status
blockNumber
bridgedBlockNumber
channelId
destinationAddress
destinationBlockNumber
destinationParaId
forwardedBlockNumber
messageId
nonce
senderAddress
timestamp
tokenAddress
txHash
amount
}
}`
let result = await queryByGraphQL(query)
return result.transferStatusToPolkadots
}

export const fetchToEthereumTransfers = async () => {
let query = `query { transferStatusToEthereums(limit: ${graphqlQuerySize}, orderBy: blockNumber_DESC) {
id
status
blockNumber
bridgedBlockNumber
channelId
destinationAddress
destinationBlockNumber
forwardedBlockNumber
messageId
nonce
senderAddress
sourceParaId
timestamp
tokenAddress
txHash
amount
}
}`
let result = await queryByGraphQL(query)
return result.transferStatusToEthereums
}

export const fetchBridgeHubOutboundMessageAccepted = async (messageID: string) => {
let query = `query { outboundMessageAcceptedOnBridgeHubs(where: {messageId_eq:"${messageID}"}) {
id
nonce
blockNumber
}
}`
let result = await queryByGraphQL(query)
return result?.outboundMessageAcceptedOnBridgeHubs[0]
}

export const fetchEthereumInboundMessageDispatched = async (messageID: string) => {
let query = `query {inboundMessageDispatchedOnEthereums(where: {messageId_eq: "${messageID}"}) {
id
channelId
blockNumber
messageId
nonce
success
timestamp
txHash
}
}`
let result = await queryByGraphQL(query)
return result?.inboundMessageDispatchedOnEthereums[0]
}

export const fetchBridgeHubInboundMessageReceived = async (messageID: string) => {
let query = `query { inboundMessageReceivedOnBridgeHubs(where: {messageId_eq:"${messageID}"}) {
id
channelId
blockNumber
messageId
nonce
timestamp
}
}`
let result = await queryByGraphQL(query)
return result?.inboundMessageReceivedOnBridgeHubs[0]
}

export const fetchMessageProcessedOnPolkadot = async (messageID: string) => {
let query = `query { messageProcessedOnPolkadots(where: {messageId_eq:"${messageID}"}) {
id
blockNumber
messageId
paraId
timestamp
success
}
}`
let result = await queryByGraphQL(query)
return result?.messageProcessedOnPolkadots[0]
}

export const fetchEstimatedDeliveryTime = async (channelId: string) => {
let query = `query { toEthereumElapse(channelId:"${channelId}") { elapse } toPolkadotElapse(channelId:"${channelId}") { elapse } }`
let result = await queryByGraphQL(query)
return result
}

export const queryByGraphQL = async (query: string) => {
let response = await fetch(graphqlApiUrl, {
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify({
query,
}),
})
let data = await response.json()
return data?.data
}
7 changes: 7 additions & 0 deletions web/packages/api/src/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -131,3 +131,10 @@ export const fetchEstimatedDeliveryTime = async (graphqlUrl: string, channelId:
let data = await response.json()
return data?.data
}

export const getEventIndex = (id: string) => {
let parts = id.split("-")
let blockNumber = parseInt(parts[0])
let eventIndex = parseInt(parts[2])
return `${blockNumber}-${eventIndex}`
}
Loading

0 comments on commit 5575e7b

Please sign in to comment.