@openocean.finance/widget
Version:
Openocean Widget for cross-chain bridging and swapping. It will drive your multi-chain strategy and attract new users from everywhere.
144 lines (125 loc) • 4.18 kB
text/typescript
import { ChainId } from '@openocean.finance/widget-sdk'
import { Currency } from '../constants/index.js'
import { WalletClient, formatUnits } from 'viem'
import { ZERO_ADDRESS } from '../constants/index.js'
import { Quote } from '../registry.js'
import {
BaseSwapAdapter,
Chain,
EvmQuoteParams,
NormalizedQuote,
NormalizedTxResponse,
SwapStatus,
} from './BaseSwapAdapter.js'
const SYMBIOSIS_API = 'https://api.symbiosis.finance/crosschain/v1'
export class SymbiosisAdapter extends BaseSwapAdapter {
constructor() {
super()
}
getName(): string {
return 'Symbiosis'
}
getIcon(): string {
return 'https://app.symbiosis.finance/images/favicon-32x32.png'
}
getSupportedChains(): Chain[] {
return [
ChainId.ETH,
ChainId.BAS,
ChainId.POL,
ChainId.AVA,
// ChainId.ZKSYNC,
ChainId.ARB,
ChainId.OPT,
ChainId.LNA,
ChainId.BAS,
ChainId.SCL,
ChainId.BLS,
ChainId.UNI,
]
}
getSupportedTokens(_sourceChain: Chain, _destChain: Chain): Currency[] {
return []
}
async getQuote(params: EvmQuoteParams): Promise<NormalizedQuote> {
const body = {
tokenAmountIn: {
address: params.fromToken.isNative ? '' : params.fromToken.address,
amount: params.amount,
chainId: params.fromChain,
decimals: params.fromToken.decimals,
},
tokenOut: {
chainId: params.toChain,
address: params.toToken.isNative ? '' : params.toToken.address,
symbol: params.toToken.symbol,
decimals: params.toToken.decimals,
},
from: params.sender,
to: params.recipient,
slippage: params.slippage,
}
const res = await fetch(`${SYMBIOSIS_API}/swap`, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify(body),
}).then(r => r.json())
if (!res.tx) throw new Error('No route found')
const formattedOutputAmount = formatUnits(BigInt(res.tokenAmountOut.amount), params.toToken.decimals)
const formattedInputAmount = formatUnits(BigInt(params.amount), params.fromToken.decimals)
const tokenInUsd = params.tokenInUsd
const tokenOutUsd = params.tokenOutUsd
const inputUsd = tokenInUsd * +formattedInputAmount
const outputUsd = tokenOutUsd * +formattedOutputAmount
return {
quoteParams: params,
outputAmount: BigInt(res.tokenAmountOut.amount),
formattedOutputAmount,
inputUsd,
outputUsd,
priceImpact: !inputUsd || !outputUsd ? NaN : ((inputUsd - outputUsd) * 100) / inputUsd,
rate: +formattedOutputAmount / +formattedInputAmount,
gasFeeUsd: 0,
timeEstimate: res.estimatedTime,
contractAddress: res.approveTo || ZERO_ADDRESS,
rawQuote: res,
// TODO: add Fee
protocolFee: 0,
platformFeePercent: 0,
}
}
async executeSwap({ quote }: Quote, walletClient: WalletClient): Promise<NormalizedTxResponse> {
const account = walletClient.account?.address
if (!account) throw new Error('WalletClient account is not defined')
const tx = await walletClient.sendTransaction({
chain: undefined,
account,
to: quote.rawQuote.tx.to,
value: BigInt(quote.rawQuote.tx.value),
data: quote.rawQuote.tx.data,
kzg: undefined,
})
return {
sender: quote.quoteParams.sender,
id: tx, // specific id for each provider
sourceTxHash: tx,
adapter: this.getName(),
sourceChain: quote.quoteParams.fromChain,
targetChain: quote.quoteParams.toChain,
inputAmount: quote.quoteParams.amount,
outputAmount: quote.outputAmount.toString(),
sourceToken: quote.quoteParams.fromToken,
targetToken: quote.quoteParams.toToken,
timestamp: new Date().getTime(),
}
}
async getTransactionStatus(p: NormalizedTxResponse): Promise<SwapStatus> {
const res = await fetch(`${SYMBIOSIS_API}/tx/${p.sourceChain}/${p.sourceTxHash}`).then(r => r.json())
return {
txHash: res?.tx?.hash || '',
status: res.status.code === 0 ? 'Success' : res.status.code === 3 ? 'Failed' : 'Processing',
}
}
}