Fortress Protocol Math

The Fortress protocol smart contracts use a system of exponential math, in order to represent fractional quantities with sufficient precision, using Exponential.sol. Most numbers are represented as a mantissa, an unsigned integer scaled by 1 * 10 ^ 18, in order to perform math at a high level of precision.

fTokens and Underlying Decimals

The exchange rates and the prices of assets are scaled by the decimals unique to each asset. Fortress fTokens are BEP-20 tokens with 8 decimals of precision, while their underlying tokens vary.

fToken

fToken Decimals

Underlying

Underlying Decimals

fBNB

8

BNB

18

fBUSD

8

BUSD

18

fUSDC

8

USDC

18

fUSDT

8

USDT

18

fDAI

8

DAI

18

fBTC

8

BTC

18

fETH

8

ETH

18

fBETH

8

BETH

18

fXRP

8

XRP

18

fFTS

8

FTS

18

fDOT

8

DOT

18

fLTC

8

LTC

18

fLINK

8

LINK

18

Interpreting Exchange Rates

The fToken exchange rate is scaled by the difference in decimals between the vToken and the underlying asset.

onefTokenInUnderlying = exchangeRateCurrent / (1  *  10  ^  (18  + underlyingDecimals - fTokenDecimals)

How to find the value of 1 fBUSD in BUSD with Web3.js JavaScript.

const fTokenDecimals = 8; // all fTokens have 8 decimal places
const underlying = new web3.eth.Contract(bep20Abi, busdAddress);
const fToken = new web3.eth.Contract(fTokenAbi, fBusdAddress);
const underlyingDecimals = await underlying.methods.decimals().call();
const exchangeRateCurrent = await fToken.methods.exchangeRateCurrent().call();
const mantissa = 18 + parseInt(underlyingDecimals) - fTokenDecimals;
const onefTokenInUnderlying = exchangeRateCurrent / Math.pow(10, mantissa);
console.log('1 fBUSD can be redeemed for', oneFTokenInUnderlying, 'BUSD');

There is not an underlying contract for BNB, so to do this with vBNB, set underlyingDecimals to 18. To find the number of underlying tokens that can be redeemed for fTokens, divide the number of fTokens by the above value oneFTokenInUnderlying.

underlyingTokens = fTokenAmount * oneFTokenInUnderlying

Calculating Accrued Interest

Fortress interest rates for each money market will update on every block in which the ratio of borrowed assets to supplied assets changes. The amount of that change is determined by the Fortress interest rate model's algorithm implemented for each money market and the amount of change to the borrowed to supplied assets ratio.

Interest accrues for all borrowers and suppliers in a money market when a wallet address interacts with the fToken contract, by "calling" one of these functions; borrow, mint, redeem and repay. When the smart contract executes one of these functions, it will then trigger the "accrueInterest" method, which then sends the interest to the underlying balance of every borrower or supplier in a money market. This interest accrues for the current block as well as each and every prior block in which the "accrueInterest" method was not triggered.

Calculating the APY Using Rate Per Block

The annual percentage yield (APY) for borrowing or supplying in each money market can be calculated using the value of supplyRatePerBlock (supply APY) or borrowRatePerBlock (borrow APY) in this formula:

Rate = fToken.supplyRatePerBlock(); // Integer
Rate = 37893566
BNB Mantissa = 1 * 10 ^ 18 (BNB has 18 decimal places)
Blocks Per Day = 20 * 60 * 24 (based on 20 blocks occurring every minute)
Days Per Year = 365

APY = ((((Rate / BNB Mantissa * Blocks Per Day + 1) ^ Days Per Year - 1)) - 1) * 100

Here is an example of calculating the supply and borrow APY with Web3.js JavaScript

const ethMantissa = 1e18;
const blocksPerDay = 20 * 60 * 24;
const daysPerYear = 365;

const fToken = new web3.eth.Contract(fBnbAbi, fBnbAddress);
const supplyRatePerBlock = await fToken.methods.supplyRatePerBlock().call();
const borrowRatePerBlock = await fToken.methods.borrowRatePerBlock().call();
const supplyApy = (((Math.pow((supplyRatePerBlock / bnbMantissa * blocksPerDay) + 1,
const borrowApy = (((Math.pow((borrowRatePerBlock / bnbMantissa * blocksPerDay) + 1,
console.log(`Supply APY for BNB ${supplyApy} %`);
console.log(`Borrow APY for BNB ${borrowApy} %`);

Last updated