Skip to content

Commit

Permalink
Merge pull request #771 from yieldprotocol/bugfix/RoundUpRepayAfterMa…
Browse files Browse the repository at this point in the history
…turity

Bugfix/round up repay after maturity
  • Loading branch information
brucedonovan authored Jan 11, 2022
2 parents 9f9e0dd + 5edf3d9 commit 2b50d9c
Show file tree
Hide file tree
Showing 14 changed files with 179 additions and 123 deletions.
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "app-v2",
"version": "2.0.59",
"version": "2.0.60",
"private": true,
"dependencies": {
"@multiavatar/multiavatar": "^1.0.6",
Expand Down
2 changes: 1 addition & 1 deletion src/components/positionItems/VaultItem.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ function VaultItem({ vault, index, condensed }: { vault: IVault; index: number;
Debt:
</Text>
<Text weight={450} size="xsmall">
{vaultsLoading && vault.id === selectedVault?.id ? <SkeletonWrap width={30} /> : vault.art_}
{vaultsLoading && vault.id === selectedVault?.id ? <SkeletonWrap width={30} /> : vault.accruedArt_}
</Text>
</Box>
</Box>
Expand Down
6 changes: 6 additions & 0 deletions src/contexts/ChainContext.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -145,6 +145,7 @@ const ChainProvider = ({ children }: any) => {

let Cauldron: any;
let Ladle: any;
let RateOracle: any;
let ChainlinkMultiOracle: any;
let CompositeMultiOracle: any;
let YearnVaultMultiOracle: any;
Expand All @@ -161,6 +162,10 @@ const ChainProvider = ({ children }: any) => {
Witch = contracts.Witch__factory.connect(addrs.Witch, fallbackProvider);

if ([1, 4, 42].includes(fallbackChainId)) {
RateOracle = contracts.CompoundMultiOracle__factory.connect(
addrs.CompoundMultiOracle,
fallbackProvider
);
ChainlinkMultiOracle = contracts.ChainlinkMultiOracle__factory.connect(
addrs.ChainlinkMultiOracle,
fallbackProvider
Expand Down Expand Up @@ -202,6 +207,7 @@ const ChainProvider = ({ children }: any) => {
newContractMap.set('Cauldron', Cauldron);
newContractMap.set('Ladle', Ladle);
newContractMap.set('Witch', Witch);
newContractMap.set('RateOracle', RateOracle);
newContractMap.set('ChainlinkMultiOracle', ChainlinkMultiOracle);
newContractMap.set('CompositeMultiOracle', CompositeMultiOracle);
newContractMap.set('ChainlinkUSDOracle', ChainlinkUSDOracle);
Expand Down
80 changes: 63 additions & 17 deletions src/contexts/UserContext.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ import {
sellFYToken,
decimal18ToDecimalN,
calcLiquidationPrice,
calcAccruedDebt,
} from '../utils/yieldMath';

import { WAD_BN, ZERO_BN } from '../utils/constants';
Expand Down Expand Up @@ -278,7 +279,7 @@ const UserProvider = ({ children }: any) => {
?.get(baseId)
?.get(ilkId);

const Oracle = contractMap.get(oracleName!);
const PriceOracle = contractMap.get(oracleName!);

const base = assetRootMap.get(baseId);
const ilk = assetRootMap.get(ilkId);
Expand All @@ -294,7 +295,7 @@ const UserProvider = ({ children }: any) => {
let price: BigNumber;
try {
// eslint-disable-next-line prefer-const
[price] = await Oracle?.peek(
[price] = await PriceOracle?.peek(
bytesToBytes32(ilkId, 6),
bytesToBytes32(baseId, 6),
decimal18ToDecimalN(WAD_BN, ilk?.decimals!)
Expand Down Expand Up @@ -345,14 +346,13 @@ const UserProvider = ({ children }: any) => {
_publicData = await Promise.all(
seriesList.map(async (series: ISeriesRoot): Promise<ISeries> => {
/* Get all the data simultanenously in a promise.all */
const [baseReserves, fyTokenReserves, totalSupply, fyTokenRealReserves, mature] =
await Promise.all([
series.poolContract.getBaseBalance(),
series.poolContract.getFYTokenBalance(),
series.poolContract.totalSupply(),
series.fyTokenContract.balanceOf(series.poolAddress),
series.isMature(),
]);
const [baseReserves, fyTokenReserves, totalSupply, fyTokenRealReserves, mature] = await Promise.all([
series.poolContract.getBaseBalance(),
series.poolContract.getFYTokenBalance(),
series.poolContract.totalSupply(),
series.fyTokenContract.balanceOf(series.poolAddress),
series.isMature(),
]);

/* Calculates the base/fyToken unit selling price */
const _sellRate = sellFYToken(
Expand All @@ -378,7 +378,7 @@ const UserProvider = ({ children }: any) => {
totalSupply,
totalSupply_: ethers.utils.formatUnits(totalSupply, series.decimals),
apr: `${Number(apr).toFixed(2)}`,
seriesIsMature: mature
seriesIsMature: mature,
};
})
);
Expand Down Expand Up @@ -432,6 +432,7 @@ const UserProvider = ({ children }: any) => {
let _vaultList: IVaultRoot[] = vaultList;
const Cauldron = contractMap.get('Cauldron');
const Witch = contractMap.get('Witch');
const RateOracle = contractMap.get('RateOracle');

/* if vaultList is empty, fetch complete Vaultlist from chain via _getVaults */
if (vaultList.length === 0) _vaultList = Array.from((await _getVaults()).values());
Expand All @@ -448,24 +449,54 @@ const UserProvider = ({ children }: any) => {
diagnostics && console.log('AssetPairInfo exists in assetPairMap');
pairData = await userState.assetPairMap.get(vault.baseId + vault.ilkId);
}
const { minDebtLimit, maxDebtLimit, minRatio, pairTotalDebt, pairPrice, limitDecimals } = pairData;

diagnostics &&
console.log(vault.id, minDebtLimit, maxDebtLimit, minRatio, pairTotalDebt, pairPrice, limitDecimals);

/* Get dynamic vault data */
const [
{ ink, art },
{ owner, seriesId, ilkId }, // update balance and series (series - because a vault can have been rolled to another series) */
] = await Promise.all([await Cauldron?.balances(vault.id), await Cauldron?.vaults(vault.id)]);

const { minDebtLimit, maxDebtLimit, minRatio, pairTotalDebt, pairPrice, limitDecimals } = pairData;
const series = seriesRootMap.get(seriesId);

let accruedArt;
let rateAtMaturity;
let rate;
if (await series?.isMature()) {
rateAtMaturity = await Cauldron?.ratesAtMaturity(seriesId);
[rate] = await RateOracle?.peek(
bytesToBytes32(vault.baseId, 6),
'0x5241544500000000000000000000000000000000000000000000000000000000', // bytes for 'RATE'
'0'
);
[accruedArt, ] = calcAccruedDebt(rate, rateAtMaturity, art);
} else {
rate = BigNumber.from('1');
rateAtMaturity = BigNumber.from('1');
accruedArt = art;
}

const baseRoot = assetRootMap.get(vault.baseId);
const ilkRoot = assetRootMap.get(ilkId);

diagnostics &&
console.log(vault.id, minDebtLimit, maxDebtLimit, minRatio, pairTotalDebt, pairPrice, limitDecimals);

const ink_ = cleanValue(ethers.utils.formatUnits(ink, ilkRoot?.decimals), ilkRoot?.digitFormat);
const art_ = cleanValue(ethers.utils.formatUnits(art, baseRoot?.decimals), baseRoot?.digitFormat);
const liquidationPrice_ = cleanValue(calcLiquidationPrice(ink_, art_, minRatio), baseRoot?.digitFormat);

const accruedArt_ = cleanValue(
ethers.utils.formatUnits(accruedArt, baseRoot?.decimals),
baseRoot?.digitFormat
);

diagnostics && console.log(vault.displayName, ' art: ', art.toString());
diagnostics && console.log(vault.displayName, ' accArt: ', accruedArt.toString());

const liquidationPrice_ = cleanValue(
calcLiquidationPrice(ink_, accruedArt_, minRatio),
baseRoot?.digitFormat
);

return {
...vault,
Expand All @@ -476,9 +507,13 @@ const UserProvider = ({ children }: any) => {
ilkId, // refreshed in case ilkId has been updated
ink,
art,
accruedArt,
rateAtMaturity,
rate,

ink_, // for display purposes only
art_, // for display purposes only
accruedArt_, // display purposes

/* attach extra pairwaise data for convenience */
minDebtLimit,
Expand Down Expand Up @@ -514,7 +549,18 @@ const UserProvider = ({ children }: any) => {

console.log('VAULTS: ', combinedVaultMap);
},
[contractMap, _getVaults, userState.vaultMap, vaultFromUrl, assetRootMap, account]
[
contractMap,
_getVaults,
userState.vaultMap,
userState.assetPairMap,
vaultFromUrl,
diagnostics,
seriesRootMap,
assetRootMap,
account,
updateAssetPair,
]
);

/* Updates the assets with relevant *user* data */
Expand Down
3 changes: 3 additions & 0 deletions src/contexts/yieldEnv.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
"1": {
"Cauldron": "0xc88191F8cb8e6D4a668B047c1C8503432c3Ca867",
"Ladle": "0x6cB18fF2A33e981D1e38A663Ca056c0a5265066A",
"CompoundMultiOracle" : "0x53FBa816BD69a7f2a096f58687f87dd3020d0d5c",
"ChainlinkMultiOracle": "0xcDCe5C87f691058B61f3A65913f1a3cBCbAd9F52",
"CompositeMultiOracle": "0xA81414a544D0bd8a28257F4038D3D24B08Dd9Bb4",
"YearnVaultMultiOracle": "0xC597E9cA52Afc13F7F5EDdaC9e53DEF569236016",
Expand All @@ -12,6 +13,7 @@
"4": {
"Cauldron": "0x8390Cd98C116F269a6E6A3b50Fb03B0931423164",
"Ladle": "0xbC0200F0AAD7C1c0bBB1CC7885E1e796DFFac3e0",
"CompoundMultiOracle" : "0xeCA876c39DF7b75281Ea78eB35912fa1CC8f9482",
"ChainlinkMultiOracle": "0xBDBF01Ee32485aF94e316C395765F5Af2bf4b4dB",
"CompositeMultiOracle": "0x8482BF1e17ceF57109F34C259d39d5B9BB9A4e13",
"YearnVaultMultiOracle": "0x88175a3e14F905ecCe464aF2A8E99f26159d4Cb8",
Expand All @@ -21,6 +23,7 @@
"42": {
"Cauldron": "0xacb1fb5E88ba69E12BDE76A4c373F1935d9fe912",
"Ladle": "0xe7bae0445B9a1DBE834a7379fbE23C6d2Bd61C59",
"CompoundMultiOracle" : "0x23F5F7a17117ba794Fcc5F46Fbf635edD2596Bb6",
"ChainlinkMultiOracle": "0xBcdc8bad83ca8053DFA6B1CBAEB7E71699254a3b",
"CompositeMultiOracle": "0xaF45D0277399E79Bf599d72fF4521f8Dc4A060E1",
"YearnVaultMultiOracle": "0xaF45D0277399E79Bf599d72fF4521f8Dc4A060E1",
Expand Down
2 changes: 1 addition & 1 deletion src/hooks/actionHooks/useRemoveLiquidity.ts
Original file line number Diff line number Diff line change
Expand Up @@ -118,7 +118,7 @@ export const useRemoveLiquidity = () => {
const fyTokenTradeSupported = fyTokenTrade.gt(ethers.constants.Zero);

const matchingVaultId: string | undefined = matchingVault?.id;
const matchingVaultDebt: BigNumber = matchingVault?.art || ZERO_BN;
const matchingVaultDebt: BigNumber = matchingVault?.accruedArt || ZERO_BN;
// Choose use use matching vault:
const useMatchingVault: boolean = !!matchingVault && matchingVaultDebt.gt(ethers.constants.Zero);
// const useMatchingVault: boolean = !!matchingVault && ( _fyTokenReceived.lte(matchingVaultDebt) || !tradeFyToken) ;
Expand Down
34 changes: 19 additions & 15 deletions src/hooks/actionHooks/useRepayDebt.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ import {
} from '../../types';
import { cleanValue, getTxCode } from '../../utils/appUtils';
import { useChain } from '../useChain';
import { calculateSlippage, maxBaseIn, secondsToFrom, sellBase } from '../../utils/yieldMath';
import { calcAccruedDebt, calculateSlippage, maxBaseIn, secondsToFrom, sellBase } from '../../utils/yieldMath';
import { useRemoveCollateral } from './useRemoveCollateral';
import { ChainContext } from '../../contexts/ChainContext';
import { ETH_BASED_ASSETS } from '../../config/assets';
Expand Down Expand Up @@ -56,32 +56,36 @@ export const useRepayDebt = () => {
series.baseReserves,
series.fyTokenReserves,
series.getTimeTillMaturity(),
series.ts,
series.ts,
series.g1,
series.decimals
);

const _inputAsFyToken = series.seriesIsMature
? calculateSlippage(_input, slippageTolerance.toString()) // if series is mature then fyToken value is simply the input.
: sellBase(
series.baseReserves,
series.fyTokenReserves,
_input,
secondsToFrom(series.maturity.toString()),
series.ts,
series.g1,
series.decimals
);
? _input
: sellBase(
series.baseReserves,
series.fyTokenReserves,
_input,
secondsToFrom(series.maturity.toString()),
series.ts,
series.g1,
series.decimals
);

const _inputAsFyTokenWithSlippage = calculateSlippage(
_inputAsFyToken,
slippageTolerance.toString(),
true // minimize
);

const inputGreaterThanDebt: boolean = ethers.BigNumber.from(_inputAsFyToken).gte(vault.art);
const inputGreaterThanDebt: boolean = ethers.BigNumber.from(_inputAsFyToken).gte(vault.accruedArt);
const inputGreaterThanMaxBaseIn = _input.gt(_MaxBaseIn);

const _inputforClose = vault.art.lt(_input)
? vault.art
: calcAccruedDebt(vault.rate, vault.rateAtMaturity, _input)[1]; // this is the input value less the accrued amount.

/* if requested, and all debt will be repaid, automatically remove collateral */
const _collateralToRemove = reclaimCollateral && inputGreaterThanDebt ? vault.ink.mul(-1) : ethers.constants.Zero;
const isEthBased = ETH_BASED_ASSETS.includes(vault.ilkId);
Expand Down Expand Up @@ -112,7 +116,7 @@ export const useRepayDebt = () => {
// after maturity
target: base,
spender: base.joinAddress,
amount: _inputAsFyToken,
amount: _input,
ignoreIf: !series.seriesIsMature || alreadyApproved === true,
},
],
Expand Down Expand Up @@ -150,7 +154,7 @@ export const useRepayDebt = () => {
/* AFTER MATURITY */
{
operation: LadleActions.Fn.CLOSE,
args: [vault.id, reclaimToAddress, _collateralToRemove, _input.mul(-1)] as LadleActions.Args.CLOSE,
args: [vault.id, reclaimToAddress, _collateralToRemove, _inputforClose.mul(-1)] as LadleActions.Args.CLOSE,
ignoreIf: !series.seriesIsMature,
},

Expand Down
Loading

0 comments on commit 2b50d9c

Please sign in to comment.