diff --git a/blockchain-watcher/config/custom-environment-variables.json b/blockchain-watcher/config/custom-environment-variables.json index e81c2ee1..0e971d70 100644 --- a/blockchain-watcher/config/custom-environment-variables.json +++ b/blockchain-watcher/config/custom-environment-variables.json @@ -48,9 +48,23 @@ } }, "acala": { - "network": "FANTOM_NETWORK", + "network": "ACALA_NETWORK", "rpcs": { - "__name": "FANTOM_RPCS", + "__name": "ACALA_RPCS", + "__format": "json" + } + }, + "optimism": { + "network": "OPTIMISM_NETWORK", + "rpcs": { + "__name": "OPTIMISM_RPCS", + "__format": "json" + } + }, + "base": { + "network": "BASE_NETWORK", + "rpcs": { + "__name": "BASE_RPCS", "__format": "json" } } diff --git a/blockchain-watcher/config/default.json b/blockchain-watcher/config/default.json index 310e695d..7af6d8d8 100644 --- a/blockchain-watcher/config/default.json +++ b/blockchain-watcher/config/default.json @@ -3,7 +3,16 @@ "port": 9090, "logLevel": "debug", "dryRun": true, - "supportedChains": ["solana", "ethereum", "avalanche", "fantom", "karura", "acala"], + "supportedChains": [ + "solana", + "ethereum", + "avalanche", + "fantom", + "karura", + "acala", + "optimism", + "base" + ], "sns": { "topicArn": "arn:aws:sns:us-east-1:000000000000:localstack-topic.fifo", "region": "us-east-1", @@ -62,6 +71,20 @@ "chainId": 12, "rpcs": ["https://eth-rpc-acala-testnet.aca-staging.network"], "timeout": 10000 + }, + "optimism": { + "name": "optimism", + "network": "goerli", + "chainId": 24, + "rpcs": ["https://goerli.optimism.io"], + "timeout": 10000 + }, + "base": { + "name": "base", + "network": "goerli", + "chainId": 30, + "rpcs": ["https://goerli.base.org"], + "timeout": 10000 } } } diff --git a/blockchain-watcher/config/mainnet.json b/blockchain-watcher/config/mainnet.json index 6313b613..7144fe18 100644 --- a/blockchain-watcher/config/mainnet.json +++ b/blockchain-watcher/config/mainnet.json @@ -23,6 +23,14 @@ "acala": { "network": "mainnet", "rpcs": ["https://eth-rpc-acala.aca-api.network"] + }, + "optimism": { + "network": "mainnet", + "rpcs": ["https://rpc.ankr.com/optimism"] + }, + "base": { + "network": "mainnet", + "rpcs": ["https://mainnet.base.org"] } } } diff --git a/blockchain-watcher/src/infrastructure/repositories/RepositoriesBuilder.ts b/blockchain-watcher/src/infrastructure/repositories/RepositoriesBuilder.ts index 9291fbf6..f15c2fe4 100644 --- a/blockchain-watcher/src/infrastructure/repositories/RepositoriesBuilder.ts +++ b/blockchain-watcher/src/infrastructure/repositories/RepositoriesBuilder.ts @@ -15,7 +15,7 @@ import { HttpClient } from "../rpc/http/HttpClient"; import { JobRepository } from "../../domain/repositories"; const SOLANA_CHAIN = "solana"; -const EVM_CHAINS = ["ethereum", "avalanche", "fantom", "karura", "acala"]; +const EVM_CHAINS = ["ethereum", "avalanche", "fantom", "karura", "acala", "optimism", "base"]; export class RepositoriesBuilder { private cfg: Config; diff --git a/blockchain-watcher/test/infrastructure/repositories/RepositoriesBuilder.test.ts b/blockchain-watcher/test/infrastructure/repositories/RepositoriesBuilder.test.ts index 02f8cb4a..c911dfe3 100644 --- a/blockchain-watcher/test/infrastructure/repositories/RepositoriesBuilder.test.ts +++ b/blockchain-watcher/test/infrastructure/repositories/RepositoriesBuilder.test.ts @@ -33,7 +33,16 @@ describe("RepositoriesBuilder", () => { it("should be return all repositories instances", async () => { // When const repos = new RepositoriesBuilder( - configMock(["solana", "ethereum", "avalanche", "fantom", "karura", "acala"]) + configMock([ + "solana", + "ethereum", + "avalanche", + "fantom", + "karura", + "acala", + "optimism", + "base", + ]) ); // Then const job = repos.getJobsRepository(); @@ -44,6 +53,8 @@ describe("RepositoriesBuilder", () => { expect(repos.getEvmBlockRepository("fantom")).toBeInstanceOf(EvmJsonRPCBlockRepository); expect(repos.getEvmBlockRepository("karura")).toBeInstanceOf(EvmJsonRPCBlockRepository); expect(repos.getEvmBlockRepository("acala")).toBeInstanceOf(EvmJsonRPCBlockRepository); + expect(repos.getEvmBlockRepository("optimism")).toBeInstanceOf(EvmJsonRPCBlockRepository); + expect(repos.getEvmBlockRepository("base")).toBeInstanceOf(EvmJsonRPCBlockRepository); expect(repos.getMetadataRepository()).toBeInstanceOf(FileMetadataRepository); expect(repos.getSnsEventRepository()).toBeInstanceOf(SnsEventRepository); expect(repos.getStatsRepository()).toBeInstanceOf(PromStatRepository); diff --git a/blockchain-watcher/test/mocks/configMock.ts b/blockchain-watcher/test/mocks/configMock.ts index 181f95e8..f920b957 100644 --- a/blockchain-watcher/test/mocks/configMock.ts +++ b/blockchain-watcher/test/mocks/configMock.ts @@ -2,7 +2,7 @@ import { SnsConfig } from "../../src/infrastructure/repositories"; import { Config, ChainRPCConfig } from "../../src/infrastructure/config"; export const configMock = (chains: string[] = []): Config => { - const platformRecord: Record = { + const chainsRecord: Record = { solana: { name: "solana", network: "devnet", @@ -45,6 +45,20 @@ export const configMock = (chains: string[] = []): Config => { rpcs: ["http://localhost"], timeout: 10000, }, + optimism: { + name: "optimism", + network: "testnet", + chainId: 12, + rpcs: ["http://localhost"], + timeout: 10000, + }, + base: { + name: "base", + network: "testnet", + chainId: 12, + rpcs: ["http://localhost"], + timeout: 10000, + }, }; const snsConfig: SnsConfig = { @@ -71,7 +85,7 @@ export const configMock = (chains: string[] = []): Config => { jobs: { dir: "./metadata-repo/jobs", }, - chains: platformRecord, + chains: chainsRecord, supportedChains: chains, }; diff --git a/deploy/blockchain-watcher/workers/ethereum-1.yaml b/deploy/blockchain-watcher/workers/ethereum-1.yaml new file mode 100644 index 00000000..adbccd80 --- /dev/null +++ b/deploy/blockchain-watcher/workers/ethereum-1.yaml @@ -0,0 +1,211 @@ +--- +apiVersion: v1 +kind: Service +metadata: + name: {{ .NAME }}-eth-1 + namespace: {{ .NAMESPACE }} + labels: + app: {{ .NAME }}-eth-1 +spec: + selector: + app: {{ .NAME }}-eth-1 + ports: + - port: {{ .PORT }} + targetPort: {{ .PORT }} + name: {{ .NAME }}-eth-1 + protocol: TCP +--- +apiVersion: v1 +kind: PersistentVolumeClaim +metadata: + name: blockchain-watcher-eth-1-pvc + namespace: {{ .NAMESPACE }} +spec: + accessModes: + - ReadWriteOnce + resources: + requests: + storage: 10Mi + storageClassName: gp2 +--- +apiVersion: v1 +kind: ConfigMap +metadata: + name: {{ .NAME }}-eth-1-jobs + namespace: {{ .NAMESPACE }} +data: + testnet-jobs.json: |- + [ + { + "id": "poll-log-message-published-optimism", + "chain": "optimism", + "source": { + "action": "PollEvmLogs", + "config": { + "blockBatchSize": 100, + "commitment": "latest", + "interval": 15000, + "addresses": ["0x6b9C8671cdDC8dEab9c719bB87cBd3e782bA6a35"], + "chain": "optimism" + } + }, + "handlers": [ + { + "action": "HandleEvmLogs", + "target": "sns", + "mapper": "evmLogMessagePublishedMapper", + "config": { + "abi": "event LogMessagePublished(address indexed sender, uint64 sequence, uint32 nonce, bytes payload, uint8 consistencyLevel)", + "filter": { + "addresses": ["0x6b9C8671cdDC8dEab9c719bB87cBd3e782bA6a35"], + "topics": ["0x6eb224fb001ed210e379b335e35efe88672a8ce935d981a6896b27ffdf52a3b2"] + } + } + } + ] + }, + { + "id": "poll-log-message-published-base", + "chain": "base", + "source": { + "action": "PollEvmLogs", + "config": { + "blockBatchSize": 100, + "commitment": "finalized", + "interval": 15000, + "addresses": ["0x23908A62110e21C04F3A4e011d24F901F911744A"], + "chain": "base" + } + }, + "handlers": [ + { + "action": "HandleEvmLogs", + "target": "sns", + "mapper": "evmLogMessagePublishedMapper", + "config": { + "abi": "event LogMessagePublished(address indexed sender, uint64 sequence, uint32 nonce, bytes payload, uint8 consistencyLevel)", + "filter": { + "addresses": ["0x23908A62110e21C04F3A4e011d24F901F911744A"], + "topics": ["0x6eb224fb001ed210e379b335e35efe88672a8ce935d981a6896b27ffdf52a3b2"] + } + } + } + ] + } + ] + mainnet-jobs.json: |- + [ + { + "id": "poll-log-message-published-optimism", + "chain": "optimism", + "source": { + "action": "PollEvmLogs", + "config": { + "blockBatchSize": 100, + "commitment": "latest", + "interval": 5000, + "addresses": ["0xEe91C335eab126dF5fDB3797EA9d6aD93aeC9722"], + "chain": "optimism" + } + }, + "handlers": [ + { + "action": "HandleEvmLogs", + "target": "sns", + "mapper": "evmLogMessagePublishedMapper", + "config": { + "abi": "event LogMessagePublished(address indexed sender, uint64 sequence, uint32 nonce, bytes payload, uint8 consistencyLevel)", + "filter": { + "addresses": ["0xEe91C335eab126dF5fDB3797EA9d6aD93aeC9722"], + "topics": ["0x6eb224fb001ed210e379b335e35efe88672a8ce935d981a6896b27ffdf52a3b2"] + } + } + } + ] + }, + { + "id": "poll-log-message-published-base", + "chain": "base", + "source": { + "action": "PollEvmLogs", + "config": { + "blockBatchSize": 100, + "commitment": "finalized", + "interval": 5000, + "addresses": ["0xbebdb6C8ddC678FfA9f8748f85C815C556Dd8ac6"], + "chain": "base" + } + }, + "handlers": [ + { + "action": "HandleEvmLogs", + "target": "sns", + "mapper": "evmLogMessagePublishedMapper", + "config": { + "abi": "event LogMessagePublished(address indexed sender, uint64 sequence, uint32 nonce, bytes payload, uint8 consistencyLevel)", + "filter": { + "addresses": ["0xbebdb6C8ddC678FfA9f8748f85C815C556Dd8ac6"], + "topics": ["0x6eb224fb001ed210e379b335e35efe88672a8ce935d981a6896b27ffdf52a3b2"] + } + } + } + ] + } + ] +--- +apiVersion: v1 +kind: Pod +metadata: + name: {{ .NAME }}-eth-1 + namespace: {{ .NAMESPACE }} + labels: + app: {{ .NAME }}-eth-1 + annotations: + prometheus.io/scrape: "true" + prometheus.io/port: "{{ .PORT }}" +spec: + restartPolicy: Always + terminationGracePeriodSeconds: 30 + serviceAccountName: event-watcher + containers: + - name: {{ .NAME }} + image: {{ .IMAGE_NAME }} + env: + - name: NODE_ENV + value: {{ .NODE_ENV }} + - name: PORT + value: "{{ .PORT }}" + - name: LOG_LEVEL + value: {{ .LOG_LEVEL }} + - name: BLOCKCHAIN_ENV + value: {{ .BLOCKCHAIN_ENV }} + - name: DRY_RUN_ENABLED + value: "{{ .DRY_RUN_ENABLED }}" + - name: SNS_TOPIC_ARN + value: {{ .SNS_TOPIC_ARN }} + - name: SNS_REGION + value: {{ .SNS_REGION }} + - name: JOBS_DIR + value: /home/node/app/jobs + resources: + limits: + memory: {{ .RESOURCES_LIMITS_MEMORY }} + cpu: {{ .RESOURCES_LIMITS_CPU }} + requests: + memory: {{ .RESOURCES_REQUESTS_MEMORY }} + cpu: {{ .RESOURCES_REQUESTS_CPU }} + volumeMounts: + - name: metadata-volume + mountPath: /home/node/app/metadata-repo + - name: jobs-volume + mountPath: /home/node/app/jobs + volumes: + - name: metadata-volume + persistentVolumeClaim: + claimName: blockchain-watcher-eth-1-pvc + - name: jobs-volume + configMap: + name: {{ .NAME }}-eth-1-jobs + items: + - key: {{ .BLOCKCHAIN_ENV }}-jobs.json + path: jobs.json