diff --git a/frontend/app/src/liquity-utils.ts b/frontend/app/src/liquity-utils.ts index 94767ff28..a88f1cd5b 100644 --- a/frontend/app/src/liquity-utils.ts +++ b/frontend/app/src/liquity-utils.ts @@ -1,6 +1,8 @@ +import type { Contracts } from "@/src/contracts"; import type { StabilityPoolDepositQuery } from "@/src/graphql/graphql"; import type { CollIndex, Dnum, PositionEarn, PositionStake, PrefixedTroveId, TroveId } from "@/src/types"; import type { Address, CollateralSymbol, CollateralToken } from "@liquity2/uikit"; +import type { Config as WagmiConfig } from "wagmi"; import { DATA_REFRESH_INTERVAL, INTEREST_RATE_INCREMENT, INTEREST_RATE_MAX, INTEREST_RATE_MIN } from "@/src/constants"; import { getCollateralContract, getContracts, getProtocolContract } from "@/src/contracts"; @@ -25,6 +27,7 @@ import * as dn from "dnum"; import { useMemo } from "react"; import { encodeAbiParameters, keccak256, parseAbiParameters } from "viem"; import { useBalance, useReadContract, useReadContracts } from "wagmi"; +import { readContract } from "wagmi/actions"; export function shortenTroveId(troveId: TroveId, chars = 8) { return troveId.length < chars * 2 + 2 @@ -452,3 +455,52 @@ export function usePredictAdjustInterestRateUpfrontFee( }, }); } + +// from https://github.com/liquity/bold/blob/204a3dec54a0e8689120ca48faf4ece5cf8ccd22/README.md#example-opentrove-transaction-with-hints +export async function getTroveOperationHints({ + wagmiConfig, + contracts, + collIndex, + interestRate, +}: { + wagmiConfig: WagmiConfig; + contracts: Contracts; + collIndex: number; + interestRate: bigint; +}): Promise<{ + upperHint: bigint; + lowerHint: bigint; +}> { + const collateral = contracts.collaterals[collIndex]; + if (!collateral) { + throw new Error(`Invalid collateral index: ${collIndex}`); + } + + const numTroves = await readContract(wagmiConfig, { + ...collateral.contracts.SortedTroves, + functionName: "getSize", + }); + + const [approxHint] = await readContract(wagmiConfig, { + ...contracts.HintHelpers, + functionName: "getApproxHint", + args: [ + BigInt(collIndex), + interestRate, + BigInt(10 * Math.sqrt(Number(numTroves))), // (10 * sqrt(troves)) gives a hint close to the right position + 42n, // random seed + ], + }); + + const [upperHint, lowerHint] = await readContract(wagmiConfig, { + ...collateral.contracts.SortedTroves, + functionName: "findInsertPosition", + args: [ + interestRate, + approxHint, + approxHint, + ], + }); + + return { upperHint, lowerHint }; +} diff --git a/frontend/app/src/screens/BorrowScreen/BorrowScreen.tsx b/frontend/app/src/screens/BorrowScreen/BorrowScreen.tsx index 4ef7cd4be..b04c9630b 100644 --- a/frontend/app/src/screens/BorrowScreen/BorrowScreen.tsx +++ b/frontend/app/src/screens/BorrowScreen/BorrowScreen.tsx @@ -413,8 +413,6 @@ export function BorrowScreen() { ownerIndex: nextOwnerIndex.data, collAmount: deposit.parsed, boldAmount: debt.parsed, - upperHint: dnum18(0), - lowerHint: dnum18(0), annualInterestRate: interestRate, maxUpfrontFee: dnum18(maxUint256), interestRateDelegate: interestRateMode === "manual" || !interestRateDelegate ? null : [ diff --git a/frontend/app/src/tx-flows/openBorrowPosition.tsx b/frontend/app/src/tx-flows/openBorrowPosition.tsx index 5dd79c4fe..fb8418a61 100644 --- a/frontend/app/src/tx-flows/openBorrowPosition.tsx +++ b/frontend/app/src/tx-flows/openBorrowPosition.tsx @@ -4,7 +4,12 @@ import { Amount } from "@/src/comps/Amount/Amount"; import { ETH_GAS_COMPENSATION } from "@/src/constants"; import { dnum18 } from "@/src/dnum-utils"; import { fmtnum } from "@/src/formatting"; -import { getCollToken, getPrefixedTroveId, usePredictOpenTroveUpfrontFee } from "@/src/liquity-utils"; +import { + getCollToken, + getPrefixedTroveId, + getTroveOperationHints, + usePredictOpenTroveUpfrontFee, +} from "@/src/liquity-utils"; import { LoanCard } from "@/src/screens/TransactionsScreen/LoanCard"; import { TransactionDetailsRow } from "@/src/screens/TransactionsScreen/TransactionsScreen"; import { TransactionStatus } from "@/src/screens/TransactionsScreen/TransactionStatus"; @@ -27,8 +32,6 @@ const RequestSchema = createRequestSchema( ownerIndex: v.number(), collAmount: vDnum(), boldAmount: vDnum(), - upperHint: vDnum(), - lowerHint: vDnum(), annualInterestRate: vDnum(), maxUpfrontFee: vDnum(), interestRateDelegate: v.union([ @@ -223,17 +226,24 @@ export const openBorrowPosition: FlowDeclaration = { if (!collateral) { throw new Error(`Invalid collateral index: ${request.collIndex}`); } - const { LeverageLSTZapper } = collateral.contracts; + + const { upperHint, lowerHint } = await getTroveOperationHints({ + wagmiConfig, + contracts, + collIndex: request.collIndex, + interestRate: request.annualInterestRate[0], + }); + return writeContract(wagmiConfig, { - ...LeverageLSTZapper, + ...collateral.contracts.LeverageLSTZapper, functionName: "openTroveWithRawETH" as const, args: [{ owner: request.owner, ownerIndex: BigInt(request.ownerIndex), collAmount: request.collAmount[0], boldAmount: request.boldAmount[0], - upperHint: request.upperHint[0], - lowerHint: request.lowerHint[0], + upperHint, + lowerHint, annualInterestRate: request.interestRateDelegate ? 0n : request.annualInterestRate[0], @@ -295,17 +305,24 @@ export const openBorrowPosition: FlowDeclaration = { if (!collateral) { throw new Error(`Invalid collateral index: ${request.collIndex}`); } - const { LeverageWETHZapper } = collateral.contracts; + + const { upperHint, lowerHint } = await getTroveOperationHints({ + wagmiConfig, + contracts, + collIndex: request.collIndex, + interestRate: request.annualInterestRate[0], + }); + return writeContract(wagmiConfig, { - ...LeverageWETHZapper, + ...collateral.contracts.LeverageWETHZapper, functionName: "openTroveWithRawETH", args: [{ owner: request.owner, ownerIndex: BigInt(request.ownerIndex), collAmount: 0n, boldAmount: request.boldAmount[0], - upperHint: request.upperHint[0], - lowerHint: request.lowerHint[0], + upperHint, + lowerHint, annualInterestRate: request.interestRateDelegate ? 0n : request.annualInterestRate[0], diff --git a/frontend/app/src/tx-flows/openLeveragePosition.tsx b/frontend/app/src/tx-flows/openLeveragePosition.tsx index 04ea7f158..ce9e5751c 100644 --- a/frontend/app/src/tx-flows/openLeveragePosition.tsx +++ b/frontend/app/src/tx-flows/openLeveragePosition.tsx @@ -5,7 +5,12 @@ import { ETH_GAS_COMPENSATION, MAX_UPFRONT_FEE } from "@/src/constants"; import { dnum18 } from "@/src/dnum-utils"; import { fmtnum } from "@/src/formatting"; import { getOpenLeveragedTroveParams } from "@/src/liquity-leverage"; -import { getCollToken, getPrefixedTroveId, usePredictOpenTroveUpfrontFee } from "@/src/liquity-utils"; +import { + getCollToken, + getPrefixedTroveId, + getTroveOperationHints, + usePredictOpenTroveUpfrontFee, +} from "@/src/liquity-utils"; import { AccountButton } from "@/src/screens/TransactionsScreen/AccountButton"; import { LoanCard } from "@/src/screens/TransactionsScreen/LoanCard"; import { TransactionDetailsRow } from "@/src/screens/TransactionsScreen/TransactionsScreen"; @@ -186,14 +191,21 @@ export const openLeveragePosition: FlowDeclaration wagmiConfig, ); + const { upperHint, lowerHint } = await getTroveOperationHints({ + wagmiConfig, + contracts, + collIndex: loan.collIndex, + interestRate: loan.interestRate[0], + }); + const txParams = { owner: loan.borrower, ownerIndex: BigInt(request.ownerIndex), collAmount: initialDeposit[0], flashLoanAmount: openLeveragedParams.flashLoanAmount, boldAmount: openLeveragedParams.effectiveBoldAmount, - upperHint: 0n, - lowerHint: 0n, + upperHint, + lowerHint, annualInterestRate: loan.batchManager ? 0n : loan.interestRate[0], batchManager: loan.batchManager ?? ADDRESS_ZERO, maxUpfrontFee: MAX_UPFRONT_FEE,