# FyToken

## Introduction

An fyToken is an instantiation of a Hifi zero-coupon bond, with a specific configuration. It is pegged to a unique Erc20 collateral type, Erc20 underlying type and expiration time. The FyToken contract is itself an Erc20.

## Gas Costs

Gas usage is not deterministic due to requisite calls to third-party Erc20 tokens. We provide the table below for guidance only:

| Action              | Typical Gas Cost |
| ------------------- | ---------------- |
| Borrow              | <130K            |
| Liquidate Borrow    | <100K            |
| Repay Borrow        | <80K             |
| Repay Borrow Behalf | <80K             |

## Erc20 Functions <a href="#non-constant-functions" id="non-constant-functions"></a>

All [Erc20](https://eips.ethereum.org/EIPS/eip-20) functions are implemented: `allowance()`, `balanceOf()`, `decimals()`, `name()`, `symbol()`, `totalSupply()`, `approve()`, `transfer()`and `transferFrom().`

## Erc2612 Functions

All [Erc2612](https://eips.ethereum.org/EIPS/eip-2612) functions are implemented: `permit()`, `nonces()` and `DOMAIN_SEPARATOR()`. Erc2612 allows users to permit another account (or contract) to use their funds using a signed message. This enables gas-less transactions and single approval/transfer transactions.

## Storage Properties

### Balance Sheet

The address of the BalanceSheet contract, the global debt registry of Hifi.

```javascript
BalanceSheetInterface public balanceSheet;
```

### Collateral

The Erc20 asset that backs the borrows of this fyToken.

```javascript
Erc20Interface public collateral;
```

### Collateral Precision Scalar

The ratio between mantissa precision (1e18) and the collateral precision.

```javascript
uint256 public collateralPrecisionScalar;
```

### Expiration Time

Unix timestamp in seconds for when this token expires.

```javascript
uint256 public expirationTime;
```

### Fintroller

The unique Fintroller associated with this contract.

```javascript
FintrollerInterface public fintroller;
```

### Redemption Pool

The unique Redemption Pool associated with this contract.

```javascript
RedemptionPoolInterface public redemptionPool;
```

### Underlying

The Erc20 underlying, or target, asset for this fyToken.

```javascript
Erc20Interface public underlying;
```

### Underlying Precision Scalar

The ratio between mantissa precision (1e18) and the underlying precision.

```javascript
uint256 public underlyingPrecisionScalar;
```

## Constant Functions <a href="#non-constant-functions" id="non-constant-functions"></a>

### Is Matured <a href="#getstream" id="getstream"></a>

Checks if the bond matured.

```javascript
function isMatured() public view returns (bool)
```

* `RETURN`: true = bond matured, otherwise it didn't.

#### Solidity

```javascript
FyTokenInterface fyToken = FyTokenInterface(0xabcd...);
uint256 isMatured = fyToken.isMatured();
```

#### Ethers.js

```javascript
const fyToken = new ethers.Contract(0xabcd..., fyTokenInterfaceABI, signer);
const isMatured = await fyToken.isMatured();
```

## Non-Constant Functions <a href="#non-constant-functions" id="non-constant-functions"></a>

### Borrow <a href="#getstream" id="getstream"></a>

Increases the debt of the caller and mints new fyToken. Emits a "Borrow" event.

```javascript
function borrow(uint256 borrowAmount) public returns (bool)
```

* `borrowAmount`: The amount of fyTokens to borrow and print into existence.
* `RETURN`: true = success, otherwise it reverts.

{% hint style="warning" %}
Requirements

* The vault must be open.
* Must be called prior to maturation.
* The amount to borrow cannot be zero.
* The "Fintroller" must allow this action to be performed.
* The locked collateral cannot be zero.
* The total supply of fyTokens cannot exceed the debt ceiling.
* The caller must not fall below the threshold collateralization ratio.
  {% endhint %}

#### Solidity <a href="#solidity-5" id="solidity-5"></a>

```javascript
FyTokenInterface fyToken = FyTokenInterface(0xabcd...);
uint256 borrowAmount = 10000000000000000000;
bool success = fyToken.borrow(borrowAmount);
require(success, "something went wrong");
```

#### Ethers.js <a href="#ethers-js-5" id="ethers-js-5"></a>

```javascript
const fyToken = new ethers.Contract(0xabcd..., fyTokenInterfaceABI, signer);
const borrowAmount = "10000000000000000000";
const borrowTx = await fyToken.borrow(borrowAmount);
await borrowTx.wait();
```

### Burn <a href="#getstream" id="getstream"></a>

Destroys `burnAmount` tokens from `holder`, reducing the token supply. Emits a "Burn" event.

```javascript
function burn(address holder, uint256 burnAmount) external returns (bool)
```

* `holder`: The account whose fyTokens to burn.
* `burnAmount`: The amount of fyTokens to burn.
* `RETURN`: true = success, otherwise it reverts.

{% hint style="warning" %}
Requirements

* Must be called prior to maturation.
* Can only be called by the "RedemptionPool".
* The amount to burn cannot be zero.
  {% endhint %}

{% hint style="info" %}
We didn't write code snippets for this function because it is not meant to be called directly. Only the "RedemptionPool" contract is allowed to call "burn".
{% endhint %}

### Liquidate Borrow <a href="#getstream" id="getstream"></a>

Repays the debt of the borrower and rewards the liquidator with a surplus of collateral. Emits a "LiquidateBorrow" event.

```javascript
function liquidateBorrow(address borrower, uint256 repayAmount) external override returns (bool)
```

* `borrower`: The account to liquidate.
* `repayAmount`: The amount of fyTokens to repay.
* `RETURN`: true = success, otherwise it reverts.

{% hint style="warning" %}
Requirements

* The vault must be open.
* The liquidator cannot liquidate themselves.
* The amount to repay cannot be zero.
* The "Fintroller" must allow this action to be performed.
* The borrower must be underwater if the bond didn't mature.
* The caller must have at least "repayAmount" fyTokens.
* The borrower must have at least "repayAmount" debt.
* The amount of clutched collateral cannot be more than what the borrower has in the vault.
  {% endhint %}

#### Solidity <a href="#solidity-5" id="solidity-5"></a>

```javascript
FyTokenInterface fyToken = FyTokenInterface(0xabcd...);
address borrower = 0xbcde...;
uint256 repayAmount = 10000000000000000000;
bool success = fyToken.liquidateBorrow(borrower, repayAmount);
require(success, "something went wrong");
```

#### Ethers.js <a href="#ethers-js-5" id="ethers-js-5"></a>

```javascript
const fyToken = new ethers.Contract(0xabcd..., fyTokenInterfaceABI, signer);
const borrower = 0xbcde...;
const repayAmount = "10000000000000000000";
const liquidateBorrowTx = await fyToken.liquidateBorrow(borrower, repayAmount);
await liquidateBorrowTx.wait();
```

### Mint <a href="#getstream" id="getstream"></a>

Prints new tokens into existence and assigns them to `beneficiary`, increasing the total supply. Emits a "Mint" event.

```javascript
function mint(address beneficiary, uint256 mintAmount) external override returns (bool)
```

* `beneficiary`: The borrower account for which to mint the tokens.
* `mintAmount`: The amount of fyTokens to print into existence.
* `RETURN`: true = success, otherwise it reverts.

{% hint style="warning" %}
Requirements

* Can only be called by the Redemption Pool.
* The amount to mint cannot be zero.
  {% endhint %}

{% hint style="info" %}
We didn't write code snippets for this function because it is not meant to be called directly. Only the "RedemptionPool" contract is allowed to call "burn".
{% endhint %}

### Repay Borrow <a href="#getstream" id="getstream"></a>

Deletes the borrower account's debt from the registry and take the fyTokens out of circulation. Emits a "RepayBorrow" event.

```javascript
function repayBorrow(uint256 repayAmount) external override returns (bool)
```

* `repayAmount` : The amount of fyTokens to repay.
* `RETURN`
  * true = success, otherwise it reverts.

{% hint style="warning" %}
Requirements

* The vault must be open.
* The amount to repay cannot be zero.
* The Fintroller must allow this action to be performed.
* The caller must have at least `repayAmount` fyTokens.
* The caller must have at least `repayAmount` debt.
  {% endhint %}

#### Solidity <a href="#solidity-5" id="solidity-5"></a>

```javascript
FyTokenInterface fyToken = FyTokenInterface(0xabcd...);
uint256 repayAmount = 10000000000000000000;
bool success = fyToken.repayBorrow(repayAmount);
require(success, "something went wrong");
```

#### Ethers.js

```javascript
const fyToken = new ethers.Contract(0xabcd..., fyTokenInterfaceABI, signer);
const repayAmount = "10000000000000000000";
const repayBorrowTx = await fyToken.repayBorrow(repayAmount);
await repayBorrowTx.wait();
```

### Repay Borrow Behalf <a href="#getstream" id="getstream"></a>

Clears the borrower account's debt from the registry and take the fyTokens out of circulation. Emits a "RepayBorrow" event.

```javascript
function repayBorrowBehalf(address borrower, uint256 repayAmount) external override returns (bool)
```

* `borrower`: The borrower account for which to repay the borrow.
* `repayAmount`: The amount of fyTokens to repay.
* `RETURN`: true = success, otherwise it reverts.

{% hint style="warning" %}
Requirements

* same as the "repayBorrow" function, but here "msg.sender" is the account that must have at least "repayAmount" fyTokens to repay the borrow for the "borrower".
  {% endhint %}

#### Solidity <a href="#solidity-5" id="solidity-5"></a>

```javascript
FyTokenInterface fyToken = FyTokenInterface(0xabcd...);
address borrower = 0xbcde...;
uint256 repayAmount = 10000000000000000000;
bool success = fyToken.repayBorrowBehalf(borrower, repayAmount);
require(success, "something went wrong");
```

#### Ethers.js <a href="#ethers-js-5" id="ethers-js-5"></a>

```javascript
const fyToken = new ethers.Contract(0xabcd..., fyTokenInterfaceABI, signer);
const borrower = 0xbcde...;
const repayAmount = "10000000000000000000";
const repayBorrowBehalfTx = await fyToken.repayBorrowBehalf(borrower, repayAmount);
await repayBorrowBehalfTx.wait();
```

### Set Fintroller <a href="#getstream" id="getstream"></a>

Updates the Fintroller contract's address saved in storage. Emits a "SetFintroller" event.

```javascript
function _setFintroller(FintrollerInterface newFintroller) external returns (bool)
```

* `newFintroller`: The address of the new Fintroller contract.
* `RETURN`: true = success, otherwise it reverts.

{% hint style="warning" %}
Requirements

* The caller must be the admin.
* The new Fintroller must pass the inspection.
  {% endhint %}

{% hint style="info" %}
We didn't write code snippets for this function because it is not meant to be called by end users. Only the protocol admin is allowed to call "setFintroller".
{% endhint %}


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://v0.docs.hifi.finance/smart-contracts/fytoken.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
