From 62b542c4ae0c4bf8a89a095a4d424262423d8a9f Mon Sep 17 00:00:00 2001 From: dissimilllate Date: Wed, 5 Jul 2023 15:54:28 +0300 Subject: [PATCH 1/5] feat: show liquidator profit in usd --- scripts/liquidation.js | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/scripts/liquidation.js b/scripts/liquidation.js index efc2d14..08d70f9 100644 --- a/scripts/liquidation.js +++ b/scripts/liquidation.js @@ -71,6 +71,7 @@ async function main() { // Store balances and liquidity info before liquidation summary.before.xcnBalance = await XCN.balanceOf(signerAddress); summary.before.xcnLockedForSupply = await oXCN.callStatic.balanceOfUnderlying(signerAddress); + summary.before.liquidatorLiquidity = await Comptroller.getAccountLiquidity(signerAddress); summary.before.borrowerLiquidity = await Comptroller.getAccountLiquidity(borrowerAddress); summary.before.borrowerXcnLockedForSupply = await oXCN.callStatic.balanceOfUnderlying(borrowerAddress); summary.before.borrowerXcnBalance = await oXCN.callStatic.borrowBalanceCurrent(borrowerAddress) @@ -116,6 +117,7 @@ async function main() { summary.after.xcnBalance = await XCN.balanceOf(signerAddress); summary.after.xcnLockedForSupply = await oXCN.callStatic.balanceOfUnderlying(signerAddress); + summary.after.liquidatorLiquidity = await Comptroller.getAccountLiquidity(signerAddress); summary.after.borrowerLiquidity = await Comptroller.getAccountLiquidity(borrowerAddress); summary.after.borrowerXcnLockedForSupply = await oXCN.callStatic.balanceOfUnderlying(borrowerAddress); summary.after.borrowerXcnBalance = await oXCN.callStatic.borrowBalanceCurrent(borrowerAddress) @@ -126,9 +128,17 @@ async function main() { console.log(`Borrower balance in XCN after liquidation: ${formatNumber(summary.after.borrowerXcnBalance / 1e18)}`); console.log(`Borrower balance locked for supply in XCN: ${formatNumber(summary.after.borrowerXcnLockedForSupply / 1e18)}`); - const liquidatorProfit = (summary.after.xcnLockedForSupply - amountToRepay) / 1e18; + + const liquidatorProfitXCN = (summary.after.xcnLockedForSupply - amountToRepay) / 1e18; + const collateralFactorXCN = (await Comptroller.callStatic.markets(oXCN.address))[1] / 1e18; + const xcnLockedForSupplyDiff = (summary.after.xcnLockedForSupply - summary.before.xcnLockedForSupply) / 1e18; + const borrowableXCN = xcnLockedForSupplyDiff * collateralFactorXCN; + const liquidityDiff = (summary.after.liquidatorLiquidity[1] - summary.before.liquidatorLiquidity[1]) / 1e18; + const xcnusdRate = liquidityDiff / borrowableXCN; + const liquidatorProfitUSD = liquidatorProfitXCN * xcnusdRate; console.log('\n'); - console.log(`Liquidator profit in XCN (locked for supply - liquidation cost): ${formatNumber(liquidatorProfit)}`); + console.log(`Liquidator profit in XCN (locked for supply - liquidation cost): ${formatNumber(liquidatorProfitXCN)}`); + console.log(`Liquidator approximate profit in USD: ${formatNumber(liquidatorProfitUSD)}`); resolve(); })); From 6a98aab13ca9588ad7972127ee6d204d074cb95f Mon Sep 17 00:00:00 2001 From: dissimilllate Date: Wed, 5 Jul 2023 17:01:26 +0300 Subject: [PATCH 2/5] chore: show protocolSeizeShareMantissa --- scripts/liquidation.js | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/scripts/liquidation.js b/scripts/liquidation.js index 08d70f9..c90ae07 100644 --- a/scripts/liquidation.js +++ b/scripts/liquidation.js @@ -57,8 +57,9 @@ async function main() { // The percent, ranging from 0% to 100%, of a liquidatable account's borrow that can be repaid in a single liquidate transaction. // https://docs.onyx.org/comptroller/close-factor const closeFactorPercentage = (await Comptroller.callStatic.closeFactorMantissa() / 1e16) + const liquidationIncentiveMantissa = (await Comptroller.callStatic.liquidationIncentiveMantissa() / 1e16); console.log('Close factor:', closeFactorPercentage, '%') - console.log('Liquidation incentive:', (await Comptroller.callStatic.liquidationIncentiveMantissa() / 1e16), '%') + console.log('Liquidation incentive:', liquidationIncentiveMantissa, '%') console.log('\n'); // Amount of XCN tokens at signer account @@ -128,6 +129,9 @@ async function main() { console.log(`Borrower balance in XCN after liquidation: ${formatNumber(summary.after.borrowerXcnBalance / 1e18)}`); console.log(`Borrower balance locked for supply in XCN: ${formatNumber(summary.after.borrowerXcnLockedForSupply / 1e18)}`); + const protocolSeizeShareMantissa = await oXCN.protocolSeizeShareMantissa() / 1e16; + console.log('\n'); + console.log('Protocol fee from repaid amount:', protocolSeizeShareMantissa, '%'); const liquidatorProfitXCN = (summary.after.xcnLockedForSupply - amountToRepay) / 1e18; const collateralFactorXCN = (await Comptroller.callStatic.markets(oXCN.address))[1] / 1e18; From 44a41dd35c3f15430497b5f62985e9038e016cc1 Mon Sep 17 00:00:00 2001 From: al-onyxprotocol Date: Tue, 18 Jul 2023 08:22:33 +0600 Subject: [PATCH 3/5] chore: add comments --- scripts/liquidation.js | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/scripts/liquidation.js b/scripts/liquidation.js index c90ae07..21c6418 100644 --- a/scripts/liquidation.js +++ b/scripts/liquidation.js @@ -51,8 +51,9 @@ async function main() { // Get exchange rates for oXCN and XCN const oXCNExchangeRate = await oXCN.callStatic.exchangeRateCurrent(); - console.log(`1 XCN in oXCN: ${formatNumber((1 / (oXCNExchangeRate / 1e28)))}`); - console.log(`1 oXCN in XCN: ${formatNumber(oXCNExchangeRate / 1e28)}`); + const oXCNExchangeRateUnscaled = oXCNExchangeRate / 1e28; + console.log(`1 XCN in oXCN: ${formatNumber((1 / oXCNExchangeRateUnscaled))}`); + console.log(`1 oXCN in XCN: ${formatNumber(oXCNExchangeRateUnscaled)}`); // The percent, ranging from 0% to 100%, of a liquidatable account's borrow that can be repaid in a single liquidate transaction. // https://docs.onyx.org/comptroller/close-factor @@ -133,14 +134,17 @@ async function main() { console.log('\n'); console.log('Protocol fee from repaid amount:', protocolSeizeShareMantissa, '%'); + // Calculate XCN rate based on current liquidity, XCN supply, and collateral factor const liquidatorProfitXCN = (summary.after.xcnLockedForSupply - amountToRepay) / 1e18; const collateralFactorXCN = (await Comptroller.callStatic.markets(oXCN.address))[1] / 1e18; const xcnLockedForSupplyDiff = (summary.after.xcnLockedForSupply - summary.before.xcnLockedForSupply) / 1e18; const borrowableXCN = xcnLockedForSupplyDiff * collateralFactorXCN; const liquidityDiff = (summary.after.liquidatorLiquidity[1] - summary.before.liquidatorLiquidity[1]) / 1e18; - const xcnusdRate = liquidityDiff / borrowableXCN; - const liquidatorProfitUSD = liquidatorProfitXCN * xcnusdRate; + const calculatedXcnUsdRate = liquidityDiff / borrowableXCN; + const liquidatorProfitUSD = liquidatorProfitXCN * calculatedXcnUsdRate; + console.log('\n'); + console.log('Calculated XCN rate:', calculatedXcnUsdRate); console.log(`Liquidator profit in XCN (locked for supply - liquidation cost): ${formatNumber(liquidatorProfitXCN)}`); console.log(`Liquidator approximate profit in USD: ${formatNumber(liquidatorProfitUSD)}`); resolve(); From d35598a1e578eea80fcda2c576b3a2095d1c0307 Mon Sep 17 00:00:00 2001 From: dissimilllate Date: Wed, 19 Jul 2023 17:08:48 +0300 Subject: [PATCH 4/5] chore: show liquidation math --- helpers/utils.js | 5 +++-- scripts/liquidation.js | 16 +++++++++++++++- 2 files changed, 18 insertions(+), 3 deletions(-) diff --git a/helpers/utils.js b/helpers/utils.js index 60ade1d..1046fd4 100644 --- a/helpers/utils.js +++ b/helpers/utils.js @@ -1,7 +1,8 @@ module.exports = { - formatNumber(number) { + formatNumber(number, maximumFractionDigits = 20) { return new Intl.NumberFormat('en-EN', { - maximumSignificantDigits: 21, + // maximumSignificantDigits: 21, + maximumFractionDigits, }).format(number); }, }; diff --git a/scripts/liquidation.js b/scripts/liquidation.js index 21c6418..a9c93c5 100644 --- a/scripts/liquidation.js +++ b/scripts/liquidation.js @@ -59,6 +59,7 @@ async function main() { // https://docs.onyx.org/comptroller/close-factor const closeFactorPercentage = (await Comptroller.callStatic.closeFactorMantissa() / 1e16) const liquidationIncentiveMantissa = (await Comptroller.callStatic.liquidationIncentiveMantissa() / 1e16); + const liquidationIncentiveCoefficient = (await Comptroller.callStatic.liquidationIncentiveMantissa() / 1e18); console.log('Close factor:', closeFactorPercentage, '%') console.log('Liquidation incentive:', liquidationIncentiveMantissa, '%') console.log('\n'); @@ -131,8 +132,21 @@ async function main() { console.log(`Borrower balance locked for supply in XCN: ${formatNumber(summary.after.borrowerXcnLockedForSupply / 1e18)}`); const protocolSeizeShareMantissa = await oXCN.protocolSeizeShareMantissa() / 1e16; + const protocolSeizeShareCoefficient = await oXCN.protocolSeizeShareMantissa() / 1e18; + const repayAmountWithIncentive = repayAmount / 1e18 * liquidationIncentiveCoefficient; + const protocolFee = repayAmountWithIncentive * protocolSeizeShareCoefficient; console.log('\n'); - console.log('Protocol fee from repaid amount:', protocolSeizeShareMantissa, '%'); + // console.log('Protocol fee from repaid amount:', protocolSeizeShareMantissa, '%'); + // console.log(`Liquidator paid: ${formatNumber(repayAmount / 1e18)}`); + + console.log(`Liquidator's profit: Repay amount * Liquidation incentive:`); + console.log(`${formatNumber(repayAmount / 1e18)} * ${formatNumber(liquidationIncentiveCoefficient)} = ${formatNumber(repayAmountWithIncentive)}`); + + console.log(`Liquidator has to pay protocol fee: ${formatNumber(protocolSeizeShareMantissa)} % of Liqudidator's profit`); + console.log(`${formatNumber(protocolSeizeShareCoefficient)} * ${formatNumber(repayAmountWithIncentive)} = ${formatNumber(protocolFee)}`); + + console.log(`Protocol fee + Liquidator's locked for supply income = Repay amount * Liquidation incentive = Borrower's locked for supply loss`); + console.log(`${formatNumber(protocolFee, 3)} + ${formatNumber((summary.after.xcnLockedForSupply - summary.before.xcnLockedForSupply) / 1e18, 3)} = ${formatNumber(repayAmount / 1e18, 3)} * ${formatNumber(liquidationIncentiveCoefficient)} = ${formatNumber((summary.before.borrowerXcnLockedForSupply - summary.after.borrowerXcnLockedForSupply) / 1e18, 3)}`); // Calculate XCN rate based on current liquidity, XCN supply, and collateral factor const liquidatorProfitXCN = (summary.after.xcnLockedForSupply - amountToRepay) / 1e18; From 233ca1b7cf60201980d71d98bf985a1a476329cb Mon Sep 17 00:00:00 2001 From: dissimilllate Date: Wed, 19 Jul 2023 17:10:31 +0300 Subject: [PATCH 5/5] chore: cleanup --- helpers/utils.js | 1 - scripts/liquidation.js | 6 +----- 2 files changed, 1 insertion(+), 6 deletions(-) diff --git a/helpers/utils.js b/helpers/utils.js index 1046fd4..8fefdff 100644 --- a/helpers/utils.js +++ b/helpers/utils.js @@ -1,7 +1,6 @@ module.exports = { formatNumber(number, maximumFractionDigits = 20) { return new Intl.NumberFormat('en-EN', { - // maximumSignificantDigits: 21, maximumFractionDigits, }).format(number); }, diff --git a/scripts/liquidation.js b/scripts/liquidation.js index a9c93c5..eb83ce7 100644 --- a/scripts/liquidation.js +++ b/scripts/liquidation.js @@ -135,16 +135,12 @@ async function main() { const protocolSeizeShareCoefficient = await oXCN.protocolSeizeShareMantissa() / 1e18; const repayAmountWithIncentive = repayAmount / 1e18 * liquidationIncentiveCoefficient; const protocolFee = repayAmountWithIncentive * protocolSeizeShareCoefficient; - console.log('\n'); - // console.log('Protocol fee from repaid amount:', protocolSeizeShareMantissa, '%'); - // console.log(`Liquidator paid: ${formatNumber(repayAmount / 1e18)}`); + console.log('\n'); console.log(`Liquidator's profit: Repay amount * Liquidation incentive:`); console.log(`${formatNumber(repayAmount / 1e18)} * ${formatNumber(liquidationIncentiveCoefficient)} = ${formatNumber(repayAmountWithIncentive)}`); - console.log(`Liquidator has to pay protocol fee: ${formatNumber(protocolSeizeShareMantissa)} % of Liqudidator's profit`); console.log(`${formatNumber(protocolSeizeShareCoefficient)} * ${formatNumber(repayAmountWithIncentive)} = ${formatNumber(protocolFee)}`); - console.log(`Protocol fee + Liquidator's locked for supply income = Repay amount * Liquidation incentive = Borrower's locked for supply loss`); console.log(`${formatNumber(protocolFee, 3)} + ${formatNumber((summary.after.xcnLockedForSupply - summary.before.xcnLockedForSupply) / 1e18, 3)} = ${formatNumber(repayAmount / 1e18, 3)} * ${formatNumber(liquidationIncentiveCoefficient)} = ${formatNumber((summary.before.borrowerXcnLockedForSupply - summary.after.borrowerXcnLockedForSupply) / 1e18, 3)}`);