Skip to content

Commit

Permalink
feat: unchained client (shapeshift#603)
Browse files Browse the repository at this point in the history
* chore: adds issue automation

* feat(unchained-client): add unchained-client package

* Dockerized generator for different environments

* Remove local openapi-generator-cli

* Pull in recent cleanup changes in unchained

* Update common-api package

* Fix docker context

* Use published docker image

* Fix ethers mock to play nicely with hdwallet

* review changes

* formatting

Co-authored-by: 0xean <[email protected]>
  • Loading branch information
kaladinlight and 0xean authored May 5, 2022
1 parent 546926b commit 0e0df76
Show file tree
Hide file tree
Showing 92 changed files with 10,827 additions and 36 deletions.
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.

# generated files
packages/unchained-client/src/generated

# dependencies
node_modules
/.pnp
Expand Down
1 change: 1 addition & 0 deletions .jest/setEnvVars.js
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
process.env.NETWORK = 'mainnet'
69 changes: 69 additions & 0 deletions __mocks__/ethers.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
/* eslint-disable @typescript-eslint/no-explicit-any */
const ethers = {
...jest.requireActual('ethers').ethers,
providers: {
JsonRpcProvider: jest.fn()
},
Contract: jest.fn().mockImplementation((address) => ({
decimals: () => {
switch (address as string) {
case '0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48':
return 6
case '0xc770EEfAd204B5180dF6a14Ee197D99d808ee52d':
return 18
case '0x470e8de2eBaef52014A47Cb5E6aF86884947F08c':
return 18
case '0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2':
return 18
default:
throw new Error(`no decimals mock for address: ${address}`)
}
},
name: () => {
switch (address as string) {
case '0xc770EEfAd204B5180dF6a14Ee197D99d808ee52d':
return 'FOX'
case '0x470e8de2eBaef52014A47Cb5E6aF86884947F08c':
return 'Uniswap V2'
case '0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2':
return 'Wrapped Ether'
default:
throw new Error(`no decimals mock for address: ${address}`)
}
},
symbol: () => {
switch (address as string) {
case '0xc770EEfAd204B5180dF6a14Ee197D99d808ee52d':
return 'FOX'
case '0x470e8de2eBaef52014A47Cb5E6aF86884947F08c':
return 'UNI-V2'
case '0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2':
return 'WETH'
default:
throw new Error(`no decimals mock for address: ${address}`)
}
}
}))
}

// extra mocks for hdwallet which uses explicit imports instead of the standard `import { ethers } from 'ethers'`
const BigNumber = jest.requireActual('ethers').BigNumber
const Bytes = jest.requireActual('ethers').Bytes
const BytesLike = jest.requireActual('ethers').BytesLike
const Signature = jest.requireActual('ethers').Signature
const Signer = jest.requireActual('ethers').Signer
const UnsignedTransaction = jest.requireActual('ethers').UnsignedTransaction
const providers = jest.requireActual('ethers').providers
const utils = jest.requireActual('ethers').utils

export {
ethers,
BigNumber,
Bytes,
BytesLike,
Signature,
Signer,
UnsignedTransaction,
providers,
utils
}
10 changes: 4 additions & 6 deletions jest.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ export default {
coverageDirectory: 'coverage',

// An array of regexp pattern strings used to skip coverage collection
coveragePathIgnorePatterns: ['/node_modules/', 'dist'],
coveragePathIgnorePatterns: ['/node_modules/', 'dist', '__mocks__', 'mockData'],

// Indicates which provider should be used to instrument code for coverage
// coverageProvider: "babel",
Expand Down Expand Up @@ -129,7 +129,7 @@ export default {
// runner: "jest-runner",

// The paths to modules that run some code to configure or set up the testing environment before each test
// setupFiles: [],
setupFiles: ['<rootDir>/.jest/setEnvVars.js'],

// A list of paths to modules that run some code to configure or set up the testing framework before each test
// setupFilesAfterEnv: [],
Expand All @@ -141,7 +141,7 @@ export default {
// snapshotSerializers: [],

// The test environment that will be used for testing
testEnvironment: 'node'
testEnvironment: 'node',

// Options that will be passed to the testEnvironment
// testEnvironmentOptions: {},
Expand All @@ -156,9 +156,7 @@ export default {
// ],

// An array of regexp pattern strings that are matched against all test paths, matched tests are skipped
// testPathIgnorePatterns: [
// "/node_modules/"
// ],
testPathIgnorePatterns: ['/node_modules/', '.d.ts', '.js', '__mocks__', 'mockData']

// The regexp pattern or array of patterns that Jest uses to detect test files
// testRegex: [],
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
"scripts": {
"local-ci": "yarn clean && yarn && yarn lint && yarn build && yarn type-check && yarn test",
"build": "lerna run build --include-dependencies",
"clean": "rimraf node_modules dist packages/**/dist packages/**/node_modules packages/**/tsconfig.build.tsbuildinfo",
"clean": "rimraf node_modules dist packages/**/dist packages/**/node_modules packages/**/tsconfig.build.tsbuildinfo packages/unchained-client/src/generated",
"dev": "lerna run dev --stream --parallel",
"lint": "eslint --cache --max-warnings=0 .",
"lint:fix": "yarn lint --fix",
Expand Down
54 changes: 54 additions & 0 deletions packages/unchained-client/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
# Unchained API Client

Provides a typescript axios client to interact with all supported unchained API's

## Installing

Using npm:
```
npm install @shapeshiftoss/unchained-client
```

Using yarn:
```
yarn add @shapeshiftoss/unchained-client
```

## Resources

- [CAIP-2](https://github.com/ChainAgnostic/CAIPs/blob/master/CAIPs/caip-2.md) naming conventions used for `chainId`
- [CAIP-19](https://github.com/ChainAgnostic/CAIPs/blob/master/CAIPs/caip-19.md) naming conventions used for `assetId`

## Usage

```
import * as unchained from '@shapeshiftoss/unchained-client'
const address = 'cosmos1t5u0jfg3ljsjrh2m9e47d4ny2hea7eehxrzdgd'
// configuration for the api client
const config = new unchained.cosmos.Configuration({ basePath: 'https://dev-api.cosmos.shapeshift.com' })
// create new instance of the api client
const apiClient = new unchained.cosmos.V1Api(config)
// create new instance of the ws client
const wsClient = new unchained.ws.Client<unchained.cosmos.Tx>('wss://dev-api.cosmos.shapeshift.com')
// create new instance of the transaction parser
// chainId is in the format of [Caip2](https://github.com/ChainAgnostic/CAIPs/blob/master/CAIPs/caip-2.md)
const parser = new unchained.cosmos.TransactionParser({ chainId: 'cosmos:cosmoshub-4' })
// example api client request
const { data } = await apiClient.getBalance({ pubkey: address })
// example websocket subscription for new transaction and transaction parsing
await this.providers.ws.subscribeTxs(
'test',
{ topic: 'txs', addresses: [address] },
async (msg) => {
const tx = await parser.parse(msg.data, msg.address)
},
(err) => console.warn(err)
)
```
6 changes: 6 additions & 0 deletions packages/unchained-client/generator/Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
FROM timbru31/java-node:11-jdk

RUN npm install @openapitools/openapi-generator-cli -g
RUN openapi-generator-cli version-manager set 5.4.0

ENTRYPOINT [ "openapi-generator-cli" ]
39 changes: 39 additions & 0 deletions packages/unchained-client/generator/dev/openapitools.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
{
"$schema": "usr/local/node_modules/@openapitools/openapi-generator-cli/config.schema.json",
"spaces": 2,
"generator-cli": {
"version": "5.4.0",
"generators": {
"ethereum": {
"inputSpec": "https://dev-api.ethereum.shapeshift.com/swagger.json",
"generatorName": "typescript-axios",
"output": "#{cwd}/../../src/generated/ethereum",
"reservedWordsMappings": { "in": "in" },
"additionalProperties": {
"supportsES6": "true",
"useSingleRequestParameter": true
}
},
"bitcoin": {
"inputSpec": "https://dev-api.bitcoin.shapeshift.com/swagger.json",
"generatorName": "typescript-axios",
"output": "#{cwd}/../../src/generated/bitcoin",
"reservedWordsMappings": { "in": "in" },
"additionalProperties": {
"supportsES6": "true",
"useSingleRequestParameter": true
}
},
"cosmos": {
"inputSpec": "https://dev-api.cosmos.shapeshift.com/swagger",
"generatorName": "typescript-axios",
"output": "#{cwd}/../../src/generated/cosmos",
"reservedWordsMappings": { "in": "in" },
"additionalProperties": {
"supportsES6": "true",
"useSingleRequestParameter": true
}
}
}
}
}
23 changes: 23 additions & 0 deletions packages/unchained-client/generator/generate.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
#!/bin/bash

IMAGE=shapeshiftdao/openapi-generator-cli-v5.4.0
USER=$(id -u):$(id -g)
ROOTDIR=$(git rev-parse --show-toplevel)/packages/unchained-client
GENDIR=$(pwd)/generator

while getopts ':e:h' flag; do
case "${flag}" in
e) env=${OPTARG};;
h) echo -e "Usage: $(basename $0) -e (local|dev|public)" && exit 1;;
:) echo -e "Option requires an argument.\nUsage: $(basename $0) -e (local|dev|public)" && exit 1;;
?) echo -e "Invalid command option.\nUsage: $(basename $0) -e (local|dev|public)" && exit 1;;
esac
done

if [[ $env == "" ]]; then
echo -e "Usage: $(basename $0) -e (local|dev|public)" && exit 1
fi

docker run --platform=linux/amd64 --rm --user $USER -e JAVA_OPTS='-Dlog.level=error' -v "$ROOTDIR:$ROOTDIR" -w $GENDIR/$env $IMAGE generate

exit 0
39 changes: 39 additions & 0 deletions packages/unchained-client/generator/local/openapitools.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
{
"$schema": "usr/local/node_modules/@openapitools/openapi-generator-cli/config.schema.json",
"spaces": 2,
"generator-cli": {
"version": "5.4.0",
"generators": {
"ethereum": {
"inputSpec": "http://api.ethereum.localhost/swagger.json",
"generatorName": "typescript-axios",
"output": "#{cwd}/../../src/generated/ethereum",
"reservedWordsMappings": { "in": "in" },
"additionalProperties": {
"supportsES6": "true",
"useSingleRequestParameter": true
}
},
"bitcoin": {
"inputSpec": "http://api.bitcoin.localhost/swagger.json",
"generatorName": "typescript-axios",
"output": "#{cwd}/../../src/generated/bitcoin",
"reservedWordsMappings": { "in": "in" },
"additionalProperties": {
"supportsES6": "true",
"useSingleRequestParameter": true
}
},
"cosmos": {
"inputSpec": "http://api.cosmos.localhost/swagger",
"generatorName": "typescript-axios",
"output": "#{cwd}/../../src/generated/cosmos",
"reservedWordsMappings": { "in": "in" },
"additionalProperties": {
"supportsES6": "true",
"useSingleRequestParameter": true
}
}
}
}
}
39 changes: 39 additions & 0 deletions packages/unchained-client/generator/public/openapitools.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
{
"$schema": "usr/local/node_modules/@openapitools/openapi-generator-cli/config.schema.json",
"spaces": 2,
"generator-cli": {
"version": "5.4.0",
"generators": {
"ethereum": {
"inputSpec": "https://api.ethereum.shapeshift.com/swagger.json",
"generatorName": "typescript-axios",
"output": "#{cwd}/../../src/generated/ethereum",
"reservedWordsMappings": { "in": "in" },
"additionalProperties": {
"supportsES6": "true",
"useSingleRequestParameter": true
}
},
"bitcoin": {
"inputSpec": "https://api.bitcoin.shapeshift.com/swagger.json",
"generatorName": "typescript-axios",
"output": "#{cwd}/../../src/generated/bitcoin",
"reservedWordsMappings": { "in": "in" },
"additionalProperties": {
"supportsES6": "true",
"useSingleRequestParameter": true
}
},
"cosmos": {
"inputSpec": "https://api.cosmos.shapeshift.com/swagger",
"generatorName": "typescript-axios",
"output": "#{cwd}/../../src/generated/cosmos",
"reservedWordsMappings": { "in": "in" },
"additionalProperties": {
"supportsES6": "true",
"useSingleRequestParameter": true
}
}
}
}
}
37 changes: 37 additions & 0 deletions packages/unchained-client/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
{
"name": "@shapeshiftoss/unchained-client",
"version": "6.11.0",
"license": "MIT",
"main": "dist/index.js",
"source": "src/index.ts",
"types": "dist/index.d.ts",
"files": [
"dist"
],
"scripts": {
"build": "yarn clean && yarn generate && tsc -p tsconfig.build.json",
"build:public": "yarn clean && yarn generate:public && tsc -p tsconfig.build.json",
"build:local": "yarn clean && yarn generate:local && tsc -p tsconfig.build.json",
"dev": "tsc --watch",
"clean": "rm -rf dist node_modules src/generated tsconfig.build.tsbuildinfo",
"generate": "./generator/generate.sh -e dev",
"generate:public": "./generator/generate.sh -e public",
"generate:local": "./generator/generate.sh -e local",
"type-check": "tsc --project ./tsconfig.build.json --noEmit"
},
"dependencies": {
"@shapeshiftoss/blockbook": "^6.11.0",
"@shapeshiftoss/caip": "^2.2.3",
"@shapeshiftoss/logger": "^1.1.2",
"@shapeshiftoss/types": "^3.1.2",
"@yfi/sdk": "^1.0.30",
"bignumber.js": "^9.0.1",
"ethers": "^5.5.3",
"isomorphic-ws": "^4.0.1",
"ws": "^8.3.0"
},
"devDependencies": {
"@shapeshiftoss/common-api": "^6.11.0",
"@types/ws": "^8.2.1"
}
}
3 changes: 3 additions & 0 deletions packages/unchained-client/src/bitcoin/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
export * from '../generated/bitcoin'
export * from './parser'
export * from './types'
Loading

0 comments on commit 0e0df76

Please sign in to comment.