F Tokens

fTokens are yield-generating tokens that are minted and burned upon deposit and withdraw. The fTokens' value is pegged to the value of the corresponding deposited asset at a 1:1 ratio, and can be safely stored, transferred or traded. All interest collected by the fTokens reserves are distributed to fTokens holders directly by continuously increasing their wallet balance.

For all minting and burning actions, see Deposit() and Withdraw() methods in the LendingPool contract.

EIP20 Methods

All standard EIP20 methods are implemented, such as balanceOf(), transfer(), transferFrom(), approve(), totalSupply(), etc.

balanceOf() will always return the most up to date balance of the user, which includes their principal balance + the interest generated by the principal balance.

EIP2612 Methods

permit()

function permit(address owner, address spender, uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s)

Allows a user to permit another account (or contract) to use their funds using a signed message. This enables gas-less transactions and single approval/transfer transactions.

Parameter
Type
Description

owner

address

The owner of the funds

spender

address

The spender for the funds

value

uint256

The amount the spender is permitted to use

deadline

uint256

The deadline timestamp that the permit is valid. Use type(uint).max for no deadline.

v

uint8

Signature parameter

r

bytes32

Signature parameter

s

bytes32

Signature parameter

import { signTypedData_v4 } from 'eth-sig-util'
import { fromRpcSig } from 'ethereumjs-util'

// ... other imports

import fTokenAbi from "./fTokenAbi.json"

// ... setup your web3 provider

const fTokenAddress = "FTOKEN_ADDRESS"
const fTokenContract = new web3.eth.Contract(fTokenAbi, fTokenAddress)

const privateKey = "YOUR_PRIVATE_KEY_WITHOUT_0x"
const chainId = 1
const owner = "OWNER_ADDRESS"
const spender = "SPENDER_ADDRESS"
const value = 100 // Amount the spender is permitted
const nonce = 1 // The next valid nonce, use `_nonces()`
const deadline = 1600093162

const permitParams = {
  types: {
    EIP712Domain: [
      { name: "name", type: "string" },
      { name: "version", type: "string" },
      { name: "chainId", type: "uint256" },
      { name: "verifyingContract", type: "address" },
    ],
    Permit: [
      { name: "owner", type: "address" },
      { name: "spender", type: "address" },
      { name: "value", type: "uint256" },
      { name: "nonce", type: "uint256" },
      { name: "deadline", type: "uint256" },
    ],
  },
  primaryType: "Permit",
  domain: {
    name: "fTOKEN_NAME",
    version: "1",
    chainId: chainId,
    verifyingContract: fTokenAddress,
  },
  message: {
    owner,
    spender,
    value,
    nonce,
    deadline,
  },
}

const signature = signTypedData_v4(
  Buffer.from(privateKey, "hex"),
  { data: permitParams }
)

// The signature can now be used to execute the transaction

const { v, r, s } = fromRpcSig(signature)

await fTokenContract.methods
    .permit({
      owner,
      spender,
      value,
      deadline,
      v,
      r,
      s
    })
    .send()
    .catch((e) => {
        throw Error(`Error permitting: ${e.message}`)
    })

_nonces()

function _nonces(address owner) public

Returns the next valid nonce to submit when calling permit()

Methods

UNDERLYING_ASSET_ADDRESS()

function UNDERLYING_ASSET_ADDRESS()

Returns the underlying asset of the fToken.

RESERVE_TREASURY_ADDRESS()

function RESERVE_TREASURY_ADDRESS()

Returns the address of the fTokens reserve treasury.

POOL()

function POOL()

Returns the address of the associated LendingPool for the fToken.

scaledBalanceOf()

function scaledBalanceOf(address user)

Returns the scaled balance of user as a uint256.

The scaled balance is the balance of the underlying asset of the user (amount deposited), divided by the current liquidity index at the moment of the update.

I.e. scaledBalance=amountDeposited/currentLiquidityIndexscaledBalance = amount Deposited / currentLiquidityIndex

This essentially 'marks' when a user has deposited in the reserve pool, and can be used to calculate the users current compounded fToken balance.

