Skip to content

Commit f866084

Browse files
authored
feat: add arbitrum nova (#877)
1 parent 1ddc87a commit f866084

26 files changed

+1898
-3
lines changed

.circleci/config.yml

+78-2
Original file line numberDiff line numberDiff line change
@@ -689,13 +689,12 @@ aliases:
689689
service-memory-limit-1: 24Gi
690690
service-storage-size-1: 1000Gi
691691
service-name-2: indexer
692-
service-image-2: shapeshiftdao/unchained-blockbook:arbitrum-e21ed51
692+
service-image-2: shapeshiftdao/unchained-blockbook:arbitrum-92a5619
693693
service-cpu-limit-2: "2"
694694
service-cpu-request-2: "1"
695695
service-memory-limit-2: 16Gi
696696
service-storage-size-2: 500Gi
697697

698-
699698
- &arbitrum-dev
700699
<<: *arbitrum
701700
environment: dev
@@ -708,6 +707,47 @@ aliases:
708707
api-memory-limit: 250Mi
709708
stateful-service-replicas: 1
710709

710+
- &arbitrum-nova
711+
assetName: arbitrum-nova
712+
pulumi-stack: public-us-east-2
713+
pulumi-dir: coinstacks/arbitrum-nova/pulumi
714+
rpc-url: http://arbitrum-nova-svc.unchained.svc.cluster.local:8547
715+
indexer-url: http://arbitrum-nova-svc.unchained.svc.cluster.local:8001
716+
indexer-ws-url: ws://arbitrum-nova-svc.unchained.svc.cluster.local:8001/websocket
717+
api-autoscaling: true
718+
api-replicas: 2
719+
api-max-replicas: 6
720+
api-cpu-limit: 500m
721+
api-cpu-request: 250m
722+
api-cpu-threshold: 75
723+
api-memory-limit: 500Mi
724+
api-memory-request: 250Mi
725+
stateful-service-replicas: 2
726+
service-name-1: daemon
727+
service-image-1: offchainlabs/nitro-node:v2.1.2-4c55843
728+
service-cpu-limit-1: "2"
729+
service-cpu-request-1: "1"
730+
service-memory-limit-1: 16Gi
731+
service-storage-size-1: 500Gi
732+
service-name-2: indexer
733+
service-image-2: shapeshiftdao/unchained-blockbook:arbitrum-92a5619
734+
service-cpu-limit-2: "2"
735+
service-cpu-request-2: "1"
736+
service-memory-limit-2: 12Gi
737+
service-storage-size-2: 500Gi
738+
739+
- &arbitrum-nova-dev
740+
<<: *arbitrum-nova
741+
environment: dev
742+
pulumi-stack: public-dev-us-east-2
743+
rpc-url: http://arbitrum-nova-svc.unchained-dev.svc.cluster.local:8547
744+
indexer-url: http://arbitrum-nova-svc.unchained-dev.svc.cluster.local:8001
745+
indexer-ws-url: ws://arbitrum-nova-svc.unchained-dev.svc.cluster.local:8001/websocket
746+
api-replicas: 1
747+
api-max-replicas: 2
748+
api-memory-limit: 250Mi
749+
stateful-service-replicas: 1
750+
711751
commands:
712752
precheck:
713753
description: install dependencies
@@ -1216,6 +1256,16 @@ workflows:
12161256
<<: *arbitrum-dev
12171257
<<: *only-develop
12181258

1259+
- deploy-coinstack-node:
1260+
name: deploy arbitrum nova develop
1261+
organization: TAXISTAKE
1262+
pulumi-command: up -f --yes
1263+
etherscan-env-var: ETHERSCAN_API_KEY_ARBITRUM_NOVA
1264+
requires:
1265+
- deploy dependencies
1266+
<<: *arbitrum-nova-dev
1267+
<<: *only-develop
1268+
12191269
- deploy-coinstack-go:
12201270
name: deploy cosmos develop
12211271
organization: TAXISTAKE
@@ -1548,6 +1598,32 @@ workflows:
15481598
<<: *arbitrum
15491599
<<: *only-main
15501600

1601+
####### ARBITRUM NOVA
1602+
- deploy-coinstack-node:
1603+
name: preview arbitrum nova
1604+
organization: TAXISTAKE
1605+
pulumi-command: preview
1606+
requires:
1607+
- validate dependencies
1608+
<<: *arbitrum-nova
1609+
<<: *only-main
1610+
1611+
- approve-coinstack:
1612+
name: approve arbitrum nova coinstack
1613+
type: approval
1614+
requires:
1615+
- preview arbitrum nova
1616+
<<: *only-main
1617+
1618+
- deploy-coinstack-node:
1619+
name: deploy arbitrum nova
1620+
organization: TAXISTAKE
1621+
pulumi-command: up -f --yes
1622+
requires:
1623+
- approve arbitrum nova coinstack
1624+
<<: *arbitrum-nova
1625+
<<: *only-main
1626+
15511627
####### COSMOS
15521628
- deploy-coinstack-go:
15531629
name: preview cosmos

docker-compose.yml

+3
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ services:
3434
- "--providers.docker.exposedbydefault=false"
3535
networks:
3636
- arbitrum_default
37+
- arbitrum-nova_default
3738
- avalanche_default
3839
- bitcoin_default
3940
- bitcoincash_default
@@ -58,6 +59,8 @@ services:
5859
networks:
5960
arbitrum_default:
6061
name: arbitrum_default
62+
arbitrum-nova_default:
63+
name: arbitrum-nova_default
6164
avalanche_default:
6265
name: avalanche_default
6366
bitcoin_default:
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
ARG BASE_IMAGE
2+
3+
FROM $BASE_IMAGE
4+
5+
# Include app
6+
WORKDIR /app/node/coinstacks/arbitrum-nova/api
7+
COPY . .
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
{
2+
"ignore": ["src/routes.ts"],
3+
"watch": ["../../../packages/*/dist/tsconfig.tsbuildinfo", "../../common/api/dist/tsconfig.tsbuildinfo", "src"],
4+
"ext": "ts",
5+
"exec": "yarn build && node dist/arbitrum-nova/api/src/app.js"
6+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
{
2+
"name": "@shapeshiftoss/arbitrum-nova-api",
3+
"version": "9.3.0",
4+
"license": "MIT",
5+
"private": true,
6+
"files": [
7+
"dist"
8+
],
9+
"scripts": {
10+
"build": "yarn generate && tsc",
11+
"clean": "rm -rf dist node_modules src/routes.ts src/swagger.json",
12+
"generate": "tsoa spec-and-routes"
13+
},
14+
"dependencies": {
15+
"@shapeshiftoss/blockbook": "^9.3.0",
16+
"@shapeshiftoss/common-api": "^9.3.0"
17+
}
18+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,90 @@
1+
import express, { json, urlencoded } from 'express'
2+
import cors from 'cors'
3+
import { join } from 'path'
4+
import { Server } from 'ws'
5+
import swaggerUi from 'swagger-ui-express'
6+
import {
7+
evm,
8+
middleware,
9+
ConnectionHandler,
10+
Registry,
11+
BlockHandler,
12+
TransactionHandler,
13+
Prometheus,
14+
} from '@shapeshiftoss/common-api'
15+
import { Tx as BlockbookTx, WebsocketClient, getAddresses, NewBlock } from '@shapeshiftoss/blockbook'
16+
import { Logger } from '@shapeshiftoss/logger'
17+
import { gasOracle, service } from './controller'
18+
import { RegisterRoutes } from './routes'
19+
20+
const PORT = process.env.PORT ?? 3000
21+
const INDEXER_WS_URL = process.env.INDEXER_WS_URL
22+
23+
if (!INDEXER_WS_URL) throw new Error('INDEXER_WS_URL env var not set')
24+
25+
export const logger = new Logger({
26+
namespace: ['unchained', 'coinstacks', 'arbitrum-nova', 'api'],
27+
level: process.env.LOG_LEVEL,
28+
})
29+
30+
const prometheus = new Prometheus({ coinstack: 'arbitrum-nova' })
31+
32+
const app = express()
33+
34+
app.use(json(), urlencoded({ extended: true }), cors(), middleware.requestLogger, middleware.metrics(prometheus))
35+
36+
app.get('/health', async (_, res) =>
37+
res.json({ status: 'up', asset: 'arbitrum-nova', connections: wsServer.clients.size })
38+
)
39+
40+
app.get('/metrics', async (_, res) => {
41+
res.setHeader('Content-Type', prometheus.register.contentType)
42+
res.send(await prometheus.register.metrics())
43+
})
44+
45+
const options: swaggerUi.SwaggerUiOptions = {
46+
customCss: '.swagger-ui .topbar { display: none }',
47+
customSiteTitle: 'ShapeShift Arbitrum Nova API Docs',
48+
customfavIcon: '/public/favi-blue.png',
49+
swaggerUrl: '/swagger.json',
50+
}
51+
52+
app.use('/public', express.static(join(__dirname, '../../../../../../common/api/public')))
53+
app.use('/swagger.json', express.static(join(__dirname, './swagger.json')))
54+
app.use('/docs', swaggerUi.serve, swaggerUi.setup(undefined, options))
55+
56+
RegisterRoutes(app)
57+
58+
// redirect any unmatched routes to docs
59+
app.get('/', async (_, res) => {
60+
res.redirect('/docs')
61+
})
62+
63+
app.use(middleware.errorHandler, middleware.notFoundHandler)
64+
65+
const blockHandler: BlockHandler<NewBlock, Array<BlockbookTx>> = async (block) => {
66+
const txs = await service.handleBlock(block.hash)
67+
return { txs }
68+
}
69+
70+
const transactionHandler: TransactionHandler<BlockbookTx, evm.Tx> = async (blockbookTx) => {
71+
const tx = await service.handleTransactionWithInternalTrace(blockbookTx)
72+
const internalAddresses = (tx.internalTxs ?? []).reduce<Array<string>>((prev, tx) => [...prev, tx.to, tx.from], [])
73+
const addresses = [...new Set([...getAddresses(blockbookTx), ...internalAddresses])]
74+
75+
return { addresses, tx }
76+
}
77+
78+
const registry = new Registry({ addressFormatter: evm.formatAddress, blockHandler, transactionHandler })
79+
80+
const server = app.listen(PORT, () => logger.info('Server started'))
81+
const wsServer = new Server({ server })
82+
83+
wsServer.on('connection', (connection) => {
84+
ConnectionHandler.start(connection, registry, prometheus)
85+
})
86+
87+
new WebsocketClient(INDEXER_WS_URL, {
88+
blockHandler: [registry.onBlock.bind(registry), gasOracle.onBlock.bind(gasOracle)],
89+
transactionHandler: registry.onTransaction.bind(registry),
90+
})

0 commit comments

Comments
 (0)