From 30fd5fd0ce1704e872b5ef2c2ec8c738e4d2d2a7 Mon Sep 17 00:00:00 2001 From: Karelian Pie Date: Thu, 11 May 2023 21:43:44 +0300 Subject: [PATCH 1/9] refactor: Try and simplify useSolver --- apps/vaults/contexts/useSolver.tsx | 222 ++++++++++++++--------------- 1 file changed, 105 insertions(+), 117 deletions(-) diff --git a/apps/vaults/contexts/useSolver.tsx b/apps/vaults/contexts/useSolver.tsx index 05c420357..f7f0eb47c 100644 --- a/apps/vaults/contexts/useSolver.tsx +++ b/apps/vaults/contexts/useSolver.tsx @@ -18,14 +18,15 @@ import type {MaybeString} from '@yearn-finance/web-lib/types'; import type {TNormalizedBN} from '@common/types/types'; import type {TInitSolverArgs, TSolverContext, TWithSolver} from '@vaults/types/solvers'; -export enum Solver { +export enum Solver { VANILLA = 'Vanilla', PARTNER_CONTRACT = 'PartnerContract', CHAIN_COIN = 'ChainCoin', INTERNAL_MIGRATION = 'InternalMigration', COWSWAP = 'Cowswap', WIDO = 'Wido', - PORTALS = 'Portals' + PORTALS = 'Portals', + NONE = 'None' } export const isSolverDisabled = { @@ -35,10 +36,18 @@ export const isSolverDisabled = { [Solver.INTERNAL_MIGRATION]: false, [Solver.COWSWAP]: false, [Solver.WIDO]: false, - [Solver.PORTALS]: false + [Solver.PORTALS]: false, + [Solver.NONE]: false }; -const DefaultWithSolverContext: TWithSolver = { +type TUpdateSolverHandler = { + request: TInitSolverArgs; + quote: PromiseSettledResult; + solver: Solver; + solverCtx: TSolverContext; +} + +const DefaultWithSolverContext: TWithSolver = { currentSolver: Solver.VANILLA, effectiveSolver: Solver.VANILLA, expectedOut: toNormalizedBN(0), @@ -51,8 +60,8 @@ const DefaultWithSolverContext: TWithSolver = { onExecuteWithdraw: async (): Promise => Promise.resolve() }; -const WithSolverContext = createContext(DefaultWithSolverContext); -function WithSolverContextApp({children}: {children: React.ReactElement}): React.ReactElement { +const WithSolverContext = createContext(DefaultWithSolverContext); +function WithSolverContextApp({children}: { children: React.ReactElement }): React.ReactElement { const {address} = useWeb3(); const {currentVault, actionParams, currentSolver, isDepositing} = useActionFlow(); const cowswap = useSolverCowswap(); @@ -62,26 +71,42 @@ function WithSolverContextApp({children}: {children: React.ReactElement}): React const chainCoin = useSolverChainCoin(); const partnerContract = useSolverPartnerContract(); const internalMigration = useSolverInternalMigration(); - const [currentSolverState, set_currentSolverState] = useState({...vanilla, hash: undefined}); + const [currentSolverState, set_currentSolverState] = useState({...vanilla, hash: undefined}); const [isLoading, set_isLoading] = useState(false); + async function handleUpdateSolver({request, quote, solver, solverCtx}: TUpdateSolverHandler): Promise { + if (quote.status !== 'fulfilled' ) { + return; + } + + const requestHash = await hash(JSON.stringify({...request, solver, expectedOut: quote.value.raw.toString()})); + performBatchedUpdates((): void => { + set_currentSolverState({...solverCtx, quote: quote.value, hash: requestHash}); + set_isLoading(false); + }); + } + /* 🔵 - Yearn Finance ************************************************************************** ** Based on the currentSolver, we initialize the solver with the required parameters. **********************************************************************************************/ - const onUpdateSolver = useCallback(async (): Promise => { - if (!actionParams?.selectedOptionFrom || !actionParams?.selectedOptionTo || !actionParams?.amount) { + const onUpdateSolver = useCallback(async (): Promise => { + if (!actionParams?.selectedOptionFrom || !actionParams?.selectedOptionTo || !actionParams?.amount.raw) { return; } set_isLoading(true); const request: TInitSolverArgs = { from: toAddress(address || ''), - inputToken: actionParams?.selectedOptionFrom, - outputToken: actionParams?.selectedOptionTo, - inputAmount: actionParams?.amount.raw, + inputToken: actionParams.selectedOptionFrom, + outputToken: actionParams.selectedOptionTo, + inputAmount: actionParams.amount.raw, isDepositing: isDepositing }; + const isValidSolver = ({quote, solver}: {quote: PromiseSettledResult; solver: Solver}): boolean => { + return quote.status === 'fulfilled' && quote?.value.raw?.gt(0) && !isSolverDisabled[solver]; + }; + switch (currentSolver) { case Solver.WIDO: case Solver.PORTALS: @@ -93,158 +118,120 @@ function WithSolverContextApp({children}: {children: React.ReactElement}): React ]; const [widoQuote, cowswapQuote, portalsQuote] = await Promise.allSettled(promises); - /************************************************************** - ** Logic is to use the primary solver (Wido) and check if a - ** quote is available. If not, we fallback to the secondary - ** solver (Cowswap). If neither are available, we set the - ** quote to 0. - **************************************************************/ + let result: [PromiseSettledResult, Solver, TSolverContext]; + if (currentSolver === Solver.WIDO && !isSolverDisabled[Solver.WIDO]) { - if (widoQuote.status === 'fulfilled' && widoQuote?.value.raw?.gt(0)) { - const requestHash = await hash(JSON.stringify({...request, solver: Solver.WIDO, expectedOut: widoQuote.value.raw.toString()})); - performBatchedUpdates((): void => { - set_currentSolverState({...wido, quote: widoQuote.value, hash: requestHash}); - set_isLoading(false); - }); - } else if (cowswapQuote.status === 'fulfilled' && cowswapQuote.value.raw?.gt(0) && !isSolverDisabled[Solver.COWSWAP]) { - const requestHash = await hash(JSON.stringify({...request, solver: Solver.COWSWAP, expectedOut: cowswapQuote.value.raw.toString()})); - performBatchedUpdates((): void => { - set_currentSolverState({...cowswap, quote: cowswapQuote.value, hash: requestHash}); - set_isLoading(false); - }); - } else if (portalsQuote.status === 'fulfilled' && portalsQuote.value.raw?.gt(0) && !isSolverDisabled[Solver.PORTALS]) { - const requestHash = await hash(JSON.stringify({...request, solver: Solver.PORTALS, expectedOut: portalsQuote.value.raw.toString()})); - performBatchedUpdates((): void => { - set_currentSolverState({...portals, quote: portalsQuote.value, hash: requestHash}); - set_isLoading(false); - }); + if (isValidSolver({quote: widoQuote, solver: Solver.WIDO})) { + result = [widoQuote, Solver.WIDO, wido]; + } else if (isValidSolver({quote:cowswapQuote, solver: Solver.COWSWAP})) { + result = [cowswapQuote, Solver.COWSWAP, cowswap]; + } else if (isValidSolver({quote:portalsQuote, solver: Solver.PORTALS})) { + result = [portalsQuote, Solver.PORTALS, portals]; } else { - const requestHash = await hash(JSON.stringify({...request, solver: 'NONE', expectedOut: '0'})); - performBatchedUpdates((): void => { - set_currentSolverState({...cowswap, quote: toNormalizedBN(0), hash: requestHash}); - set_isLoading(false); - }); + result = [{status: 'fulfilled', value: toNormalizedBN(0)}, Solver.NONE, vanilla]; + } + const [quote, solver, solverCtx] = result; + await handleUpdateSolver({request, quote, solver, solverCtx}); return; } - /************************************************************** - ** Logic is to use the primary solver (Cowswap) and check if a - ** quote is available. If not, we fallback to the secondary - ** solver (Wido). If neither are available, we set the - ** quote to 0. - **************************************************************/ if (currentSolver === Solver.COWSWAP && !isSolverDisabled[Solver.COWSWAP]) { - if (cowswapQuote.status === 'fulfilled' && cowswapQuote.value.raw?.gt(0)) { - const requestHash = await hash(JSON.stringify({...request, solver: Solver.COWSWAP, expectedOut: cowswapQuote.value.raw.toString()})); - performBatchedUpdates((): void => { - set_currentSolverState({...cowswap, quote: cowswapQuote.value, hash: requestHash}); - set_isLoading(false); - }); - } else if (widoQuote.status === 'fulfilled' && widoQuote.value.raw?.gt(0) && !isSolverDisabled[Solver.WIDO]) { - const requestHash = await hash(JSON.stringify({...request, solver: Solver.WIDO, expectedOut: widoQuote.value.raw.toString()})); - performBatchedUpdates((): void => { - set_currentSolverState({...wido, quote: widoQuote.value, hash: requestHash}); - set_isLoading(false); - }); - } else if (portalsQuote.status === 'fulfilled' && portalsQuote.value.raw?.gt(0) && !isSolverDisabled[Solver.PORTALS]) { - const requestHash = await hash(JSON.stringify({...request, solver: Solver.PORTALS, expectedOut: portalsQuote.value.raw.toString()})); - performBatchedUpdates((): void => { - set_currentSolverState({...portals, quote: portalsQuote.value, hash: requestHash}); - set_isLoading(false); - }); + if (isValidSolver({quote:cowswapQuote, solver: Solver.COWSWAP})) { + result = [cowswapQuote, Solver.COWSWAP, cowswap]; + } else if (isValidSolver({quote: widoQuote, solver: Solver.WIDO})) { + result = [widoQuote, Solver.WIDO, wido]; + } else if (isValidSolver({quote:portalsQuote, solver: Solver.PORTALS})) { + result = [portalsQuote, Solver.PORTALS, portals]; } else { - const requestHash = await hash(JSON.stringify({...request, solver: 'NONE', expectedOut: '0'})); - performBatchedUpdates((): void => { - set_currentSolverState({...wido, quote: toNormalizedBN(0), hash: requestHash}); - set_isLoading(false); - }); + result = [{status: 'fulfilled', value: toNormalizedBN(0)}, Solver.NONE, vanilla]; } + const [quote, solver, solverCtx] = result; + await handleUpdateSolver({request, quote, solver, solverCtx}); + return; } - /************************************************************** - ** Logic is to use the primary solver (Portals) and check if a - ** quote is available. If not, we fallback to the secondary - ** solver (Wido). If neither are available, we set the - ** quote to 0. - **************************************************************/ if (currentSolver === Solver.PORTALS && !isSolverDisabled[Solver.PORTALS]) { - if (portalsQuote.status === 'fulfilled' && portalsQuote.value.raw?.gt(0)) { - const requestHash = await hash(JSON.stringify({...request, solver: Solver.PORTALS, expectedOut: portalsQuote.value.raw.toString()})); - performBatchedUpdates((): void => { - set_currentSolverState({...portals, quote: portalsQuote.value, hash: requestHash}); - set_isLoading(false); - }); - } else if (widoQuote.status === 'fulfilled' && widoQuote.value.raw?.gt(0) && !isSolverDisabled[Solver.WIDO]) { - const requestHash = await hash(JSON.stringify({...request, solver: Solver.WIDO, expectedOut: widoQuote.value.raw.toString()})); - performBatchedUpdates((): void => { - set_currentSolverState({...wido, quote: widoQuote.value, hash: requestHash}); - set_isLoading(false); - }); - } else if (cowswapQuote.status === 'fulfilled' && cowswapQuote.value.raw?.gt(0) && !isSolverDisabled[Solver.COWSWAP]) { - const requestHash = await hash(JSON.stringify({...request, solver: Solver.COWSWAP, expectedOut: cowswapQuote.value.raw.toString()})); - performBatchedUpdates((): void => { - set_currentSolverState({...cowswap, quote: cowswapQuote.value, hash: requestHash}); - set_isLoading(false); - }); + if (isValidSolver({quote:portalsQuote, solver: Solver.PORTALS})) { + result = [portalsQuote, Solver.PORTALS, portals]; + } else if (isValidSolver({quote: widoQuote, solver: Solver.WIDO})) { + result = [widoQuote, Solver.WIDO, wido]; + } else if (isValidSolver({quote:cowswapQuote, solver: Solver.COWSWAP})) { + result = [cowswapQuote, Solver.COWSWAP, cowswap]; } else { - const requestHash = await hash(JSON.stringify({...request, solver: 'NONE', expectedOut: '0'})); - performBatchedUpdates((): void => { - set_currentSolverState({...wido, quote: toNormalizedBN(0), hash: requestHash}); - set_isLoading(false); - }); + result = [{status: 'fulfilled', value: toNormalizedBN(0)}, Solver.NONE, vanilla]; } + const [quote, solver, solverCtx] = result; + await handleUpdateSolver({request, quote, solver, solverCtx}); + return; } set_isLoading(false); break; } + case Solver.CHAIN_COIN: { const quote = await chainCoin.init(request); - const requestHash = await hash(JSON.stringify({...request, solver: Solver.CHAIN_COIN, expectedOut: quote.raw.toString()})); - performBatchedUpdates((): void => { - set_currentSolverState({...chainCoin, quote, hash: requestHash}); - set_isLoading(false); + await handleUpdateSolver({ + request, + quote: { + status: 'fulfilled', + value: quote + }, + solver: Solver.CHAIN_COIN, + solverCtx: chainCoin }); break; } case Solver.PARTNER_CONTRACT: { const quote = await partnerContract.init(request); - const requestHash = await hash(JSON.stringify({...request, solver: Solver.PARTNER_CONTRACT, expectedOut: quote.raw.toString()})); - performBatchedUpdates((): void => { - set_currentSolverState({...partnerContract, quote, hash: requestHash}); - set_isLoading(false); + await handleUpdateSolver({ + request, + quote:{ + status: 'fulfilled', + value: quote + }, + solver: Solver.PARTNER_CONTRACT, + solverCtx: partnerContract }); break; } case Solver.INTERNAL_MIGRATION: { request.migrator = currentVault.migration.contract; const quote = await internalMigration.init(request); - const requestHash = await hash(JSON.stringify({...request, solver: Solver.INTERNAL_MIGRATION, expectedOut: quote.raw.toString()})); - performBatchedUpdates((): void => { - set_currentSolverState({...internalMigration, quote, hash: requestHash}); - set_isLoading(false); + await handleUpdateSolver({ + request, + quote:{ + status: 'fulfilled', + value: quote + }, + solver: Solver.INTERNAL_MIGRATION, + solverCtx: internalMigration }); break; } default: { const quote = await vanilla.init(request); - const requestHash = await hash(JSON.stringify({...request, solver: Solver.VANILLA, expectedOut: quote.raw.toString()})); - performBatchedUpdates((): void => { - set_currentSolverState({...vanilla, quote, hash: requestHash}); - set_isLoading(false); + await handleUpdateSolver({ + request, + quote: { + status: 'fulfilled', + value: quote + }, + solver: Solver.VANILLA, + solverCtx: vanilla }); } } - // eslint-disable-next-line react-hooks/exhaustive-deps + // eslint-disable-next-line react-hooks/exhaustive-deps }, [address, actionParams, currentSolver, cowswap.init, vanilla.init, wido.init, internalMigration.init, isDepositing, currentVault.migration.contract]); //Ignore the warning, it's a false positive useDebouncedEffect((): void => { onUpdateSolver(); }, [onUpdateSolver], 0); - const contextValue = useDeepCompareMemo((): TWithSolver => ({ + const contextValue = useDeepCompareMemo((): TWithSolver => ({ currentSolver: currentSolver, effectiveSolver: currentSolverState?.type, expectedOut: currentSolverState?.quote || toNormalizedBN(0), @@ -264,5 +251,6 @@ function WithSolverContextApp({children}: {children: React.ReactElement}): React ); } + export {WithSolverContextApp}; export const useSolver = (): TWithSolver => useContext(WithSolverContext); From f83e17e36263b3882e500aef3115ee39f04d6a47 Mon Sep 17 00:00:00 2001 From: Karelian Pie Date: Fri, 12 May 2023 10:55:08 +0300 Subject: [PATCH 2/9] refactor: Remove dup --- apps/vaults/contexts/useSolver.tsx | 64 ++++++++++++------------------ 1 file changed, 25 insertions(+), 39 deletions(-) diff --git a/apps/vaults/contexts/useSolver.tsx b/apps/vaults/contexts/useSolver.tsx index f7f0eb47c..96b1e809d 100644 --- a/apps/vaults/contexts/useSolver.tsx +++ b/apps/vaults/contexts/useSolver.tsx @@ -118,53 +118,39 @@ function WithSolverContextApp({children}: { children: React.ReactElement }): Rea ]; const [widoQuote, cowswapQuote, portalsQuote] = await Promise.allSettled(promises); - let result: [PromiseSettledResult, Solver, TSolverContext]; + const solverPriority = [Solver.WIDO, Solver.COWSWAP, Solver.PORTALS, Solver.VANILLA]; - if (currentSolver === Solver.WIDO && !isSolverDisabled[Solver.WIDO]) { - if (isValidSolver({quote: widoQuote, solver: Solver.WIDO})) { - result = [widoQuote, Solver.WIDO, wido]; - } else if (isValidSolver({quote:cowswapQuote, solver: Solver.COWSWAP})) { - result = [cowswapQuote, Solver.COWSWAP, cowswap]; - } else if (isValidSolver({quote:portalsQuote, solver: Solver.PORTALS})) { - result = [portalsQuote, Solver.PORTALS, portals]; - } else { - result = [{status: 'fulfilled', value: toNormalizedBN(0)}, Solver.NONE, vanilla]; - - } - const [quote, solver, solverCtx] = result; - await handleUpdateSolver({request, quote, solver, solverCtx}); - return; + const solvers = {} as any; + + if (isValidSolver({quote: widoQuote, solver: Solver.WIDO})) { + solvers[Solver.WIDO] = [widoQuote, Solver.WIDO, wido]; } - if (currentSolver === Solver.COWSWAP && !isSolverDisabled[Solver.COWSWAP]) { - if (isValidSolver({quote:cowswapQuote, solver: Solver.COWSWAP})) { - result = [cowswapQuote, Solver.COWSWAP, cowswap]; - } else if (isValidSolver({quote: widoQuote, solver: Solver.WIDO})) { - result = [widoQuote, Solver.WIDO, wido]; - } else if (isValidSolver({quote:portalsQuote, solver: Solver.PORTALS})) { - result = [portalsQuote, Solver.PORTALS, portals]; - } else { - result = [{status: 'fulfilled', value: toNormalizedBN(0)}, Solver.NONE, vanilla]; - } - const [quote, solver, solverCtx] = result; - await handleUpdateSolver({request, quote, solver, solverCtx}); - return; + if (isValidSolver({quote: cowswapQuote, solver: Solver.COWSWAP})) { + solvers[Solver.COWSWAP] = [cowswapQuote, Solver.COWSWAP, cowswap]; } - if (currentSolver === Solver.PORTALS && !isSolverDisabled[Solver.PORTALS]) { - if (isValidSolver({quote:portalsQuote, solver: Solver.PORTALS})) { - result = [portalsQuote, Solver.PORTALS, portals]; - } else if (isValidSolver({quote: widoQuote, solver: Solver.WIDO})) { - result = [widoQuote, Solver.WIDO, wido]; - } else if (isValidSolver({quote:cowswapQuote, solver: Solver.COWSWAP})) { - result = [cowswapQuote, Solver.COWSWAP, cowswap]; - } else { - result = [{status: 'fulfilled', value: toNormalizedBN(0)}, Solver.NONE, vanilla]; + if (isValidSolver({quote: portalsQuote, solver: Solver.PORTALS})) { + solvers[Solver.PORTALS] = [portalsQuote, Solver.PORTALS, portals]; + } + + solvers[Solver.VANILLA] = [{status: 'fulfilled', value: toNormalizedBN(0)}, Solver.NONE, vanilla]; + + const currentSolverIndex = solverPriority.indexOf(currentSolver); + if (currentSolverIndex > -1) { + solverPriority.splice(currentSolverIndex, 1); // Remove currentSolver from its current position + } + solverPriority.unshift(currentSolver); // Add currentSolver back to the beginning of the array + + solverPriority.forEach(async (currentSolver: Solver): Promise => { + if (!solvers[currentSolver]) { + return; } - const [quote, solver, solverCtx] = result; + + const [quote, solver, solverCtx] = solvers[currentSolver]; await handleUpdateSolver({request, quote, solver, solverCtx}); return; - } + }); set_isLoading(false); From 864e512f785ebd1ddec73a0f031e9cbd1c647e59 Mon Sep 17 00:00:00 2001 From: Karelian Pie Date: Fri, 12 May 2023 11:09:45 +0300 Subject: [PATCH 3/9] refactor: Make arr immutable --- apps/vaults/contexts/useSolver.tsx | 16 +++++----------- 1 file changed, 5 insertions(+), 11 deletions(-) diff --git a/apps/vaults/contexts/useSolver.tsx b/apps/vaults/contexts/useSolver.tsx index 96b1e809d..bf75f38cb 100644 --- a/apps/vaults/contexts/useSolver.tsx +++ b/apps/vaults/contexts/useSolver.tsx @@ -136,24 +136,18 @@ function WithSolverContextApp({children}: { children: React.ReactElement }): Rea solvers[Solver.VANILLA] = [{status: 'fulfilled', value: toNormalizedBN(0)}, Solver.NONE, vanilla]; - const currentSolverIndex = solverPriority.indexOf(currentSolver); - if (currentSolverIndex > -1) { - solverPriority.splice(currentSolverIndex, 1); // Remove currentSolver from its current position - } - solverPriority.unshift(currentSolver); // Add currentSolver back to the beginning of the array + const newSolverPriority = [currentSolver, ...solverPriority.filter((solver): boolean => solver !== currentSolver)]; - solverPriority.forEach(async (currentSolver: Solver): Promise => { + for (const currentSolver of newSolverPriority) { if (!solvers[currentSolver]) { - return; + continue; } const [quote, solver, solverCtx] = solvers[currentSolver]; await handleUpdateSolver({request, quote, solver, solverCtx}); return; - }); - - set_isLoading(false); - + } + break; } From b0a16fa058006f4c29e31a4947618fe5730dafc3 Mon Sep 17 00:00:00 2001 From: Karelian Pie Date: Fri, 12 May 2023 11:12:29 +0300 Subject: [PATCH 4/9] refactor: Cleanup --- apps/vaults/contexts/useSolver.tsx | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/apps/vaults/contexts/useSolver.tsx b/apps/vaults/contexts/useSolver.tsx index bf75f38cb..5506ab49e 100644 --- a/apps/vaults/contexts/useSolver.tsx +++ b/apps/vaults/contexts/useSolver.tsx @@ -111,12 +111,11 @@ function WithSolverContextApp({children}: { children: React.ReactElement }): Rea case Solver.WIDO: case Solver.PORTALS: case Solver.COWSWAP: { - const promises = [ + const [widoQuote, cowswapQuote, portalsQuote] = await Promise.allSettled([ wido.init(request, currentSolver === Solver.WIDO), cowswap.init(request, currentSolver === Solver.COWSWAP), portals.init(request, currentSolver === Solver.PORTALS) - ]; - const [widoQuote, cowswapQuote, portalsQuote] = await Promise.allSettled(promises); + ]); const solverPriority = [Solver.WIDO, Solver.COWSWAP, Solver.PORTALS, Solver.VANILLA]; @@ -147,7 +146,7 @@ function WithSolverContextApp({children}: { children: React.ReactElement }): Rea await handleUpdateSolver({request, quote, solver, solverCtx}); return; } - + break; } From c5103d9934381dcb2c07ba2afa589af1deceac07 Mon Sep 17 00:00:00 2001 From: Karelian Pie Date: Fri, 12 May 2023 11:18:43 +0300 Subject: [PATCH 5/9] refactor: Cleanup other solvers --- apps/vaults/contexts/useSolver.tsx | 48 +++++------------------------- 1 file changed, 8 insertions(+), 40 deletions(-) diff --git a/apps/vaults/contexts/useSolver.tsx b/apps/vaults/contexts/useSolver.tsx index 5506ab49e..5f9ca26a0 100644 --- a/apps/vaults/contexts/useSolver.tsx +++ b/apps/vaults/contexts/useSolver.tsx @@ -151,56 +151,24 @@ function WithSolverContextApp({children}: { children: React.ReactElement }): Rea } case Solver.CHAIN_COIN: { - const quote = await chainCoin.init(request); - await handleUpdateSolver({ - request, - quote: { - status: 'fulfilled', - value: quote - }, - solver: Solver.CHAIN_COIN, - solverCtx: chainCoin - }); + const [quote] = await Promise.allSettled([chainCoin.init(request)]); + await handleUpdateSolver({request, quote, solver: Solver.CHAIN_COIN, solverCtx: chainCoin}); break; } case Solver.PARTNER_CONTRACT: { - const quote = await partnerContract.init(request); - await handleUpdateSolver({ - request, - quote:{ - status: 'fulfilled', - value: quote - }, - solver: Solver.PARTNER_CONTRACT, - solverCtx: partnerContract - }); + const [quote] = await Promise.allSettled([partnerContract.init(request)]); + await handleUpdateSolver({request, quote, solver: Solver.PARTNER_CONTRACT, solverCtx: partnerContract}); break; } case Solver.INTERNAL_MIGRATION: { request.migrator = currentVault.migration.contract; - const quote = await internalMigration.init(request); - await handleUpdateSolver({ - request, - quote:{ - status: 'fulfilled', - value: quote - }, - solver: Solver.INTERNAL_MIGRATION, - solverCtx: internalMigration - }); + const [quote] = await Promise.allSettled([internalMigration.init(request)]); + await handleUpdateSolver({request, quote, solver: Solver.INTERNAL_MIGRATION, solverCtx: internalMigration}); break; } default: { - const quote = await vanilla.init(request); - await handleUpdateSolver({ - request, - quote: { - status: 'fulfilled', - value: quote - }, - solver: Solver.VANILLA, - solverCtx: vanilla - }); + const [quote] = await Promise.allSettled([vanilla.init(request)]); + await handleUpdateSolver({request, quote, solver: Solver.VANILLA, solverCtx: vanilla}); } } // eslint-disable-next-line react-hooks/exhaustive-deps From c2f62f42be54282c0c866213bc9e6422eb2ce3f6 Mon Sep 17 00:00:00 2001 From: Karelian Pie Date: Fri, 12 May 2023 13:27:49 +0300 Subject: [PATCH 6/9] refactor: Type --- apps/vaults/contexts/useSolver.tsx | 37 +++++++++++++++--------------- 1 file changed, 18 insertions(+), 19 deletions(-) diff --git a/apps/vaults/contexts/useSolver.tsx b/apps/vaults/contexts/useSolver.tsx index 5f9ca26a0..b3640989b 100644 --- a/apps/vaults/contexts/useSolver.tsx +++ b/apps/vaults/contexts/useSolver.tsx @@ -25,8 +25,7 @@ export enum Solver { INTERNAL_MIGRATION = 'InternalMigration', COWSWAP = 'Cowswap', WIDO = 'Wido', - PORTALS = 'Portals', - NONE = 'None' + PORTALS = 'Portals' } export const isSolverDisabled = { @@ -36,8 +35,7 @@ export const isSolverDisabled = { [Solver.INTERNAL_MIGRATION]: false, [Solver.COWSWAP]: false, [Solver.WIDO]: false, - [Solver.PORTALS]: false, - [Solver.NONE]: false + [Solver.PORTALS]: false }; type TUpdateSolverHandler = { @@ -117,24 +115,25 @@ function WithSolverContextApp({children}: { children: React.ReactElement }): Rea portals.init(request, currentSolver === Solver.PORTALS) ]); - const solverPriority = [Solver.WIDO, Solver.COWSWAP, Solver.PORTALS, Solver.VANILLA]; - - const solvers = {} as any; - + const solvers: { + [key in Solver]?: [PromiseSettledResult, TSolverContext]; + } = {}; + if (isValidSolver({quote: widoQuote, solver: Solver.WIDO})) { - solvers[Solver.WIDO] = [widoQuote, Solver.WIDO, wido]; + solvers[Solver.WIDO] = [widoQuote, wido]; } - + if (isValidSolver({quote: cowswapQuote, solver: Solver.COWSWAP})) { - solvers[Solver.COWSWAP] = [cowswapQuote, Solver.COWSWAP, cowswap]; + solvers[Solver.COWSWAP] = [cowswapQuote, cowswap]; } - + if (isValidSolver({quote: portalsQuote, solver: Solver.PORTALS})) { - solvers[Solver.PORTALS] = [portalsQuote, Solver.PORTALS, portals]; + solvers[Solver.PORTALS] = [portalsQuote, portals]; } - - solvers[Solver.VANILLA] = [{status: 'fulfilled', value: toNormalizedBN(0)}, Solver.NONE, vanilla]; - + + solvers[Solver.VANILLA] = [{status: 'fulfilled', value: toNormalizedBN(0)}, vanilla]; + + const solverPriority = [Solver.WIDO, Solver.COWSWAP, Solver.PORTALS, Solver.VANILLA]; const newSolverPriority = [currentSolver, ...solverPriority.filter((solver): boolean => solver !== currentSolver)]; for (const currentSolver of newSolverPriority) { @@ -142,14 +141,13 @@ function WithSolverContextApp({children}: { children: React.ReactElement }): Rea continue; } - const [quote, solver, solverCtx] = solvers[currentSolver]; - await handleUpdateSolver({request, quote, solver, solverCtx}); + const [quote, solverCtx] = solvers[currentSolver] ?? solvers[Solver.VANILLA]; + await handleUpdateSolver({request, quote, solver: currentSolver, solverCtx}); return; } break; } - case Solver.CHAIN_COIN: { const [quote] = await Promise.allSettled([chainCoin.init(request)]); await handleUpdateSolver({request, quote, solver: Solver.CHAIN_COIN, solverCtx: chainCoin}); @@ -171,6 +169,7 @@ function WithSolverContextApp({children}: { children: React.ReactElement }): Rea await handleUpdateSolver({request, quote, solver: Solver.VANILLA, solverCtx: vanilla}); } } + // eslint-disable-next-line react-hooks/exhaustive-deps }, [address, actionParams, currentSolver, cowswap.init, vanilla.init, wido.init, internalMigration.init, isDepositing, currentVault.migration.contract]); //Ignore the warning, it's a false positive From 2a5604e00db2b184bb5d2a662d16025f8a801673 Mon Sep 17 00:00:00 2001 From: Karelian Pie Date: Fri, 12 May 2023 13:44:13 +0300 Subject: [PATCH 7/9] refactor: Remove duplication --- apps/vaults/contexts/useSolver.tsx | 61 +++++++++++++++--------------- 1 file changed, 30 insertions(+), 31 deletions(-) diff --git a/apps/vaults/contexts/useSolver.tsx b/apps/vaults/contexts/useSolver.tsx index b3640989b..2401968a8 100644 --- a/apps/vaults/contexts/useSolver.tsx +++ b/apps/vaults/contexts/useSolver.tsx @@ -42,7 +42,7 @@ type TUpdateSolverHandler = { request: TInitSolverArgs; quote: PromiseSettledResult; solver: Solver; - solverCtx: TSolverContext; + ctx: TSolverContext; } const DefaultWithSolverContext: TWithSolver = { @@ -72,14 +72,14 @@ function WithSolverContextApp({children}: { children: React.ReactElement }): Rea const [currentSolverState, set_currentSolverState] = useState({...vanilla, hash: undefined}); const [isLoading, set_isLoading] = useState(false); - async function handleUpdateSolver({request, quote, solver, solverCtx}: TUpdateSolverHandler): Promise { - if (quote.status !== 'fulfilled' ) { + async function handleUpdateSolver({request, quote, solver, ctx}: TUpdateSolverHandler): Promise { + if (quote.status !== 'fulfilled') { return; } - + const requestHash = await hash(JSON.stringify({...request, solver, expectedOut: quote.value.raw.toString()})); performBatchedUpdates((): void => { - set_currentSolverState({...solverCtx, quote: quote.value, hash: requestHash}); + set_currentSolverState({...ctx, quote: quote.value, hash: requestHash}); set_isLoading(false); }); } @@ -101,7 +101,7 @@ function WithSolverContextApp({children}: { children: React.ReactElement }): Rea isDepositing: isDepositing }; - const isValidSolver = ({quote, solver}: {quote: PromiseSettledResult; solver: Solver}): boolean => { + const isValidSolver = ({quote, solver}: { quote: PromiseSettledResult; solver: Solver }): boolean => { return quote.status === 'fulfilled' && quote?.value.raw?.gt(0) && !isSolverDisabled[solver]; }; @@ -116,33 +116,32 @@ function WithSolverContextApp({children}: { children: React.ReactElement }): Rea ]); const solvers: { - [key in Solver]?: [PromiseSettledResult, TSolverContext]; + [key in Solver]?: { quote: PromiseSettledResult; ctx: TSolverContext }; } = {}; - - if (isValidSolver({quote: widoQuote, solver: Solver.WIDO})) { - solvers[Solver.WIDO] = [widoQuote, wido]; - } - - if (isValidSolver({quote: cowswapQuote, solver: Solver.COWSWAP})) { - solvers[Solver.COWSWAP] = [cowswapQuote, cowswap]; - } - - if (isValidSolver({quote: portalsQuote, solver: Solver.PORTALS})) { - solvers[Solver.PORTALS] = [portalsQuote, portals]; - } - - solvers[Solver.VANILLA] = [{status: 'fulfilled', value: toNormalizedBN(0)}, vanilla]; - + + [ + {solver: Solver.WIDO, quote: widoQuote, ctx: wido}, + {solver: Solver.COWSWAP, quote: cowswapQuote, ctx: cowswap}, + {solver: Solver.PORTALS, quote: portalsQuote, ctx: portals} + ].forEach(({solver, quote, ctx}): void => { + if (isValidSolver({quote, solver})) { + solvers[solver] = {quote, ctx}; + } + }); + + solvers[Solver.VANILLA] = {quote: {status: 'fulfilled', value: toNormalizedBN(0)}, ctx: vanilla}; + const solverPriority = [Solver.WIDO, Solver.COWSWAP, Solver.PORTALS, Solver.VANILLA]; + const newSolverPriority = [currentSolver, ...solverPriority.filter((solver): boolean => solver !== currentSolver)]; - for (const currentSolver of newSolverPriority) { - if (!solvers[currentSolver]) { + for (const solver of newSolverPriority) { + if (!solvers[solver]) { continue; } - const [quote, solverCtx] = solvers[currentSolver] ?? solvers[Solver.VANILLA]; - await handleUpdateSolver({request, quote, solver: currentSolver, solverCtx}); + const {quote, ctx} = solvers[solver] ?? solvers[Solver.VANILLA]; + await handleUpdateSolver({request, quote, solver, ctx}); return; } @@ -150,26 +149,26 @@ function WithSolverContextApp({children}: { children: React.ReactElement }): Rea } case Solver.CHAIN_COIN: { const [quote] = await Promise.allSettled([chainCoin.init(request)]); - await handleUpdateSolver({request, quote, solver: Solver.CHAIN_COIN, solverCtx: chainCoin}); + await handleUpdateSolver({request, quote, solver: Solver.CHAIN_COIN, ctx: chainCoin}); break; } case Solver.PARTNER_CONTRACT: { const [quote] = await Promise.allSettled([partnerContract.init(request)]); - await handleUpdateSolver({request, quote, solver: Solver.PARTNER_CONTRACT, solverCtx: partnerContract}); + await handleUpdateSolver({request, quote, solver: Solver.PARTNER_CONTRACT, ctx: partnerContract}); break; } case Solver.INTERNAL_MIGRATION: { request.migrator = currentVault.migration.contract; const [quote] = await Promise.allSettled([internalMigration.init(request)]); - await handleUpdateSolver({request, quote, solver: Solver.INTERNAL_MIGRATION, solverCtx: internalMigration}); + await handleUpdateSolver({request, quote, solver: Solver.INTERNAL_MIGRATION, ctx: internalMigration}); break; } default: { const [quote] = await Promise.allSettled([vanilla.init(request)]); - await handleUpdateSolver({request, quote, solver: Solver.VANILLA, solverCtx: vanilla}); + await handleUpdateSolver({request, quote, solver: Solver.VANILLA, ctx: vanilla}); } } - + // eslint-disable-next-line react-hooks/exhaustive-deps }, [address, actionParams, currentSolver, cowswap.init, vanilla.init, wido.init, internalMigration.init, isDepositing, currentVault.migration.contract]); //Ignore the warning, it's a false positive From 69adc617ae7e82e9c7832f1615e67d2ebeca68b1 Mon Sep 17 00:00:00 2001 From: Karelian Pie Date: Fri, 12 May 2023 14:01:48 +0300 Subject: [PATCH 8/9] feat: Solver.NONE --- apps/vaults/contexts/useSolver.tsx | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/apps/vaults/contexts/useSolver.tsx b/apps/vaults/contexts/useSolver.tsx index 2401968a8..c2dec8c47 100644 --- a/apps/vaults/contexts/useSolver.tsx +++ b/apps/vaults/contexts/useSolver.tsx @@ -25,7 +25,8 @@ export enum Solver { INTERNAL_MIGRATION = 'InternalMigration', COWSWAP = 'Cowswap', WIDO = 'Wido', - PORTALS = 'Portals' + PORTALS = 'Portals', + NONE = 'None' } export const isSolverDisabled = { @@ -35,7 +36,8 @@ export const isSolverDisabled = { [Solver.INTERNAL_MIGRATION]: false, [Solver.COWSWAP]: false, [Solver.WIDO]: false, - [Solver.PORTALS]: false + [Solver.PORTALS]: false, + [Solver.NONE]: false }; type TUpdateSolverHandler = { @@ -129,7 +131,7 @@ function WithSolverContextApp({children}: { children: React.ReactElement }): Rea } }); - solvers[Solver.VANILLA] = {quote: {status: 'fulfilled', value: toNormalizedBN(0)}, ctx: vanilla}; + solvers[Solver.NONE] = {quote: {status: 'fulfilled', value: toNormalizedBN(0)}, ctx: vanilla}; const solverPriority = [Solver.WIDO, Solver.COWSWAP, Solver.PORTALS, Solver.VANILLA]; @@ -140,7 +142,7 @@ function WithSolverContextApp({children}: { children: React.ReactElement }): Rea continue; } - const {quote, ctx} = solvers[solver] ?? solvers[Solver.VANILLA]; + const {quote, ctx} = solvers[solver] ?? solvers[Solver.NONE]; await handleUpdateSolver({request, quote, solver, ctx}); return; } From 24cb8aad8002cfc13f51306cae75a0ea862dfcd2 Mon Sep 17 00:00:00 2001 From: Karelian Pie Date: Fri, 12 May 2023 14:03:17 +0300 Subject: [PATCH 9/9] fix: Typo --- apps/vaults/contexts/useSolver.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/vaults/contexts/useSolver.tsx b/apps/vaults/contexts/useSolver.tsx index c2dec8c47..42b09a33b 100644 --- a/apps/vaults/contexts/useSolver.tsx +++ b/apps/vaults/contexts/useSolver.tsx @@ -133,7 +133,7 @@ function WithSolverContextApp({children}: { children: React.ReactElement }): Rea solvers[Solver.NONE] = {quote: {status: 'fulfilled', value: toNormalizedBN(0)}, ctx: vanilla}; - const solverPriority = [Solver.WIDO, Solver.COWSWAP, Solver.PORTALS, Solver.VANILLA]; + const solverPriority = [Solver.WIDO, Solver.COWSWAP, Solver.PORTALS, Solver.NONE]; const newSolverPriority = [currentSolver, ...solverPriority.filter((solver): boolean => solver !== currentSolver)];