Skip to content

Commit

Permalink
feat: rework code + new features (#61)
Browse files Browse the repository at this point in the history
* feat: rework code + new features

- rework code to make it easier to follow
- throw errors if chain props are not fetched
- render json errors instead of plain text

* fix: tests

* fix: lint

* fix: ci with yarn 4.1.1

* fix: test and publish workflow

* fix: ci
  • Loading branch information
emmanuelm41 authored May 31, 2024
1 parent f76627c commit 6e223ee
Show file tree
Hide file tree
Showing 18 changed files with 352 additions and 222 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/check.ts.yml
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ jobs:
node-version: 20
- name: Install dependencies
run: |
npm -g install yarn
corepack enable
yarn install
- name: Run formatter
run: yarn format
Expand Down
Binary file modified .yarn/install-state.gz
Binary file not shown.
6 changes: 3 additions & 3 deletions chains.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,6 @@ chains:
- id: 'astr'
name: 'Astar'
url: "wss://astar.api.onfinality.io/public-ws"
- id: 'wsd-local'
name: 'Westend Local'
url: "ws://85.208.51.8:36003"
- id: 'roc'
name: 'Rococo'
url: "wss://rococo-rpc.polkadot.io"
63 changes: 50 additions & 13 deletions docs/openapi.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,9 @@ openapi: 3.0.0
info:
title: Ledger Polkadot Generic API
description: This API provides a way to generate the required shortened metadata to sign a transaction on a Ledger device.
version: 1.2.1
version: 1.3.0
servers:
- url: https://api.zondax.ch/dot/generic
- url: https://api.zondax.ch/polkadot
description: Production server
paths:
/chains:
Expand Down Expand Up @@ -38,6 +38,10 @@ paths:
$ref: '#/components/schemas/ChainProps'
'404':
description: Chain not found
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorFound'
/node/metadata/flush:
post:
summary: Flush cache
Expand All @@ -60,6 +64,10 @@ paths:
description: The cache was flushed successfully
'404':
description: Chain not found
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorFound'
/node/metadata:
post:
summary: Retrieve complete node metadata
Expand All @@ -80,6 +88,10 @@ paths:
$ref: '#/components/schemas/Metadata'
'404':
description: Chain not found
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorFound'
/node/metadata/hash:
post:
summary: Retrieve metadata digest hash
Expand All @@ -100,6 +112,10 @@ paths:
$ref: '#/components/schemas/MetadataHash'
'404':
description: Chain not found
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorFound'
/transaction/metadata:
post:
summary: Retrieve shortened metadata for a tx
Expand All @@ -124,13 +140,26 @@ paths:
application/json:
schema:
$ref: '#/components/schemas/ShortenedMetadata'
'400':
description: Missing fields on request
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorFound'
'404':
description: Chain not found
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorFound'
components:
schemas:
Metadata:
type: object
description: JSON metadata retrieved from the node
properties:
metadata:
type: object
description: JSON metadata retrieved from the node
ShortenedMetadata:
type: object
properties:
Expand Down Expand Up @@ -167,16 +196,19 @@ components:
- bnc
ChainProps:
properties:
base58Prefix:
type: number
decimals:
type: number
tokenSymbol:
type: string
specName:
type: string
specVersion:
type: number
props:
type: object
properties:
base58Prefix:
type: number
decimals:
type: number
tokenSymbol:
type: string
specName:
type: string
specVersion:
type: number
ChainConfig:
required:
- id
Expand Down Expand Up @@ -207,3 +239,8 @@ components:
url:
type: string
description: Node API URL used internally to get metadata from
ErrorFound:
type: object
properties:
errorMessage:
type: string
4 changes: 3 additions & 1 deletion earthly-dockerfile/Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -26,11 +26,13 @@ FROM node:20-slim
# Set the working directory in the container
WORKDIR /app

RUN corepack enable

# Copy package.json, yarn.lock
COPY package.json yarn.lock ./

# Install production dependencies only
RUN yarn install --production
RUN yarn workspaces focus --production

# Copy the transpiled JavaScript from the builder stage
COPY --from=builder /app/dist ./dist
Expand Down
15 changes: 15 additions & 0 deletions src/handlers/chains.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import { Chain, getChains } from '../utils/chains'
import { Request, Response } from 'express'

export const chains = (req: Request, res: Response) => {
const chains = getChains()
const chainsFiltered = chains.map(({ name, id, url }: Chain) => {
return {
name,
id,
url: url,
}
})

res.status(200).json({ chains: chainsFiltered })
}
30 changes: 30 additions & 0 deletions src/handlers/nodeMetadata.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
import { Chain, getChains } from '../utils/chains'
import { renderChainNotFoundError, renderInternalError } from '../utils/errors'
import { cacheMetadata } from '../utils/metadata'
import { Request, Response } from 'express'
import { ChainConfig } from '../utils/types'

export const nodeMetadata = async (req: Request, res: Response) => {
const chains = getChains()
const { id: chainId }: ChainConfig = req.body

const chain = chains.find((b: Chain) => b.id === chainId)
if (!chain) {
renderChainNotFoundError(res)
return
}

if (chain.metadata) {
res.status(200).json({ metadata: chain.metadata })
return
}

try {
await cacheMetadata(chain)
} catch (e) {
renderInternalError(res, e)
return
}

res.status(200).json({ metadata: chain.metadata })
}
21 changes: 21 additions & 0 deletions src/handlers/nodeMetadataFlush.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import { Chain, getChains } from '../utils/chains'
import { renderChainNotFoundError } from '../utils/errors'
import { Request, Response } from 'express'
import { ChainConfig } from '../utils/types'

export const nodeMetadataFlush = (req: Request, res: Response) => {
const chains = getChains()
const { id: chainId }: ChainConfig = req.body

const chain = chains.find((b: Chain) => b.id === chainId)
if (!chain) {
renderChainNotFoundError(res)
return
}

chain.metadata = undefined
chain.metadataHex = undefined
chain.props = undefined

res.status(200).json()
}
37 changes: 37 additions & 0 deletions src/handlers/nodeMetadataHash.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
import { Chain, getChains } from '../utils/chains'
import { renderChainNotFoundError, renderGetMetadataFirstError, renderInternalError } from '../utils/errors'
import { cacheMetadata } from '../utils/metadata'
import { getMetadataDigest } from '../../rust'
import { Request, Response } from 'express'
import { ChainConfig } from '../utils/types'

export const nodeMetadataHash = async (req: Request, res: Response) => {
const chains = getChains()
const { id: chainId }: ChainConfig = req.body

const chain = chains.find((b: Chain) => b.id === chainId)
if (!chain) {
renderChainNotFoundError(res)
return
}

let { props, metadataHex } = chain
if (!props || !metadataHex) {
try {
await cacheMetadata(chain)
} catch (e) {
renderInternalError(res, e)
return
}
}

;({ props, metadataHex } = chain)
if (!props || !metadataHex) {
renderGetMetadataFirstError(res)
return
}

const metadataHash = getMetadataDigest({ metadata: metadataHex, props })

res.status(200).json({ metadataHash })
}
35 changes: 35 additions & 0 deletions src/handlers/nodeProps.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
import { Chain, getChains } from '../utils/chains'
import { renderChainNotFoundError, renderGetMetadataFirstError, renderInternalError } from '../utils/errors'
import { cacheMetadata } from '../utils/metadata'
import { Request, Response } from 'express'
import { ChainConfig } from '../utils/types'

export const nodeProps = async (req: Request, res: Response) => {
const chains = getChains()

const { id: chainId }: ChainConfig = req.body

const chain = chains.find((b: Chain) => b.id === chainId)
if (!chain) {
renderChainNotFoundError(res)
return
}

let { props } = chain
if (!props) {
try {
await cacheMetadata(chain)
} catch (e) {
renderInternalError(res, e)
return
}
}

;({ props } = chain)
if (!props) {
renderGetMetadataFirstError(res)
return
}

res.status(200).json({ props: { ...props } })
}
53 changes: 53 additions & 0 deletions src/handlers/transactionMetadata.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
import { Response, Request } from 'express'
import { Chain, getChains } from '../utils/chains'
import { renderChainNotFoundError, renderGetMetadataFirstError, renderInternalError, renderMissingTxBlobError } from '../utils/errors'
import { cacheMetadata } from '../utils/metadata'
import { getShortMetadataFromTxBlob } from '../../rust'
import { TxToSign } from '../utils/types'

export const transactionMetadata = async (req: Request, res: Response) => {
const chains = getChains()

const {
chain: { id: chainId },
}: TxToSign = req.body
let { txBlob }: TxToSign = req.body

const chain = chains.find((b: Chain) => b.id === chainId)
if (!chain) {
renderChainNotFoundError(res)
return
}

let { props, metadataHex } = chain
if (!props || !metadataHex === undefined) {
try {
await cacheMetadata(chain)
} catch (e) {
renderInternalError(res, e)
return
}
}

;({ props, metadataHex } = chain)
if (!props || !metadataHex) {
renderGetMetadataFirstError(res)
return
}

if (!txBlob) {
renderMissingTxBlobError(res)
return
}

try {
if (txBlob.substring(0, 2) == '0x') {
txBlob = txBlob.substring(2)
}

const txMetadata = Buffer.from(getShortMetadataFromTxBlob({ txBlob, metadata: metadataHex, props }), 'hex')
res.status(200).send({ txMetadata: '0x' + txMetadata.toString('hex') })
} catch (e) {
renderInternalError(res, e)
}
}
Loading

0 comments on commit 6e223ee

Please sign in to comment.