From 0ad916725ff2eb577dac5ced086e0baa88a5df6f Mon Sep 17 00:00:00 2001 From: "frankind.eth" Date: Wed, 20 Mar 2024 15:15:36 -0300 Subject: [PATCH] fix: replace PropellerHeads quote API by solve API --- packages/swap/package.json | 2 +- packages/swap/src/common/estimateGasList.ts | 2 +- .../src/providers/propeller-heads/index.ts | 112 ++++++++++-------- .../src/providers/propeller-heads/types.ts | 24 ++-- packages/swap/src/types/index.ts | 1 - packages/swap/tests/swap.test.ts | 12 +- 6 files changed, 94 insertions(+), 59 deletions(-) diff --git a/packages/swap/package.json b/packages/swap/package.json index 532d3932a..7f7144d1e 100644 --- a/packages/swap/package.json +++ b/packages/swap/package.json @@ -10,7 +10,7 @@ "scripts": { "build": "tsup src/index.ts --format esm,cjs --dts --clean", "lint": "prettier --write .", - "test": "ts-mocha -p tsconfig.json tests/**/prope*.test.ts" + "test": "ts-mocha -p tsconfig.json tests/**/*.test.ts" }, "engines": { "node": ">=14.15.0" diff --git a/packages/swap/src/common/estimateGasList.ts b/packages/swap/src/common/estimateGasList.ts index b38debad0..5d4626cd8 100644 --- a/packages/swap/src/common/estimateGasList.ts +++ b/packages/swap/src/common/estimateGasList.ts @@ -100,7 +100,7 @@ const useStandardEstimate = ( }) .catch(() => null); -const estimateGasList = ( +const estimateGasList = async ( transactions: EVMTransaction[], network: SupportedNetworkName ): Promise<{ diff --git a/packages/swap/src/providers/propeller-heads/index.ts b/packages/swap/src/providers/propeller-heads/index.ts index 9ac876d28..25dd13b58 100644 --- a/packages/swap/src/providers/propeller-heads/index.ts +++ b/packages/swap/src/providers/propeller-heads/index.ts @@ -1,5 +1,6 @@ import Web3Eth from "web3-eth"; import { numberToHex, stringToHex, toBN } from "web3-utils"; +import estimateGasList from "../../common/estimateGasList"; import { EVMTransaction, getQuoteOptions, @@ -15,7 +16,6 @@ import { StatusOptionsResponse, SupportedNetworkName, SwapQuote, - SwapTransaction, TokenType, TransactionStatus, TransactionType, @@ -122,7 +122,8 @@ class PropellerHeads extends ProviderClass { private getPropellerHeadsSwap( options: getQuoteOptions, - meta: QuoteMetaOptions + meta: QuoteMetaOptions, + accurateEstimate: boolean ): Promise { if ( !PropellerHeads.isSupported( @@ -151,13 +152,13 @@ class PropellerHeads extends ProviderClass { NetworkNamesToSupportedProppellerHeadsBlockchains[this.network], }); - return fetch(`${BASE_URL}/solver/quote?${params.toString()}`, { + return fetch(`${BASE_URL}/solver/solve?${params.toString()}`, { method: "POST", body: JSON.stringify(body), }) .then((res) => res.json()) .then(async (response: PropellerHeadsResponseType) => { - const transactions: SwapTransaction[] = []; + const transactions: EVMTransaction[] = []; if (options.fromToken.address !== NATIVE_TOKEN_ADDRESS) { const approvalTxs = await getAllowanceTransactions({ infinityApproval: meta.infiniteApproval, @@ -169,19 +170,30 @@ class PropellerHeads extends ProviderClass { }); transactions.push(...approvalTxs); } - console.log(response); transactions.push({ from: options.fromAddress, gasLimit: GAS_LIMITS.swap, to: options.fromAddress, value: numberToHex(options.amount), - data: stringToHex(JSON.stringify(response)), + data: response.solutions[0].call_data, type: TransactionType.evm, }); + if (accurateEstimate) { + const accurateGasEstimate = await estimateGasList( + transactions, + this.network + ); + if (accurateGasEstimate) { + if (accurateGasEstimate.isError) return null; + transactions.forEach((tx, idx) => { + tx.gasLimit = accurateGasEstimate.result[idx]; + }); + } + } return { transactions, - toTokenAmount: toBN(response.quotes[0].buy_amount), - fromTokenAmount: toBN(response.quotes[0].sell_amount), + toTokenAmount: toBN(response.solutions[0].orders[0].buy_amount), + fromTokenAmount: toBN(response.solutions[0].orders[0].sell_amount), }; }) .catch((e) => { @@ -194,51 +206,55 @@ class PropellerHeads extends ProviderClass { options: getQuoteOptions, meta: QuoteMetaOptions ): Promise { - return this.getPropellerHeadsSwap(options, meta).then(async (res) => { - if (!res) return null; - const response: ProviderQuoteResponse = { - fromTokenAmount: res.fromTokenAmount, - additionalNativeFees: toBN(0), - toTokenAmount: res.toTokenAmount, - provider: this.name, - quote: { - meta, - options, + return this.getPropellerHeadsSwap(options, meta, false).then( + async (res) => { + if (!res) return null; + const response: ProviderQuoteResponse = { + fromTokenAmount: res.fromTokenAmount, + additionalNativeFees: toBN(0), + toTokenAmount: res.toTokenAmount, provider: this.name, - }, - totalGaslimit: res.transactions.reduce( - (total: number, curVal: EVMTransaction) => - total + toBN(curVal.gasLimit).toNumber(), - 0 - ), - minMax: await this.getMinMaxAmount(), - }; - return response; - }); + quote: { + meta, + options, + provider: this.name, + }, + totalGaslimit: res.transactions.reduce( + (total: number, curVal: EVMTransaction) => + total + toBN(curVal.gasLimit).toNumber(), + 0 + ), + minMax: await this.getMinMaxAmount(), + }; + return response; + } + ); } getSwap(quote: SwapQuote): Promise { - return this.getPropellerHeadsSwap(quote.options, quote.meta).then((res) => { - if (!res) return null; - const feeConfig = - FEE_CONFIGS[this.name][quote.meta.walletIdentifier].fee || 0; - const response: ProviderSwapResponse = { - fromTokenAmount: res.fromTokenAmount, - additionalNativeFees: toBN(0), - provider: this.name, - toTokenAmount: res.toTokenAmount, - transactions: res.transactions, - slippage: quote.meta.slippage || DEFAULT_SLIPPAGE, - fee: feeConfig * 100, - getStatusObject: async ( - options: StatusOptions - ): Promise => ({ - options, + return this.getPropellerHeadsSwap(quote.options, quote.meta, true).then( + (res) => { + if (!res) return null; + const feeConfig = + FEE_CONFIGS[this.name][quote.meta.walletIdentifier].fee || 0; + const response: ProviderSwapResponse = { + fromTokenAmount: res.fromTokenAmount, + additionalNativeFees: toBN(0), provider: this.name, - }), - }; - return response; - }); + toTokenAmount: res.toTokenAmount, + transactions: res.transactions, + slippage: quote.meta.slippage || DEFAULT_SLIPPAGE, + fee: feeConfig * 100, + getStatusObject: async ( + options: StatusOptions + ): Promise => ({ + options, + provider: this.name, + }), + }; + return response; + } + ); } getStatus(options: StatusOptions): Promise { diff --git a/packages/swap/src/providers/propeller-heads/types.ts b/packages/swap/src/providers/propeller-heads/types.ts index 509fa731c..df73f79ac 100644 --- a/packages/swap/src/providers/propeller-heads/types.ts +++ b/packages/swap/src/providers/propeller-heads/types.ts @@ -2,16 +2,26 @@ import { BN, EVMTransaction } from "../../types"; export interface PropellerHeadsResponseType { request_id: string; - quotes: [ + solutions: [ { - sell_token: string; - buy_token: string; - sell_amount: string; - buy_amount: string; - external_id: string; + orders: [ + { + origin_address: string; + sell_token: string; + buy_token: string; + sell_amount: string; + executed_sell_amount: string; + buy_amount: string; + executed_buy_amount: string; + external_id: string; + receiver: string; + } + ]; + call_data: string; + gas: string; + target_address: string; } ]; - gas: number; buy_tokens: [ { symbol: string; diff --git a/packages/swap/src/types/index.ts b/packages/swap/src/types/index.ts index c98fbb9eb..c678e5477 100644 --- a/packages/swap/src/types/index.ts +++ b/packages/swap/src/types/index.ts @@ -27,7 +27,6 @@ export enum SupportedNetworkName { Klaytn = NetworkNames.Klaytn, Aurora = NetworkNames.Aurora, Zksync = NetworkNames.ZkSync, - Starknet = NetworkNames.Starknet, } // eslint-disable-next-line no-shadow diff --git a/packages/swap/tests/swap.test.ts b/packages/swap/tests/swap.test.ts index ac4c723c2..a20822d15 100644 --- a/packages/swap/tests/swap.test.ts +++ b/packages/swap/tests/swap.test.ts @@ -1,3 +1,4 @@ +import { toBN } from "web3-utils"; import { expect } from "chai"; import Web3Eth from "web3-eth"; import Swap from "../src"; @@ -8,9 +9,9 @@ import { WalletIdentifier, } from "../src/types"; import { + amount, fromToken, toToken, - amount, fromAddress, toAddress, nodeURL, @@ -72,14 +73,19 @@ describe("Swap", () => { (q) => q.provider === ProviderName.changelly ); const zeroxQuote = quotes.find((q) => q.provider === ProviderName.zerox); + const propellerHeadsQuote = quotes.find( + (q) => q.provider === ProviderName.propellerHeads + ); if (quotes?.length > 3) { const rangoQuote = quotes.find((q) => q.provider === ProviderName.rango); expect(rangoQuote!.provider).to.be.eq(ProviderName.rango); } + expect(zeroxQuote).to.be.eq(undefined); expect(changellyQuote!.provider).to.be.eq(ProviderName.changelly); expect(oneInceQuote!.provider).to.be.eq(ProviderName.oneInch); expect(paraswapQuote!.provider).to.be.eq(ProviderName.paraswap); + expect(propellerHeadsQuote!.provider).to.be.eq(ProviderName.propellerHeads); const swapOneInch = await enkryptSwap.getSwap(oneInceQuote!.quote); expect(swapOneInch?.fromTokenAmount.toString()).to.be.eq(amount.toString()); expect(swapOneInch?.transactions.length).to.be.eq(2); @@ -107,11 +113,15 @@ describe("Swap", () => { (q) => q.provider === ProviderName.changelly ); const zeroxQuote = quotes.find((q) => q.provider === ProviderName.zerox); + const propellerHeadsQuote = quotes.find( + (q) => q.provider === ProviderName.propellerHeads + ); // const rangoQuote = quotes.find((q) => q.provider === ProviderName.rango); expect(zeroxQuote!.provider).to.be.eq(ProviderName.zerox); expect(changellyQuote!.provider).to.be.eq(ProviderName.changelly); expect(oneInceQuote!.provider).to.be.eq(ProviderName.oneInch); expect(paraswapQuote!.provider).to.be.eq(ProviderName.paraswap); + expect(propellerHeadsQuote!.provider).to.be.eq(ProviderName.propellerHeads); // expect(rangoQuote!.provider).to.be.eq(ProviderName.rango); }).timeout(10000); });