Skip to content

Commit

Permalink
feat(hapi-evm): add hyperion
Browse files Browse the repository at this point in the history
  • Loading branch information
leisterfrancisco committed Jul 22, 2023
1 parent 142056e commit 86a6a92
Show file tree
Hide file tree
Showing 34 changed files with 417 additions and 11 deletions.
1 change: 1 addition & 0 deletions hapi-evm/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
"graphql": "16",
"graphql-request": "^6.0.0",
"joi": "^17.9.2",
"moment": "^2.29.4",
"node-fetch": "^3.3.1",
"web3": "^4.0.3",
"websocket": "^1.0.34"
Expand Down
4 changes: 4 additions & 0 deletions hapi-evm/src/config/hyperion.config.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
export const api =
process.env.HAPI_HYPERION_API || 'https://test.telos.eosusa.io'
export const startAt =
process.env.HAPI_HYPERION_START_AT || '2021-06-02T00:00:00.000+00:00'
1 change: 1 addition & 0 deletions hapi-evm/src/config/index.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
export * as serverConfig from './server.config'
export * as hasuraConfig from './hasura.config'
export * as networkConfig from './network.config'
export * as hyperionConfig from './hyperion.config'
2 changes: 1 addition & 1 deletion hapi-evm/src/models/default.model.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,6 @@ export type TableType = keyof typeof Tables

export interface Worker {
name: string
intervalSec: number
intervalSec?: number
action: () => Promise<void>
}
3 changes: 0 additions & 3 deletions hapi-evm/src/models/gas/interfaces.ts

This file was deleted.

1 change: 0 additions & 1 deletion hapi-evm/src/models/gas/queries.ts

This file was deleted.

File renamed without changes.
4 changes: 4 additions & 0 deletions hapi-evm/src/models/hyperion-state/interfaces.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
export interface HyperionState {
id: string
last_synced_at: string
}
94 changes: 94 additions & 0 deletions hapi-evm/src/models/hyperion-state/queries.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
import { gql } from 'graphql-request'

import { coreUtil } from '../../utils'
import { HyperionState } from './interfaces'

interface HyperionStateResponse {
evm_hyperion_state: HyperionState[]
}

interface HyperionStateInsertOneResponse {
insert_evm_hyperion_state_one: {
id: string
}
}

export const save = async (lastSyncedAt: string) => {
const mutation = gql`
mutation ($payload: evm_hyperion_state_insert_input!) {
insert_evm_hyperion_state_one(object: $payload) {
id
}
}
`

const data =
await coreUtil.hasura.default.request<HyperionStateInsertOneResponse>(
mutation,
{
payload: {
last_synced_at: lastSyncedAt
}
}
)

return data.insert_evm_hyperion_state_one
}

export const update = async (id: string, lastSyncedAt: string) => {
const mutation = gql`
mutation ($id: uuid!, $payload: evm_hyperion_state_set_input) {
update_evm_hyperion_state_by_pk(pk_columns: { id: $id }, _set: $payload) {
id
last_synced_at
}
}
`

await coreUtil.hasura.default.request(mutation, {
id,
payload: {
last_synced_at: lastSyncedAt
}
})
}

export const getState = async () => {
const query = gql`
query {
evm_hyperion_state(
where: { id: { _neq: "00000000-0000-0000-0000-000000000000" } }
limit: 1
) {
id
last_synced_at
}
}
`
const data = await coreUtil.hasura.default.request<HyperionStateResponse>(
query
)

if (!data.evm_hyperion_state.length) {
return
}

const state = data.evm_hyperion_state[0]

return {
id: state.id,
lastSyncedAt: state.last_synced_at
}
}

export const saveOrUpdate = async (lastSyncedAt: string) => {
const currentState = await getState()

if (!currentState) {
await save(lastSyncedAt)

return
}

await update(currentState.id, lastSyncedAt)
}
2 changes: 2 additions & 0 deletions hapi-evm/src/models/incoming-transfer/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
export * as interfaces from './interfaces'
export * as queries from './queries'
12 changes: 12 additions & 0 deletions hapi-evm/src/models/incoming-transfer/interfaces.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
export interface IncomingTransfer {
id?: string
block: number
transaction_id: string
from: string
to: string
amount: number
symbol: string
memo: string
quantity: string
timestamp: string
}
34 changes: 34 additions & 0 deletions hapi-evm/src/models/incoming-transfer/queries.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
import { gql } from 'graphql-request'

import { coreUtil } from '../../utils'
import { IncomingTransfer } from './interfaces'

// interface IncomingTransferResponse {
// evm_incoming_transfer: IncomingTransfer[]
// }

interface IncomingTransferInsertOneResponse {
insert_evm_incoming_transfer_one: {
id: string
}
}

