# Savings Module Integration

The Savings module provides a yield-bearing vault system built on the ERC4626 standard, allowing users to deposit Parallel stablecoins and earn interest through a configurable inflation rate mechanism.

These are simple ERC4626 contracts which do not invest the tokens deposited in it, but simply mint new tokens based on a rate defined by governance. This [repo](https://github.com/parallel-protocol/parallel-parallelizer/tree/main/contracts/savings) contains the contract implementation.

As such, apart from the savings module contract smart contract risk, there is no extra trust assumption between owning a stablecoin and owning a stablecoin in a staking contract to earn a yield from it.

{% hint style="info" %}
Savings Module contracts addresses for Parallel stablecoins across all chains can be obtained [here](https://docs.parallel.best/developers-hub/contract-addresses/parallel-v3).
{% endhint %}

## Overview

Savings module contracts act as interest-bearing vaults where users can deposit their Parallel stablecoins and automatically earn yield over time. The system uses a sophisticated inflation rate mechanism that compounds interest continuously, providing predictable returns for depositors.

### Key Features

* **ERC4626 Standard**: Full compatibility with the industry-standard vault interface
* **Continuous Compounding**: Interest accrues continuously based on a configurable rate
* **Governance-Controlled**: Interest rates are managed by trusted addresses and governance
* **Pause Functionality**: Emergency pause mechanism for security
* **Upgradeable**: UUPS proxy pattern for future improvements

### How It Works

1. **Deposit**: Users deposit Parallel stablecoins (eg. USDp) and receive vault shares (eg. sUSDp)
2. **Interest Accrual**: The vault continuously mints new tokens based on the inflation rate
3. **Share Value Growth**: As the total assets increase, each share becomes more valuable
4. **Withdrawal**: Users can redeem shares for the underlying assets plus accrued interest

## Core Functions

### Depositing Assets

#### **Deposit Exact Amount (`deposit`)**

```solidity
function deposit(uint256 assets, address receiver)
    external returns (uint256 shares);
```

**Parameters:**

* `assets`: Exact amount of underlying tokens to deposit
* `receiver`: Address that will receive the vault shares

**Returns:**

* `shares`: Number of vault shares minted to the receiver

**Prerequisites:**

* Approve the Savings module contract to spend your underlying tokens
* Contract must not be paused

#### **Mint Exact Shares (`mint`)**

```solidity
function mint(uint256 shares, address receiver)
    external returns (uint256 assets);
```

**Parameters:**

* `shares`: Exact number of vault shares to mint
* `receiver`: Address that will receive the vault shares

**Returns:**

* `assets`: Amount of underlying tokens required for the deposit

**Use Case:** When you want a specific number of shares rather than a specific asset amount

### Withdrawing Assets

#### **Withdraw Exact Amount (`withdraw`)**

```solidity
function withdraw(
    uint256 assets,
    address receiver,
    address owner
) external returns (uint256 shares);
```

**Parameters:**

* `assets`: Exact amount of underlying tokens to withdraw
* `receiver`: Address that will receive the underlying tokens
* `owner`: Address that owns the shares being redeemed

**Returns:**

* `shares`: Number of vault shares burned

#### **Redeem Exact Shares (`redeem`)**

```solidity
function redeem(
    uint256 shares,
    address receiver,
    address owner
) external returns (uint256 assets);
```

**Parameters:**

* `shares`: Exact number of vault shares to redeem
* `receiver`: Address that will receive the underlying tokens
* `owner`: Address that owns the shares being redeemed

**Returns:**

* `assets`: Amount of underlying tokens received

## View Functions

### **Get Total Assets (`totalAssets`)**

```solidity
function totalAssets() external view returns (uint256);
```

Returns the total amount of underlying assets held by the vault, including accrued interest.

### **Estimate Annual Percentage Yield (`estimatedAPR`)**

The contract comes with a wrapper `estimatedAPR` function which gives the estimated APY in base 18 for depositing in this contract.

A 1% APY for this function would correspond to a value of 10000000000000000.

```solidity
function estimatedAPR() external view returns (uint256 apr);
```

{% hint style="info" %}
Despite the function name, this returns the **Annual Percentage Yield (APY)** based on the current inflation rate, not the Annual Percentage Rate (APR). The function name is misleading but the return value represents the compounded yield.
{% endhint %}

### **Compute Updated Assets (`computeUpdatedAssets`)**

You can anticipate (assuming the inflation rate does not change) how much you'll earn for a period of time by depositing in the contract by calling the `computeUpdatedAssets` function:

```solidity
function computeUpdatedAssets(uint256 _totalAssets, uint256 exp)
    external view returns (uint256);
```

**Parameters:**

* `_totalAssets`: Current total assets amount
* `exp`: Time period in seconds

**Returns:**

* Updated asset amount after the specified time period

### Integration Patterns

#### Basic Deposit Flow

```solidity
// 1. Get current yield information
uint256 currentAPY = savings.estimatedAPR(); // Note: function name is misleading, returns APY

// 2. Approve tokens
IERC20(underlyingAsset).approve(address(savings), depositAmount);

// 3. Deposit assets
uint256 shares = savings.deposit(depositAmount, msg.sender);

// 4. Track the deposit
emit Deposit(msg.sender, depositAmount, shares);
```

#### Withdrawal Flow

```solidity
// 1. Check current share value
uint256 totalAssets = savings.totalAssets();
uint256 totalShares = savings.totalSupply();
uint256 shareValue = totalAssets * 1e18 / totalShares;

// 2. Calculate shares needed for desired amount
uint256 sharesNeeded = (desiredAmount * 1e18) / shareValue;

// 3. Redeem shares
uint256 assetsReceived = savings.redeem(sharesNeeded, msg.sender, msg.sender);

// 4. Track the withdrawal
emit Withdrawal(msg.sender, assetsReceived, sharesNeeded);
```

#### Monitoring Interest Accrual

```solidity
// Track user's position over time
struct UserPosition {
    uint256 shares;
    uint256 depositTime;
    uint256 lastCheckpoint;
}

function getUserYield(address user) external view returns (uint256) {
    UserPosition memory position = userPositions[user];
    uint256 currentAssets = savings.totalAssets();
    uint256 currentShares = savings.totalSupply();

    // Calculate current value of user's shares
    uint256 currentValue = (position.shares * currentAssets) / currentShares;

    // Calculate original deposit value (approximate)
    uint256 originalValue = position.shares; // Assuming 1:1 at deposit

    return currentValue - originalValue;
}
```

## Rate modifications <a href="#rate-modifications" id="rate-modifications"></a>

The inflation rate in a Savings module contract is encoded by keepers whitelisted by the DAO. As such, **it is non dilutive** and does not vary as people deposit more capital or withdraw their assets.

Depending on the stablecoin and on the setup, governance may follow different update schedules. And the frequency of updates may vary from every week to every several months. Between two updates, depositors in Savings module contract are guaranteed to earn a fixed rate on their assets.
