Skip to content

Commit

Permalink
feat: adds uniswap util bestQuoteSwap
Browse files Browse the repository at this point in the history
  • Loading branch information
doncesarts committed Aug 1, 2022
1 parent 086309a commit 527e694
Show file tree
Hide file tree
Showing 3 changed files with 56 additions and 11 deletions.
7 changes: 6 additions & 1 deletion tasks/emissions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -182,19 +182,24 @@ subtask("revenue-split-buy-back", "Buy back MTA from mUSD and mBTC gov fees")
bAssetMinSlippage: 1, // 1%
rewardMinSlippage: 1, // 1%
mAssetMinBalance: simpleToExactAmount(1000), // 1k USD
// Provide two fees options to the swap, function splitBuyBackRewards will get the best quote.
swapFees: [
[3000, 3000],
[500, 10000],
], // [USDC/WETH 0.3%, MTA/WETH 0.3%] [USDC/WETH 0.05%, MTA/WETH 1%]
}

const mbtc = {
address: resolveAddress("mBTC", chain),
bAssetMinSlippage: 3, // 3%
rewardMinSlippage: 2, // 2%
mAssetMinBalance: simpleToExactAmount(10, 14), // 10 wBTC
swapFees: [[3000, 3000]], // 0.3%, 0.3%
}
const mAssets = [musd, mbtc]
const request = {
mAssets,
revenueSplitBuyBack,
swapFees: [3000, 3000], // 0.3%, 0.3%, pools fee
blockNumber: "latest",
}
const tx = await splitBuyBackRewards(signer, request)
Expand Down
18 changes: 9 additions & 9 deletions tasks/utils/emissions-split-buy-back.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,19 +3,19 @@ import { Signer } from "@ethersproject/abstract-signer"
import { ContractTransaction } from "ethers"
import { BN, simpleToExactAmount } from "@utils/math"
import { RevenueSplitBuyBack, IERC20Metadata__factory, Masset__factory } from "types/generated"
import { EncodedPaths, encodeUniswapPath, getWETHPath, quoteSwap } from "@utils/peripheral/uniswap"
import { EncodedPaths, encodeUniswapPath, getWETHPath, bestQuoteSwap } from "@utils/peripheral/uniswap"

export interface MAssetSwap {
address: string
bAssetMinSlippage: number
rewardMinSlippage: number
mAssetMinBalance: number | BN
swapFees: number[][] // Options of fees to quote
}