export const save = async (payload: IncomingTransfer) => {
const mutation = gql`
mutation ($payload: evm_incoming_transfer_insert_input!) {
insert_evm_incoming_transfer_one(object: $payload) {
id
}
}
`

const data =
await coreUtil.hasura.default.request<IncomingTransferInsertOneResponse>(
mutation,
{
payload
}
)

return data.insert_evm_incoming_transfer_one
}
5 changes: 3 additions & 2 deletions hapi-evm/src/models/index.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
export * as gasModel from './gas'
export * as defaultModel from './default.model'
export * as blockModel from './block'
export * as transactionModel from './transaction'
export * as defaultModel from './default.model'
export * as hyperionStateModel from './hyperion-state'
export * as incomingTransferModel from './incoming-transfer'
4 changes: 2 additions & 2 deletions hapi-evm/src/routes/v1/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,8 +25,8 @@ const baseRoute = '/v1'

// (OK) Average gas usage: Show to average gas usage in the last 100 blocks.
// () Average transactions per second (block and eosio.token -> ERC20).
// - () internal TLOS transactions. (tEVM address -> tEVM address)
// - () incoming TLOS transactions. (EOS address -> tEVM address)
// - (NO) internal TLOS transactions. (tEVM address -> tEVM address)
// - (OK) incoming TLOS transactions. (EOS address -> tEVM address)
// - () outgoing TLOS transactions. (tEVM address -> EOS address) HOW?
// (OK) Daily transactions.
// (OK) ATH.
Expand Down
170 changes: 170 additions & 0 deletions hapi-evm/src/services/hyperion/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,170 @@
import moment, { DurationInputArg2 } from 'moment'

import { hyperionConfig } from '../../config'
import { coreUtil, timeUtil } from '../../utils'
import { hyperionStateModel } from '../../models'

import updaters from './updaters'

interface GetActionsParams {
after: string
before: string
skip: number
}

interface GetActionsResponse {
hasMore: boolean
actions: any[]
}

const TIME_BEFORE_IRREVERSIBILITY = 164

const getLastSyncedAt = async () => {
const state = await hyperionStateModel.queries.getState()

if (state) {
return state.lastSyncedAt
}

await hyperionStateModel.queries.saveOrUpdate(hyperionConfig.startAt)

return hyperionConfig.startAt
}

const getGap = (lastSyncedAt: string) => {
if (moment().diff(moment(lastSyncedAt), 'days') > 0) {
return {
amount: 1,
unit: 'day'
}
}

if (moment().diff(moment(lastSyncedAt), 'hours') > 0) {
return {
amount: 1,
unit: 'hour'
}
}

if (
moment().diff(moment(lastSyncedAt), 'seconds') >=
TIME_BEFORE_IRREVERSIBILITY * 2
) {
return {
amount: TIME_BEFORE_IRREVERSIBILITY,
unit: 'seconds'
}
}

if (
moment().diff(moment(lastSyncedAt), 'seconds') >=
TIME_BEFORE_IRREVERSIBILITY + 10
) {
return {
amount: 10,
unit: 'seconds'
}
}

return {
amount: 1,
unit: 'seconds'
}
}

const getActions = async (
params: GetActionsParams
): Promise<GetActionsResponse> => {
const limit = 100
const { data } = await coreUtil.axios.default.get(
`${hyperionConfig.api}/v2/history/get_actions`,
{
params: {
...params,
account: 'eosio.evm', // TODO: get it from updater using the notified_account field
limit,
filter: updaters.map(updater => updater.type).join(','),
sort: 'asc',
simple: true,
checkLib: true
}
}
)

const notIrreversible = data.simple_actions.find(
(item: any) => !item.irreversible
)

if (notIrreversible) {
await timeUtil.sleep(1)

return getActions(params)
}

return {
hasMore: data.total.value > limit + params.skip || false,
actions: data.simple_actions
}
}

const runUpdaters = async (actions: any[]) => {
for (let index = 0; index < actions.length; index++) {
const action = actions[index]
const updater = updaters.find(item =>
item.type.startsWith(`${action.contract}:${action.action}`)
)

if (!updater) {
continue
}

await updater.apply(action)
}
}

const sync = async (): Promise<void> => {
console.log('SYNCING')
await coreUtil.hasura.hasuraAssembled()
const lastSyncedAt = await getLastSyncedAt()
const gap = getGap(lastSyncedAt)
const after = moment(lastSyncedAt).toISOString()
const before = moment(after)
.add(gap.amount, gap.unit as DurationInputArg2)
.toISOString()
const diff = moment().diff(moment(before), 'seconds')
let skip = 0
let hasMore = true
let actions = []

if (diff < TIME_BEFORE_IRREVERSIBILITY) {
await timeUtil.sleep(TIME_BEFORE_IRREVERSIBILITY - diff)

return sync()
}

try {
while (hasMore) {
;({ hasMore, actions } = await getActions({ after, before, skip }))
skip += actions.length
await runUpdaters(actions)
}
} catch (error: any) {
console.error('hyperion error', error.message)
await timeUtil.sleep(5)

return sync()
}

await hyperionStateModel.queries.saveOrUpdate(before)

return sync()
}

const syncWorker = () => {
return {
name: 'SYNC ACTIONS',
action: sync
}
}

export default { syncWorker }
3 changes: 3 additions & 0 deletions hapi-evm/src/services/hyperion/updaters/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
import tokenTransferUpdater from './token-transfer.updater'

export default [tokenTransferUpdater]
Loading

0 comments on commit 86a6a92

Please sign in to comment.