From 5d20c326a038a430a38f28815ba65af71152118b Mon Sep 17 00:00:00 2001 From: sarneijim <38540290+sarneijim@users.noreply.github.com> Date: Tue, 29 Aug 2023 11:39:12 +0100 Subject: [PATCH] feat: support customFees in swap web app mode (#4174) * feat: support customFees in swap web app mode * fix: add other custom params * feat: update wallet-api dependencies * fix: fix async call getCustomFeesPerFamily * fix: fix typecheck * refactor: move getCustomFeesPerFamily to common * fix: fix lint * fix: remove feesStrategy as mandatory to open swap web app * fix: add convertToNonAtomicUnit utils * chore: update wallet-api server call after upgrade * fix: fix lint --- .changeset/mighty-fireants-stare.md | 6 +++ .../screens/exchange/Swap2/Form/index.tsx | 26 +++++++----- .../src/exchange/swap/completeExchange.ts | 3 +- .../src/exchange/swap/webApp/index.ts | 1 + .../src/exchange/swap/webApp/utils.ts | 41 +++++++++++++++++++ pnpm-lock.yaml | 32 ++++++--------- 6 files changed, 78 insertions(+), 31 deletions(-) create mode 100644 .changeset/mighty-fireants-stare.md create mode 100644 libs/ledger-live-common/src/exchange/swap/webApp/index.ts create mode 100644 libs/ledger-live-common/src/exchange/swap/webApp/utils.ts diff --git a/.changeset/mighty-fireants-stare.md b/.changeset/mighty-fireants-stare.md new file mode 100644 index 000000000000..436361646902 --- /dev/null +++ b/.changeset/mighty-fireants-stare.md @@ -0,0 +1,6 @@ +--- +"ledger-live-desktop": patch +"@ledgerhq/live-common": patch +--- + +Support customFees in swap web app mode diff --git a/apps/ledger-live-desktop/src/renderer/screens/exchange/Swap2/Form/index.tsx b/apps/ledger-live-desktop/src/renderer/screens/exchange/Swap2/Form/index.tsx index cc6e999a9c68..40f6845190e9 100644 --- a/apps/ledger-live-desktop/src/renderer/screens/exchange/Swap2/Form/index.tsx +++ b/apps/ledger-live-desktop/src/renderer/screens/exchange/Swap2/Form/index.tsx @@ -3,6 +3,10 @@ import { useSwapTransaction, usePageState, } from "@ledgerhq/live-common/exchange/swap/hooks/index"; +import { + getCustomFeesPerFamily, + convertToNonAtomicUnit, +} from "@ledgerhq/live-common/exchange/swap/webApp/index"; import { getProviderName, getCustomDappUrl } from "@ledgerhq/live-common/exchange/swap/utils/index"; import React, { useCallback, useEffect, useRef, useState } from "react"; import { useTranslation } from "react-i18next"; @@ -39,7 +43,6 @@ import EmptyState from "./Rates/EmptyState"; import { AccountLike, Feature } from "@ledgerhq/types-live"; import BigNumber from "bignumber.js"; import { CryptoCurrency, TokenCurrency } from "@ledgerhq/types-cryptoassets"; -import { SwapSelectorStateType } from "@ledgerhq/live-common/exchange/swap/types"; import { SWAP_RATES_TIMEOUT } from "../../config"; const Wrapper = styled(Box).attrs({ @@ -133,6 +136,7 @@ const SwapForm = () => { const refreshTime = useRefreshRates(swapTransaction.swap, { pause: pauseRefreshing, }); + const refreshIdle = useCallback(() => { idleState && setIdleState(false); idleTimeout.current && clearInterval(idleTimeout.current); @@ -141,19 +145,20 @@ const SwapForm = () => { }, idleTime); }, [idleState]); - const swapWebAppRedirection = useCallback(() => { + const swapWebAppRedirection = useCallback(async () => { const { to, from } = swapTransaction.swap; const transaction = swapTransaction.transaction; const { account: fromAccount, parentAccount: fromParentAccount } = from; const { account: toAccount, parentAccount: toParentAccount } = to; - const feesStrategy = transaction?.feesStrategy; - const rateId = exchangeRate?.rateId || "1234"; - if (fromAccount && toAccount && feesStrategy) { + const { feesStrategy } = transaction || {}; + + const rateId = exchangeRate?.rateId || "12345"; + if (fromAccount && toAccount) { const fromAccountId = accountToWalletAPIAccount(fromAccount, fromParentAccount)?.id; const toAccountId = accountToWalletAPIAccount(toAccount, toParentAccount)?.id; - const fromMagnitude = - (fromAccount as unknown as SwapSelectorStateType)?.currency?.units[0].magnitude || 0; - const fromAmount = transaction?.amount.shiftedBy(-fromMagnitude); + const fromAmount = convertToNonAtomicUnit(transaction?.amount, fromAccount); + + const customFeesParams = feesStrategy === "custom" ? getCustomFeesPerFamily(transaction) : {}; history.push({ pathname: "/swap-web", @@ -163,11 +168,12 @@ const SwapForm = () => { toAccountId, fromAmount, quoteId: encodeURIComponent(rateId), - feeStrategy: feesStrategy.toUpperCase(), // Custom fee is not supported yet + feeStrategy: feesStrategy?.toUpperCase(), + ...customFeesParams, }, }); } - }, [history, swapTransaction, provider, exchangeRate?.rateId]); + }, [swapTransaction.swap, swapTransaction.transaction, exchangeRate?.rateId, history, provider]); useEffect(() => { if (swapTransaction.swap.rates.status === "success") { diff --git a/libs/ledger-live-common/src/exchange/swap/completeExchange.ts b/libs/ledger-live-common/src/exchange/swap/completeExchange.ts index 8c64ba6dac3a..c548796c4685 100644 --- a/libs/ledger-live-common/src/exchange/swap/completeExchange.ts +++ b/libs/ledger-live-common/src/exchange/swap/completeExchange.ts @@ -73,6 +73,7 @@ const completeExchange = ( const payoutAccount = getMainAccount(toAccount, toParentAccount); const accountBridge = getAccountBridge(refundAccount); const mainPayoutCurrency = getAccountCurrency(payoutAccount); + const payoutCurrency = getAccountCurrency(toAccount); const refundCurrency = getAccountCurrency(fromAccount); const mainRefundCurrency = getAccountCurrency(refundAccount); if (mainPayoutCurrency.type !== "CryptoCurrency") @@ -126,7 +127,7 @@ const completeExchange = ( if (unsubscribed) return; const { config: payoutAddressConfig, signature: payoutAddressConfigSignature } = - getCurrencyExchangeConfig(mainPayoutCurrency); + getCurrencyExchangeConfig(payoutCurrency); try { currentStep = "CHECK_PAYOUT_ADDRESS"; diff --git a/libs/ledger-live-common/src/exchange/swap/webApp/index.ts b/libs/ledger-live-common/src/exchange/swap/webApp/index.ts new file mode 100644 index 000000000000..178cd64f81d7 --- /dev/null +++ b/libs/ledger-live-common/src/exchange/swap/webApp/index.ts @@ -0,0 +1 @@ +export * from "./utils"; diff --git a/libs/ledger-live-common/src/exchange/swap/webApp/utils.ts b/libs/ledger-live-common/src/exchange/swap/webApp/utils.ts new file mode 100644 index 000000000000..e98ec7a2d7ab --- /dev/null +++ b/libs/ledger-live-common/src/exchange/swap/webApp/utils.ts @@ -0,0 +1,41 @@ +import { getGasLimit as getEthGasLimit } from "../../../families/ethereum/transaction"; +import { getGasLimit as getEvmGasLimit } from "@ledgerhq/coin-evm/logic"; + +export const getCustomFeesPerFamily = transaction => { + const { family, maxFeePerGas, maxPriorityFeePerGas, userGasLimit, customGasLimit, feePerByte } = + transaction; + + switch (family) { + case "ethereum": { + return { + maxFeePerGas, + maxPriorityFeePerGas, + userGasLimit, + gasLimit: getEthGasLimit(transaction), + }; + } + case "evm": { + return { + maxFeePerGas, + maxPriorityFeePerGas, + gasLimit: getEvmGasLimit(transaction), + customGasLimit, + }; + } + case "bitcoin": { + return { + feePerByte, + }; + } + default: + return {}; + } +}; + +export const convertToNonAtomicUnit = (amount, account) => { + const fromMagnitude = + account.type === "TokenAccount" + ? account.token.units[0].magnitude || 0 + : account.currency?.units[0].magnitude || 0; + return amount.shiftedBy(-fromMagnitude); +}; diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 6b60ebaf1699..1bda83ae2f82 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -28719,7 +28719,6 @@ packages: /binary-extensions@2.2.0: resolution: {integrity: sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==} engines: {node: '>=8'} - requiresBuild: true /binary@0.3.0: resolution: {integrity: sha512-D4H1y5KYwpJgK8wk1Cue5LLPgmwHKYSChkbspQg5JtVuR5ulGckxfR62H3AE9UDkdMC8yyXlqYihuz3Aqg2XZg==} @@ -29449,7 +29448,7 @@ packages: dev: false /builtin-status-codes@3.0.0: - resolution: {integrity: sha512-HpGFw18DgFWlncDfjTa2rcQ4W88O1mC8e8yZ2AvQY5KDaktSTwo+KRf6nHK6FRI5FyRyb/5T6+TSxfP7QyGsmQ==} + resolution: {integrity: sha1-hZgoeOIbmOHGZCXgPQF0eI9Wnug=} /builtins@1.0.3: resolution: {integrity: sha512-uYBjakWipfaO/bXI7E8rq6kpwHRZK5cNYrUv2OzZSI/FvmdMyXJ2tG9dKcjEC5YHmHpUAwsargWIZNWdxb/bnQ==} @@ -30668,7 +30667,7 @@ packages: resolution: {integrity: sha512-ty/fTekppD2fIwRvnZAVdeOiGd1c7YXEixbgJTNzqcxJWKQnjJ/V1bNEEE6hygpM3WjwHFUVK6HTjWSzV4a8sQ==} /constants-browserify@1.0.0: - resolution: {integrity: sha512-xFxOwqIzR/e1k1gLiWEophSCMqXcwVHIH7akf7b/vxcUeGunlj3hvZaaqxwHsTgn+IndtkQJgSztIDWeumWJDQ==} + resolution: {integrity: sha1-wguW2MYXdIqvHBYCF2DNJ/y4y3U=} /contains-path@0.1.0: resolution: {integrity: sha512-OKZnPGeMQy2RPaUIBPFFd71iNf4791H12MCRuVQDnzGRwCYNYmTDy5pdafo2SLAcEMKzTOQnLWG4QdcjeJUMEg==} @@ -36596,7 +36595,6 @@ packages: /fill-range@7.0.1: resolution: {integrity: sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==} engines: {node: '>=8'} - requiresBuild: true dependencies: to-regex-range: 5.0.1 @@ -37230,7 +37228,7 @@ packages: engines: {node: '>=10'} dependencies: at-least-node: 1.0.0 - graceful-fs: 4.2.11 + graceful-fs: 4.2.10 jsonfile: 6.1.0 universalify: 2.0.0 @@ -38764,7 +38762,7 @@ packages: resolve-alpn: 1.2.1 /https-browserify@1.0.0: - resolution: {integrity: sha512-J+FkSdyD+0mA0N+81tMotaRMfSL9SGi+xpD3T6YApKsc3bGSXJlfXri3VyFOeYkfLRQisDk1W+jIFFKBeUBbBg==} + resolution: {integrity: sha1-7AbBDgo0wPL68Zn3/X/Hj//QPHM=} /https-proxy-agent@5.0.1: resolution: {integrity: sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA==} @@ -39260,7 +39258,6 @@ packages: /is-binary-path@2.1.0: resolution: {integrity: sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==} engines: {node: '>=8'} - requiresBuild: true dependencies: binary-extensions: 2.2.0 @@ -39390,7 +39387,6 @@ packages: /is-extglob@2.1.1: resolution: {integrity: sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==} engines: {node: '>=0.10.0'} - requiresBuild: true /is-finite@1.1.0: resolution: {integrity: sha512-cdyMtqX/BOqqNBBiKlIVkytNHm49MtMlYyn1zxzvJKWmFMlGzm+ry5BBfYyeY9YmNKbRSo/o7OX9w9ale0wg3w==} @@ -39520,7 +39516,6 @@ packages: /is-number@7.0.0: resolution: {integrity: sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==} engines: {node: '>=0.12.0'} - requiresBuild: true /is-obj@1.0.1: resolution: {integrity: sha512-l4RyHgRqGN4Y3+9JHVrNqO+tN0rV5My76uW5/nuO4K1b6vw5G8d/cmFjP9tRfEsdhZNt0IFdZuK/c2Vr4Nb+Qg==} @@ -42656,7 +42651,7 @@ packages: '@types/node': 18.16.19 chalk: 4.1.2 ci-info: 3.3.2 - graceful-fs: 4.2.11 + graceful-fs: 4.2.10 picomatch: 2.3.1 /jest-util@29.5.0: @@ -49107,7 +49102,7 @@ packages: url-parse: 1.5.10 /os-browserify@0.3.0: - resolution: {integrity: sha512-gjcpUc3clBf9+210TRaDWbf+rZZZEshZ+DlXMRCeAjp0xhTrnQsKHypIy1J3d5hKdUzj69t708EHtU8P6bUn0A==} + resolution: {integrity: sha1-hUNzx/XCMVkU/Jv8a9gjj92h7Cc=} /os-homedir@1.0.2: resolution: {integrity: sha512-B5JU3cabzk8c67mRRd3ECmROafjYMXbuzlwtqdM8IbS8ktlTix8aFGb2bAGKrSRIlnfKwovGUUr72JUPyOb6kQ==} @@ -49487,7 +49482,6 @@ packages: /path-dirname@1.0.2: resolution: {integrity: sha512-ALzNPpyNq9AqXMBjeymIjFDAkAFH06mHJH/cSBHAgU0s4vfpBn6b2nf8tiRLvagKD8RbTpq2FKTBg7cl9l3c7Q==} - requiresBuild: true /path-exists@2.1.0: resolution: {integrity: sha512-yTltuKuhtNeFJKa1PiRzfLAU5182q1y4Eb4XCJ3PBqyzEDkAZRzBrKKBct682ls9reBVHf9udYLN5Nd+K1B9BQ==} @@ -51941,7 +51935,7 @@ packages: resolution: {integrity: sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==} /prr@0.0.0: - resolution: {integrity: sha512-LmUECmrW7RVj6mDWKjTXfKug7TFGdiz9P18HMcO4RHL+RW7MCOGNvpj5j47Rnp6ne6r4fZ2VzyUWEpKbg+tsjQ==} + resolution: {integrity: sha1-GoS4WQgyVQFBGFPQCB7j+obikmo=} dev: false /prr@1.0.1: @@ -52120,11 +52114,11 @@ packages: strict-uri-encode: 2.0.0 /querystring-es3@0.2.1: - resolution: {integrity: sha512-773xhDQnZBMFobEiztv8LIl70ch5MSF/jUQVlhwFyBILqq96anmoctVIYz+ZRp0qbCKATTn6ev02M3r7Ga5vqA==} + resolution: {integrity: sha1-nsYfeQSYdXB9aUFFlv2Qek1xHnM=} engines: {node: '>=0.4.x'} /querystring@0.2.0: - resolution: {integrity: sha512-X/xY82scca2tau62i9mDyU9K+I+djTMUsvwf7xnUX5GLvVzgJybOJf4Y6o9Zx3oJK/LSXg5tTZBjwzqVPaPO2g==} + resolution: {integrity: sha1-sgmEkgO7Jd+CDadW50cAWHhSFiA=} engines: {node: '>=0.4.x'} deprecated: The querystring API is considered Legacy. new code should use the URLSearchParams API instead. @@ -54279,7 +54273,6 @@ packages: /readdirp@3.6.0: resolution: {integrity: sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==} engines: {node: '>=8.10.0'} - requiresBuild: true dependencies: picomatch: 2.3.1 @@ -58407,7 +58400,7 @@ packages: dev: true /to-arraybuffer@1.0.1: - resolution: {integrity: sha512-okFlQcoGTi4LQBG/PgSYblw9VOyptsz2KJZqc6qtgGdes8VktzUQkj4BI2blit072iS8VODNcMA+tvnS9dnuMA==} + resolution: {integrity: sha1-fSKbH8xjfkZsoIEYCDanqr/4P0M=} /to-camel-case@1.0.0: resolution: {integrity: sha512-nD8pQi5H34kyu1QDMFjzEIYqk0xa9Alt6ZfrdEMuHCFOfTLhDG5pgTu/aAM9Wt9lXILwlXmWP43b8sav0GNE8Q==} @@ -58444,7 +58437,6 @@ packages: /to-regex-range@5.0.1: resolution: {integrity: sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==} engines: {node: '>=8.0'} - requiresBuild: true dependencies: is-number: 7.0.0 @@ -59177,7 +59169,7 @@ packages: typescript: 5.1.3 /tty-browserify@0.0.0: - resolution: {integrity: sha512-JVa5ijo+j/sOoHGjw0sxw734b1LhBkQ3bvUGNdxnVXDCX81Yx7TFgnZygxrIIWn23hbfTaMYLwRmAxFyDuFmIw==} + resolution: {integrity: sha1-oVe6QC2iTpv5V/mqadUk7tQpAaY=} /tty-table@4.1.6: resolution: {integrity: sha512-kRj5CBzOrakV4VRRY5kUWbNYvo/FpOsz65DzI5op9P+cHov3+IqPbo1JE1ZnQGkHdZgNFDsrEjrfqqy/Ply9fw==} @@ -60036,7 +60028,7 @@ packages: dev: false /url@0.11.0: - resolution: {integrity: sha512-kbailJa29QrtXnxgq+DdCEGlbTeYM2eJUxsz6vjZavrCYPMIFHMKQmSKYAIuUK2i7hgPm28a8piX5NTUtM/LKQ==} + resolution: {integrity: sha1-ODjpfPxgUh63PFJajlW/3Z4uKPE=} dependencies: punycode: 1.3.2 querystring: 0.2.0