export interface MainParams {
revenueSplitBuyBack: RevenueSplitBuyBack
mAssets: MAssetSwap[]
swapFees: number[]
blockNumber: number | string
}
export interface BuyBackRewardsParams extends MainParams {
Expand Down Expand Up @@ -56,7 +56,7 @@ export interface BuyBackRewardsParams extends MainParams {
* - uniswapPaths The Uniswap V3 bytes encoded paths.
*/
export const calculateBuyBackRewardsQuote = async (signer: Signer, params: MainParams): Promise<BuyBackRewardsParams> => {
const { revenueSplitBuyBack, mAssets, swapFees, blockNumber } = params
const { revenueSplitBuyBack, mAssets, blockNumber } = params
const mAssetsToBuyBack: MAssetSwap[] = []
const minBassetsAmounts: BN[] = []
const minRewardsAmounts: BN[] = []
Expand All @@ -81,8 +81,6 @@ export const calculateBuyBackRewardsQuote = async (signer: Signer, params: MainP

const bAssetDecimals = await bAssetContract.decimals()
const bAssetSymbol: string = await bAssetContract.symbol()
// console.log(`ts: ${mAssetSymbol} balance: ${mAssetBalance.toString()}`);

// Validate if the mAsset balance is grater than the minimum balance to buy back, default is zero.
if (mAssetBalance.gt(mAsset.mAssetMinBalance)) {
// mAssetAmount = 10000e18 * (1e18 - 0.4e18 / 1e18) = 6000e18
Expand Down Expand Up @@ -113,22 +111,23 @@ export const calculateBuyBackRewardsQuote = async (signer: Signer, params: MainP
mAssetAmount: mAssetAmount.toString(),
minBassetsAmount: minBassetsAmount.toString(),
bAssetRedeemAmount: bAssetRedeemAmount.toString(),
swapFees: mAsset.swapFees.toString(),
})

// 2 ============ minRewardsAmount ============//

const fromToken = { address: bAsset, decimals: bAssetDecimals }
const toToken = { address: rewardsToken, decimals: rTokenDecimals }

// Get the best quote possible
// eslint-disable-next-line no-await-in-loop
const { outAmount, exchangeRate } = await quoteSwap(
const { outAmount, exchangeRate, fees } = await bestQuoteSwap(
signer,
fromToken,
toToken,
bAssetRedeemAmount,
blockNumber,
undefined,
swapFees,
mAsset.swapFees,
)
const rewardSlippage = 100 - mAsset.rewardMinSlippage
// minRewardsAmount = 5880e6 * (98/100) /1e6 * 1e18 = 5880e6 (USDC)
Expand All @@ -149,10 +148,11 @@ export const calculateBuyBackRewardsQuote = async (signer: Signer, params: MainP
exchangeRate: exchangeRate.toString(),
bAssetDecimals: bAssetDecimals.toString(),
rTokenDecimals: rTokenDecimals.toString(),
bestFees: fees.toString(),
})

// 3 ============ Uniswap path ============//
const uniswapPath = encodeUniswapPath(getWETHPath(bAsset, rewardsToken), swapFees)
const uniswapPath = encodeUniswapPath(getWETHPath(bAsset, rewardsToken), fees)
uniswapPaths.push(uniswapPath)
console.log(`ts: swap ${bAssetSymbol} to ${rTokenSymbol}, encodeUniswapPath: ${uniswapPath.encoded.toString()}`)
}
Expand Down
42 changes: 41 additions & 1 deletion test-utils/peripheral/uniswap.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ export interface EncodedPaths {
export interface SwapQuote {
outAmount: BN
exchangeRate: BN
fees: number[]
}
export interface Token {
address: string
Expand Down Expand Up @@ -74,5 +75,44 @@ export const quoteSwap = async (
const outAmount = await quoteExactInput(quoter, encodedPath.encoded, inAmount, blockNumber)
const exchangeRate = inAmount.div(outAmount.div(simpleToExactAmount(1, to.decimals)))
// Exchange rate is not precise enough, better to relay on the output amount.
return { outAmount, exchangeRate }
return { outAmount, exchangeRate, fees }
}
/**
* For the same pair of tokens, it gives the best quote based on the router fees.
* If only one fee pair is provided it returns only that fee route quote.
*
* @param {Signer} signer
* @param {Token} from
* @param {Token} to
* @param {BN} inAmount
* @param {(number | string)} blockNumber
* @param {number[][]} fees
* @param {string[]} [path]
* @return {*} {Promise<SwapQuote>}
*/
export const bestQuoteSwap = async (
signer: Signer,
from: Token,
to: Token,
inAmount: BN,
blockNumber: number | string,
fees: number[][],
path?: string[],
): Promise<SwapQuote> => {
// Get quote value from UniswapV3
const uniswapPath = path || getWETHPath(from.address, to.address)
const quoter = IUniswapV3Quoter__factory.connect(uniswapQuoterV3Address, signer)

// Use Uniswap V3
// Exchange rate is not precise enough, better to relay on the output amount.
const quotes = await Promise.all(
fees.map(async (feePair) => {
const encodedPath = encodeUniswapPath(uniswapPath, feePair)
const outAmount = await quoteExactInput(quoter, encodedPath.encoded, inAmount, blockNumber)
const exchangeRate = inAmount.div(outAmount.div(simpleToExactAmount(1, to.decimals)))
return { encodedPath, outAmount, exchangeRate, fees: feePair }
}),
)
// Get the quote that gives more output amount
return quotes.reduce((bestQuote, quote) => (bestQuote.outAmount > quote.outAmount ? bestQuote : quote))
}

0 comments on commit 527e694

Please sign in to comment.