forked from shapeshift/lib
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat: add execute quote (shapeshift#87)
* initial setup of executeQuote * add guard clause logic to executeQuote with tests * cleanup from merge * add adapter logic to executeQuote; add tests * fix unimplemented methods for thorchain swapper
- Loading branch information
Showing
7 changed files
with
192 additions
and
18 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
20 changes: 12 additions & 8 deletions
20
packages/swapper/src/swappers/thorchain/ThorchainSwapper.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,30 +1,34 @@ | ||
import { Asset, SwapperType } from '@shapeshiftoss/types' | ||
import { Asset, SwapperType, Quote, ExecQuoteOutput } from '@shapeshiftoss/types' | ||
import { Swapper } from '../../api' | ||
|
||
export class ThorchainSwapper implements Swapper { | ||
getType() { | ||
return SwapperType.Thorchain | ||
} | ||
|
||
async getQuote() { | ||
return undefined | ||
async getQuote(): Promise<Quote> { | ||
throw new Error('ThorchainSwapper: getQuote unimplemented') | ||
} | ||
|
||
async buildQuoteTx() { | ||
return undefined | ||
async buildQuoteTx(): Promise<Quote> { | ||
throw new Error('ThorchainSwapper: getQuote unimplemented') | ||
} | ||
|
||
getUsdRate(input: Pick<Asset, 'symbol' | 'tokenId'>): Promise<string> { | ||
console.info(input) | ||
throw new Error('Method not implemented.') | ||
throw new Error('ThorchainSwapper: getUsdRate unimplemented') | ||
} | ||
|
||
getAvailableAssets(assets: Asset[]): Asset[] { | ||
console.info(assets) | ||
throw new Error('Method not implemented.') | ||
throw new Error('ThorchainSwapper: getAvailableAssets unimplemented') | ||
} | ||
canTradePair(sellAsset: Asset, buyAsset: Asset): boolean { | ||
console.info(sellAsset, buyAsset) | ||
throw new Error('Method not implemented.') | ||
throw new Error('ThorchainSwapper: canTradePair unimplemented') | ||
} | ||
|
||
async executeQuote(): Promise<ExecQuoteOutput> { | ||
throw new Error('ThorchainSwapper: executeQuote unimplemented') | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
88 changes: 88 additions & 0 deletions
88
packages/swapper/src/swappers/zrx/executeQuote/executeQuote.test.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,88 @@ | ||
import { HDWallet } from '@shapeshiftoss/hdwallet-core' | ||
import { ExecQuoteInput } from '@shapeshiftoss/types' | ||
import { executeQuote } from './executeQuote' | ||
import { setupQuote } from '../utils/test-data/setupSwapQuote' | ||
import { ZrxSwapperDeps } from '../ZrxSwapper' | ||
|
||
describe('executeQuote', () => { | ||
const { quoteInput, sellAsset } = setupQuote() | ||
const txid = '0xffaac3dd529171e8a9a2adaf36b0344877c4894720d65dfd86e4b3a56c5a857e' | ||
const wallet = <HDWallet>{} | ||
const adapterManager = { | ||
byChain: jest.fn(() => ({ | ||
buildSendTransaction: jest.fn(() => Promise.resolve({ txToSign: '0000000000000000' })), | ||
signTransaction: jest.fn(() => Promise.resolve('0000000000000000000')), | ||
broadcastTransaction: jest.fn(() => Promise.resolve(txid)) | ||
})) | ||
} | ||
const deps = ({ adapterManager } as unknown) as ZrxSwapperDeps | ||
|
||
it('throws an error if quote.success is false', async () => { | ||
const args = { | ||
quote: { ...quoteInput, success: false }, | ||
wallet | ||
} | ||
await expect(executeQuote(deps, args)).rejects.toThrow( | ||
'ZrxSwapper:executeQuote Cannot execute a failed quote' | ||
) | ||
}) | ||
|
||
it('throws an error if sellAsset.network is not provided', async () => { | ||
const args = ({ | ||
quote: { ...quoteInput, sellAsset: { ...sellAsset, network: '' } }, | ||
wallet | ||
} as unknown) as ExecQuoteInput | ||
await expect(executeQuote(deps, args)).rejects.toThrow( | ||
'ZrxSwapper:executeQuote sellAssetNetwork and sellAssetSymbol are required' | ||
) | ||
}) | ||
|
||
it('throws an error if sellAsset.symbol is not provided', async () => { | ||
const args = { | ||
quote: { ...quoteInput, sellAsset: { ...sellAsset, symbol: '' } }, | ||
wallet | ||
} | ||
await expect(executeQuote(deps, args)).rejects.toThrow( | ||
'ZrxSwapper:executeQuote sellAssetNetwork and sellAssetSymbol are required' | ||
) | ||
}) | ||
|
||
it('throws an error if quote.sellAssetAccountId is not provided', async () => { | ||
const args = { | ||
quote: { ...quoteInput, sellAssetAccountId: '' }, | ||
wallet | ||
} | ||
await expect(executeQuote(deps, args)).rejects.toThrow( | ||
'ZrxSwapper:executeQuote sellAssetAccountId is required' | ||
) | ||
}) | ||
|
||
it('throws an error if quote.sellAmount is not provided', async () => { | ||
const args = { | ||
quote: { ...quoteInput, sellAmount: '' }, | ||
wallet | ||
} | ||
await expect(executeQuote(deps, args)).rejects.toThrow( | ||
'ZrxSwapper:executeQuote sellAmount is required' | ||
) | ||
}) | ||
|
||
it('throws an error if quote.depositAddress is not provided', async () => { | ||
const args = { | ||
quote: { ...quoteInput, depositAddress: '' }, | ||
wallet | ||
} | ||
await expect(executeQuote(deps, args)).rejects.toThrow( | ||
'ZrxSwapper:executeQuote depositAddress is required' | ||
) | ||
}) | ||
|
||
it('returns txid', async () => { | ||
const args = { | ||
quote: { ...quoteInput, depositAddress: '0x728F1973c71f7567dE2a34Fa2838D4F0FB7f9765' }, | ||
wallet | ||
} | ||
|
||
expect(await executeQuote(deps, args)).toEqual({ txid }) | ||
}) | ||
}) |
51 changes: 51 additions & 0 deletions
51
packages/swapper/src/swappers/zrx/executeQuote/executeQuote.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,51 @@ | ||
import { numberToHex } from 'web3-utils' | ||
import { ExecQuoteInput, ExecQuoteOutput } from '@shapeshiftoss/types' | ||
import { SwapError } from '../../../api' | ||
import { ZrxSwapperDeps } from '../ZrxSwapper' | ||
import { DEFAULT_ETH_PATH } from '../utils/constants' | ||
|
||
export async function executeQuote( | ||
{ adapterManager }: ZrxSwapperDeps, | ||
{ quote, wallet }: ExecQuoteInput | ||
): Promise<ExecQuoteOutput> { | ||
const { sellAsset } = quote | ||
|
||
if (!quote.success) { | ||
throw new SwapError('ZrxSwapper:executeQuote Cannot execute a failed quote') | ||
} | ||
|
||
if (!sellAsset.network || !sellAsset.symbol) { | ||
throw new SwapError('ZrxSwapper:executeQuote sellAssetNetwork and sellAssetSymbol are required') | ||
} | ||
|
||
if (!quote.sellAssetAccountId) { | ||
throw new SwapError('ZrxSwapper:executeQuote sellAssetAccountId is required') | ||
} | ||
|
||
if (!quote.sellAmount) { | ||
throw new SwapError('ZrxSwapper:executeQuote sellAmount is required') | ||
} | ||
|
||
if (!quote.depositAddress) { | ||
throw new SwapError('ZrxSwapper:executeQuote depositAddress is required') | ||
} | ||
|
||
// value is 0 for erc20s | ||
const value = sellAsset.symbol === 'ETH' ? numberToHex(quote.sellAmount || 0) : '0x0' | ||
const adapter = adapterManager.byChain(sellAsset.chain) | ||
|
||
const { txToSign } = await adapter.buildSendTransaction({ | ||
value, | ||
wallet, | ||
to: quote.depositAddress, | ||
path: DEFAULT_ETH_PATH, | ||
fee: numberToHex(quote.feeData?.gasPrice || 0), | ||
limit: numberToHex(quote.feeData?.estimatedGas || 0) | ||
}) | ||
|
||
const signedTx = await adapter.signTransaction({ txToSign, wallet }) | ||
|
||
const txid = await adapter.broadcastTransaction(signedTx) | ||
|
||
return { txid } | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters