Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Partially implement 0x swap plugins #329

Closed
wants to merge 2 commits into from
Closed
Show file tree
Hide file tree
Changes from all 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
6 changes: 5 additions & 1 deletion src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@ import { makeGodexPlugin } from './swap/central/godex'
import { makeLetsExchangePlugin } from './swap/central/letsexchange'
import { makeSideshiftPlugin } from './swap/central/sideshift'
import { makeSwapuzPlugin } from './swap/central/swapuz'
import { make0xGaslessPlugin } from './swap/defi/0x/0xGasless'
import { make0xSwapPlugin } from './swap/defi/0x/0xSwap'
import { makeCosmosIbcPlugin } from './swap/defi/cosmosIbc'
import { makeLifiPlugin } from './swap/defi/lifi'
import { makeThorchainPlugin } from './swap/defi/thorchain'
Expand Down Expand Up @@ -36,7 +38,9 @@ const plugins = {
tombSwap: makeTombSwapPlugin,
transfer: makeTransferPlugin,
velodrome: makeVelodromePlugin,
xrpdex
xrpdex,
'0xswap': make0xSwapPlugin,
'0xgasless': make0xGaslessPlugin
}

declare global {
Expand Down
118 changes: 118 additions & 0 deletions src/swap/defi/0x/0xGasless.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,118 @@
import { add } from 'biggystring'
import {
EdgeCorePluginFactory,
EdgeNetworkFee,
EdgeSwapApproveOptions,
EdgeSwapInfo,
EdgeSwapQuote,
EdgeSwapResult
} from 'edge-core-js/types'

import { ZeroXApi } from './api'
import { EXPIRATION_MS, NATIVE_TOKEN_ADDRESS } from './constants'
import { asInitOptions } from './types'
import { getCurrencyCode, getTokenAddress } from './util'

const swapInfo: EdgeSwapInfo = {
displayName: '0x Gasless Swap',
pluginId: '0xgasless',
supportEmail: '[email protected]'
}

export const make0xGaslessPlugin: EdgeCorePluginFactory = opts => {
const { io } = opts
const initOptions = asInitOptions(opts.initOptions)

const api = new ZeroXApi(io, initOptions.apiKey)

return {
swapInfo,
fetchSwapQuote: async (swapRequest): Promise<EdgeSwapQuote> => {
// The fromWallet and toWallet must be of the same currency plugin
// type and therefore of the same network.
if (
swapRequest.fromWallet.currencyInfo.pluginId !==
swapRequest.toWallet.currencyInfo.pluginId
) {
throw new Error('Swap between different networks is not supported')
}

const fromTokenAddress = getTokenAddress(
swapRequest.fromWallet,
swapRequest.fromTokenId
)
const toTokenAddress = getTokenAddress(
swapRequest.toWallet,
swapRequest.toTokenId
)

if (swapRequest.quoteFor === 'max') {
throw new Error('Max quotes not supported')
}

// From wallet address
const {
publicAddress: fromWalletAddress
} = await swapRequest.fromWallet.getReceiveAddress({
tokenId: swapRequest.fromTokenId
})

// Amount request parameter/field name to use in the quote request
const amountField =
swapRequest.quoteFor === 'from' ? 'sellAmount' : 'buyAmount'

// Get quote from ZeroXApi
const chainId = api.getChainIdFromPluginId(
swapRequest.fromWallet.currencyInfo.pluginId
)
const apiSwapQuote = await api.gaslessSwapQuote(chainId, {
sellToken: fromTokenAddress ?? NATIVE_TOKEN_ADDRESS,
buyToken: toTokenAddress ?? NATIVE_TOKEN_ADDRESS,
takerAddress: fromWalletAddress,
[amountField]: swapRequest.nativeAmount
})

if (!apiSwapQuote.liquidityAvailable)
throw new Error('No liquidity available')

const { gasFee, zeroExFee } = apiSwapQuote.fees

if (
gasFee.feeToken.toLocaleLowerCase() !==
fromTokenAddress?.toLocaleLowerCase() ||
zeroExFee.feeToken.toLocaleLowerCase() !==
fromTokenAddress?.toLocaleLowerCase()
) {
throw new Error(
'Quoted fees must be in the same token as the from token in the swap request'
)
}

const fromCurrencyCode = getCurrencyCode(
swapRequest.fromWallet,
swapRequest.fromTokenId
)
const networkFee: EdgeNetworkFee = {
currencyCode: fromCurrencyCode,
nativeAmount: add(gasFee.feeAmount, zeroExFee.feeAmount)
}

return {
approve: async (
opts?: EdgeSwapApproveOptions
): Promise<EdgeSwapResult> => {
throw new Error('Approve not yet implemented')
},
close: async () => {},
expirationDate: new Date(Date.now() + EXPIRATION_MS),
fromNativeAmount: apiSwapQuote.sellAmount,
isEstimate: false,
networkFee,
pluginId: swapInfo.pluginId,
request: swapRequest,
swapInfo: swapInfo,
toNativeAmount: apiSwapQuote.buyAmount
}
}
}
}
89 changes: 89 additions & 0 deletions src/swap/defi/0x/0xSwap.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
import { mul } from 'biggystring'
import {
EdgeCorePluginFactory,
EdgeNetworkFee,
EdgeSwapApproveOptions,
EdgeSwapInfo,
EdgeSwapQuote,
EdgeSwapResult
} from 'edge-core-js/types'

import { ZeroXApi } from './api'
import { EXPIRATION_MS, NATIVE_TOKEN_ADDRESS } from './constants'
import { asInitOptions } from './types'
import { getTokenAddress } from './util'

const swapInfo: EdgeSwapInfo = {
displayName: '0x Swap',
pluginId: '0x',
supportEmail: '[email protected]'
}

export const make0xSwapPlugin: EdgeCorePluginFactory = opts => {
const { io } = opts
const initOptions = asInitOptions(opts.initOptions)

const api = new ZeroXApi(io, initOptions.apiKey)

return {
swapInfo,
fetchSwapQuote: async (swapRequest): Promise<EdgeSwapQuote> => {
// The fromWallet and toWallet must be of the same currency plugin
// type and therefore of the same network.
if (
swapRequest.fromWallet.currencyInfo.pluginId !==
swapRequest.toWallet.currencyInfo.pluginId
) {
throw new Error('Swap between different networks is not supported')
}

const fromTokenAddress = getTokenAddress(
swapRequest.fromWallet,
swapRequest.fromTokenId
)
const toTokenAddress = getTokenAddress(
swapRequest.toWallet,
swapRequest.toTokenId
)

if (swapRequest.quoteFor === 'max') {
throw new Error('Max quotes not supported')
}

const amountField =
swapRequest.quoteFor === 'from' ? 'sellAmount' : 'buyAmount'

// Get quote from ZeroXApi
const apiEndpoint = api.getEndpointFromPluginId(
swapRequest.fromWallet.currencyInfo.pluginId
)
const apiSwapQuote = await api.swapQuote(apiEndpoint, {
sellToken: fromTokenAddress ?? NATIVE_TOKEN_ADDRESS,
buyToken: toTokenAddress ?? NATIVE_TOKEN_ADDRESS,
[amountField]: swapRequest.nativeAmount
})

const networkFee: EdgeNetworkFee = {
currencyCode: swapRequest.fromWallet.currencyInfo.currencyCode,
nativeAmount: mul(apiSwapQuote.gas, apiSwapQuote.gasPrice)
}

return {
approve: async (
opts?: EdgeSwapApproveOptions
): Promise<EdgeSwapResult> => {
throw new Error('Approve not yet implemented')
},
close: async () => {},
expirationDate: new Date(Date.now() + EXPIRATION_MS),
fromNativeAmount: apiSwapQuote.sellAmount,
isEstimate: false,
networkFee,
pluginId: swapInfo.pluginId,
request: swapRequest,
swapInfo: swapInfo,
toNativeAmount: apiSwapQuote.buyAmount
}
}
}
}
Loading
Loading