diff --git a/package.json b/package.json index d7c4dc1..1a183b7 100644 --- a/package.json +++ b/package.json @@ -52,13 +52,14 @@ "typescript": "^4.8.4" }, "workspaces": [ - "packages/core", + "packages/base", "packages/bsc", + "packages/core", "packages/ethereum", "packages/framework", "packages/indexer-example", - "packages/solana", "packages/oasys", - "packages/oasys-verse" + "packages/oasys-verse", + "packages/solana" ] } \ No newline at end of file diff --git a/packages/base/README.md b/packages/base/README.md new file mode 100644 index 0000000..589ece4 --- /dev/null +++ b/packages/base/README.md @@ -0,0 +1 @@ +# Framework Ethereum Package diff --git a/packages/base/index.ts b/packages/base/index.ts new file mode 100644 index 0000000..99be4a6 --- /dev/null +++ b/packages/base/index.ts @@ -0,0 +1,32 @@ +import { BlockchainFrameworkImplementation } from '@aleph-indexer/framework' +import { baseFetcherClientFactory } from './src/services/fetcher/client.js' +import { baseIndexerClientFactory } from './src/services/indexer/client.js' +import { baseParserClientFactory } from './src/services/parser/client.js' +import { baseFetcherFactory } from './src/services/fetcher/factory.js' +import { baseIndexerFactory } from './src/services/indexer/factory.js' +import { baseParserFactory } from './src/services/parser/factory.js' +import { baseWorkerDomainFactory } from './src/domain/worker.js' + +export * from './src/domain/worker.js' +export * from './src/services/fetcher/index.js' +export * from './src/services/parser/index.js' +export * from './src/services/indexer/index.js' + +export default { + fetcher: { + main: baseFetcherFactory, + client: baseFetcherClientFactory, + }, + parser: { + main: baseParserFactory, + client: baseParserClientFactory, + }, + indexer: { + main: baseIndexerFactory, + client: baseIndexerClientFactory, + domain: { + worker: baseWorkerDomainFactory, + main: null, + }, + }, +} as BlockchainFrameworkImplementation diff --git a/packages/base/package.json b/packages/base/package.json new file mode 100644 index 0000000..2432a39 --- /dev/null +++ b/packages/base/package.json @@ -0,0 +1,43 @@ +{ + "name": "@aleph-indexer/base", + "version": "1.1.11", + "description": "", + "main": "dist/index.js", + "module": "dist/index.js", + "types": "dist/index.d.ts", + "type": "module", + "files": [ + "dist" + ], + "publishConfig": { + "access": "public" + }, + "scripts": { + "build": "tsc", + "test": "echo \"Error: no test specified\" && exit 1" + }, + "author": "ALEPH.im", + "license": "ISC", + "peerDependencies": { + "graphql": "^15.8.0", + "graphql-type-json": "^0.3.2", + "luxon": "3.2.1" + }, + "devDependencies": { + "@types/luxon": "3.2.0", + "@types/node": "^17.0.33", + "graphql": "^15.8.0", + "graphql-type-json": "^0.3.2", + "luxon": "3.2.1" + }, + "dependencies": { + "@aleph-indexer/core": "^1.1.10", + "@aleph-indexer/ethereum": "^1.1.11", + "@aleph-indexer/framework": "^1.1.11", + "moleculer": "^0.14.24" + }, + "typedoc": { + "entryPoint": "./index.ts", + "displayName": "Base Indexer Framework" + } +} \ No newline at end of file diff --git a/packages/base/src/domain/index.ts b/packages/base/src/domain/index.ts new file mode 100644 index 0000000..d8b8b10 --- /dev/null +++ b/packages/base/src/domain/index.ts @@ -0,0 +1 @@ +export * from './worker.js' diff --git a/packages/base/src/domain/worker.ts b/packages/base/src/domain/worker.ts new file mode 100644 index 0000000..9a25221 --- /dev/null +++ b/packages/base/src/domain/worker.ts @@ -0,0 +1,31 @@ +import { ParserContext } from '@aleph-indexer/framework' +import { + BaseParsedLog, + BaseParsedTransaction, +} from '../services/parser/src/types.js' + +export type BaseTransactionIndexerWorkerDomainI = { + baseTransactionBufferLength?: number // default 1000 + baseFilterTransaction( + context: ParserContext, + entity: BaseParsedTransaction, + ): Promise + baseIndexTransactions( + context: ParserContext, + entities: BaseParsedTransaction[], + ): Promise +} + +export type BaseLogIndexerWorkerDomainI = { + baseLogBufferLength?: number // default 1000 + baseFilterLog(context: ParserContext, entity: BaseParsedLog): Promise + baseIndexLogs( + context: ParserContext, + entities: BaseParsedLog[], + ): Promise +} + +export type BaseIndexerWorkerDomainI = BaseTransactionIndexerWorkerDomainI & + BaseLogIndexerWorkerDomainI + +export { ethereumWorkerDomainFactory as baseWorkerDomainFactory } from '@aleph-indexer/ethereum' diff --git a/packages/base/src/sdk/client.ts b/packages/base/src/sdk/client.ts new file mode 100644 index 0000000..e492d87 --- /dev/null +++ b/packages/base/src/sdk/client.ts @@ -0,0 +1,36 @@ +import { BlockchainId } from '@aleph-indexer/framework' +import { + EthereumAccountTransactionHistoryStorage, + EthereumClient, + EthereumClientOptions, + EthereumLogBloomStorage, +} from '@aleph-indexer/ethereum' + +export class BaseClient extends EthereumClient { + protected genesisBlockTimestamp = 1686789347000 + + constructor( + protected blockchainId: BlockchainId, + protected options: EthereumClientOptions, + protected accountSignatureDAL?: EthereumAccountTransactionHistoryStorage, + protected logBloomDAL?: EthereumLogBloomStorage, + ) { + super(blockchainId, options, accountSignatureDAL, logBloomDAL) + + // @note: Quick fix for BASE it doesn't affect ethereum + // Take a look at https://github.com/web3/web3.js/pull/3948#issuecomment-821779691 + // @note: Take a look at: + // @note: https://github.com/web3/web3.js/pull/3948#issuecomment-821779691 + console.log('⚡️ monkey patched "web3-utils" "hexToNumber" for BASE chain') + + const hexToNumberOld = this.sdk.utils.hexToNumber + this.sdk.utils.hexToNumber = function (value) { + try { + return hexToNumberOld(value) + } catch (e: any) { + if (e?.message !== 'Number can only safely store up to 53 bits') throw e + return Number.MAX_SAFE_INTEGER + } + } + } +} diff --git a/packages/base/src/sdk/index.ts b/packages/base/src/sdk/index.ts new file mode 100644 index 0000000..9dfc2ec --- /dev/null +++ b/packages/base/src/sdk/index.ts @@ -0,0 +1 @@ +export * from './client.js' diff --git a/packages/base/src/services/fetcher/client.ts b/packages/base/src/services/fetcher/client.ts new file mode 100644 index 0000000..ed2e946 --- /dev/null +++ b/packages/base/src/services/fetcher/client.ts @@ -0,0 +1,3 @@ +import { ethereumFetcherClientFactory } from '@aleph-indexer/ethereum' + +export { ethereumFetcherClientFactory as baseFetcherClientFactory } diff --git a/packages/base/src/services/fetcher/factory.ts b/packages/base/src/services/fetcher/factory.ts new file mode 100644 index 0000000..7501bd0 --- /dev/null +++ b/packages/base/src/services/fetcher/factory.ts @@ -0,0 +1,59 @@ +/* eslint-disable prettier/prettier */ +import { ServiceBroker } from 'moleculer' +import { Utils } from '@aleph-indexer/core' +import { + BlockchainFetcherI, + FetcherMsClient, + BlockchainId, + getBlockchainEnv +} from '@aleph-indexer/framework' +import { ethereumConfigFactory, ethereumDalsFetcherFactory, ethereumFetcherInstanceFactory } from '@aleph-indexer/ethereum' +import { BaseClient } from '../../sdk/index.js' + +export function baseClientFetcherFactory( + blockchainId: BlockchainId, + config: ReturnType, + DALs: ReturnType): BaseClient { + const url = getBlockchainEnv(blockchainId, 'RPC', true) + + return new BaseClient( + blockchainId, + { ...config, url }, + DALs.accountTransactionHistoryDAL, + DALs.logBloomDAL + ) +} + +export async function baseFetcherFactory( + blockchainId: BlockchainId, + basePath: string, + broker: ServiceBroker, + fetcherClient: FetcherMsClient, +): Promise { + if (basePath) await Utils.ensurePath(basePath) + + // Config + + const config = ethereumConfigFactory(blockchainId) + + // DALs + + const DALs = ethereumDalsFetcherFactory(basePath) + + // Instances + + const baseClient = baseClientFetcherFactory( + blockchainId, + config, + DALs + ) + + return ethereumFetcherInstanceFactory( + blockchainId, + broker, + fetcherClient, + baseClient, + config, + DALs + ) +} diff --git a/packages/base/src/services/fetcher/index.ts b/packages/base/src/services/fetcher/index.ts new file mode 100644 index 0000000..5255e62 --- /dev/null +++ b/packages/base/src/services/fetcher/index.ts @@ -0,0 +1,2 @@ +export * from './client.js' +export * from './factory.js' diff --git a/packages/base/src/services/indexer/client.ts b/packages/base/src/services/indexer/client.ts new file mode 100644 index 0000000..48a216e --- /dev/null +++ b/packages/base/src/services/indexer/client.ts @@ -0,0 +1,3 @@ +import { ethereumIndexerClientFactory } from '@aleph-indexer/ethereum' + +export { ethereumIndexerClientFactory as baseIndexerClientFactory } diff --git a/packages/base/src/services/indexer/factory.ts b/packages/base/src/services/indexer/factory.ts new file mode 100644 index 0000000..a2dbf07 --- /dev/null +++ b/packages/base/src/services/indexer/factory.ts @@ -0,0 +1,3 @@ +import { ethereumIndexerFactory } from '@aleph-indexer/ethereum' + +export { ethereumIndexerFactory as baseIndexerFactory } diff --git a/packages/base/src/services/indexer/index.ts b/packages/base/src/services/indexer/index.ts new file mode 100644 index 0000000..5255e62 --- /dev/null +++ b/packages/base/src/services/indexer/index.ts @@ -0,0 +1,2 @@ +export * from './client.js' +export * from './factory.js' diff --git a/packages/base/src/services/parser/client.ts b/packages/base/src/services/parser/client.ts new file mode 100644 index 0000000..3bbba86 --- /dev/null +++ b/packages/base/src/services/parser/client.ts @@ -0,0 +1,3 @@ +import { ethereumParserClientFactory } from '@aleph-indexer/ethereum' + +export { ethereumParserClientFactory as baseParserClientFactory } diff --git a/packages/base/src/services/parser/factory.ts b/packages/base/src/services/parser/factory.ts new file mode 100644 index 0000000..a19e1df --- /dev/null +++ b/packages/base/src/services/parser/factory.ts @@ -0,0 +1,39 @@ +/* eslint-disable prettier/prettier */ +import { BlockchainId, BlockchainParserI, getBlockchainEnv } from '@aleph-indexer/framework' +import {ethereumAbiParserFactory, ethereumParserInstanceFactory } from '@aleph-indexer/ethereum' +import { BaseClient } from '../../sdk/index.js' +import { BaseParsedTransaction, BaseRawTransaction } from './src/types.js' + +export function baseClientParserFactory( + blockchainId: BlockchainId, +): BaseClient { + const url = getBlockchainEnv(blockchainId, 'RPC', true) + + return new BaseClient(blockchainId, { url }) +} + +export async function baseParserFactory( + blockchainId: BlockchainId, + basePath: string, + layoutPath?: string, +): Promise< + BlockchainParserI< + BaseRawTransaction, + BaseParsedTransaction + > +> { + const baseClient = baseClientParserFactory(blockchainId) + + const baseAbiFactory = await ethereumAbiParserFactory( + blockchainId, + baseClient, + basePath, + layoutPath + ) + + return ethereumParserInstanceFactory( + blockchainId, + baseClient, + baseAbiFactory, + ) +} diff --git a/packages/base/src/services/parser/index.ts b/packages/base/src/services/parser/index.ts new file mode 100644 index 0000000..80f7eec --- /dev/null +++ b/packages/base/src/services/parser/index.ts @@ -0,0 +1,3 @@ +export * from './client.js' +export * from './factory.js' +export * from './src/types.js' diff --git a/packages/base/src/services/parser/src/types.ts b/packages/base/src/services/parser/src/types.ts new file mode 100644 index 0000000..d441764 --- /dev/null +++ b/packages/base/src/services/parser/src/types.ts @@ -0,0 +1,11 @@ +import { + EthereumParsedAccountState, + EthereumParsedLog, + EthereumParsedTransaction, + EthereumRawTransaction, +} from '@aleph-indexer/ethereum' + +export type BaseRawTransaction = EthereumRawTransaction +export type BaseParsedTransaction = EthereumParsedTransaction +export type BaseParsedLog = EthereumParsedLog +export type BaseParsedAccountState = EthereumParsedAccountState diff --git a/packages/base/tsconfig.json b/packages/base/tsconfig.json new file mode 100644 index 0000000..2c2914c --- /dev/null +++ b/packages/base/tsconfig.json @@ -0,0 +1,16 @@ +{ + "extends": "../../tsconfig.json", + "compilerOptions": { + "outDir": "dist" + }, + "exclude": [ + "node_modules", + "dist", + "scripts", + "tests", + "**/*.spec.ts", + "**/*.test.ts", + "**/__tests__", + "**/__mocks__" + ] +} \ No newline at end of file diff --git a/packages/base/types.d.ts b/packages/base/types.d.ts new file mode 100644 index 0000000..00b16af --- /dev/null +++ b/packages/base/types.d.ts @@ -0,0 +1 @@ +export * from '../../types' diff --git a/packages/ethereum/src/services/parser/src/abiFactory.ts b/packages/ethereum/src/services/parser/src/abiFactory.ts index 03e6d11..174a7ee 100644 --- a/packages/ethereum/src/services/parser/src/abiFactory.ts +++ b/packages/ethereum/src/services/parser/src/abiFactory.ts @@ -69,6 +69,12 @@ export class EthereumAbiFactory { const body: any = await response.json() + // @note: We are supporting etherscan and blockscout kind of EVM explorer + + if (body.abi) { + return body.abi as Abi + } + // @note: Rate limit error sent with status 200 OK... // { // "status": "0", diff --git a/packages/framework/package.json b/packages/framework/package.json index bc59fa5..942e656 100644 --- a/packages/framework/package.json +++ b/packages/framework/package.json @@ -19,6 +19,7 @@ "author": "ALEPH.im", "license": "ISC", "peerDependencies": { + "@aleph-indexer/base": "^1.x", "@aleph-indexer/bsc": "^1.x", "@aleph-indexer/ethereum": "^1.x", "@aleph-indexer/oasys": "^1.x", @@ -30,6 +31,9 @@ "nats": "^2.x" }, "peerDependenciesMeta": { + "@aleph-indexer/base": { + "optional": true + }, "@aleph-indexer/bsc": { "optional": true }, @@ -64,4 +68,4 @@ "entryPoint": "./index.ts", "displayName": "Indexer Framework" } -} +} \ No newline at end of file diff --git a/packages/framework/src/types.ts b/packages/framework/src/types.ts index 2ece27e..1a94a00 100644 --- a/packages/framework/src/types.ts +++ b/packages/framework/src/types.ts @@ -48,8 +48,9 @@ export type ParsedEntity

= RawEntity & { export type BlockchainId = string export enum BlockchainChain { - Ethereum = 'ethereum', + Base = 'base', Bsc = 'bsc', + Ethereum = 'ethereum', Solana = 'solana', Oasys = 'oasys', OasysVerse = 'oasys-verse', diff --git a/packages/indexer-example/src/domain/main.ts b/packages/indexer-example/src/domain/main.ts index 34f8371..7543494 100644 --- a/packages/indexer-example/src/domain/main.ts +++ b/packages/indexer-example/src/domain/main.ts @@ -22,6 +22,7 @@ export default class MainDomain const OAXTokenOasys = '0x4688e596fb8ffaa9f7c1f02985b44651cf642123' const contractHomeverse = '0x7aB9B14Eb42913fe48AC01f3BB453cA7BEf343EA' const alephTokenSol = '3UCMiSnkcnkPE1pgQ5ggPCBv6dXgVUy16TmMUe1WpG9x' + const wethTokenBase = '0x4200000000000000000000000000000000000006' const accountIndexerConfigs = [] @@ -94,6 +95,19 @@ export default class MainDomain }) } + if (this.context.supportedBlockchains.includes(BlockchainChain.Base)) { + accountIndexerConfigs.push({ + blockchainId: BlockchainChain.Base, + account: wethTokenBase, + meta: -1, + index: { + transactions: false, + state: false, + logs: true, + }, + }) + } + return accountIndexerConfigs } } diff --git a/packages/indexer-example/src/domain/worker.ts b/packages/indexer-example/src/domain/worker.ts index 8a681bd..c9d1fd5 100644 --- a/packages/indexer-example/src/domain/worker.ts +++ b/packages/indexer-example/src/domain/worker.ts @@ -183,4 +183,34 @@ export default class WorkerDomain ): Promise { console.log('Index homeverse log', JSON.stringify(entities, null, 2)) } + + // Base + + async baseFilterTransaction( + context: ParserContext, + entity: EthereumParsedTransaction, + ): Promise { + return true + } + + async baseIndexTransactions( + context: ParserContext, + entities: EthereumParsedTransaction[], + ): Promise { + console.log('Index base transaction', JSON.stringify(entities, null, 2)) + } + + async baseFilterLog( + context: ParserContext, + entity: EthereumParsedLog, + ): Promise { + return true + } + + async baseIndexLogs( + context: ParserContext, + entities: EthereumParsedLog[], + ): Promise { + console.log('Index base log', JSON.stringify(entities, null, 2)) + } }