Skip to content
This repository was archived by the owner on Apr 11, 2023. It is now read-only.

feat: bring over buildQuoteTx logic from platform-shared #71

Merged
merged 16 commits into from
Sep 29, 2021
Merged
Show file tree
Hide file tree
Changes from 12 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 7 additions & 1 deletion packages/swapper/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,14 @@
},
"dependencies": {
"@shapeshiftoss/asset-service": "^1.0.0",
"@shapeshiftoss/chain-adapters": "^1.0.0",
"@shapeshiftoss/hdwallet-core": "^1.16.2-alpha.0",
"axios": "^0.21.4",
"bignumber.js": "^9.0.1"
"web3": "^1.5.2",
"bignumber.js": "^9.0.1",
"retry-axios": "^2.6.0"
},
"devDependencies": {
"web3-utils": "^1.5.2"
}
}
14 changes: 14 additions & 0 deletions packages/swapper/src/api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ export enum SwapperType {
Thorchain = 'Thorchain'
}

export class SwapError extends Error {}

export interface FeeData {
fee?: string
gas?: string
Expand Down Expand Up @@ -84,10 +86,22 @@ export interface GetQuoteInput {
minimum?: string
}

export type BuildQuoteTxArgs = {
input: GetQuoteInput
wallet: HDWallet
}

export interface Swapper {
/** Returns the swapper type */
getType(): SwapperType

/**
* Get a Quote along with an unsigned transaction that can be signed and broadcast to execute the swap
* @param input
* @param wallet
**/
buildQuoteTx?(args: BuildQuoteTxArgs): Promise<Quote>

/**
* Get a basic quote (rate) for a trading pair
* @param input
Expand Down
13 changes: 10 additions & 3 deletions packages/swapper/src/manager/SwapperManager.test.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,16 @@
/* eslint-disable @typescript-eslint/ban-ts-comment */
import Web3 from 'web3'
import { SwapperType } from '../api'
import { ThorchainSwapper, ZrxSwapper } from '../swappers'
import { SwapperManager } from './SwapperManager'
import { ChainAdapterManager } from '@shapeshiftoss/chain-adapters'

describe('SwapperManager', () => {
const zrxSwapperDeps = {
web3: <Web3>{},
adapterManager: <ChainAdapterManager>{}
}

describe('constructor', () => {
it('should return an instance', () => {
const manager = new SwapperManager()
Expand All @@ -22,7 +29,7 @@ describe('SwapperManager', () => {
const manager = new SwapperManager()
manager
.addSwapper(SwapperType.Thorchain, new ThorchainSwapper())
.addSwapper(SwapperType.Zrx, new ZrxSwapper())
.addSwapper(SwapperType.Zrx, new ZrxSwapper(zrxSwapperDeps))
expect(manager.getSwapper(SwapperType.Zrx)).toBeInstanceOf(ZrxSwapper)
})

Expand All @@ -31,7 +38,7 @@ describe('SwapperManager', () => {
expect(() => {
swapper
.addSwapper(SwapperType.Thorchain, new ThorchainSwapper())
.addSwapper(SwapperType.Thorchain, new ZrxSwapper())
.addSwapper(SwapperType.Thorchain, new ZrxSwapper(zrxSwapperDeps))
}).toThrow('already exists')
})
})
Expand All @@ -47,7 +54,7 @@ describe('SwapperManager', () => {
const swapper = new SwapperManager()
swapper
.addSwapper(SwapperType.Thorchain, new ThorchainSwapper())
.addSwapper(SwapperType.Zrx, new ZrxSwapper())
.addSwapper(SwapperType.Zrx, new ZrxSwapper(zrxSwapperDeps))

expect(swapper.getSwapper(SwapperType.Thorchain)).toBeInstanceOf(ThorchainSwapper)
expect(swapper.getSwapper(SwapperType.Zrx)).toBeInstanceOf(ZrxSwapper)
Expand Down
49 changes: 35 additions & 14 deletions packages/swapper/src/swappers/zrx/ZrxSwapper.test.ts
Original file line number Diff line number Diff line change
@@ -1,14 +1,22 @@
import { ChainTypes, NetworkTypes, ContractTypes } from '@shapeshiftoss/asset-service'
import Web3 from 'web3'
import { HDWallet } from '@shapeshiftoss/hdwallet-core'
import { ChainAdapterManager } from '@shapeshiftoss/chain-adapters'
import { ChainTypes, NetworkTypes, ContractTypes, Asset } from '@shapeshiftoss/asset-service'
import { ZrxSwapper } from '..'
import { SwapperType, ZrxError } from '../..'
import { DEFAULT_SLIPPAGE } from './constants'
import { GetQuoteInput, SwapperType, ZrxError } from '../..'
import { DEFAULT_SLIPPAGE } from './utils/constants'
import { buildQuoteTx } from '../zrx/buildQuoteTx/buildQuoteTx'
import { getZrxQuote } from './getQuote/getQuote'

jest.mock('../zrx/buildQuoteTx/buildQuoteTx', () => ({
buildQuoteTx: jest.fn()
}))

jest.mock('./getQuote/getQuote', () => ({
getZrxQuote: jest.fn()
}))

const BTC = {
const BTC = ({
name: 'bitcoin',
chain: ChainTypes.Bitcoin,
network: NetworkTypes.MAINNET,
Expand All @@ -23,8 +31,8 @@ const BTC = {
sendSupport: false,
receiveSupport: false,
symbol: 'BTC'
}
const WETH = {
} as unknown) as Asset
const WETH = ({
name: 'WETH',
chain: ChainTypes.Ethereum,
network: NetworkTypes.MAINNET,
Expand All @@ -39,8 +47,8 @@ const WETH = {
sendSupport: true,
receiveSupport: true,
symbol: 'WETH'
}
const FOX = {
} as unknown) as Asset
const FOX = ({
name: 'Fox',
chain: ChainTypes.Ethereum,
network: NetworkTypes.MAINNET,
Expand All @@ -53,7 +61,7 @@ const FOX = {
sendSupport: true,
receiveSupport: true,
symbol: 'FOX'
}
} as unknown) as Asset

const setupQuote = () => {
const sellAmount = '1000000000000000000'
Expand All @@ -70,14 +78,20 @@ const setupQuote = () => {
}

describe('ZrxSwapper', () => {
const input = <GetQuoteInput>{}
const wallet = <HDWallet>{}
const web3 = <Web3>{}
const adapterManager = <ChainAdapterManager>{}
const zrxSwapperDeps = { web3, adapterManager }

it('calls getZrxQuote on getQuote', async () => {
const { quoteInput } = setupQuote()
const swapper = new ZrxSwapper()
const swapper = new ZrxSwapper(zrxSwapperDeps)
await swapper.getQuote(quoteInput)
expect(getZrxQuote).toHaveBeenCalled()
})
it('returns Zrx type', () => {
const swapper = new ZrxSwapper()
const swapper = new ZrxSwapper(zrxSwapperDeps)
const type = swapper.getType()
expect(type).toBe(SwapperType.Zrx)
})
Expand All @@ -87,18 +101,25 @@ describe('ZrxSwapper', () => {
expect(error.message).toBe(`ZrxError:${message}`)
})
it('available assets filters out all non-ethereum assets', () => {
const swapper = new ZrxSwapper()
const swapper = new ZrxSwapper(zrxSwapperDeps)
const availableAssets = swapper.getAvailableAssets([BTC, FOX, WETH])
expect(availableAssets).toStrictEqual([FOX, WETH])
})
it('canTradePair fails on non-eth chains', () => {
const swapper = new ZrxSwapper()
const swapper = new ZrxSwapper(zrxSwapperDeps)
const canTradePair = swapper.canTradePair(BTC, WETH)
expect(canTradePair).toBeFalsy()
})
it('canTradePair succeeds on eth chains', () => {
const swapper = new ZrxSwapper()
const swapper = new ZrxSwapper(zrxSwapperDeps)
const canTradePair = swapper.canTradePair(FOX, WETH)
expect(canTradePair).toBeTruthy()
})
it('calls buildQuoteTx on swapper.buildQuoteTx', async () => {
const swapper = new ZrxSwapper(zrxSwapperDeps)
const args = { input, wallet }

await swapper.buildQuoteTx(args)
expect(buildQuoteTx).toHaveBeenCalled()
})
})
35 changes: 34 additions & 1 deletion packages/swapper/src/swappers/zrx/ZrxSwapper.ts
Original file line number Diff line number Diff line change
@@ -1,17 +1,50 @@
import Web3 from 'web3'
import { Asset, ChainTypes } from '@shapeshiftoss/asset-service'
import { GetQuoteInput, Quote, Swapper, SwapperType } from '../../api'
import { ChainAdapterManager } from '@shapeshiftoss/chain-adapters'
import { BuildQuoteTxArgs, GetQuoteInput, Quote, Swapper, SwapperType } from '../../api'

import { buildQuoteTx } from './buildQuoteTx/buildQuoteTx'
import { getZrxQuote } from './getQuote/getQuote'
import { getDeps } from '../zrx/utils/helpers/helpers'

export type ZrxSwapperDeps = {
adapterManager: ChainAdapterManager
web3: Web3
}

export class ZrxError extends Error {
constructor(message: string) {
super(message)
this.message = `ZrxError:${message}`
}
}

export class ZrxSwapper implements Swapper {
public static swapperName = 'ZrxSwapper'
adapterManager: ChainAdapterManager
web3: Web3

constructor(deps: ZrxSwapperDeps) {
this.adapterManager = deps.adapterManager
this.web3 = deps.web3
}

private getDeps<
T extends typeof ZrxSwapper,
P = Parameters<typeof getDeps>[],
R = ReturnType<typeof getDeps>
>(): R {
return getDeps.call<T, P[], R>((this as unknown) as T)
}

getType() {
return SwapperType.Zrx
}

async buildQuoteTx({ input, wallet }: BuildQuoteTxArgs): Promise<Quote> {
return buildQuoteTx(this.getDeps(), { input, wallet })
}

async getQuote(input: GetQuoteInput): Promise<Quote> {
return getZrxQuote(input)
}
Expand Down
Loading