From ff814d3dad5d13283e72508e105060a1f403ea61 Mon Sep 17 00:00:00 2001 From: rodrigopavezi Date: Mon, 23 Sep 2024 22:28:05 -0300 Subject: [PATCH 01/53] feat: add conversion pairs configuration --- .../src/lib/create-invoice-form.svelte | 32 +- .../src/lib/invoice/form-view.svelte | 10 +- .../src/lib/invoice/form.svelte | 19 +- shared/utils/currencyConversionPairs.ts | 1201 +++++++++++++++++ shared/utils/initCurrencyManager.ts | 32 +- 5 files changed, 1280 insertions(+), 14 deletions(-) create mode 100644 shared/utils/currencyConversionPairs.ts diff --git a/packages/create-invoice-form/src/lib/create-invoice-form.svelte b/packages/create-invoice-form/src/lib/create-invoice-form.svelte index 16205463..efb68bfb 100644 --- a/packages/create-invoice-form/src/lib/create-invoice-form.svelte +++ b/packages/create-invoice-form/src/lib/create-invoice-form.svelte @@ -8,7 +8,7 @@ // Utils import { calculateInvoiceTotals } from "@requestnetwork/shared-utils/invoiceTotals"; import { config as defaultConfig } from "@requestnetwork/shared-utils/config"; - import { initializeCurrencyManager } from "@requestnetwork/shared-utils/initCurrencyManager"; + import { getCurrencySupportedNetworksForConversion, initializeCurrencyManager } from "@requestnetwork/shared-utils/initCurrencyManager"; // Components import Button from "@requestnetwork/shared-components/button.svelte"; @@ -18,6 +18,7 @@ import { InvoiceForm, InvoiceView } from "./invoice"; import { getInitialFormData, prepareRequestParams } from "./utils"; import type { RequestNetwork } from "@requestnetwork/request-client.js"; + import { Types } from "@requestnetwork/request-client.js"; export let config: IConfig; export let signer: string = ""; @@ -34,20 +35,22 @@ const networkSet = new Set(); currencyManager.knownCurrencies.forEach((currency: any) => { - networkSet.add(currency.network); + if(currency.network) { + networkSet.add(currency.network); + } }); return Array.from(networkSet); }; - let networks = extractUniqueNetworkNames(); + let networks: (string | undefined)[] = extractUniqueNetworkNames(); let network = networks[0]; const handleNetworkChange = (network: string) => { if (network) { const newCurrencies = currencyManager.knownCurrencies.filter( - (currency: any) => currency.network === network + (currency: any) => currency.type === Types.RequestLogic.CURRENCY.ISO4217 || currency.network === network ); network = network; @@ -61,10 +64,24 @@ let appStatus: APP_STATUS[] = []; let formData = getInitialFormData(); let defaultCurrencies = currencyManager.knownCurrencies.filter( - (currency: any) => currency.network === network + (currency: any) => currency.type === Types.RequestLogic.CURRENCY.ISO4217 || currency.network === network ); - let currency = defaultCurrencies[0]; + let currency = defaultCurrencies.filter( + (currency: any) => currency.type !== Types.RequestLogic.CURRENCY.ISO4217 + )[0]; + let invoiceCurrency = defaultCurrencies[0]; + + const handleInvoiceCurrencyChange = (value: string) => { + invoiceCurrency = value; + + if (invoiceCurrency.type === Types.RequestLogic.CURRENCY.ISO4217) { + + networks = getCurrencySupportedNetworksForConversion(invoiceCurrency.hash, currencyManager); + } else { + networks = extractUniqueNetworkNames(); + } + }; const handleCurrencyChange = (value: string) => { currency = value; @@ -174,6 +191,7 @@ bind:defaultCurrencies bind:payeeAddressError bind:clientAddressError + {handleInvoiceCurrencyChange} {handleCurrencyChange} {handleNetworkChange} {networks} @@ -181,7 +199,9 @@
Promise; export let invoiceTotals = { amountWithoutTax: 0, @@ -164,10 +166,14 @@

Payment Chain - {currency.network[0].toUpperCase() + currency.network.slice(1)} + {network.toUpperCase() + network.slice(1)}

Invoice Currency + {invoiceCurrency.symbol} +

+

+ Currency {currency.symbol} ({currency.network})

diff --git a/packages/create-invoice-form/src/lib/invoice/form.svelte b/packages/create-invoice-form/src/lib/invoice/form.svelte index 3762f3c1..4b5f5383 100644 --- a/packages/create-invoice-form/src/lib/invoice/form.svelte +++ b/packages/create-invoice-form/src/lib/invoice/form.svelte @@ -17,10 +17,12 @@ import { calculateItemTotal } from "@requestnetwork/shared-utils/invoiceTotals"; import { checkAddress } from "@requestnetwork/shared-utils/checkEthAddress"; import { inputDateFormat } from "@requestnetwork/shared-utils/formatDate"; + import { Types } from '@requestnetwork/request-client.js'; export let config: IConfig; export const invoiceNumber: number = 1; export let formData: CustomFormData; + export let handleInvoiceCurrencyChange: (value: string) => void; export let handleCurrencyChange: (value: string) => void; export let handleNetworkChange: (chainId: string) => void; @@ -306,6 +308,16 @@ + + ({ + value: currency, + label: `${currency.symbol} ${currency?.network ? `(${currency?.network})` : ""}`, + }))} + onchange={handleInvoiceCurrencyChange} + /> - ({ + options={defaultCurrencies.filter( + (currency) => currency.type !== Types.RequestLogic.CURRENCY.ISO4217 + ).map((currency) => ({ value: currency, - label: `${currency.symbol} (${currency.network})`, + label: `${currency.symbol} (${currency?.network})`, }))} onchange={handleCurrencyChange} /> diff --git a/shared/utils/currencyConversionPairs.ts b/shared/utils/currencyConversionPairs.ts new file mode 100644 index 00000000..bb9f61d8 --- /dev/null +++ b/shared/utils/currencyConversionPairs.ts @@ -0,0 +1,1201 @@ +/** + * Hardcoded currency conversion pairs. + * A live version of this would be fetched from the Price Aggregators subgraphs + * https://thegraph.com/explorer/profile/0x63d2062aacf71e26dea7111ec556558fe8199384?view=Subgraphs&chain=arbitrum-one + * + */ + +export const currencyConversionPairs = { + base: [ + { + input: '0x775eb53d00dd0acd3ec1696472105d579b9b386b', + outputs: [ + '0x833589fcd6edb6e08f4c7c32d4f71b54bda02913', + '0xb678b03f3f3a6ea652ad1d183032fac176d83b08', + ], + }, + { + input: '0x833589fcd6edb6e08f4c7c32d4f71b54bda02913', + outputs: ['0x775eb53d00dd0acd3ec1696472105d579b9b386b'], + }, + { + input: '0xb678b03f3f3a6ea652ad1d183032fac176d83b08', + outputs: ['0x775eb53d00dd0acd3ec1696472105d579b9b386b'], + }, + ], + 'arbitrum-one': [ + { + input: '0x013f29832cd6525c4c6df81c2aae8032a1ff2db2', + outputs: ['0x775eb53d00dd0acd3ec1696472105d579b9b386b'], + }, + { + input: '0x0bbb60891a1688271573e5ea4cba84f18cbc0f2d', + outputs: ['0x775eb53d00dd0acd3ec1696472105d579b9b386b'], + }, + { + input: '0x0ee88324f875d378f9a06643830934cadff6b1e5', + outputs: ['0x775eb53d00dd0acd3ec1696472105d579b9b386b'], + }, + { + input: '0x17b4158805772ced11225e77339f90beb5aae968', + outputs: ['0x775eb53d00dd0acd3ec1696472105d579b9b386b'], + }, + { + input: '0x2e9a6df78e42a30712c10a9dc4b1c8656f8f2879', + outputs: ['0x775eb53d00dd0acd3ec1696472105d579b9b386b'], + }, + { + input: '0x4f99f266506be1475e943b2f097827011bfa4e93', + outputs: ['0x775eb53d00dd0acd3ec1696472105d579b9b386b'], + }, + { + input: '0x539bde0d7dbd336b79148aa742883198bbf60342', + outputs: ['0x775eb53d00dd0acd3ec1696472105d579b9b386b'], + }, + { + input: '0x66710cc1372861ec5d5537c075b527b7b3c63c5f', + outputs: ['0x775eb53d00dd0acd3ec1696472105d579b9b386b'], + }, + { + input: '0x775eb53d00dd0acd3ec1696472105d579b9b386b', + outputs: [ + '0x0ee88324f875d378f9a06643830934cadff6b1e5', + '0x17b4158805772ced11225e77339f90beb5aae968', + '0xda10009cbd5d07dd0cecc66161fc93d7c9000da1', + '0xff970a61a04b1ca14834a43f5de4533ebddb5cc8', + '0xfd086bc7cd5c481dcc9c85ebe478a1c0b69fcbb9', + '0x4f99f266506be1475e943b2f097827011bfa4e93', + '0xfa6faefc053e6c8e393a73dcc12b09fcde019d25', + '0xfac26e3fd40adcdc6652f705d983b4830c00716c', + '0x013f29832cd6525c4c6df81c2aae8032a1ff2db2', + '0xf68fb12aa78e5c2b3eebd71441a990cd5757055c', + '0xe4dddfe67e7164b0fe14e218d80dc4c08edc01cb', + '0x0bbb60891a1688271573e5ea4cba84f18cbc0f2d', + '0x539bde0d7dbd336b79148aa742883198bbf60342', + '0x2e9a6df78e42a30712c10a9dc4b1c8656f8f2879', + '0xce80759e72fe1d3c07be79ffecc76a7a9b46c641', + '0xd4d42f0b6def4ce0383636770ef773390d85c61a', + '0xaf88d065e77c8cc2239327c5edb3a432268e5831', + '0x912ce59144191c1204e64559fe8253a0e49e6548', + '0xb50731ca2fd80afe3910a4800225d4845cad266f', + '0xb7a41bb9ad3cdc5db0e35c12e78106fa3f21693d', + '0x66710cc1372861ec5d5537c075b527b7b3c63c5f', + ], + }, + { + input: '0x912ce59144191c1204e64559fe8253a0e49e6548', + outputs: ['0x775eb53d00dd0acd3ec1696472105d579b9b386b'], + }, + { + input: '0xaf88d065e77c8cc2239327c5edb3a432268e5831', + outputs: ['0x775eb53d00dd0acd3ec1696472105d579b9b386b'], + }, + { + input: '0xb50731ca2fd80afe3910a4800225d4845cad266f', + outputs: ['0x775eb53d00dd0acd3ec1696472105d579b9b386b'], + }, + { + input: '0xb7a41bb9ad3cdc5db0e35c12e78106fa3f21693d', + outputs: ['0x775eb53d00dd0acd3ec1696472105d579b9b386b'], + }, + { + input: '0xce80759e72fe1d3c07be79ffecc76a7a9b46c641', + outputs: ['0x775eb53d00dd0acd3ec1696472105d579b9b386b'], + }, + { + input: '0xd4d42f0b6def4ce0383636770ef773390d85c61a', + outputs: ['0x775eb53d00dd0acd3ec1696472105d579b9b386b'], + }, + { + input: '0xda10009cbd5d07dd0cecc66161fc93d7c9000da1', + outputs: ['0x775eb53d00dd0acd3ec1696472105d579b9b386b'], + }, + { + input: '0xe4dddfe67e7164b0fe14e218d80dc4c08edc01cb', + outputs: ['0x775eb53d00dd0acd3ec1696472105d579b9b386b'], + }, + { + input: '0xf68fb12aa78e5c2b3eebd71441a990cd5757055c', + outputs: ['0x775eb53d00dd0acd3ec1696472105d579b9b386b'], + }, + { + input: '0xfa6faefc053e6c8e393a73dcc12b09fcde019d25', + outputs: ['0x775eb53d00dd0acd3ec1696472105d579b9b386b'], + }, + { + input: '0xfac26e3fd40adcdc6652f705d983b4830c00716c', + outputs: ['0x775eb53d00dd0acd3ec1696472105d579b9b386b'], + }, + { + input: '0xfd086bc7cd5c481dcc9c85ebe478a1c0b69fcbb9', + outputs: ['0x775eb53d00dd0acd3ec1696472105d579b9b386b'], + }, + { + input: '0xff970a61a04b1ca14834a43f5de4533ebddb5cc8', + outputs: ['0x775eb53d00dd0acd3ec1696472105d579b9b386b'], + }, + ], + avalanche: [ + { + input: '0x17b4158805772ced11225e77339f90beb5aae968', + outputs: ['0x775eb53d00dd0acd3ec1696472105d579b9b386b'], + }, + { + input: '0x775eb53d00dd0acd3ec1696472105d579b9b386b', + outputs: [ + '0xf32cf7fcbb71d3d5ef75612538abd69e81d64aa9', + '0xd586e7f844cea2f87f50152665bcbc2c279d8d70', + '0xa7d7079b0fead91f3e65f86e8915cb59c1a4c664', + '0xc7198437980c041c805a1edcba50c1ce5db95118', + '0xfac26e3fd40adcdc6652f705d983b4830c00716c', + '0x17b4158805772ced11225e77339f90beb5aae968', + '0xf68fb12aa78e5c2b3eebd71441a990cd5757055c', + '0xb97ef9ef8734c71904d8002f8b6bc66dd9c48a6e', + '0x9702230a8ea53601f5cd2dc00fdbc13d4df4a8c7', + '0xb50731ca2fd80afe3910a4800225d4845cad266f', + '0xb7a41bb9ad3cdc5db0e35c12e78106fa3f21693d', + ], + }, + { + input: '0x9702230a8ea53601f5cd2dc00fdbc13d4df4a8c7', + outputs: ['0x775eb53d00dd0acd3ec1696472105d579b9b386b'], + }, + { + input: '0xa7d7079b0fead91f3e65f86e8915cb59c1a4c664', + outputs: ['0x775eb53d00dd0acd3ec1696472105d579b9b386b'], + }, + { + input: '0xb50731ca2fd80afe3910a4800225d4845cad266f', + outputs: ['0x775eb53d00dd0acd3ec1696472105d579b9b386b'], + }, + { + input: '0xb7a41bb9ad3cdc5db0e35c12e78106fa3f21693d', + outputs: ['0x775eb53d00dd0acd3ec1696472105d579b9b386b'], + }, + { + input: '0xb97ef9ef8734c71904d8002f8b6bc66dd9c48a6e', + outputs: ['0x775eb53d00dd0acd3ec1696472105d579b9b386b'], + }, + { + input: '0xc7198437980c041c805a1edcba50c1ce5db95118', + outputs: ['0x775eb53d00dd0acd3ec1696472105d579b9b386b'], + }, + { + input: '0xd586e7f844cea2f87f50152665bcbc2c279d8d70', + outputs: ['0x775eb53d00dd0acd3ec1696472105d579b9b386b'], + }, + { + input: '0xf32cf7fcbb71d3d5ef75612538abd69e81d64aa9', + outputs: ['0x775eb53d00dd0acd3ec1696472105d579b9b386b'], + }, + { + input: '0xf68fb12aa78e5c2b3eebd71441a990cd5757055c', + outputs: ['0x775eb53d00dd0acd3ec1696472105d579b9b386b'], + }, + { + input: '0xfac26e3fd40adcdc6652f705d983b4830c00716c', + outputs: ['0x775eb53d00dd0acd3ec1696472105d579b9b386b'], + }, + ], + bsc: [ + { + input: '0x013f29832cd6525c4c6df81c2aae8032a1ff2db2', + outputs: ['0x775eb53d00dd0acd3ec1696472105d579b9b386b'], + }, + { + input: '0x0e09fabb73bd3ade0a17ecc321fd13a19e81ce82', + outputs: [ + '0x281162bd0b7a4162cb676bc4873734497b3af025', + '0x775eb53d00dd0acd3ec1696472105d579b9b386b', + ], + }, + { + input: '0x17b4158805772ced11225e77339f90beb5aae968', + outputs: ['0x775eb53d00dd0acd3ec1696472105d579b9b386b'], + }, + { + input: '0x1af3f329e8be154074d8769d1ffa4ee058b1dbc3', + outputs: [ + '0x281162bd0b7a4162cb676bc4873734497b3af025', + '0x775eb53d00dd0acd3ec1696472105d579b9b386b', + ], + }, + { + input: '0x2170ed0880ac9a755fd29b2688956bd959f933f8', + outputs: ['0x775eb53d00dd0acd3ec1696472105d579b9b386b'], + }, + { + input: '0x281162bd0b7a4162cb676bc4873734497b3af025', + outputs: [ + '0x775eb53d00dd0acd3ec1696472105d579b9b386b', + '0xe9e7cea3dedca5984780bafc599bd69add087d56', + '0x1af3f329e8be154074d8769d1ffa4ee058b1dbc3', + '0x0e09fabb73bd3ade0a17ecc321fd13a19e81ce82', + '0x8ac76a51cc950d9822d68b83fe1ad97b32cd580d', + '0x55d398326f99059ff775485246999027b3197955', + ], + }, + { + input: '0x4f99f266506be1475e943b2f097827011bfa4e93', + outputs: ['0x775eb53d00dd0acd3ec1696472105d579b9b386b'], + }, + { + input: '0x4fabb145d64652a948d72533023f6e7a623c7c53', + outputs: ['0x775eb53d00dd0acd3ec1696472105d579b9b386b'], + }, + { + input: '0x52f3d6575032420a7038d5b096820be555c7c707', + outputs: ['0x775eb53d00dd0acd3ec1696472105d579b9b386b'], + }, + { + input: '0x55d398326f99059ff775485246999027b3197955', + outputs: [ + '0x281162bd0b7a4162cb676bc4873734497b3af025', + '0x775eb53d00dd0acd3ec1696472105d579b9b386b', + ], + }, + { + input: '0x5b6d224c4bb5465d5faae5cb81614857964ce12b', + outputs: ['0x775eb53d00dd0acd3ec1696472105d579b9b386b'], + }, + { + input: '0x6ecfc28d0c11b296581339a7300cfb345b26153a', + outputs: ['0x775eb53d00dd0acd3ec1696472105d579b9b386b'], + }, + { + input: '0x717774da93a8ed092f7dba0acbb6977bf4fef912', + outputs: ['0x775eb53d00dd0acd3ec1696472105d579b9b386b'], + }, + { + input: '0x775eb53d00dd0acd3ec1696472105d579b9b386b', + outputs: [ + '0x4fabb145d64652a948d72533023f6e7a623c7c53', + '0x4f99f266506be1475e943b2f097827011bfa4e93', + '0x281162bd0b7a4162cb676bc4873734497b3af025', + '0xb50731ca2fd80afe3910a4800225d4845cad266f', + '0xe9e7cea3dedca5984780bafc599bd69add087d56', + '0xfac26e3fd40adcdc6652f705d983b4830c00716c', + '0x1af3f329e8be154074d8769d1ffa4ee058b1dbc3', + '0x17b4158805772ced11225e77339f90beb5aae968', + '0x013f29832cd6525c4c6df81c2aae8032a1ff2db2', + '0xab6ce0b86d905929340c640e8bcba8751feea10e', + '0xf68fb12aa78e5c2b3eebd71441a990cd5757055c', + '0x855b97276779c0e7a6ec28a449a55cba41003fa0', + '0x5b6d224c4bb5465d5faae5cb81614857964ce12b', + '0x9cc25aa34c6d7a4b572355ebc062aa1a60a85082', + '0x779987c9a457ffb220c3c3544817db67f7654507', + '0x52f3d6575032420a7038d5b096820be555c7c707', + '0x0e09fabb73bd3ade0a17ecc321fd13a19e81ce82', + '0x8ac76a51cc950d9822d68b83fe1ad97b32cd580d', + '0x55d398326f99059ff775485246999027b3197955', + '0x6ecfc28d0c11b296581339a7300cfb345b26153a', + '0xce80759e72fe1d3c07be79ffecc76a7a9b46c641', + '0x717774da93a8ed092f7dba0acbb6977bf4fef912', + '0xb59490ab09a0f526cc7305822ac65f2ab12f9723', + '0x2170ed0880ac9a755fd29b2688956bd959f933f8', + ], + }, + { + input: '0x779987c9a457ffb220c3c3544817db67f7654507', + outputs: ['0x775eb53d00dd0acd3ec1696472105d579b9b386b'], + }, + { + input: '0x855b97276779c0e7a6ec28a449a55cba41003fa0', + outputs: ['0x775eb53d00dd0acd3ec1696472105d579b9b386b'], + }, + { + input: '0x8ac76a51cc950d9822d68b83fe1ad97b32cd580d', + outputs: [ + '0x281162bd0b7a4162cb676bc4873734497b3af025', + '0x775eb53d00dd0acd3ec1696472105d579b9b386b', + ], + }, + { + input: '0x9cc25aa34c6d7a4b572355ebc062aa1a60a85082', + outputs: ['0x775eb53d00dd0acd3ec1696472105d579b9b386b'], + }, + { + input: '0xab6ce0b86d905929340c640e8bcba8751feea10e', + outputs: ['0x775eb53d00dd0acd3ec1696472105d579b9b386b'], + }, + { + input: '0xb50731ca2fd80afe3910a4800225d4845cad266f', + outputs: ['0x775eb53d00dd0acd3ec1696472105d579b9b386b'], + }, + { + input: '0xb59490ab09a0f526cc7305822ac65f2ab12f9723', + outputs: ['0x775eb53d00dd0acd3ec1696472105d579b9b386b'], + }, + { + input: '0xce80759e72fe1d3c07be79ffecc76a7a9b46c641', + outputs: ['0x775eb53d00dd0acd3ec1696472105d579b9b386b'], + }, + { + input: '0xe9e7cea3dedca5984780bafc599bd69add087d56', + outputs: [ + '0x281162bd0b7a4162cb676bc4873734497b3af025', + '0x775eb53d00dd0acd3ec1696472105d579b9b386b', + ], + }, + { + input: '0xf68fb12aa78e5c2b3eebd71441a990cd5757055c', + outputs: ['0x775eb53d00dd0acd3ec1696472105d579b9b386b'], + }, + { + input: '0xfac26e3fd40adcdc6652f705d983b4830c00716c', + outputs: ['0x775eb53d00dd0acd3ec1696472105d579b9b386b'], + }, + ], + fantom: [ + { + input: '0x03049758a18d1589388d7a74fb71c3fcce11d286', + outputs: ['0x775eb53d00dd0acd3ec1696472105d579b9b386b'], + }, + { + input: '0x04068da6c83afcfa0e13ba15a6696662335d5b75', + outputs: ['0x775eb53d00dd0acd3ec1696472105d579b9b386b'], + }, + { + input: '0x049d68029688eabf473097a2fc38ef61633a3c7a', + outputs: ['0x775eb53d00dd0acd3ec1696472105d579b9b386b'], + }, + { + input: '0x10bf4137b0558c33c2dc9f71c3bb81c2865fa2fb', + outputs: ['0x775eb53d00dd0acd3ec1696472105d579b9b386b'], + }, + { + input: '0x17b4158805772ced11225e77339f90beb5aae968', + outputs: ['0x775eb53d00dd0acd3ec1696472105d579b9b386b'], + }, + { + input: '0x27f26f00e1605903645bbabc0a73e35027dccd45', + outputs: ['0x775eb53d00dd0acd3ec1696472105d579b9b386b'], + }, + { + input: '0x2f733095b80a04b38b0d10cc884524a3d09b836a', + outputs: ['0x775eb53d00dd0acd3ec1696472105d579b9b386b'], + }, + { + input: '0x56ee926bd8c72b2d5fa1af4d9e4cbb515a1e3adc', + outputs: ['0x775eb53d00dd0acd3ec1696472105d579b9b386b'], + }, + { + input: '0x657a1861c15a3ded9af0b6799a195a249ebdcbc6', + outputs: ['0x775eb53d00dd0acd3ec1696472105d579b9b386b'], + }, + { + input: '0x658b0c7613e890ee50b8c4bc6a3f41ef411208ad', + outputs: ['0x775eb53d00dd0acd3ec1696472105d579b9b386b'], + }, + { + input: '0x6a07a792ab2965c72a5b8088d3a069a7ac3a993b', + outputs: ['0x775eb53d00dd0acd3ec1696472105d579b9b386b'], + }, + { + input: '0x775eb53d00dd0acd3ec1696472105d579b9b386b', + outputs: [ + '0xfac26e3fd40adcdc6652f705d983b4830c00716c', + '0x04068da6c83afcfa0e13ba15a6696662335d5b75', + '0x940f41f0ec9ba1a34cf001cc03347ac092f5f6b5', + '0xae75a438b2e0cb8bb01ec1e1e376de11d44477cc', + '0x56ee926bd8c72b2d5fa1af4d9e4cbb515a1e3adc', + '0xb3654dc3d10ea7645f8319668e8f54d2574fbdc8', + '0xf5af88e117747e87fc5929f2ff87221b1447652e', + '0x8d11ec38a3eb5e956b052f67da8bdc9bef8abf3e', + '0x657a1861c15a3ded9af0b6799a195a249ebdcbc6', + '0x27f26f00e1605903645bbabc0a73e35027dccd45', + '0x03049758a18d1589388d7a74fb71c3fcce11d286', + '0x6a07a792ab2965c72a5b8088d3a069a7ac3a993b', + '0x658b0c7613e890ee50b8c4bc6a3f41ef411208ad', + '0xe1146b9ac456fcbb60644c36fd3f868a9072fc6e', + '0x17b4158805772ced11225e77339f90beb5aae968', + '0x10bf4137b0558c33c2dc9f71c3bb81c2865fa2fb', + '0x049d68029688eabf473097a2fc38ef61633a3c7a', + '0x2f733095b80a04b38b0d10cc884524a3d09b836a', + ], + }, + { + input: '0x8d11ec38a3eb5e956b052f67da8bdc9bef8abf3e', + outputs: ['0x775eb53d00dd0acd3ec1696472105d579b9b386b'], + }, + { + input: '0x940f41f0ec9ba1a34cf001cc03347ac092f5f6b5', + outputs: ['0x775eb53d00dd0acd3ec1696472105d579b9b386b'], + }, + { + input: '0xae75a438b2e0cb8bb01ec1e1e376de11d44477cc', + outputs: ['0x775eb53d00dd0acd3ec1696472105d579b9b386b'], + }, + { + input: '0xb3654dc3d10ea7645f8319668e8f54d2574fbdc8', + outputs: ['0x775eb53d00dd0acd3ec1696472105d579b9b386b'], + }, + { + input: '0xe1146b9ac456fcbb60644c36fd3f868a9072fc6e', + outputs: ['0x775eb53d00dd0acd3ec1696472105d579b9b386b'], + }, + { + input: '0xf5af88e117747e87fc5929f2ff87221b1447652e', + outputs: ['0x775eb53d00dd0acd3ec1696472105d579b9b386b'], + }, + { + input: '0xfac26e3fd40adcdc6652f705d983b4830c00716c', + outputs: ['0x775eb53d00dd0acd3ec1696472105d579b9b386b'], + }, + ], + mainnet: [ + { + input: '0x0000000000085d4780b73119b644ae5ecd22b376', + outputs: [ + '0xf5af88e117747e87fc5929f2ff87221b1447652e', + '0x775eb53d00dd0acd3ec1696472105d579b9b386b', + ], + }, + { + input: '0x00a8b738e453ffd858a7edf03bccfe20412f0eb0', + outputs: ['0x775eb53d00dd0acd3ec1696472105d579b9b386b'], + }, + { + input: '0x013f29832cd6525c4c6df81c2aae8032a1ff2db2', + outputs: ['0x775eb53d00dd0acd3ec1696472105d579b9b386b'], + }, + { + input: '0x03049758a18d1589388d7a74fb71c3fcce11d286', + outputs: ['0x321162cd933e2be498cd2267a90534a804051b11'], + }, + { + input: '0x056fd409e1d7a124bd7017459dfea2f387b6d5cd', + outputs: [ + '0xf5af88e117747e87fc5929f2ff87221b1447652e', + '0x775eb53d00dd0acd3ec1696472105d579b9b386b', + ], + }, + { + input: '0x0bbb60891a1688271573e5ea4cba84f18cbc0f2d', + outputs: ['0x775eb53d00dd0acd3ec1696472105d579b9b386b'], + }, + { + input: '0x0d8775f648430679a709e98d2b0cb6250d2887ef', + outputs: [ + '0xf5af88e117747e87fc5929f2ff87221b1447652e', + '0x775eb53d00dd0acd3ec1696472105d579b9b386b', + ], + }, + { + input: '0x0f5d2fb29fb7d3cfee444a200298f468908cc942', + outputs: ['0xf5af88e117747e87fc5929f2ff87221b1447652e'], + }, + { + input: '0x17b4158805772ced11225e77339f90beb5aae968', + outputs: ['0x775eb53d00dd0acd3ec1696472105d579b9b386b'], + }, + { + input: '0x1a4b46696b2bb4794eb3d4c26f1c55f9170fa4c5', + outputs: ['0x775eb53d00dd0acd3ec1696472105d579b9b386b'], + }, + { + input: '0x1f573d6fb3f13d689ff844b4ce37794d79a7ff1c', + outputs: [ + '0x775eb53d00dd0acd3ec1696472105d579b9b386b', + '0xf5af88e117747e87fc5929f2ff87221b1447652e', + ], + }, + { + input: '0x321162cd933e2be498cd2267a90534a804051b11', + outputs: ['0x03049758a18d1589388d7a74fb71c3fcce11d286'], + }, + { + input: '0x3845badade8e6dff049820680d1f14bd3903a5d0', + outputs: ['0x775eb53d00dd0acd3ec1696472105d579b9b386b'], + }, + { + input: '0x4d224452801aced8b2f0aebe155379bb5d594381', + outputs: ['0x775eb53d00dd0acd3ec1696472105d579b9b386b'], + }, + { + input: '0x4e15361fd6b4bb609fa63c81a2be19d873717870', + outputs: ['0xf5af88e117747e87fc5929f2ff87221b1447652e'], + }, + { + input: '0x4f99f266506be1475e943b2f097827011bfa4e93', + outputs: ['0x775eb53d00dd0acd3ec1696472105d579b9b386b'], + }, + { + input: '0x4fabb145d64652a948d72533023f6e7a623c7c53', + outputs: [ + '0xf5af88e117747e87fc5929f2ff87221b1447652e', + '0x775eb53d00dd0acd3ec1696472105d579b9b386b', + ], + }, + { + input: '0x607f4c5bb672230e8672085532f7e901544a7375', + outputs: ['0xf5af88e117747e87fc5929f2ff87221b1447652e'], + }, + { + input: '0x66710cc1372861ec5d5537c075b527b7b3c63c5f', + outputs: ['0x775eb53d00dd0acd3ec1696472105d579b9b386b'], + }, + { + input: '0x6810e776880c02933d47db1b9fc05908e5386b96', + outputs: ['0xf5af88e117747e87fc5929f2ff87221b1447652e'], + }, + { + input: '0x6b175474e89094c44da98b954eedeac495271d0f', + outputs: [ + '0xf5af88e117747e87fc5929f2ff87221b1447652e', + '0x775eb53d00dd0acd3ec1696472105d579b9b386b', + ], + }, + { + input: '0x6b3595068778dd592e39a122f4f5a5cf09c90fe2', + outputs: [ + '0xf5af88e117747e87fc5929f2ff87221b1447652e', + '0x775eb53d00dd0acd3ec1696472105d579b9b386b', + ], + }, + { + input: '0x6ea6803339cfeadd84b5b62820c548f53ff7d8e9', + outputs: ['0x775eb53d00dd0acd3ec1696472105d579b9b386b'], + }, + { + input: '0x775eb53d00dd0acd3ec1696472105d579b9b386b', + outputs: [ + '0x4f99f266506be1475e943b2f097827011bfa4e93', + '0xfa6faefc053e6c8e393a73dcc12b09fcde019d25', + '0xf5af88e117747e87fc5929f2ff87221b1447652e', + '0x1f573d6fb3f13d689ff844b4ce37794d79a7ff1c', + '0x8290333cef9e6d528dd5618fb97a76f268f3edd4', + '0x7fc66500c84a76ad7e9c93437bfc5ac33e2ddae9', + '0xce80759e72fe1d3c07be79ffecc76a7a9b46c641', + '0xfac26e3fd40adcdc6652f705d983b4830c00716c', + '0xdac17f958d2ee523a2206206994597c13d831ec7', + '0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48', + '0x013f29832cd6525c4c6df81c2aae8032a1ff2db2', + '0x17b4158805772ced11225e77339f90beb5aae968', + '0x6b175474e89094c44da98b954eedeac495271d0f', + '0x3845badade8e6dff049820680d1f14bd3903a5d0', + '0x8ab7404063ec4dbcfd4598215992dc3f8ec853d7', + '0xdefa4e8a7bcba345f687a2f1456f5edd9ce97202', + '0xe6c09adc89ff4467cea20bc7760e3e59e7c0671d', + '0x0d8775f648430679a709e98d2b0cb6250d2887ef', + '0x956f47f50a910163d8bf957cf5846d573e7f87ca', + '0xf68fb12aa78e5c2b3eebd71441a990cd5757055c', + '0x0bbb60891a1688271573e5ea4cba84f18cbc0f2d', + '0xb50731ca2fd80afe3910a4800225d4845cad266f', + '0xab6ce0b86d905929340c640e8bcba8751feea10e', + '0xbc396689893d065f41bc2c6ecbee5e0085233447', + '0x6b3595068778dd592e39a122f4f5a5cf09c90fe2', + '0xb7a41bb9ad3cdc5db0e35c12e78106fa3f21693d', + '0x00a8b738e453ffd858a7edf03bccfe20412f0eb0', + '0x1a4b46696b2bb4794eb3d4c26f1c55f9170fa4c5', + '0xd46ba6d942050d489dbd938a2c909a5d5039a161', + '0x77fba179c79de5b7653f68b5039af940ada60ce0', + '0x4fabb145d64652a948d72533023f6e7a623c7c53', + '0x853d955acef822db058eb8505911ed77f175b99e', + '0x056fd409e1d7a124bd7017459dfea2f387b6d5cd', + '0xe28b3b32b6c345a34ff64674606124dd5aceca30', + '0x7d1afa7b718fb893db30a3abc0cfc608aacfebb0', + '0x0000000000085d4780b73119b644ae5ecd22b376', + '0x8e870d67f660d95d5be530380d0ec0bd388289e1', + '0x6ea6803339cfeadd84b5b62820c548f53ff7d8e9', + '0xf57e7e7c23978c3caec3c3548e3d615c346e79ff', + '0x66710cc1372861ec5d5537c075b527b7b3c63c5f', + '0xc011a73ee8576fb46f5e1c5751ca3b9fe0af2a6f', + '0x4d224452801aced8b2f0aebe155379bb5d594381', + ], + }, + { + input: '0x77fba179c79de5b7653f68b5039af940ada60ce0', + outputs: ['0x775eb53d00dd0acd3ec1696472105d579b9b386b'], + }, + { + input: '0x7d1afa7b718fb893db30a3abc0cfc608aacfebb0', + outputs: ['0x775eb53d00dd0acd3ec1696472105d579b9b386b'], + }, + { + input: '0x7fc66500c84a76ad7e9c93437bfc5ac33e2ddae9', + outputs: [ + '0x775eb53d00dd0acd3ec1696472105d579b9b386b', + '0xf5af88e117747e87fc5929f2ff87221b1447652e', + ], + }, + { + input: '0x8290333cef9e6d528dd5618fb97a76f268f3edd4', + outputs: ['0x775eb53d00dd0acd3ec1696472105d579b9b386b'], + }, + { + input: '0x853d955acef822db058eb8505911ed77f175b99e', + outputs: [ + '0xf5af88e117747e87fc5929f2ff87221b1447652e', + '0x775eb53d00dd0acd3ec1696472105d579b9b386b', + ], + }, + { + input: '0x8ab7404063ec4dbcfd4598215992dc3f8ec853d7', + outputs: ['0x775eb53d00dd0acd3ec1696472105d579b9b386b'], + }, + { + input: '0x8e870d67f660d95d5be530380d0ec0bd388289e1', + outputs: ['0x775eb53d00dd0acd3ec1696472105d579b9b386b'], + }, + { + input: '0x8f693ca8d21b157107184d29d398a8d082b38b76', + outputs: ['0xf5af88e117747e87fc5929f2ff87221b1447652e'], + }, + { + input: '0x956f47f50a910163d8bf957cf5846d573e7f87ca', + outputs: ['0x775eb53d00dd0acd3ec1696472105d579b9b386b'], + }, + { + input: '0x9f8f72aa9304c8b593d555f12ef6589cc3a579a2', + outputs: ['0xf5af88e117747e87fc5929f2ff87221b1447652e'], + }, + { + input: '0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48', + outputs: [ + '0x775eb53d00dd0acd3ec1696472105d579b9b386b', + '0xf5af88e117747e87fc5929f2ff87221b1447652e', + ], + }, + { + input: '0xa117000000f279d81a1d3cc75430faa017fa5a2e', + outputs: ['0xf5af88e117747e87fc5929f2ff87221b1447652e'], + }, + { + input: '0xab6ce0b86d905929340c640e8bcba8751feea10e', + outputs: ['0x775eb53d00dd0acd3ec1696472105d579b9b386b'], + }, + { + input: '0xb50731ca2fd80afe3910a4800225d4845cad266f', + outputs: ['0x775eb53d00dd0acd3ec1696472105d579b9b386b'], + }, + { + input: '0xb7a41bb9ad3cdc5db0e35c12e78106fa3f21693d', + outputs: ['0x775eb53d00dd0acd3ec1696472105d579b9b386b'], + }, + { + input: '0xb8c77482e45f1f44de1745f52c74426c631bdd52', + outputs: ['0xf5af88e117747e87fc5929f2ff87221b1447652e'], + }, + { + input: '0xbb0e17ef65f82ab018d8edd776e8dd940327b28b', + outputs: ['0xf5af88e117747e87fc5929f2ff87221b1447652e'], + }, + { + input: '0xbc396689893d065f41bc2c6ecbee5e0085233447', + outputs: [ + '0xf5af88e117747e87fc5929f2ff87221b1447652e', + '0x775eb53d00dd0acd3ec1696472105d579b9b386b', + ], + }, + { + input: '0xc011a73ee8576fb46f5e1c5751ca3b9fe0af2a6f', + outputs: ['0x775eb53d00dd0acd3ec1696472105d579b9b386b'], + }, + { + input: '0xc944e90c64b2c07662a292be6244bdf05cda44a7', + outputs: ['0xf5af88e117747e87fc5929f2ff87221b1447652e'], + }, + { + input: '0xce80759e72fe1d3c07be79ffecc76a7a9b46c641', + outputs: ['0x775eb53d00dd0acd3ec1696472105d579b9b386b'], + }, + { + input: '0xd46ba6d942050d489dbd938a2c909a5d5039a161', + outputs: ['0x775eb53d00dd0acd3ec1696472105d579b9b386b'], + }, + { + input: '0xdac17f958d2ee523a2206206994597c13d831ec7', + outputs: [ + '0x775eb53d00dd0acd3ec1696472105d579b9b386b', + '0xf5af88e117747e87fc5929f2ff87221b1447652e', + ], + }, + { + input: '0xde30da39c46104798bb5aa3fe8b9e0e1f348163f', + outputs: ['0xf5af88e117747e87fc5929f2ff87221b1447652e'], + }, + { + input: '0xdefa4e8a7bcba345f687a2f1456f5edd9ce97202', + outputs: [ + '0xf5af88e117747e87fc5929f2ff87221b1447652e', + '0x775eb53d00dd0acd3ec1696472105d579b9b386b', + ], + }, + { + input: '0xe28b3b32b6c345a34ff64674606124dd5aceca30', + outputs: ['0x775eb53d00dd0acd3ec1696472105d579b9b386b'], + }, + { + input: '0xe6c09adc89ff4467cea20bc7760e3e59e7c0671d', + outputs: ['0x775eb53d00dd0acd3ec1696472105d579b9b386b'], + }, + { + input: '0xf57e7e7c23978c3caec3c3548e3d615c346e79ff', + outputs: ['0x775eb53d00dd0acd3ec1696472105d579b9b386b'], + }, + { + input: '0xf5af88e117747e87fc5929f2ff87221b1447652e', + outputs: [ + '0x775eb53d00dd0acd3ec1696472105d579b9b386b', + '0x1f573d6fb3f13d689ff844b4ce37794d79a7ff1c', + '0xa117000000f279d81a1d3cc75430faa017fa5a2e', + '0x7fc66500c84a76ad7e9c93437bfc5ac33e2ddae9', + '0x9f8f72aa9304c8b593d555f12ef6589cc3a579a2', + '0x4e15361fd6b4bb609fa63c81a2be19d873717870', + '0xdac17f958d2ee523a2206206994597c13d831ec7', + '0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48', + '0x6b175474e89094c44da98b954eedeac495271d0f', + '0xc944e90c64b2c07662a292be6244bdf05cda44a7', + '0x0f5d2fb29fb7d3cfee444a200298f468908cc942', + '0xdefa4e8a7bcba345f687a2f1456f5edd9ce97202', + '0x8f693ca8d21b157107184d29d398a8d082b38b76', + '0xbb0e17ef65f82ab018d8edd776e8dd940327b28b', + '0xde30da39c46104798bb5aa3fe8b9e0e1f348163f', + '0x0d8775f648430679a709e98d2b0cb6250d2887ef', + '0xb8c77482e45f1f44de1745f52c74426c631bdd52', + '0x6810e776880c02933d47db1b9fc05908e5386b96', + '0xbc396689893d065f41bc2c6ecbee5e0085233447', + '0x607f4c5bb672230e8672085532f7e901544a7375', + '0x6b3595068778dd592e39a122f4f5a5cf09c90fe2', + '0x4fabb145d64652a948d72533023f6e7a623c7c53', + '0x853d955acef822db058eb8505911ed77f175b99e', + '0x056fd409e1d7a124bd7017459dfea2f387b6d5cd', + '0x0000000000085d4780b73119b644ae5ecd22b376', + ], + }, + { + input: '0xf68fb12aa78e5c2b3eebd71441a990cd5757055c', + outputs: ['0x775eb53d00dd0acd3ec1696472105d579b9b386b'], + }, + { + input: '0xfa6faefc053e6c8e393a73dcc12b09fcde019d25', + outputs: ['0x775eb53d00dd0acd3ec1696472105d579b9b386b'], + }, + { + input: '0xfac26e3fd40adcdc6652f705d983b4830c00716c', + outputs: ['0x775eb53d00dd0acd3ec1696472105d579b9b386b'], + }, + ], + matic: [ + { + input: '0x013f29832cd6525c4c6df81c2aae8032a1ff2db2', + outputs: ['0x775eb53d00dd0acd3ec1696472105d579b9b386b'], + }, + { + input: '0x0bbb60891a1688271573e5ea4cba84f18cbc0f2d', + outputs: ['0x775eb53d00dd0acd3ec1696472105d579b9b386b'], + }, + { + input: '0x11485b23f0d3db30edb6c876abcc18d699a43e7d', + outputs: ['0x775eb53d00dd0acd3ec1696472105d579b9b386b'], + }, + { + input: '0x17b4158805772ced11225e77339f90beb5aae968', + outputs: ['0x775eb53d00dd0acd3ec1696472105d579b9b386b'], + }, + { + input: '0x23c7fe5a44ca213deed6f3e2e714d747fcbcdbf0', + outputs: [ + '0x775eb53d00dd0acd3ec1696472105d579b9b386b', + '0xf5af88e117747e87fc5929f2ff87221b1447652e', + ], + }, + { + input: '0x2791bca1f2de4661ed88a30c99a7a9449aa84174', + outputs: [ + '0x775eb53d00dd0acd3ec1696472105d579b9b386b', + '0xf5af88e117747e87fc5929f2ff87221b1447652e', + ], + }, + { + input: '0x385eeac5cb85a38a9a07a70c73e0a3271cfb54a7', + outputs: ['0x775eb53d00dd0acd3ec1696472105d579b9b386b'], + }, + { + input: '0x3c499c542cef5e3811e1192ce70d8cc03d5c3359', + outputs: ['0x775eb53d00dd0acd3ec1696472105d579b9b386b'], + }, + { + input: '0x4f99f266506be1475e943b2f097827011bfa4e93', + outputs: ['0x775eb53d00dd0acd3ec1696472105d579b9b386b'], + }, + { + input: '0x5fe2b58c013d7601147dcdd68c143a77499f5531', + outputs: ['0x775eb53d00dd0acd3ec1696472105d579b9b386b'], + }, + { + input: '0x66710cc1372861ec5d5537c075b527b7b3c63c5f', + outputs: ['0x775eb53d00dd0acd3ec1696472105d579b9b386b'], + }, + { + input: '0x6ea6803339cfeadd84b5b62820c548f53ff7d8e9', + outputs: ['0x775eb53d00dd0acd3ec1696472105d579b9b386b'], + }, + { + input: '0x717774da93a8ed092f7dba0acbb6977bf4fef912', + outputs: ['0x775eb53d00dd0acd3ec1696472105d579b9b386b'], + }, + { + input: '0x775eb53d00dd0acd3ec1696472105d579b9b386b', + outputs: [ + '0xc2132d05d31c914a87c6611c10748aeb04b58e8f', + '0x2791bca1f2de4661ed88a30c99a7a9449aa84174', + '0x8f3cf7ad23cd3cadbd9735aff958023239c6a063', + '0xfa6faefc053e6c8e393a73dcc12b09fcde019d25', + '0xce80759e72fe1d3c07be79ffecc76a7a9b46c641', + '0x013f29832cd6525c4c6df81c2aae8032a1ff2db2', + '0x17b4158805772ced11225e77339f90beb5aae968', + '0x4f99f266506be1475e943b2f097827011bfa4e93', + '0xfac26e3fd40adcdc6652f705d983b4830c00716c', + '0x831753dd7087cac61ab5644b308642cc1c33dc13', + '0xbbba073c31bf03b8acf7c28ef0738decf3695683', + '0x23c7fe5a44ca213deed6f3e2e714d747fcbcdbf0', + '0x6ea6803339cfeadd84b5b62820c548f53ff7d8e9', + '0xe6c09adc89ff4467cea20bc7760e3e59e7c0671d', + '0x11485b23f0d3db30edb6c876abcc18d699a43e7d', + '0xab6ce0b86d905929340c640e8bcba8751feea10e', + '0xf68fb12aa78e5c2b3eebd71441a990cd5757055c', + '0x0bbb60891a1688271573e5ea4cba84f18cbc0f2d', + '0x717774da93a8ed092f7dba0acbb6977bf4fef912', + '0xe0b52e49357fd4daf2c15e02058dce6bc0057db4', + '0xb50731ca2fd80afe3910a4800225d4845cad266f', + '0x5fe2b58c013d7601147dcdd68c143a77499f5531', + '0xb7a41bb9ad3cdc5db0e35c12e78106fa3f21693d', + '0xa25ef954247c614a0036730b129960bc94db36fa', + '0x385eeac5cb85a38a9a07a70c73e0a3271cfb54a7', + '0x967da4048cd07ab37855c090aaf366e4ce1b9f48', + '0x66710cc1372861ec5d5537c075b527b7b3c63c5f', + '0x3c499c542cef5e3811e1192ce70d8cc03d5c3359', + '0xb5c064f955d8e7f38fe0460c556a72987494ee17', + ], + }, + { + input: '0x831753dd7087cac61ab5644b308642cc1c33dc13', + outputs: [ + '0x775eb53d00dd0acd3ec1696472105d579b9b386b', + '0xf5af88e117747e87fc5929f2ff87221b1447652e', + ], + }, + { + input: '0x8f3cf7ad23cd3cadbd9735aff958023239c6a063', + outputs: [ + '0x775eb53d00dd0acd3ec1696472105d579b9b386b', + '0xf5af88e117747e87fc5929f2ff87221b1447652e', + ], + }, + { + input: '0x967da4048cd07ab37855c090aaf366e4ce1b9f48', + outputs: ['0x775eb53d00dd0acd3ec1696472105d579b9b386b'], + }, + { + input: '0xa25ef954247c614a0036730b129960bc94db36fa', + outputs: ['0x775eb53d00dd0acd3ec1696472105d579b9b386b'], + }, + { + input: '0xab6ce0b86d905929340c640e8bcba8751feea10e', + outputs: ['0x775eb53d00dd0acd3ec1696472105d579b9b386b'], + }, + { + input: '0xb50731ca2fd80afe3910a4800225d4845cad266f', + outputs: ['0x775eb53d00dd0acd3ec1696472105d579b9b386b'], + }, + { + input: '0xb5c064f955d8e7f38fe0460c556a72987494ee17', + outputs: [ + '0xf5af88e117747e87fc5929f2ff87221b1447652e', + '0x775eb53d00dd0acd3ec1696472105d579b9b386b', + ], + }, + { + input: '0xb7a41bb9ad3cdc5db0e35c12e78106fa3f21693d', + outputs: ['0x775eb53d00dd0acd3ec1696472105d579b9b386b'], + }, + { + input: '0xbbba073c31bf03b8acf7c28ef0738decf3695683', + outputs: ['0x775eb53d00dd0acd3ec1696472105d579b9b386b'], + }, + { + input: '0xc2132d05d31c914a87c6611c10748aeb04b58e8f', + outputs: [ + '0x775eb53d00dd0acd3ec1696472105d579b9b386b', + '0xf5af88e117747e87fc5929f2ff87221b1447652e', + ], + }, + { + input: '0xce80759e72fe1d3c07be79ffecc76a7a9b46c641', + outputs: ['0x775eb53d00dd0acd3ec1696472105d579b9b386b'], + }, + { + input: '0xe0b52e49357fd4daf2c15e02058dce6bc0057db4', + outputs: ['0x775eb53d00dd0acd3ec1696472105d579b9b386b'], + }, + { + input: '0xe6c09adc89ff4467cea20bc7760e3e59e7c0671d', + outputs: ['0x775eb53d00dd0acd3ec1696472105d579b9b386b'], + }, + { + input: '0xf5af88e117747e87fc5929f2ff87221b1447652e', + outputs: [ + '0xc2132d05d31c914a87c6611c10748aeb04b58e8f', + '0x2791bca1f2de4661ed88a30c99a7a9449aa84174', + '0x8f3cf7ad23cd3cadbd9735aff958023239c6a063', + '0x831753dd7087cac61ab5644b308642cc1c33dc13', + '0x23c7fe5a44ca213deed6f3e2e714d747fcbcdbf0', + '0xb5c064f955d8e7f38fe0460c556a72987494ee17', + ], + }, + { + input: '0xf68fb12aa78e5c2b3eebd71441a990cd5757055c', + outputs: ['0x775eb53d00dd0acd3ec1696472105d579b9b386b'], + }, + { + input: '0xfa6faefc053e6c8e393a73dcc12b09fcde019d25', + outputs: ['0x775eb53d00dd0acd3ec1696472105d579b9b386b'], + }, + { + input: '0xfac26e3fd40adcdc6652f705d983b4830c00716c', + outputs: ['0x775eb53d00dd0acd3ec1696472105d579b9b386b'], + }, + ], + moonbeam: [ + { + input: '0x55c50d787fbea1573a0b86545b4a22de0b2d1dc4', + outputs: ['0x775eb53d00dd0acd3ec1696472105d579b9b386b'], + }, + { + input: '0x775eb53d00dd0acd3ec1696472105d579b9b386b', + outputs: [ + '0x55c50d787fbea1573a0b86545b4a22de0b2d1dc4', + '0x818ec0a7fe18ff94269904fced6ae3dae6d6dc0b', + '0x931715fee2d06333043d11f658c8ce934ac61d0c', + '0x8f552a71efe5eefc207bf75485b356a0b3f01ec9', + ], + }, + { + input: '0x818ec0a7fe18ff94269904fced6ae3dae6d6dc0b', + outputs: ['0x775eb53d00dd0acd3ec1696472105d579b9b386b'], + }, + { + input: '0x8f552a71efe5eefc207bf75485b356a0b3f01ec9', + outputs: ['0x775eb53d00dd0acd3ec1696472105d579b9b386b'], + }, + { + input: '0x931715fee2d06333043d11f658c8ce934ac61d0c', + outputs: ['0x775eb53d00dd0acd3ec1696472105d579b9b386b'], + }, + ], + optimism: [ + { + input: '0x0b2c639c533813f4aa9d7837caf62653d097ff85', + outputs: ['0x775eb53d00dd0acd3ec1696472105d579b9b386b'], + }, + { + input: '0x17b4158805772ced11225e77339f90beb5aae968', + outputs: ['0x775eb53d00dd0acd3ec1696472105d579b9b386b'], + }, + { + input: '0x4f99f266506be1475e943b2f097827011bfa4e93', + outputs: ['0x775eb53d00dd0acd3ec1696472105d579b9b386b'], + }, + { + input: '0x76fb31fb4af56892a25e32cfc43de717950c9278', + outputs: ['0x775eb53d00dd0acd3ec1696472105d579b9b386b'], + }, + { + input: '0x775eb53d00dd0acd3ec1696472105d579b9b386b', + outputs: [ + '0x4f99f266506be1475e943b2f097827011bfa4e93', + '0x17b4158805772ced11225e77339f90beb5aae968', + '0xbc396689893d065f41bc2c6ecbee5e0085233447', + '0xfa6faefc053e6c8e393a73dcc12b09fcde019d25', + '0xda10009cbd5d07dd0cecc66161fc93d7c9000da1', + '0xab6ce0b86d905929340c640e8bcba8751feea10e', + '0xf68fb12aa78e5c2b3eebd71441a990cd5757055c', + '0x7f5c764cbc14f9669b88837ca1490cca17c31607', + '0x94b008aa00579c1307b0ef2c499ad98a8ce58e58', + '0x9cc25aa34c6d7a4b572355ebc062aa1a60a85082', + '0x779987c9a457ffb220c3c3544817db67f7654507', + '0x76fb31fb4af56892a25e32cfc43de717950c9278', + '0xa00e3a3511aac35ca78530c85007afcd31753819', + '0x9e1028f5f1d5ede59748ffcee5532509976840e0', + '0x8700daec35af8ff88c16bdf0418774cb3d7599b4', + '0x0b2c639c533813f4aa9d7837caf62653d097ff85', + ], + }, + { + input: '0x779987c9a457ffb220c3c3544817db67f7654507', + outputs: ['0x775eb53d00dd0acd3ec1696472105d579b9b386b'], + }, + { + input: '0x7f5c764cbc14f9669b88837ca1490cca17c31607', + outputs: ['0x775eb53d00dd0acd3ec1696472105d579b9b386b'], + }, + { + input: '0x8700daec35af8ff88c16bdf0418774cb3d7599b4', + outputs: ['0x775eb53d00dd0acd3ec1696472105d579b9b386b'], + }, + { + input: '0x94b008aa00579c1307b0ef2c499ad98a8ce58e58', + outputs: ['0x775eb53d00dd0acd3ec1696472105d579b9b386b'], + }, + { + input: '0x9cc25aa34c6d7a4b572355ebc062aa1a60a85082', + outputs: ['0x775eb53d00dd0acd3ec1696472105d579b9b386b'], + }, + { + input: '0x9e1028f5f1d5ede59748ffcee5532509976840e0', + outputs: ['0x775eb53d00dd0acd3ec1696472105d579b9b386b'], + }, + { + input: '0xa00e3a3511aac35ca78530c85007afcd31753819', + outputs: ['0x775eb53d00dd0acd3ec1696472105d579b9b386b'], + }, + { + input: '0xab6ce0b86d905929340c640e8bcba8751feea10e', + outputs: ['0x775eb53d00dd0acd3ec1696472105d579b9b386b'], + }, + { + input: '0xbc396689893d065f41bc2c6ecbee5e0085233447', + outputs: ['0x775eb53d00dd0acd3ec1696472105d579b9b386b'], + }, + { + input: '0xda10009cbd5d07dd0cecc66161fc93d7c9000da1', + outputs: ['0x775eb53d00dd0acd3ec1696472105d579b9b386b'], + }, + { + input: '0xf68fb12aa78e5c2b3eebd71441a990cd5757055c', + outputs: ['0x775eb53d00dd0acd3ec1696472105d579b9b386b'], + }, + { + input: '0xfa6faefc053e6c8e393a73dcc12b09fcde019d25', + outputs: ['0x775eb53d00dd0acd3ec1696472105d579b9b386b'], + }, + ], + sepolia: [ + { + input: '0x013f29832cd6525c4c6df81c2aae8032a1ff2db2', + outputs: ['0x775eb53d00dd0acd3ec1696472105d579b9b386b'], + }, + { + input: '0x17b4158805772ced11225e77339f90beb5aae968', + outputs: ['0x775eb53d00dd0acd3ec1696472105d579b9b386b'], + }, + { + input: '0x370de27fdb7d1ff1e1baa7d11c5820a324cf623c', + outputs: ['0x775eb53d00dd0acd3ec1696472105d579b9b386b'], + }, + { + input: '0x6b175474e89094c44da98b954eedeac495271d0f', + outputs: ['0x775eb53d00dd0acd3ec1696472105d579b9b386b'], + }, + { + input: '0x775eb53d00dd0acd3ec1696472105d579b9b386b', + outputs: [ + '0xbb3546497a53cd710beb11b84c5240327f145bcb', + '0x370de27fdb7d1ff1e1baa7d11c5820a324cf623c', + '0xf046b3ca5ae2879c6bacc4d42faf363ee8379f78', + '0xf5af88e117747e87fc5929f2ff87221b1447652e', + '0x6b175474e89094c44da98b954eedeac495271d0f', + '0x17b4158805772ced11225e77339f90beb5aae968', + '0x013f29832cd6525c4c6df81c2aae8032a1ff2db2', + '0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48', + ], + }, + { + input: '0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48', + outputs: ['0x775eb53d00dd0acd3ec1696472105d579b9b386b'], + }, + { + input: '0xbb3546497a53cd710beb11b84c5240327f145bcb', + outputs: ['0x775eb53d00dd0acd3ec1696472105d579b9b386b'], + }, + { + input: '0xf046b3ca5ae2879c6bacc4d42faf363ee8379f78', + outputs: ['0x775eb53d00dd0acd3ec1696472105d579b9b386b'], + }, + { + input: '0xf5af88e117747e87fc5929f2ff87221b1447652e', + outputs: ['0x775eb53d00dd0acd3ec1696472105d579b9b386b'], + }, + ], + xdai: [ + { + input: '0x17b4158805772ced11225e77339f90beb5aae968', + outputs: ['0x775eb53d00dd0acd3ec1696472105d579b9b386b'], + }, + { + input: '0x5fd896d248fbfa54d26855c267859eb1b4daee72', + outputs: ['0x775eb53d00dd0acd3ec1696472105d579b9b386b'], + }, + { + input: '0x775eb53d00dd0acd3ec1696472105d579b9b386b', + outputs: [ + '0xddafbb505ad214d7b80b1f830fccc89b60fb7a83', + '0x5fd896d248fbfa54d26855c267859eb1b4daee72', + '0xfadc59d012ba3c110b08a15b7755a5cb7cbe77d7', + '0xfac26e3fd40adcdc6652f705d983b4830c00716c', + '0x17b4158805772ced11225e77339f90beb5aae968', + '0x9c58bacc331c9aa871afd802db6379a98e80cedb', + '0xf68fb12aa78e5c2b3eebd71441a990cd5757055c', + ], + }, + { + input: '0x9c58bacc331c9aa871afd802db6379a98e80cedb', + outputs: ['0x775eb53d00dd0acd3ec1696472105d579b9b386b'], + }, + { + input: '0xddafbb505ad214d7b80b1f830fccc89b60fb7a83', + outputs: ['0x775eb53d00dd0acd3ec1696472105d579b9b386b'], + }, + { + input: '0xf68fb12aa78e5c2b3eebd71441a990cd5757055c', + outputs: ['0x775eb53d00dd0acd3ec1696472105d579b9b386b'], + }, + { + input: '0xfac26e3fd40adcdc6652f705d983b4830c00716c', + outputs: ['0x775eb53d00dd0acd3ec1696472105d579b9b386b'], + }, + { + input: '0xfadc59d012ba3c110b08a15b7755a5cb7cbe77d7', + outputs: ['0x775eb53d00dd0acd3ec1696472105d579b9b386b'], + }, + ], +}; + +/** + * Converts currency conversion pair to currency manager format + * + * @param currencyConversionPair + * @returns formatted currency conversion pair for currency manager + */ + +export const convertToCurrencyManagerFormat = (currencyConversionPair) => { + return currencyConversionPair.reduce( + (a, v) => ({ + ...a, + [v.input]: v.outputs.reduce((a, v) => ({ ...a, [v]: 1 }), {}), + }), + {}, + ); +}; + +/** + * Formatted currency conversion pairs for currency manager + */ +export const formattedCurrencyConversionPairs = { + 'arbitrum-one': convertToCurrencyManagerFormat( + currencyConversionPairs['arbitrum-one'], + ), + avalanche: convertToCurrencyManagerFormat( + currencyConversionPairs['avalanche'], + ), + base: convertToCurrencyManagerFormat(currencyConversionPairs['base']), + bsc: convertToCurrencyManagerFormat(currencyConversionPairs['bsc']), + mainnet: convertToCurrencyManagerFormat(currencyConversionPairs['mainnet']), + matic: convertToCurrencyManagerFormat(currencyConversionPairs['matic']), + moonbeam: convertToCurrencyManagerFormat(currencyConversionPairs['moonbeam']), + optimism: convertToCurrencyManagerFormat(currencyConversionPairs['optimism']), + sepolia: convertToCurrencyManagerFormat(currencyConversionPairs['sepolia']), + xdai: convertToCurrencyManagerFormat(currencyConversionPairs['xdai']), +}; diff --git a/shared/utils/initCurrencyManager.ts b/shared/utils/initCurrencyManager.ts index 56534b46..1c6f7384 100644 --- a/shared/utils/initCurrencyManager.ts +++ b/shared/utils/initCurrencyManager.ts @@ -1,6 +1,21 @@ import { CurrencyManager } from "@requestnetwork/currency"; const defaultCurrencyIds = [ + "USD", + "EUR", + "GBP", + "CHF", + "SGD", + "AUD", + "BRL", + "CAD", + "INR", + "JPY", + "KRW", + "IDR", + "NZD", + "TRY", + "CNY", "FAU-sepolia", "USDC-mainnet", "USDT-mainnet", @@ -46,6 +61,7 @@ const defaultCurrencyIds = [ ]; import { Types } from "@requestnetwork/request-client.js"; +import { formattedCurrencyConversionPairs } from './currencyConversionPairs' export function initializeCurrencyManager( customCurrencies: any[] @@ -58,7 +74,7 @@ export function initializeCurrencyManager( currenciesToUse = defaultCurrencies; - if (customCurrencies.length > 0) { + if (customCurrencies?.length > 0) { currenciesToUse.push(...customCurrencies); } @@ -74,11 +90,13 @@ export function initializeCurrencyManager( t.network === currency.network && t.address?.toLowerCase() === currency.address?.toLowerCase() ); + } else if (currency.type === Types.RequestLogic.CURRENCY.ISO4217) { + return t.type === currency.type && t.symbol === currency.symbol; } }) ); - return new CurrencyManager(currenciesToUse); + return new CurrencyManager(currenciesToUse, {}, formattedCurrencyConversionPairs); } export function initializeCurrencyManagerWithCurrencyIDS( @@ -89,7 +107,15 @@ export function initializeCurrencyManagerWithCurrencyIDS( }); return { - currencyManager: new CurrencyManager(currencies), + currencyManager: new CurrencyManager(currencies, {}, formattedCurrencyConversionPairs), currencies, }; } + +export const getCurrencySupportedNetworksForConversion = (currencyHash: string, currencyManager: any) : (string | undefined)[] => { + return Object.keys(currencyManager.conversionPairs).map((network) => { + if (currencyManager.conversionPairs[network][currencyHash]) { + return network; + } + }).filter((network) => network); +} \ No newline at end of file From c7d3c8c1968d9a6d91340ef6de73d85f248af6c8 Mon Sep 17 00:00:00 2001 From: rodrigopavezi Date: Tue, 24 Sep 2024 22:48:20 -0300 Subject: [PATCH 02/53] feat: create conversion payment request --- .../src/lib/create-invoice-form.svelte | 6 +- .../src/lib/invoice/form-view.svelte | 8 +- .../src/lib/utils/prepareRequest.ts | 81 ++++++++++++++----- .../src/lib/dashboard/invoice-view.svelte | 45 ++++++++++- .../src/lib/view-requests.svelte | 20 ++++- .../src/utils/getCurrency.ts | 2 +- 6 files changed, 133 insertions(+), 29 deletions(-) diff --git a/packages/create-invoice-form/src/lib/create-invoice-form.svelte b/packages/create-invoice-form/src/lib/create-invoice-form.svelte index efb68bfb..9583e83a 100644 --- a/packages/create-invoice-form/src/lib/create-invoice-form.svelte +++ b/packages/create-invoice-form/src/lib/create-invoice-form.svelte @@ -55,7 +55,9 @@ network = network; defaultCurrencies = newCurrencies; - currency = newCurrencies[0]; + currency = newCurrencies.filter( + (currency: any) => currency.type !== Types.RequestLogic.CURRENCY.ISO4217 + )[0]; } }; @@ -149,6 +151,7 @@ const requestCreateParameters = prepareRequestParams({ signer, formData, + invoiceCurrency, currency, invoiceTotals, }); @@ -201,7 +204,6 @@ config={activeConfig} {invoiceCurrency} {currency} - {network} bind:formData bind:canSubmit {invoiceTotals} diff --git a/packages/create-invoice-form/src/lib/invoice/form-view.svelte b/packages/create-invoice-form/src/lib/invoice/form-view.svelte index 75959283..d3045d87 100644 --- a/packages/create-invoice-form/src/lib/invoice/form-view.svelte +++ b/packages/create-invoice-form/src/lib/invoice/form-view.svelte @@ -13,14 +13,16 @@ import { config as defaultConfig } from "@requestnetwork/shared-utils/config"; import { calculateItemTotal } from "@requestnetwork/shared-utils/invoiceTotals"; import { formatDate } from "@requestnetwork/shared-utils/formatDate"; + import { Types } from '@requestnetwork/request-client.js'; export let defaultCurrencies; export let config: IConfig; export let canSubmit = false; export let formData: CustomFormData; - export let currency = {}; + export let currency = defaultCurrencies.filter( + (currency: any) => currency.type !== Types.RequestLogic.CURRENCY.ISO4217 + )[0]; export let invoiceCurrency = {}; - export let network = ""; export let submitForm: (e: Event) => Promise; export let invoiceTotals = { amountWithoutTax: 0, @@ -166,7 +168,7 @@

Payment Chain - {network.toUpperCase() + network.slice(1)} + {currency.network[0].toUpperCase() + currency.network.slice(1)}

Invoice Currency diff --git a/packages/create-invoice-form/src/lib/utils/prepareRequest.ts b/packages/create-invoice-form/src/lib/utils/prepareRequest.ts index 879bcdb3..1524ef05 100644 --- a/packages/create-invoice-form/src/lib/utils/prepareRequest.ts +++ b/packages/create-invoice-form/src/lib/utils/prepareRequest.ts @@ -1,8 +1,10 @@ import { Types, Utils } from "@requestnetwork/request-client.js"; import type { CustomFormData } from "@requestnetwork/shared-types"; +import { get } from 'svelte/store' import { parseUnits, zeroAddress } from "viem"; interface IRequestParams { + invoiceCurrency: any; currency: any; formData: CustomFormData; invoiceTotals: { @@ -13,20 +15,73 @@ interface IRequestParams { signer: string; } +const getPaymentNetwork = (invoiceCurrency: any, currency: any, formData: CustomFormData) => { + if ( + invoiceCurrency.type === Types.RequestLogic.CURRENCY.ISO4217 && + currency.type === Types.RequestLogic.CURRENCY.ETH + ) { + return { + id: Types.Extension.PAYMENT_NETWORK_ID.ANY_TO_ETH_PROXY, + parameters: { + network: currency.network, + paymentAddress: formData.payeeAddress, + feeAddress: zeroAddress, + feeAmount: "0", + }, + }; + } else if ( + invoiceCurrency.type === Types.RequestLogic.CURRENCY.ISO4217 && + currency.type === Types.RequestLogic.CURRENCY.ERC20 + ) { + return { + id: Types.Extension.PAYMENT_NETWORK_ID.ANY_TO_ERC20_PROXY, + parameters: { + network: currency.network, + paymentAddress: formData.payeeAddress, + feeAddress: zeroAddress, + feeAmount: "0", + acceptedTokens: [currency.address], + }, + }; + } else if (currency.type === Types.RequestLogic.CURRENCY.ETH) { + return { + id: Types.Extension.PAYMENT_NETWORK_ID.ETH_FEE_PROXY_CONTRACT, + parameters: { + paymentNetworkName: currency.network, + paymentAddress: formData.payeeAddress, + feeAddress: zeroAddress, + feeAmount: "0", + }, + } + } else { + return { + id: Types.Extension.PAYMENT_NETWORK_ID.ERC20_FEE_PROXY_CONTRACT, + parameters: { + paymentNetworkName: currency.network, + paymentAddress: formData.payeeAddress, + feeAddress: zeroAddress, + feeAmount: "0", + }, + } + } +}; + export const prepareRequestParams = ({ signer, + invoiceCurrency, currency, formData, invoiceTotals, }: IRequestParams): Types.ICreateRequestParameters => { const isERC20 = currency.type === Types.RequestLogic.CURRENCY.ERC20; + const isERC20InvoiceCurrency = invoiceCurrency.type === Types.RequestLogic.CURRENCY.ERC20; return { requestInfo: { currency: { - type: currency.type, - value: isERC20 ? currency.address : "eth", - network: currency.network, + type: invoiceCurrency.type, + value: isERC20InvoiceCurrency ? invoiceCurrency.address : invoiceCurrency.symbol, + network: invoiceCurrency.network, }, expectedAmount: parseUnits( invoiceTotals.totalAmount.toString(), @@ -42,18 +97,8 @@ export const prepareRequestParams = ({ }, timestamp: Utils.getCurrentTimestampInSecond(), }, - paymentNetwork: { - id: - currency.type === Types.RequestLogic.CURRENCY.ETH - ? Types.Extension.PAYMENT_NETWORK_ID.ETH_FEE_PROXY_CONTRACT - : Types.Extension.PAYMENT_NETWORK_ID.ERC20_FEE_PROXY_CONTRACT, - parameters: { - paymentNetworkName: currency.network, - paymentAddress: formData.payeeAddress, - feeAddress: zeroAddress, - feeAmount: "0", - }, - }, + paymentNetwork: getPaymentNetwork(invoiceCurrency, currency, formData), + paymentCurrency: isERC20 ? currency.address : currency.symbol, contentData: { meta: { format: "rnf_invoice", @@ -71,17 +116,17 @@ export const prepareRequestParams = ({ quantity: Number(item.quantity), unitPrice: parseUnits( item.unitPrice.toString(), - currency.decimals + invoiceCurrency.decimals ).toString(), discount: parseUnits( item.discount.toString(), - currency.decimals + invoiceCurrency.decimals ).toString(), tax: { type: "percentage", amount: item.tax.amount.toString(), }, - currency: isERC20 ? currency.address : currency.symbol, + currency: isERC20InvoiceCurrency ? invoiceCurrency.address : invoiceCurrency.symbol, })), paymentTerms: { dueDate: new Date(formData.dueDate).toISOString(), diff --git a/packages/invoice-dashboard/src/lib/dashboard/invoice-view.svelte b/packages/invoice-dashboard/src/lib/dashboard/invoice-view.svelte index 510f2239..add257d5 100644 --- a/packages/invoice-dashboard/src/lib/dashboard/invoice-view.svelte +++ b/packages/invoice-dashboard/src/lib/dashboard/invoice-view.svelte @@ -2,7 +2,9 @@ import { getPaymentNetworkExtension } from "@requestnetwork/payment-detection"; import { approveErc20, + approveErc20ForProxyConversion, hasErc20Approval, + hasErc20ApprovalForProxyConversion, payRequest, } from "@requestnetwork/payment-processor"; import { @@ -38,6 +40,7 @@ let network = request?.currencyInfo?.network || "mainnet"; // FIXME: Use a non deprecated function let currency = getCurrencyFromManager(request.currencyInfo, currencyManager); + let paymentCurrencies: any = []; let statuses: any = []; let isPaid = false; let loading = false; @@ -53,6 +56,7 @@ let unsupportedNetwork = false; let correctChain = wallet?.chains[0].id === String(getNetworkIdFromNetworkName(network)); + let paymentNetworkExtension: any = null; const generateDetailParagraphs = (info: any) => { return [ @@ -110,6 +114,20 @@ ); signer = walletClientToSigner(wallet); requestData = singleRequest?.getData(); + paymentNetworkExtension = getPaymentNetworkExtension(requestData); + + if (paymentNetworkExtension?.id === Types.Extension.PAYMENT_NETWORK_ID.ANY_TO_ERC20_PROXY) { + paymentCurrencies = paymentNetworkExtension?.values?.acceptedTokens.map( + (token: any) => currencyManager.fromAddress(token, paymentNetworkExtension?.values?.network) + ); + } else if( paymentNetworkExtension?.id === Types.Extension.PAYMENT_NETWORK_ID.ANY_TO_ETH_PROXY) { + paymentCurrencies = [currencyManager.getNativeCurrency( + Types.RequestLogic.CURRENCY.ETH, + paymentNetworkExtension?.values?.network + )]; + } else { + paymentCurrencies = [currency]; + } if (requestData.currencyInfo.type === Types.RequestLogic.CURRENCY.ERC20) { approved = await checkApproval(requestData, signer); @@ -119,6 +137,7 @@ isPaid = requestData?.balance?.balance! >= requestData?.expectedAmount; loading = false; } catch (err: any) { + console.log("Error while checking invoice: ", err); loading = false; if (String(err).includes("Unsupported payment")) { unsupportedNetwork = true; @@ -157,7 +176,17 @@ }; const checkApproval = async (requestData: any, signer: any) => { - return await hasErc20Approval(requestData!, address!, signer); + if ( + paymentNetworkExtension?.id === + Types.Extension.PAYMENT_NETWORK_ID.ERC20_FEE_PROXY_CONTRACT + ) { + return await hasErc20Approval(requestData!, address!, signer) + } else if(paymentNetworkExtension?.id === + Types.Extension.PAYMENT_NETWORK_ID.ANY_TO_ERC20_PROXY) { + return await hasErc20ApprovalForProxyConversion(requestData!, address!, requestData.currencyInfo.value, signer, requestData.expectedAmount); + } + + return false; }; async function approve() { @@ -165,12 +194,17 @@ loading = true; if ( - getPaymentNetworkExtension(requestData!)?.id === + paymentNetworkExtension?.id === Types.Extension.PAYMENT_NETWORK_ID.ERC20_FEE_PROXY_CONTRACT ) { const approvalTx = await approveErc20(requestData!, signer); await approvalTx.wait(2); approved = true; + } else if(paymentNetworkExtension?.id === + Types.Extension.PAYMENT_NETWORK_ID.ANY_TO_ERC20_PROXY) { + const approvalTx = await approveErc20ForProxyConversion(requestData!, requestData.currencyInfo.value, signer); + await approvalTx.wait(2); + approved = true; } loading = false; } catch (err) { @@ -291,13 +325,18 @@

Payment Chain: - {currency?.network || "-"} + {paymentCurrencies[0]?.network || "-"}

Invoice Currency: {currency?.symbol || "-"}

+

+ Currency: + {paymentCurrencies[0]?.symbol || "-"} +

+ {#if request?.contentData?.invoiceItems}
diff --git a/packages/invoice-dashboard/src/lib/view-requests.svelte b/packages/invoice-dashboard/src/lib/view-requests.svelte index bb5e9ef5..4c1896e7 100644 --- a/packages/invoice-dashboard/src/lib/view-requests.svelte +++ b/packages/invoice-dashboard/src/lib/view-requests.svelte @@ -34,6 +34,7 @@ import { capitalize, debounce, exportToPDF, formatAddress } from "../utils"; import { getCurrencyFromManager } from "../utils/getCurrency"; import { Drawer, InvoiceView } from "./dashboard"; + import { getPaymentNetworkExtension } from '@requestnetwork/payment-detection'; export let config: IConfig; export let wallet: WalletState; @@ -225,13 +226,28 @@ currencyManager ); + let paymentCurrencies = [currencyInfo] + + const paymentNetworkExtension = getPaymentNetworkExtension(request); + + if (paymentNetworkExtension?.id === Types.Extension.PAYMENT_NETWORK_ID.ANY_TO_ERC20_PROXY) { + paymentCurrencies = paymentNetworkExtension?.values?.acceptedTokens.map( + (token: any) => currencyManager.fromAddress(token, paymentNetworkExtension?.values?.network) + ); + } else if( paymentNetworkExtension?.id === Types.Extension.PAYMENT_NETWORK_ID.ANY_TO_ETH_PROXY) { + paymentCurrencies = [currencyManager.getNativeCurrency( + Types.RequestLogic.CURRENCY.ETH, + paymentNetworkExtension?.values?.network + )]; + } + return { ...request, formattedAmount: formatUnits( BigInt(request.expectedAmount), - currencyInfo?.decimals ?? 18 + paymentCurrencies[0]?.decimals ?? 18 ), - currencySymbol: currencyInfo!.symbol, + currencySymbol: paymentCurrencies[0]?.symbol!, }; } ); diff --git a/packages/invoice-dashboard/src/utils/getCurrency.ts b/packages/invoice-dashboard/src/utils/getCurrency.ts index b8c0332a..0c317dbe 100644 --- a/packages/invoice-dashboard/src/utils/getCurrency.ts +++ b/packages/invoice-dashboard/src/utils/getCurrency.ts @@ -8,7 +8,7 @@ export const getCurrencyFromManager = ( const currencyResult = currency.type === Types.RequestLogic.CURRENCY.ETH ? currencyManager.getNativeCurrency(currency.type, currency.network!) - : currencyManager.fromAddress(currency.value, currency.network); + : currency.type === Types.RequestLogic.CURRENCY.ISO4217 ? currencyManager.fromSymbol(currency.value, currency.network): currencyManager.fromAddress(currency.value, currency.network); return currencyResult; }; From 160fefa427b63fbe619ea974ce5c708a2007a17d Mon Sep 17 00:00:00 2001 From: rodrigopavezi Date: Thu, 26 Sep 2024 09:54:26 -0300 Subject: [PATCH 03/53] feat: add payments and other fixes --- .../src/lib/create-invoice-form.svelte | 29 ++-- .../src/lib/invoice/form-view.svelte | 17 +- .../src/lib/invoice/form.svelte | 25 ++- .../src/lib/utils/prepareRequest.ts | 2 +- .../src/lib/dashboard/invoice-view.svelte | 37 ++++- .../src/lib/view-requests.svelte | 15 +- .../invoice-dashboard/src/utils/chainlink.ts | 35 ++++ .../invoice-dashboard/src/utils/conversion.ts | 49 ++++++ .../src/utils/generateInvoice.ts | 4 +- .../src/utils/getConversionPaymentValues.ts | 150 ++++++++++++++++++ shared/utils/initCurrencyManager.ts | 2 +- 11 files changed, 319 insertions(+), 46 deletions(-) create mode 100644 packages/invoice-dashboard/src/utils/chainlink.ts create mode 100644 packages/invoice-dashboard/src/utils/conversion.ts create mode 100644 packages/invoice-dashboard/src/utils/getConversionPaymentValues.ts diff --git a/packages/create-invoice-form/src/lib/create-invoice-form.svelte b/packages/create-invoice-form/src/lib/create-invoice-form.svelte index 9583e83a..ea967b2f 100644 --- a/packages/create-invoice-form/src/lib/create-invoice-form.svelte +++ b/packages/create-invoice-form/src/lib/create-invoice-form.svelte @@ -45,19 +45,19 @@ let networks: (string | undefined)[] = extractUniqueNetworkNames(); - let network = networks[0]; + let network: any = undefined; + let currency: any = undefined; + let invoiceCurrency: any = undefined; - const handleNetworkChange = (network: string) => { - if (network) { + const handleNetworkChange = (newNetwork: string) => { + if (newNetwork) { const newCurrencies = currencyManager.knownCurrencies.filter( - (currency: any) => currency.type === Types.RequestLogic.CURRENCY.ISO4217 || currency.network === network + (currency: any) => currency.type === Types.RequestLogic.CURRENCY.ISO4217 || currency.network === newNetwork ); - network = network; + network = newNetwork; defaultCurrencies = newCurrencies; - currency = newCurrencies.filter( - (currency: any) => currency.type !== Types.RequestLogic.CURRENCY.ISO4217 - )[0]; + currency = undefined; } }; @@ -69,14 +69,11 @@ (currency: any) => currency.type === Types.RequestLogic.CURRENCY.ISO4217 || currency.network === network ); - let currency = defaultCurrencies.filter( - (currency: any) => currency.type !== Types.RequestLogic.CURRENCY.ISO4217 - )[0]; - let invoiceCurrency = defaultCurrencies[0]; - const handleInvoiceCurrencyChange = (value: string) => { invoiceCurrency = value; - + network = undefined; + currency = undefined; + if (invoiceCurrency.type === Types.RequestLogic.CURRENCY.ISO4217) { networks = getCurrencySupportedNetworksForConversion(invoiceCurrency.hash, currencyManager); @@ -198,6 +195,10 @@ {handleCurrencyChange} {handleNetworkChange} {networks} + {currencyManager} + {invoiceCurrency} + {currency} + {network} />
currency.type !== Types.RequestLogic.CURRENCY.ISO4217 - )[0]; - export let invoiceCurrency = {}; + export let currency: any; + export let invoiceCurrency: any; export let submitForm: (e: Event) => Promise; export let invoiceTotals = { amountWithoutTax: 0, @@ -168,16 +166,15 @@

Payment Chain - {currency.network[0].toUpperCase() + currency.network.slice(1)} + {currency? currency?.network[0]?.toUpperCase() + currency?.network?.slice(1): ""}

Invoice Currency - {invoiceCurrency.symbol} + {invoiceCurrency ? invoiceCurrency?.symbol: ""}

- Currency - {currency.symbol} - ({currency.network}) + Settlement Currency + {currency? `${currency?.symbol} (${currency?.network})` : ""}

Invoice Type @@ -229,7 +226,7 @@ > Due: {currency.symbol} + >{currency? currency?.symbol : ""} {" "} {invoiceTotals.totalAmount.toFixed(2)} diff --git a/packages/create-invoice-form/src/lib/invoice/form.svelte b/packages/create-invoice-form/src/lib/invoice/form.svelte index 4b5f5383..14eb337e 100644 --- a/packages/create-invoice-form/src/lib/invoice/form.svelte +++ b/packages/create-invoice-form/src/lib/invoice/form.svelte @@ -30,6 +30,10 @@ export let defaultCurrencies: any = []; export let payeeAddressError = false; export let clientAddressError = false; + export let currencyManager: any; + export let invoiceCurrency: any; + export let currency: any; + export let network: any; let creatorId = ""; @@ -98,6 +102,14 @@ } }; + const filterSettlementCurrencies = (currency: any) => { + return invoiceCurrency? ( + invoiceCurrency.type === Types.RequestLogic.CURRENCY.ISO4217 ? + currency.type !== Types.RequestLogic.CURRENCY.ISO4217 && currencyManager?.getConversionPath(invoiceCurrency, currency, currency.network)?.length > 0 : + invoiceCurrency.hash === currency.hash + ) : false; + }; + const addInvoiceItem = () => { const newItem = { description: "", @@ -311,6 +323,7 @@ ({ value: currency, @@ -321,19 +334,21 @@ { + selectedValue={network} + options={networks.map((networkItem) => { return { - value: network, - label: network[0].toUpperCase() + network.slice(1), + value: networkItem, + label: networkItem[0]?.toUpperCase() + networkItem?.slice(1), }; })} onchange={handleNetworkChange} /> currency.type !== Types.RequestLogic.CURRENCY.ISO4217 + (currency) => filterSettlementCurrencies(currency) ).map((currency) => ({ value: currency, label: `${currency.symbol} (${currency?.network})`, diff --git a/packages/create-invoice-form/src/lib/utils/prepareRequest.ts b/packages/create-invoice-form/src/lib/utils/prepareRequest.ts index 1524ef05..8fc79c6e 100644 --- a/packages/create-invoice-form/src/lib/utils/prepareRequest.ts +++ b/packages/create-invoice-form/src/lib/utils/prepareRequest.ts @@ -85,7 +85,7 @@ export const prepareRequestParams = ({ }, expectedAmount: parseUnits( invoiceTotals.totalAmount.toString(), - currency.decimals + invoiceCurrency.decimals ).toString(), payee: { type: Types.Identity.TYPE.ETHEREUM_ADDRESS, diff --git a/packages/invoice-dashboard/src/lib/dashboard/invoice-view.svelte b/packages/invoice-dashboard/src/lib/dashboard/invoice-view.svelte index add257d5..2f1eeeb2 100644 --- a/packages/invoice-dashboard/src/lib/dashboard/invoice-view.svelte +++ b/packages/invoice-dashboard/src/lib/dashboard/invoice-view.svelte @@ -29,6 +29,7 @@ import { formatUnits } from "viem"; import { exportToPDF, walletClientToSigner } from "../../utils"; import { getCurrencyFromManager } from "../../utils/getCurrency"; + import { getConversionPaymentValues } from '../../utils/getConversionPaymentValues'; export let config; export let wallet: WalletState | undefined; @@ -129,8 +130,10 @@ paymentCurrencies = [currency]; } - if (requestData.currencyInfo.type === Types.RequestLogic.CURRENCY.ERC20) { - approved = await checkApproval(requestData, signer); + network = paymentCurrencies[0]?.network || "mainnet"; + + if (paymentCurrencies[0].type === Types.RequestLogic.CURRENCY.ERC20) { + approved = await checkApproval(requestData, paymentCurrencies, signer); } else { approved = true; } @@ -154,7 +157,25 @@ ); statuses = [...statuses, "Waiting for payment"]; - const paymentTx = await payRequest(requestData, signer); + + let paymentSettings = undefined; + if ( + paymentNetworkExtension?.id === + Types.Extension.PAYMENT_NETWORK_ID.ANY_TO_ERC20_PROXY || paymentNetworkExtension?.id === + Types.Extension.PAYMENT_NETWORK_ID.ANY_TO_ETH_PROXY + ) { + const { conversion } = await getConversionPaymentValues({ + baseAmount: requestData?.expectedAmount, + denominationCurrency: currency!, + selectedPaymentCurrency: paymentCurrencies[0]!, + currencyManager, + provider: signer, + fromAddress: address, + }); + paymentSettings = conversion; + } + + const paymentTx = await payRequest(requestData, signer, undefined, undefined, paymentSettings); await paymentTx.wait(2); statuses = [...statuses, "Payment detected"]; @@ -175,7 +196,7 @@ } }; - const checkApproval = async (requestData: any, signer: any) => { + const checkApproval = async (requestData: any, paymentCurrencies: any[], signer: any) => { if ( paymentNetworkExtension?.id === Types.Extension.PAYMENT_NETWORK_ID.ERC20_FEE_PROXY_CONTRACT @@ -183,7 +204,7 @@ return await hasErc20Approval(requestData!, address!, signer) } else if(paymentNetworkExtension?.id === Types.Extension.PAYMENT_NETWORK_ID.ANY_TO_ERC20_PROXY) { - return await hasErc20ApprovalForProxyConversion(requestData!, address!, requestData.currencyInfo.value, signer, requestData.expectedAmount); + return await hasErc20ApprovalForProxyConversion(requestData!, address!, paymentCurrencies[0].address, signer, requestData.expectedAmount); } return false; @@ -202,7 +223,7 @@ approved = true; } else if(paymentNetworkExtension?.id === Types.Extension.PAYMENT_NETWORK_ID.ANY_TO_ERC20_PROXY) { - const approvalTx = await approveErc20ForProxyConversion(requestData!, requestData.currencyInfo.value, signer); + const approvalTx = await approveErc20ForProxyConversion(requestData!, paymentCurrencies[0].address, signer); await approvalTx.wait(2); approved = true; } @@ -278,7 +299,7 @@ { try { - await exportToPDF(request, currency, config.logo); + await exportToPDF(request, currency, paymentCurrencies, config.logo); } catch (error) { toast.error(`Failed to export PDF`, { description: `${error}`, @@ -333,7 +354,7 @@

- Currency: + Settlement Currency: {paymentCurrencies[0]?.symbol || "-"}

diff --git a/packages/invoice-dashboard/src/lib/view-requests.svelte b/packages/invoice-dashboard/src/lib/view-requests.svelte index 4c1896e7..66799b30 100644 --- a/packages/invoice-dashboard/src/lib/view-requests.svelte +++ b/packages/invoice-dashboard/src/lib/view-requests.svelte @@ -220,34 +220,36 @@ ): Types.IRequestDataWithEvents & { formattedAmount: string; currencySymbol: string; + paymentCurrencies: any[]; } => { const currencyInfo = getCurrencyFromManager( request.currencyInfo, currencyManager ); - let paymentCurrencies = [currencyInfo] + let paymentNetworkExtension = getPaymentNetworkExtension(request); + let paymentCurrencies = [currencyInfo]; - const paymentNetworkExtension = getPaymentNetworkExtension(request); - if (paymentNetworkExtension?.id === Types.Extension.PAYMENT_NETWORK_ID.ANY_TO_ERC20_PROXY) { paymentCurrencies = paymentNetworkExtension?.values?.acceptedTokens.map( (token: any) => currencyManager.fromAddress(token, paymentNetworkExtension?.values?.network) ); } else if( paymentNetworkExtension?.id === Types.Extension.PAYMENT_NETWORK_ID.ANY_TO_ETH_PROXY) { paymentCurrencies = [currencyManager.getNativeCurrency( - Types.RequestLogic.CURRENCY.ETH, + Types.RequestLogic.CURRENCY.ETH, paymentNetworkExtension?.values?.network )]; } + return { ...request, formattedAmount: formatUnits( BigInt(request.expectedAmount), - paymentCurrencies[0]?.decimals ?? 18 + currencyInfo?.decimals ?? 18 ), - currencySymbol: paymentCurrencies[0]?.symbol!, + currencySymbol: currencyInfo!.symbol, + paymentCurrencies, }; } ); @@ -559,6 +561,7 @@ request.currencyInfo, currencyManager ), + request.paymentCurrencies, config.logo ); } catch (error) { diff --git a/packages/invoice-dashboard/src/utils/chainlink.ts b/packages/invoice-dashboard/src/utils/chainlink.ts new file mode 100644 index 00000000..562b2c94 --- /dev/null +++ b/packages/invoice-dashboard/src/utils/chainlink.ts @@ -0,0 +1,35 @@ +import { isISO4217Currency } from "@requestnetwork/currency"; +import { chainlinkConversionPath } from "@requestnetwork/smart-contracts"; +import { CurrencyTypes } from "@requestnetwork/types"; +import { BigNumber, providers } from "ethers"; + +export const getChainlinkRate = async ( + from: CurrencyTypes.CurrencyDefinition, + to: CurrencyTypes.CurrencyDefinition, + { + network, + provider, + currencyManager, + }: { + network: CurrencyTypes.EvmChainName; + provider: providers.Provider; + currencyManager: CurrencyTypes.ICurrencyManager; + }, +) => { + const chainlink = chainlinkConversionPath.connect(network, provider); + const path = currencyManager.getConversionPath(from, to, network); + if (!path) return null; + const result = await chainlink.getRate(path); + if (!result) return null; + + // ChainlinkConversionPath uses 8 decimals for fiat. + const fromDecimals = isISO4217Currency(from) ? 8 : from.decimals; + const toDecimals = isISO4217Currency(to) ? 8 : to.decimals; + const value = result.rate + .mul(BigNumber.from(10).pow(fromDecimals)) + .div(BigNumber.from(10).pow(toDecimals)); + return { + value, + decimals: result.decimals.toString().length - 1, + }; +}; diff --git a/packages/invoice-dashboard/src/utils/conversion.ts b/packages/invoice-dashboard/src/utils/conversion.ts new file mode 100644 index 00000000..94280f3e --- /dev/null +++ b/packages/invoice-dashboard/src/utils/conversion.ts @@ -0,0 +1,49 @@ +import { isISO4217Currency } from "@requestnetwork/currency"; +import { CurrencyTypes } from "@requestnetwork/types"; +import { EvmChainName } from "@requestnetwork/types/dist/currency-types"; +import { providers, utils } from "ethers"; +import { getChainlinkRate } from './chainlink' + +/** + * Maximum slippage (swap) or conversion evolution (conversion pn) + */ +const MAX_SLIPPAGE_DEFAULT = 1.03; +const MAX_SLIPPAGE_LOW_VOLATILITY = 1.01; +export const lowVolatilityTokens = ["DAI", "USDC", "USDT"]; + +export const getSlippageMargin = (currency: any) => { + return lowVolatilityTokens.includes(currency.symbol) + ? MAX_SLIPPAGE_LOW_VOLATILITY + : MAX_SLIPPAGE_DEFAULT; +}; + +/** + * Get the conversion rate between two currencies. + */ +export const getConversionRate = async ({ + from, + to, + currencyManager, + provider, +}: { + from: CurrencyTypes.CurrencyDefinition; + to: CurrencyTypes.CurrencyDefinition; + currencyManager?: CurrencyTypes.ICurrencyManager; + provider?: providers.Provider; +}) => { + if (!isISO4217Currency(to) && currencyManager && provider) { + const network = to.network as EvmChainName; + try { + const chainlinkRate = await getChainlinkRate(from, to, { + network, + currencyManager, + provider, + }); + if (chainlinkRate) { + return Number(utils.formatUnits(chainlinkRate.value, chainlinkRate.decimals)) + } + } catch (e) { + console.error("Error getting chainlink rate", e); + } + } +}; diff --git a/packages/invoice-dashboard/src/utils/generateInvoice.ts b/packages/invoice-dashboard/src/utils/generateInvoice.ts index 18f61d0f..7c3faf62 100644 --- a/packages/invoice-dashboard/src/utils/generateInvoice.ts +++ b/packages/invoice-dashboard/src/utils/generateInvoice.ts @@ -19,6 +19,7 @@ async function ensureHtml2PdfLoaded() { export const exportToPDF = async ( invoice: any, currency: any, + paymentCurrencies: any[], logo: string ) => { await ensureHtml2PdfLoaded(); @@ -80,8 +81,9 @@ export const exportToPDF = async (
- Payment Chain: ${invoice.currencyInfo?.network || "-"}
+ Payment Chain: ${paymentCurrencies[0]?.network || "-"}
Invoice Currency: ${invoice.currency || "-"}
+ Settlement Currency: ${paymentCurrencies[0]?.symbol || "-"}
Invoice Type: Regular Invoice
diff --git a/packages/invoice-dashboard/src/utils/getConversionPaymentValues.ts b/packages/invoice-dashboard/src/utils/getConversionPaymentValues.ts new file mode 100644 index 00000000..318fcb99 --- /dev/null +++ b/packages/invoice-dashboard/src/utils/getConversionPaymentValues.ts @@ -0,0 +1,150 @@ +import { CurrencyManager } from "@requestnetwork/currency"; +import { CurrencyTypes } from "@requestnetwork/types"; +import { getAnyErc20Balance } from "@requestnetwork/payment-processor"; +import { BigNumber, BigNumberish, providers, utils } from "ethers"; + +import { getConversionRate, getSlippageMargin } from './conversion' + +export type SlippageLevel = "safe" | "risky"; + +export const formatUnits = ( + amount: BigNumber, + token: CurrencyTypes.CurrencyDefinition, +): string => { + return utils.formatUnits(amount, token.decimals); +}; + +export const toFixedDecimal = (numberToFormat: number, decimals?: number) => { + const MAX_DECIMALS = decimals !== undefined ? decimals : 5; + return Number(numberToFormat.toFixed(MAX_DECIMALS)); +}; + +export const amountToFixedDecimal = ( + amount: BigNumberish, + currency: CurrencyTypes.CurrencyDefinition, + decimals?: number, +) => { + return toFixedDecimal( + parseFloat(formatUnits(BigNumber.from(amount), currency)), + decimals, + ); +}; + +/** + * Converts a number, even floating, to a BigNumber + * @param amount Number to convert, may float + * @param token Token + */ +export const bigAmountify = ( + amount: number, + token: Pick, +): BigNumber => { + let [whole, decimals] = amount.toString().split("."); + let pow = "0"; + let powSign = true; + + if (decimals && decimals.includes("e")) { + powSign = !decimals.includes("e-"); + [decimals, pow] = powSign ? decimals.split("e") : decimals.split("e-"); + whole = whole; + } + + const wholeBn = utils.parseUnits(whole, token.decimals); + const power = BigNumber.from(10).pow(pow); + + if (decimals) { + const decimalsBn = utils + .parseUnits(decimals, token.decimals) + .div(BigNumber.from(10).pow(decimals.length)); + return powSign + ? wholeBn.add(decimalsBn).mul(power) + : wholeBn.add(decimalsBn).div(power); + } + return wholeBn; +}; + +/** + * Utility method to compute various settings associated to a payment involving conversion only + */ +export const getConversionPaymentValues = async ({ + baseAmount, + denominationCurrency, + selectedPaymentCurrency, + currencyManager, + provider, + fromAddress, +}: { + baseAmount: number; + denominationCurrency: CurrencyTypes.CurrencyDefinition; + selectedPaymentCurrency: CurrencyTypes.CurrencyDefinition; + currencyManager: CurrencyManager; + provider?: providers.Provider; + fromAddress?: string; +}): Promise => { + const conversionRate = await getConversionRate({ + from: denominationCurrency, + to: selectedPaymentCurrency, + currencyManager, + provider, + }); + + const minConversionAmount = bigAmountify( + baseAmount * Number(conversionRate), + selectedPaymentCurrency, + ); + + const safeConversionAmount = bigAmountify( + baseAmount * Number(conversionRate) * getSlippageMargin(selectedPaymentCurrency), + selectedPaymentCurrency, + ); + + const userBalance = BigNumber.from( + fromAddress && + provider && + "address" in selectedPaymentCurrency && + selectedPaymentCurrency.address + ? await getAnyErc20Balance( + selectedPaymentCurrency.address, + fromAddress, + provider, + ) + : safeConversionAmount, + ); + + const hasEnoughForSlippage = userBalance.gte(safeConversionAmount); + const hasEnough = userBalance.gte(minConversionAmount); + const isRisky = hasEnough && !hasEnoughForSlippage; + const slippageLevel = isRisky ? "risky" : ("safe" as SlippageLevel); + const conversionAmount = isRisky ? userBalance : safeConversionAmount; + + const conversion = { + currency: CurrencyManager.toStorageCurrency(selectedPaymentCurrency), + maxToSpend: conversionAmount.toString(), + currencyManager, + }; + + const totalAmountInPaymentCurrency = { + value: amountToFixedDecimal( + minConversionAmount, + selectedPaymentCurrency, + 4, + ), + currency: selectedPaymentCurrency, + }; + const safeBalance = { + value: amountToFixedDecimal( + safeConversionAmount, + selectedPaymentCurrency, + 4, + ), + currency: selectedPaymentCurrency, + }; + + return { + conversion, + slippageLevel, + totalAmountInPaymentCurrency, + safeBalance, + rate: conversionRate, + }; +}; diff --git a/shared/utils/initCurrencyManager.ts b/shared/utils/initCurrencyManager.ts index 1c6f7384..e315729c 100644 --- a/shared/utils/initCurrencyManager.ts +++ b/shared/utils/initCurrencyManager.ts @@ -118,4 +118,4 @@ export const getCurrencySupportedNetworksForConversion = (currencyHash: string, return network; } }).filter((network) => network); -} \ No newline at end of file +} \ No newline at end of file From 4257ed6980b40a1d9da692995470414bcbbdbca8 Mon Sep 17 00:00:00 2001 From: Rodrigo Serviuc Pavezi Date: Thu, 26 Sep 2024 13:22:32 -0300 Subject: [PATCH 04/53] Update shared/utils/currencyConversionPairs.ts Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> --- shared/utils/currencyConversionPairs.ts | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/shared/utils/currencyConversionPairs.ts b/shared/utils/currencyConversionPairs.ts index bb9f61d8..0b4ba9d6 100644 --- a/shared/utils/currencyConversionPairs.ts +++ b/shared/utils/currencyConversionPairs.ts @@ -1173,8 +1173,17 @@ export const currencyConversionPairs = { export const convertToCurrencyManagerFormat = (currencyConversionPair) => { return currencyConversionPair.reduce( (a, v) => ({ - ...a, - [v.input]: v.outputs.reduce((a, v) => ({ ...a, [v]: 1 }), {}), +export const convertToCurrencyManagerFormat = (currencyConversionPair) => { + const result = {}; + for (const pair of currencyConversionPair) { + const outputs = {}; + for (const output of pair.outputs) { + outputs[output] = 1; + } + result[pair.input] = outputs; + } + return result; +}; }), {}, ); From d119054f358fc7bd5f6195f5239ec71716c978b5 Mon Sep 17 00:00:00 2001 From: rodrigopavezi Date: Thu, 26 Sep 2024 13:34:46 -0300 Subject: [PATCH 05/53] fix: typings --- .../src/lib/create-invoice-form.svelte | 15 ++++---- .../src/lib/invoice/form-view.svelte | 8 ++--- .../src/lib/invoice/form.svelte | 7 ++-- .../src/lib/utils/prepareRequest.ts | 8 ++--- .../src/lib/dashboard/invoice-view.svelte | 17 +++++----- .../src/lib/react/InvoiceDashboard.d.ts | 5 ++- .../invoice-dashboard/src/lib/types/index.ts | 1 + .../src/lib/view-requests.svelte | 13 ++++--- .../invoice-dashboard/src/utils/chainlink.ts | 34 +++++++++++-------- .../invoice-dashboard/src/utils/conversion.ts | 2 +- .../src/utils/generateInvoice.ts | 5 +-- shared/utils/currencyConversionPairs.ts | 11 ++---- 12 files changed, 65 insertions(+), 61 deletions(-) diff --git a/packages/create-invoice-form/src/lib/create-invoice-form.svelte b/packages/create-invoice-form/src/lib/create-invoice-form.svelte index ea967b2f..890c663c 100644 --- a/packages/create-invoice-form/src/lib/create-invoice-form.svelte +++ b/packages/create-invoice-form/src/lib/create-invoice-form.svelte @@ -19,6 +19,7 @@ import { getInitialFormData, prepareRequestParams } from "./utils"; import type { RequestNetwork } from "@requestnetwork/request-client.js"; import { Types } from "@requestnetwork/request-client.js"; + import { CurrencyTypes } from "@requestnetwork/types"; export let config: IConfig; export let signer: string = ""; @@ -34,7 +35,7 @@ const extractUniqueNetworkNames = (): string[] => { const networkSet = new Set(); - currencyManager.knownCurrencies.forEach((currency: any) => { + currencyManager.knownCurrencies.forEach((currency: CurrencyTypes.CurrencyDefinition) => { if(currency.network) { networkSet.add(currency.network); } @@ -46,13 +47,13 @@ let networks: (string | undefined)[] = extractUniqueNetworkNames(); let network: any = undefined; - let currency: any = undefined; - let invoiceCurrency: any = undefined; + let currency: CurrencyTypes.CurrencyDefinition | undefined = undefined; + let invoiceCurrency: CurrencyTypes.CurrencyDefinition | undefined = undefined; const handleNetworkChange = (newNetwork: string) => { if (newNetwork) { const newCurrencies = currencyManager.knownCurrencies.filter( - (currency: any) => currency.type === Types.RequestLogic.CURRENCY.ISO4217 || currency.network === newNetwork + (currency: CurrencyTypes.CurrencyDefinition) => currency.type === Types.RequestLogic.CURRENCY.ISO4217 || currency.network === newNetwork ); network = newNetwork; @@ -66,10 +67,10 @@ let appStatus: APP_STATUS[] = []; let formData = getInitialFormData(); let defaultCurrencies = currencyManager.knownCurrencies.filter( - (currency: any) => currency.type === Types.RequestLogic.CURRENCY.ISO4217 || currency.network === network + (currency: CurrencyTypes.CurrencyDefinition) => currency.type === Types.RequestLogic.CURRENCY.ISO4217 || currency.network === network ); - const handleInvoiceCurrencyChange = (value: string) => { + const handleInvoiceCurrencyChange = (value: CurrencyTypes.CurrencyDefinition) => { invoiceCurrency = value; network = undefined; currency = undefined; @@ -82,7 +83,7 @@ } }; - const handleCurrencyChange = (value: string) => { + const handleCurrencyChange = (value: CurrencyTypes.CurrencyDefinition) => { currency = value; }; diff --git a/packages/create-invoice-form/src/lib/invoice/form-view.svelte b/packages/create-invoice-form/src/lib/invoice/form-view.svelte index c1be6fcb..b8164b9d 100644 --- a/packages/create-invoice-form/src/lib/invoice/form-view.svelte +++ b/packages/create-invoice-form/src/lib/invoice/form-view.svelte @@ -8,19 +8,19 @@ // Types import type { IConfig, CustomFormData } from "@requestnetwork/shared-types"; + import { CurrencyTypes } from "@requestnetwork/types"; // Utils import { config as defaultConfig } from "@requestnetwork/shared-utils/config"; import { calculateItemTotal } from "@requestnetwork/shared-utils/invoiceTotals"; import { formatDate } from "@requestnetwork/shared-utils/formatDate"; - import { Types } from '@requestnetwork/request-client.js'; export let defaultCurrencies; export let config: IConfig; export let canSubmit = false; export let formData: CustomFormData; - export let currency: any; - export let invoiceCurrency: any; + export let currency: CurrencyTypes.CurrencyDefinition | undefined; + export let invoiceCurrency: CurrencyTypes.CurrencyDefinition | undefined; export let submitForm: (e: Event) => Promise; export let invoiceTotals = { amountWithoutTax: 0, @@ -166,7 +166,7 @@

Payment Chain - {currency? currency?.network[0]?.toUpperCase() + currency?.network?.slice(1): ""} + {currency?.network ? currency.network.charAt(0).toUpperCase() + currency.network.slice(1).toLowerCase() : ""}

Invoice Currency diff --git a/packages/create-invoice-form/src/lib/invoice/form.svelte b/packages/create-invoice-form/src/lib/invoice/form.svelte index 14eb337e..5a668de4 100644 --- a/packages/create-invoice-form/src/lib/invoice/form.svelte +++ b/packages/create-invoice-form/src/lib/invoice/form.svelte @@ -18,6 +18,7 @@ import { checkAddress } from "@requestnetwork/shared-utils/checkEthAddress"; import { inputDateFormat } from "@requestnetwork/shared-utils/formatDate"; import { Types } from '@requestnetwork/request-client.js'; + import { CurrencyTypes } from "@requestnetwork/types"; export let config: IConfig; export const invoiceNumber: number = 1; @@ -31,8 +32,8 @@ export let payeeAddressError = false; export let clientAddressError = false; export let currencyManager: any; - export let invoiceCurrency: any; - export let currency: any; + export let invoiceCurrency: CurrencyTypes.CurrencyDefinition | undefined; + export let currency: CurrencyTypes.CurrencyDefinition | undefined; export let network: any; let creatorId = ""; @@ -102,7 +103,7 @@ } }; - const filterSettlementCurrencies = (currency: any) => { + const filterSettlementCurrencies = (currency: CurrencyTypes.CurrencyDefinition) => { return invoiceCurrency? ( invoiceCurrency.type === Types.RequestLogic.CURRENCY.ISO4217 ? currency.type !== Types.RequestLogic.CURRENCY.ISO4217 && currencyManager?.getConversionPath(invoiceCurrency, currency, currency.network)?.length > 0 : diff --git a/packages/create-invoice-form/src/lib/utils/prepareRequest.ts b/packages/create-invoice-form/src/lib/utils/prepareRequest.ts index 8fc79c6e..eb741f1b 100644 --- a/packages/create-invoice-form/src/lib/utils/prepareRequest.ts +++ b/packages/create-invoice-form/src/lib/utils/prepareRequest.ts @@ -1,11 +1,11 @@ import { Types, Utils } from "@requestnetwork/request-client.js"; import type { CustomFormData } from "@requestnetwork/shared-types"; -import { get } from 'svelte/store' import { parseUnits, zeroAddress } from "viem"; +import { CurrencyTypes } from "@requestnetwork/types"; interface IRequestParams { - invoiceCurrency: any; - currency: any; + invoiceCurrency: CurrencyTypes.CurrencyDefinition; + currency: CurrencyTypes.CurrencyDefinition; formData: CustomFormData; invoiceTotals: { amountWithoutTax: number; @@ -15,7 +15,7 @@ interface IRequestParams { signer: string; } -const getPaymentNetwork = (invoiceCurrency: any, currency: any, formData: CustomFormData) => { +const getPaymentNetwork = (invoiceCurrency: CurrencyTypes.CurrencyDefinition, currency: CurrencyTypes.CurrencyDefinition, formData: CustomFormData) => { if ( invoiceCurrency.type === Types.RequestLogic.CURRENCY.ISO4217 && currency.type === Types.RequestLogic.CURRENCY.ETH diff --git a/packages/invoice-dashboard/src/lib/dashboard/invoice-view.svelte b/packages/invoice-dashboard/src/lib/dashboard/invoice-view.svelte index 2f1eeeb2..23c098e2 100644 --- a/packages/invoice-dashboard/src/lib/dashboard/invoice-view.svelte +++ b/packages/invoice-dashboard/src/lib/dashboard/invoice-view.svelte @@ -11,6 +11,7 @@ Types, type RequestNetwork, } from "@requestnetwork/request-client.js"; + import { CurrencyTypes } from "@requestnetwork/types"; import { toast } from "svelte-sonner"; // Components import Accordion from "@requestnetwork/shared-components/accordion.svelte"; @@ -38,10 +39,10 @@ export let currencyManager: any; export let isRequestPayed: boolean; - let network = request?.currencyInfo?.network || "mainnet"; + let network: string | undefined = request?.currencyInfo?.network || "mainnet"; // FIXME: Use a non deprecated function - let currency = getCurrencyFromManager(request.currencyInfo, currencyManager); - let paymentCurrencies: any = []; + let currency: CurrencyTypes.CurrencyDefinition | undefined = getCurrencyFromManager(request.currencyInfo, currencyManager); + let paymentCurrencies: (CurrencyTypes.CurrencyDefinition | undefined)[] = []; let statuses: any = []; let isPaid = false; let loading = false; @@ -118,7 +119,7 @@ paymentNetworkExtension = getPaymentNetworkExtension(requestData); if (paymentNetworkExtension?.id === Types.Extension.PAYMENT_NETWORK_ID.ANY_TO_ERC20_PROXY) { - paymentCurrencies = paymentNetworkExtension?.values?.acceptedTokens.map( + paymentCurrencies = paymentNetworkExtension?.values?.acceptedTokens?.map( (token: any) => currencyManager.fromAddress(token, paymentNetworkExtension?.values?.network) ); } else if( paymentNetworkExtension?.id === Types.Extension.PAYMENT_NETWORK_ID.ANY_TO_ETH_PROXY) { @@ -132,7 +133,7 @@ network = paymentCurrencies[0]?.network || "mainnet"; - if (paymentCurrencies[0].type === Types.RequestLogic.CURRENCY.ERC20) { + if (paymentCurrencies[0]?.type === Types.RequestLogic.CURRENCY.ERC20) { approved = await checkApproval(requestData, paymentCurrencies, signer); } else { approved = true; @@ -204,7 +205,7 @@ return await hasErc20Approval(requestData!, address!, signer) } else if(paymentNetworkExtension?.id === Types.Extension.PAYMENT_NETWORK_ID.ANY_TO_ERC20_PROXY) { - return await hasErc20ApprovalForProxyConversion(requestData!, address!, paymentCurrencies[0].address, signer, requestData.expectedAmount); + return await hasErc20ApprovalForProxyConversion(requestData!, address!, paymentCurrencies[0]?.address, signer, requestData.expectedAmount); } return false; @@ -223,7 +224,7 @@ approved = true; } else if(paymentNetworkExtension?.id === Types.Extension.PAYMENT_NETWORK_ID.ANY_TO_ERC20_PROXY) { - const approvalTx = await approveErc20ForProxyConversion(requestData!, paymentCurrencies[0].address, signer); + const approvalTx = await approveErc20ForProxyConversion(requestData!, paymentCurrencies[0]?.address, signer); await approvalTx.wait(2); approved = true; } @@ -499,7 +500,7 @@ type="button" text="Switch Network" padding="px-[12px] py-[6px]" - onClick={() => switchNetworkIfNeeded(network)} + onClick={() => switchNetworkIfNeeded(network || "mainnet")} /> {:else if !approved && !isPaid && !isPayee && !unsupportedNetwork}

diff --git a/shared/utils/generateInvoice.ts b/shared/utils/generateInvoice.ts index a9309503..1fe607b1 100644 --- a/shared/utils/generateInvoice.ts +++ b/shared/utils/generateInvoice.ts @@ -106,14 +106,13 @@ export const exportToPDF = async ( ${invoice.contentData?.buyerInfo?.taxRegistration ? `

VAT: ${invoice.contentData.buyerInfo.taxRegistration}

` : ""} - +
Payment Chain: ${paymentCurrencies.length > 0 ? paymentCurrencies[0]?.network : "-"}
Invoice Currency: ${invoice.currency || "-"}
Settlement Currency: ${paymentCurrencies.length > 0 ? paymentCurrencies[0]?.symbol : "-"}
- Invoice Type: Regular Invoice
- +
From 6838eaca3862a2439a41b8faaf7e051218bc296e Mon Sep 17 00:00:00 2001 From: MantisClone Date: Thu, 7 Nov 2024 16:31:24 -0500 Subject: [PATCH 23/53] Trim trailing whitespace --- shared/utils/generateInvoice.ts | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/shared/utils/generateInvoice.ts b/shared/utils/generateInvoice.ts index 1fe607b1..f98f72c1 100644 --- a/shared/utils/generateInvoice.ts +++ b/shared/utils/generateInvoice.ts @@ -55,18 +55,18 @@ export const exportToPDF = async (