Example:

  • User A deposits 100 ETH at the liquidity index of 1.1

  • User B deposits another amount into the same pool

  • The liquidity index is now 1.2.

  • Therefore to calculate User A's current compounded fToken balance, the reverse operation should be performed: fTokenBalance=scaledBalancecurrentLiquidityIndexfTokenBalance = scaledBalance * currentLiquidityIndex

getScaledUserBalanceAndSupply()

function getScaledUserBalanceAndSupply(address user)

Returns the scaled balance of user and the principal total supply.

Return values

Type
Description

uint256

scaled balance of user

uint256

principal total supply

scaledTotalSupply()

function scaledTotalSupply()

Returns the scaled total supply of the fToken as uint256.

The scaled total supply is the sum of all the updated stored balances, divided by the reserve index at the moment of the update.

function isTransferAllowed(address user, uint256 amount)

Returns true if a transfer is allowed.

Specifically, a transfer will fail if the resulting Health Factor of user will end up being below 1.

FToken ABI
{
  "abi": [
    {
      "inputs": [],
      "stateMutability": "nonpayable",
      "type": "constructor"
    },
    {
      "anonymous": false,
      "inputs": [
        {
          "indexed": true,
          "internalType": "address",
          "name": "owner",
          "type": "address"
        },
        {
          "indexed": true,
          "internalType": "address",
          "name": "spender",
          "type": "address"
        },
        {
          "indexed": false,
          "internalType": "uint256",
          "name": "value",
          "type": "uint256"
        }
      ],
      "name": "Approval",
      "type": "event"
    },
    {
      "anonymous": false,
      "inputs": [
        {
          "indexed": true,
          "internalType": "address",
          "name": "from",
          "type": "address"
        },
        {
          "indexed": true,
          "internalType": "address",
          "name": "to",
          "type": "address"
        },
        {
          "indexed": false,
          "internalType": "uint256",
          "name": "value",
          "type": "uint256"
        },
        {
          "indexed": false,
          "internalType": "uint256",
          "name": "index",
          "type": "uint256"
        }
      ],
      "name": "BalanceTransfer",
      "type": "event"
    },
    {
      "anonymous": false,
      "inputs": [
        {
          "indexed": true,
          "internalType": "address",
          "name": "from",
          "type": "address"
        },
        {
          "indexed": true,
          "internalType": "address",
          "name": "target",
          "type": "address"
        },
        {
          "indexed": false,
          "internalType": "uint256",
          "name": "value",
          "type": "uint256"
        },
        {
          "indexed": false,
          "internalType": "uint256",
          "name": "index",
          "type": "uint256"
        }
      ],
      "name": "Burn",
      "type": "event"
    },
    {
      "anonymous": false,
      "inputs": [
        {
          "indexed": false,
          "internalType": "uint256",
          "name": "creatorAddress",
          "type": "uint256"
        }
      ],
      "name": "CreatorAddressUpdated",
      "type": "event"
    },
    {
      "anonymous": false,
      "inputs": [
        {
          "indexed": false,
          "internalType": "uint256",
          "name": "creatorPercentage",
          "type": "uint256"
        }
      ],
      "name": "CreatorPecentageUpdated",
      "type": "event"
    },
    {
      "anonymous": false,
      "inputs": [
        {
          "indexed": true,
          "internalType": "address",
          "name": "underlyingCollateral",
          "type": "address"
        },
        {
          "indexed": true,
          "internalType": "address",
          "name": "underlyingAsset",
          "type": "address"
        },
        {
          "indexed": true,
          "internalType": "address",
          "name": "lendingPool",
          "type": "address"
        },
        {
          "indexed": false,
          "internalType": "address",
          "name": "incentivesController",
          "type": "address"
        },
        {
          "indexed": false,
          "internalType": "address",
          "name": "treasury",
          "type": "address"
        },
        {
          "indexed": false,
          "internalType": "address",
          "name": "creator",
          "type": "address"
        },
        {
          "indexed": false,
          "internalType": "uint256",
          "name": "creatorPercentage",
          "type": "uint256"
        },
        {
          "indexed": false,
          "internalType": "uint256",
          "name": "auctionCallerPercentage",
          "type": "uint256"
        },
        {
          "indexed": false,
          "internalType": "uint256",
          "name": "auctionCreatorPercentage",
          "type": "uint256"
        }
      ],
      "name": "Initialized",
      "type": "event"
    },
    {
      "anonymous": false,
      "inputs": [
        {
          "indexed": false,
          "internalType": "uint8",
          "name": "version",
          "type": "uint8"
        }
      ],
      "name": "Initialized",
      "type": "event"
    },
    {
      "anonymous": false,
      "inputs": [
        {
          "indexed": true,
          "internalType": "address",
          "name": "from",
          "type": "address"
        },
        {
          "indexed": false,
          "internalType": "uint256",
          "name": "value",
          "type": "uint256"
        },
        {
          "indexed": false,
          "internalType": "uint256",
          "name": "index",
          "type": "uint256"
        }
      ],
      "name": "Mint",
      "type": "event"
    },
    {
      "anonymous": false,
      "inputs": [
        {
          "indexed": true,
          "internalType": "address",
          "name": "from",
          "type": "address"
        },
        {
          "indexed": true,
          "internalType": "address",
          "name": "to",
          "type": "address"
        },
        {
          "indexed": false,
          "internalType": "uint256",
          "name": "value",
          "type": "uint256"
        }
      ],
      "name": "Transfer",
      "type": "event"
    },
    {
      "inputs": [],
      "name": "POOL",
      "outputs": [
        {
          "internalType": "contract ILendingPool",
          "name": "",
          "type": "address"
        }
      ],
      "stateMutability": "view",
      "type": "function"
    },
    {
      "inputs": [],
      "name": "RESERVE_TREASURY_ADDRESS",
      "outputs": [
        {
          "internalType": "address",
          "name": "",
          "type": "address"
        }
      ],
      "stateMutability": "view",
      "type": "function"
    },
    {
      "inputs": [],
      "name": "UNDERLYING_ASSET_ADDRESS",
      "outputs": [
        {
          "internalType": "address",
          "name": "",
          "type": "address"
        }
      ],
      "stateMutability": "view",
      "type": "function"
    },
    {
      "inputs": [],
      "name": "UNDERLYING_COLLATERAL_ADDRESS",
      "outputs": [
        {
          "internalType": "address",
          "name": "",
          "type": "address"
        }
      ],
      "stateMutability": "view",
      "type": "function"
    },
    {
      "inputs": [],
      "name": "UNDERLYING_MAX_TOKEN_ID",
      "outputs": [
        {
          "internalType": "uint256",
          "name": "",
          "type": "uint256"
        }
      ],
      "stateMutability": "view",
      "type": "function"
    },
    {
      "inputs": [],
      "name": "UNDERLYING_MIN_TOKEN_ID",
      "outputs": [
        {
          "internalType": "uint256",
          "name": "",
          "type": "uint256"
        }
      ],
      "stateMutability": "view",
      "type": "function"
    },
    {
      "inputs": [
        {
          "internalType": "address",
          "name": "owner",
          "type": "address"
        },
        {
          "internalType": "address",
          "name": "spender",
          "type": "address"
        }
      ],
      "name": "allowance",
      "outputs": [
        {
          "internalType": "uint256",
          "name": "",
          "type": "uint256"
        }
      ],
      "stateMutability": "view",
      "type": "function"
    },
    {
      "inputs": [
        {
          "internalType": "address",
          "name": "spender",
          "type": "address"
        },
        {
          "internalType": "uint256",
          "name": "amount",
          "type": "uint256"
        }
      ],
      "name": "approve",
      "outputs": [
        {
          "internalType": "bool",
          "name": "",
          "type": "bool"
        }
      ],
      "stateMutability": "nonpayable",
      "type": "function"
    },
    {
      "inputs": [
        {
          "internalType": "address",
          "name": "user",
          "type": "address"
        }
      ],
      "name": "balanceOf",
      "outputs": [
        {
          "internalType": "uint256",
          "name": "",
          "type": "uint256"
        }
      ],
      "stateMutability": "view",
      "type": "function"
    },
    {
      "inputs": [
        {
          "internalType": "address",
          "name": "user",
          "type": "address"
        },
        {
          "internalType": "address",
          "name": "receiverOfUnderlying",
          "type": "address"
        },
        {
          "internalType": "uint256",
          "name": "amount",
          "type": "uint256"
        },
        {
          "internalType": "uint256",
          "name": "index",
          "type": "uint256"
        }
      ],
      "name": "burn",
      "outputs": [],
      "stateMutability": "nonpayable",
      "type": "function"
    },
    {
      "inputs": [],
      "name": "decimals",
      "outputs": [
        {
          "internalType": "uint8",
          "name": "",
          "type": "uint8"
        }
      ],
      "stateMutability": "view",
      "type": "function"
    },
    {
      "inputs": [
        {
          "internalType": "address",
          "name": "spender",
          "type": "address"
        },
        {
          "internalType": "uint256",
          "name": "subtractedValue",
          "type": "uint256"
        }
      ],
      "name": "decreaseAllowance",
      "outputs": [
        {
          "internalType": "bool",
          "name": "",
          "type": "bool"
        }
      ],
      "stateMutability": "nonpayable",
      "type": "function"
    },
    {
      "inputs": [],
      "name": "exchangeRate",
      "outputs": [
        {
          "internalType": "uint256",
          "name": "",
          "type": "uint256"
        }
      ],
      "stateMutability": "view",
      "type": "function"
    },
    {
      "inputs": [],
      "name": "getAuctionCallerPercentage",
      "outputs": [
        {
          "internalType": "uint256",
          "name": "",
          "type": "uint256"
        }
      ],
      "stateMutability": "view",
      "type": "function"
    },
    {
      "inputs": [],
      "name": "getAuctionCreatorPercentage",
      "outputs": [
        {
          "internalType": "uint256",
          "name": "",
          "type": "uint256"
        }
      ],
      "stateMutability": "view",
      "type": "function"
    },
    {
      "inputs": [],
      "name": "getPoolIncentivesController",
      "outputs": [
        {
          "internalType": "contract IPoolIncentivesController",
          "name": "",
          "type": "address"
        }
      ],
      "stateMutability": "view",
      "type": "function"
    },
    {
      "inputs": [],
      "name": "getReserveCreatorAddress",
      "outputs": [
        {
          "internalType": "address",
          "name": "",
          "type": "address"
        }
      ],
      "stateMutability": "view",
      "type": "function"
    },
    {
      "inputs": [],
      "name": "getReserveCreatorPercentage",
      "outputs": [
        {
          "internalType": "uint256",
          "name": "",
          "type": "uint256"
        }
      ],
      "stateMutability": "view",
      "type": "function"
    },
    {
      "inputs": [],
      "name": "getReserveNormalizationFactor",
      "outputs": [
        {
          "internalType": "uint256",
          "name": "",
          "type": "uint256"
        }
      ],
      "stateMutability": "view",
      "type": "function"
    },
    {
      "inputs": [
        {
          "internalType": "address",
          "name": "user",
          "type": "address"
        }
      ],
      "name": "getScaledUserBalanceAndSupply",
      "outputs": [
        {
          "internalType": "uint256",
          "name": "",
          "type": "uint256"
        },
        {
          "internalType": "uint256",
          "name": "",
          "type": "uint256"
        }
      ],
      "stateMutability": "view",
      "type": "function"
    },
    {
      "inputs": [
        {
          "internalType": "address",
          "name": "spender",
          "type": "address"
        },
        {
          "internalType": "uint256",
          "name": "addedValue",
          "type": "uint256"
        }
      ],
      "name": "increaseAllowance",
      "outputs": [
        {
          "internalType": "bool",
          "name": "",
          "type": "bool"
        }
      ],
      "stateMutability": "nonpayable",
      "type": "function"
    },
    {
      "inputs": [
        {
          "internalType": "contract IAddressProvider",
          "name": "addressProvider",
          "type": "address"
        },
        {
          "components": [
            {
              "internalType": "address",
              "name": "underlyingCollateral",
              "type": "address"
            },
            {
              "internalType": "string",
              "name": "underlyingCollateralName",
              "type": "string"
            },
            {
              "internalType": "string",
              "name": "underlyingCollateralSymbol",
              "type": "string"
            },
            {
              "internalType": "uint256",
              "name": "underlyingMaxTokenId",
              "type": "uint256"
            },
            {
              "internalType": "uint256",
              "name": "underlyingMinTokenId",
              "type": "uint256"
            },
            {
              "internalType": "address",
              "name": "underlyingAsset",
              "type": "address"
            },
            {
              "internalType": "string",
              "name": "underlyingAssetName",
              "type": "string"
            },
            {
              "internalType": "string",
              "name": "underlyingAssetSymbol",
              "type": "string"
            },
            {
              "internalType": "uint8",
              "name": "underlyingAssetDecimals",
              "type": "uint8"
            },
            {
              "internalType": "address",
              "name": "fTokenImpl",
              "type": "address"
            },
            {
              "internalType": "string",
              "name": "fTokenName",
              "type": "string"
            },
            {
              "internalType": "string",
              "name": "fTokenSymbol",
              "type": "string"
            },
            {
              "internalType": "address",
              "name": "stableDebtTokenImpl",
              "type": "address"
            },
            {
              "internalType": "string",
              "name": "stableDebtTokenName",
              "type": "string"
            },
            {
              "internalType": "string",
              "name": "stableDebtTokenSymbol",
              "type": "string"
            },
            {
              "internalType": "address",
              "name": "variableDebtTokenImpl",
              "type": "address"
            },
            {
              "internalType": "string",
              "name": "variableDebtTokenName",
              "type": "string"
            },
            {
              "internalType": "string",
              "name": "variableDebtTokenSymbol",
              "type": "string"
            },
            {
              "internalType": "address",
              "name": "interestRateStrategy",
              "type": "address"
            },
            {
              "internalType": "uint256",
              "name": "baseLTV",
              "type": "uint256"
            },
            {
              "internalType": "address",
              "name": "treasury",
              "type": "address"
            },
            {
              "internalType": "address",
              "name": "creator",
              "type": "address"
            },
            {
              "internalType": "uint256",
              "name": "creatorPercentage",
              "type": "uint256"
            },
            {
              "internalType": "uint256",
              "name": "auctionCallerPercentage",
              "type": "uint256"
            },
            {
              "internalType": "uint256",
              "name": "auctionCreatorPercentage",
              "type": "uint256"
            },
            {
              "internalType": "string",
              "name": "assetPriceFeed",
              "type": "string"
            }
          ],
          "internalType": "struct ConfigTypes.InitReserveInput",
          "name": "input",
          "type": "tuple"
        }
      ],
      "name": "initialize",
      "outputs": [],
      "stateMutability": "nonpayable",
      "type": "function"
    },
    {
      "inputs": [
        {
          "internalType": "address",
          "name": "user",
          "type": "address"
        },
        {
          "internalType": "uint256",
          "name": "amount",
          "type": "uint256"
        },
        {
          "internalType": "uint256",
          "name": "index",
          "type": "uint256"
        }
      ],
      "name": "mint",
      "outputs": [
        {
          "internalType": "bool",
          "name": "",
          "type": "bool"
        }
      ],
      "stateMutability": "nonpayable",
      "type": "function"
    },
    {
      "inputs": [
        {
          "internalType": "address",
          "name": "user",
          "type": "address"
        },
        {
          "internalType": "address",
          "name": "caller",
          "type": "address"
        },
        {
          "internalType": "address",
          "name": "owner",
          "type": "address"
        },
        {
          "internalType": "uint256",
          "name": "amount",
          "type": "uint256"
        },
        {
          "internalType": "uint256",
          "name": "liquidationFee",
          "type": "uint256"
        },
        {
          "internalType": "uint256",
          "name": "index",
          "type": "uint256"
        }
      ],
      "name": "mintAuctionPaymentToStakeholders",
      "outputs": [],
      "stateMutability": "nonpayable",
      "type": "function"
    },
    {
      "inputs": [
        {
          "internalType": "address",
          "name": "user",
          "type": "address"
        },
        {
          "internalType": "uint256",
          "name": "amount",
          "type": "uint256"
        },
        {
          "internalType": "uint256",
          "name": "index",
          "type": "uint256"
        }
      ],
      "name": "mintStableDebtRepaymentToStakeholders",
      "outputs": [],
      "stateMutability": "nonpayable",
      "type": "function"
    },
    {
      "inputs": [
        {
          "internalType": "uint256",
          "name": "amount",
          "type": "uint256"
        },
        {
          "internalType": "uint256",
          "name": "index",
          "type": "uint256"
        }
      ],
      "name": "mintVariableDebtRepaymentToStakeholders",
      "outputs": [],
      "stateMutability": "nonpayable",
      "type": "function"
    },
    {
      "inputs": [],
      "name": "name",
      "outputs": [
        {
          "internalType": "string",
          "name": "",
          "type": "string"
        }
      ],
      "stateMutability": "view",
      "type": "function"
    },
    {
      "inputs": [
        {
          "internalType": "address",
          "name": "user",
          "type": "address"
        }
      ],
      "name": "scaledBalanceOf",
      "outputs": [
        {
          "internalType": "uint256",
          "name": "",
          "type": "uint256"
        }
      ],
      "stateMutability": "view",
      "type": "function"
    },
    {
      "inputs": [],
      "name": "scaledTotalSupply",
      "outputs": [
        {
          "internalType": "uint256",
          "name": "",
          "type": "uint256"
        }
      ],
      "stateMutability": "view",
      "type": "function"
    },
    {
      "inputs": [
        {
          "internalType": "uint256",
          "name": "auctionCallerPercentage",
          "type": "uint256"
        }
      ],
      "name": "setAuctionCallerPercentage",
      "outputs": [],
      "stateMutability": "nonpayable",
      "type": "function"
    },
    {
      "inputs": [
        {
          "internalType": "uint256",
          "name": "auctionCreatorPercentage",
          "type": "uint256"
        }
      ],
      "name": "setAuctionCreatorPercentage",
      "outputs": [],
      "stateMutability": "nonpayable",
      "type": "function"
    },
    {
      "inputs": [
        {
          "internalType": "address",
          "name": "creator",
          "type": "address"
        }
      ],
      "name": "setReserveCreatorAddress",
      "outputs": [],
      "stateMutability": "nonpayable",
      "type": "function"
    },
    {
      "inputs": [
        {
          "internalType": "uint256",
          "name": "creatorPercentage",
          "type": "uint256"
        }
      ],
      "name": "setReserveCreatorPercentage",
      "outputs": [],
      "stateMutability": "nonpayable",
      "type": "function"
    },
    {
      "inputs": [],
      "name": "symbol",
      "outputs": [
        {
          "internalType": "string",
          "name": "",
          "type": "string"
        }
      ],
      "stateMutability": "view",
      "type": "function"
    },
    {
      "inputs": [],
      "name": "totalSupply",
      "outputs": [
        {
          "internalType": "uint256",
          "name": "",
          "type": "uint256"
        }
      ],
      "stateMutability": "view",
      "type": "function"
    },
    {
      "inputs": [
        {
          "internalType": "address",
          "name": "to",
          "type": "address"
        },
        {
          "internalType": "uint256",
          "name": "amount",
          "type": "uint256"
        }
      ],
      "name": "transfer",
      "outputs": [
        {
          "internalType": "bool",
          "name": "",
          "type": "bool"
        }
      ],
      "stateMutability": "nonpayable",
      "type": "function"
    },
    {
      "inputs": [
        {
          "internalType": "address",
          "name": "from",
          "type": "address"
        },
        {
          "internalType": "address",
          "name": "to",
          "type": "address"
        },
        {
          "internalType": "uint256",
          "name": "amount",
          "type": "uint256"
        }
      ],
      "name": "transferFrom",
      "outputs": [
        {
          "internalType": "bool",
          "name": "",
          "type": "bool"
        }
      ],
      "stateMutability": "nonpayable",
      "type": "function"