From 5623a6ff82fa97d53c2a927813543ff2ec827624 Mon Sep 17 00:00:00 2001 From: Dong-Ha Kim Date: Thu, 17 Oct 2024 10:45:57 +0200 Subject: [PATCH 1/5] feat: manual rebalancer support --- src/utils/constants.ts | 8 ++++++ src/views/Bridge/hooks/useBridgeAction.ts | 31 +++++++++++++++++++++-- 2 files changed, 37 insertions(+), 2 deletions(-) diff --git a/src/utils/constants.ts b/src/utils/constants.ts index 2e734eb28..07c1f9412 100644 --- a/src/utils/constants.ts +++ b/src/utils/constants.ts @@ -528,3 +528,11 @@ export const vercelApiBaseUrl = export const defaultSwapSlippage = Number( process.env.REACT_APP_DEFAULT_SWAP_SLIPPAGE || 0.5 ); + +// List of addresses that have special manual rebalancing rights in the FE +export const manualRebalancerAddresses = String( + process.env.REACT_APP_MANUAL_REBALANCER_ADDRESSES || + "0x1d933Fd71FF07E69f066d50B39a7C34EB3b69F05" +) + .split(",") + .map(ethers.utils.getAddress); diff --git a/src/views/Bridge/hooks/useBridgeAction.ts b/src/views/Bridge/hooks/useBridgeAction.ts index 868bd4bfb..0c84e3c91 100644 --- a/src/views/Bridge/hooks/useBridgeAction.ts +++ b/src/views/Bridge/hooks/useBridgeAction.ts @@ -3,7 +3,7 @@ import { TransferQuoteReceivedProperties, ampli, } from "ampli"; -import { BigNumber, constants, providers } from "ethers"; +import { BigNumber, constants, providers, utils } from "ethers"; import { useConnection, useApprove, @@ -23,6 +23,8 @@ import { sendSpokePoolVerifierDepositTx, sendDepositV3Tx, sendSwapAndBridgeTx, + manualRebalancerAddresses, + ChainId, } from "utils"; import { TransferQuote } from "./useTransferQuote"; import { SelectedRoute } from "../utils"; @@ -153,7 +155,32 @@ export function useBridgeAction( let tx: providers.TransactionResponse; - if (isSwapRoute) { + // If the connected wallet is configured as a manual rebalancer and the origin + // chain is mainnet, we force the deposit to be unprofitable with a long + // exclusivity. The idea is to have these deposits paid out as a slow fill, in + // which case the SpokePool's own balance will be used to complete the fill, and + // the HubPool will pull funds back from the mainnet SpokePool instead. This + // allows us to skip the 7 day bridges and ensure a safe level of HubPool liquidity + if ( + manualRebalancerAddresses.includes(utils.getAddress(frozenAccount)) && + frozenRoute.fromChain === ChainId.MAINNET + ) { + const { spokePool } = await getSpokePoolAndVerifier(frozenRoute); + tx = await sendDepositV3Tx( + signer, + { + ...frozenDepositArgs, + inputTokenAddress: frozenRoute.fromTokenAddress, + outputTokenAddress: frozenRoute.toTokenAddress, + // Force overrides to make deposit unattractive for relayers + relayerFeePct: BigNumber.from(0), + exclusiveRelayer: frozenAccount, + exclusivityDeadline: 30, // seconds + }, + spokePool, + networkMismatchHandler + ); + } else if (isSwapRoute) { tx = await sendSwapAndBridgeTx( signer, { From 504f70dfbb3d8bc48dc5fe10d1a39414a6918049 Mon Sep 17 00:00:00 2001 From: Dong-Ha Kim Date: Thu, 17 Oct 2024 10:58:59 +0200 Subject: [PATCH 2/5] fixup --- src/views/Bridge/hooks/useBridgeAction.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/views/Bridge/hooks/useBridgeAction.ts b/src/views/Bridge/hooks/useBridgeAction.ts index 0c84e3c91..bb4f403f1 100644 --- a/src/views/Bridge/hooks/useBridgeAction.ts +++ b/src/views/Bridge/hooks/useBridgeAction.ts @@ -175,7 +175,7 @@ export function useBridgeAction( // Force overrides to make deposit unattractive for relayers relayerFeePct: BigNumber.from(0), exclusiveRelayer: frozenAccount, - exclusivityDeadline: 30, // seconds + exclusivityDeadline: 30 * 60, // 30 minutes }, spokePool, networkMismatchHandler From 4b62541e850d34fa68218ef5334c487e32ce6d12 Mon Sep 17 00:00:00 2001 From: Paul <108695806+pxrl@users.noreply.github.com> Date: Fri, 18 Oct 2024 15:32:33 +0200 Subject: [PATCH 3/5] Update src/views/Bridge/hooks/useBridgeAction.ts --- src/views/Bridge/hooks/useBridgeAction.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/views/Bridge/hooks/useBridgeAction.ts b/src/views/Bridge/hooks/useBridgeAction.ts index bb4f403f1..9b100a097 100644 --- a/src/views/Bridge/hooks/useBridgeAction.ts +++ b/src/views/Bridge/hooks/useBridgeAction.ts @@ -175,7 +175,7 @@ export function useBridgeAction( // Force overrides to make deposit unattractive for relayers relayerFeePct: BigNumber.from(0), exclusiveRelayer: frozenAccount, - exclusivityDeadline: 30 * 60, // 30 minutes + exclusivityDeadline: 10 * 60, // 10 minutes }, spokePool, networkMismatchHandler From b170091116120299dcb25fb2d343df816e0f7420 Mon Sep 17 00:00:00 2001 From: Dong-Ha Kim Date: Fri, 25 Oct 2024 12:54:38 +0200 Subject: [PATCH 4/5] prevent max. limits for manual rebalancer --- api/suggested-fees.ts | 5 +++-- src/views/Bridge/hooks/useBridge.ts | 8 +++++--- 2 files changed, 8 insertions(+), 5 deletions(-) diff --git a/api/suggested-fees.ts b/api/suggested-fees.ts index 280ac2965..f15cc05fb 100644 --- a/api/suggested-fees.ts +++ b/api/suggested-fees.ts @@ -211,7 +211,9 @@ const handler = async ( .mul(parseUnits(tokenPriceUsd.toString(), 18)) .div(parseUnits("1", inputToken.decimals)); - if (amount.gt(maxDeposit)) { + const skipAmountLimitEnabled = skipAmountLimit === "true"; + + if (!skipAmountLimitEnabled && amount.gt(maxDeposit)) { throw new AmountTooHighError({ message: `Amount exceeds max. deposit limit: ${ethers.utils.formatUnits( maxDeposit, @@ -237,7 +239,6 @@ const handler = async ( const isAmountTooLow = BigNumber.from(amountInput).lt(minDeposit); - const skipAmountLimitEnabled = skipAmountLimit === "true"; if (!skipAmountLimitEnabled && isAmountTooLow) { throw new AmountTooLowError({ message: `Sent amount is too low relative to fees`, diff --git a/src/views/Bridge/hooks/useBridge.ts b/src/views/Bridge/hooks/useBridge.ts index 40d54ec3f..2a9cb6087 100644 --- a/src/views/Bridge/hooks/useBridge.ts +++ b/src/views/Bridge/hooks/useBridge.ts @@ -1,9 +1,9 @@ import { useEffect, useState } from "react"; -import { BigNumber } from "ethers"; +import { BigNumber, utils } from "ethers"; import { useConnection, useIsWrongNetwork, useAmplitude } from "hooks"; import { ampli } from "ampli"; -import { defaultSwapSlippage, bnZero } from "utils"; +import { defaultSwapSlippage, bnZero, manualRebalancerAddresses } from "utils"; import { useBridgeAction } from "./useBridgeAction"; import { useToAccount } from "./useToAccount"; @@ -58,12 +58,14 @@ export function useBridge() { shouldUpdateQuote && (transferQuoteQuery.isInitialLoading || feesQuery.isInitialLoading) && !transferQuote; + const isManualRebalancer = + account && manualRebalancerAddresses.includes(utils.getAddress(account)); const { error: amountValidationError } = validateBridgeAmount( parsedAmount, quotedFees?.isAmountTooLow, maxBalance, - limitsQuery.limits?.maxDeposit, + isManualRebalancer ? maxBalance : limitsQuery.limits?.maxDeposit, selectedRoute.type === "swap" && quotedSwap?.minExpectedInputTokenAmount ? BigNumber.from(quotedSwap?.minExpectedInputTokenAmount) : parsedAmount From 3e389bae63a2264e029437c5609f75ad54326c87 Mon Sep 17 00:00:00 2001 From: Dong-Ha Kim Date: Fri, 25 Oct 2024 13:59:46 +0200 Subject: [PATCH 5/5] fixup --- src/views/Bridge/hooks/useBridge.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/views/Bridge/hooks/useBridge.ts b/src/views/Bridge/hooks/useBridge.ts index 2a9cb6087..71ad05f34 100644 --- a/src/views/Bridge/hooks/useBridge.ts +++ b/src/views/Bridge/hooks/useBridge.ts @@ -1,5 +1,5 @@ import { useEffect, useState } from "react"; -import { BigNumber, utils } from "ethers"; +import { BigNumber, utils, constants } from "ethers"; import { useConnection, useIsWrongNetwork, useAmplitude } from "hooks"; import { ampli } from "ampli"; @@ -65,7 +65,7 @@ export function useBridge() { parsedAmount, quotedFees?.isAmountTooLow, maxBalance, - isManualRebalancer ? maxBalance : limitsQuery.limits?.maxDeposit, + isManualRebalancer ? constants.MaxUint256 : limitsQuery.limits?.maxDeposit, selectedRoute.type === "swap" && quotedSwap?.minExpectedInputTokenAmount ? BigNumber.from(quotedSwap?.minExpectedInputTokenAmount) : parsedAmount