Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Tapio Protocol

Tapio is a liquidity aggregator that acts as the middle layer between self-pegging assets and downstream DeFi applications. Liquidity is a cornerstone of DeFi and represents the most significant use case for self-pegging assets when paired with complementary tokens. However, once these assets are utilized in liquidity pools and the resulting SPA token is obtained, the journey often stalls, leaving limited options for further use. Additionally, the ecosystem faces heavy fragmentation of self-pegging asset liquidity, with individual protocols employing distinct reward mechanisms, token models, and architectures—resulting in an increasingly fragmented and inefficient landscape.

Introducing the Tapio SPA Token—the first utility-focused SPA token designed for the self-pegging asset ecosystem. Serving as both a liquidity aggregator and an arbitrage hub, it fundamentally operates as a rebasing SPA token that represents diverse stable pools within Tapio Finance. These pools include pairings between self-pegging assets and their complements, such as:

  • stETH-ETH
  • USDT-USDC
  • rETH-wstETH

Unlike traditional liquidity pools in DEXs, the Tapio SPA Token you receive after depositing assets is pegged to the underlying assets and can be seamlessly used within DeFi or as a medium of exchange, just like any other asset. The Tapio SPA Token also accrues underlying token rewards and fees generated by the pools—such as swaps, redemptions, and more—delivering an attractive real yield APR even before engaging in further DeFi activities.

For added flexibility, the Tapio SPA Token can be wrapped into a wrapped SPA token, adopting an "interest rate" model that simplifies integration and cross-chain usage.

As a synthetic asset protocol, Tapio Finance dynamically adjusts the pricing curves of self-pegging asset pools, enabling efficient swaps and arbitrage opportunities. This ensures the stability of tapETH while unlocking excellent use cases for Tapio's liquidity pools.

Overview

In Tapio, users can:

  • Create new AMM pools using Factory.
  • Mint, swap and redeem tokens in pools.
  • Wrap and unwrap SPA tokens.

The protocol is built using modular, upgradeable components and is based on CurveFi's StableSwap algorithm. This design ensuring the system can adapt and scale with evolving protocol requirements.

Contracts

Tapio uses several core contracts to facilitate management of pools and it's functionality:

SelfPeggingAssetFactory

The SelfPeggingAssetFactory contract automates the deployment of new pools, simplifying their creation and management. All pools deployed through the Factory are governed by Pike's governance system.

SelfPeggingAsset

The SelfPeggingAsset conttract represents a AMM pool. It allows users to swap, mint and redeem tokens of the pool. It implements the StableSwap algorithm.

SPAToken

The SPAToken is an ERC20 rebase token issued by StableSwap pools to liquidity providers.

SPAToken balances are dynamic and reflect the holder's share of the total SPAToken supply managed by the protocol. Since account shares are not normalized, the contract tracks the total sum of all shares to compute each account's token balance using the formula:

shares[account] * _totalSupply / _totalShares

Here, _totalSupply represents the total amount of SPAToken managed by the protocol.

WSPAToken

The WSPAToken is an ERC4626 standard token that represents an account's share of the total SPAToken supply. Unlike SPAToken, which dynamically updates balances based on staking rewards and swap fees, WSPAToken balances only change during transfers.

Designed as a "power user" token, WSPAToken caters to DeFi protocols that do not support rebasable tokens. The contract serves as a trustless wrapper, accepting SPAToken and minting WSPAToken in return. When users choose to unwrap, the contract burns their WSPAToken and returns the corresponding locked SPAToken.

Usage

This is a list of the most frequently needed commands.

Build

Build the contracts:

$ forge build

Clean

Delete the build artifacts and cache directories:

$ forge clean

Compile

Compile the contracts:

$ forge build

Coverage

Get a test coverage report:

$ forge coverage

Deploy to Testnet and Verify

Deploy to Base Testnet and automatically verify contracts:

$ forge script ./script/Testnet.s.sol -vvv --rpc-url basesepolia --broadcast --verify

Before deploying make sure you configure the neccessary variables in .env file. To just test the scripts with just a dry run remove the --broadcast flag.

Manually Verifying Contracts on Testnet Explorer

Here is an example on how to verify a contract on base sepolia:

$ forge verify-contract <contract-address> <contract-name> --watch --etherscan-api-key <basescan-api-key>  --chain-id 84532 --constructor-args <encoded-constructor-args>

You can find the contract name and constructor args in the broadcast directory. To encode the constructor args you can use: https://abi.hashex.org/

Format

Format the contracts:

$ forge fmt

Gas Usage

Get a gas report:

$ forge test --gas-report

Lint

Lint the contracts:

$ yarn run lint

Test

Run the tests:

$ forge test

Generate test coverage and output result to the terminal:

$ yarn run test:coverage

Generate test coverage with lcov report (you'll have to open the ./coverage/index.html file in your browser, to do so simply copy paste the path):

$ yarn run test:coverage:report

Scope

src/
├── SPAToken.sol
├── SelfPeggingAsset.sol
├── SelfPeggingAssetFactory.sol
├── WSPAToken.sol
├── interfaces
│   ├── IExchangeRateProvider.sol
│   └── ISPAToken.sol
├── misc
│   ├── ConstantExchangeRateProvider.sol
│   ├── ERC4626ExchangeRate.sol
│   ├── OracleExchangeRate.sol
│   └── reth
│       ├── RocketTokenExchangeRateProvider.sol
│       └── RocketTokenRETHInterface.sol
└── mock
    ├── MockERC4626Token.sol
    ├── MockExchangeRateProvider.sol
    ├── MockOracle.sol
    ├── MockToken.sol
    ├── MockTokenERC4626.sol
    └── WETH.sol

License

This project is licensed under MIT.

Contents

IExchangeRateProvider

Git Source

Author: Nuts Finance Developer

Interface for tokens with exchange rate functionality

Functions

exchangeRate

Returns the exchange rate of the token.

function exchangeRate() external view returns (uint256);

Returns

NameTypeDescription
<none>uint256The exchange rate of the token.

exchangeRateDecimals

Returns the exchange rate decimals.

function exchangeRateDecimals() external view returns (uint256);

Returns

NameTypeDescription
<none>uint256The exchange rate decimals of the token.

IKeeper

Git Source

Interface for the Keeper contract that enforces parameter bounds for curators

Functions

rampA

Allows curators to gradually ramp the A coefficient within allowed bounds

function rampA(uint256 newA, uint256 endTime) external;

Parameters

NameTypeDescription
newAuint256The target A value
endTimeuint256Timestamp when ramping should complete

setMinRampTime

Set the minimum ramp time

function setMinRampTime(uint256 newMinRampTime) external;

Parameters

NameTypeDescription
newMinRampTimeuint256is the new minimum ramp time

setSwapFee

Set the swap fee within allowed bounds

function setSwapFee(uint256 newFee) external;

Parameters

NameTypeDescription
newFeeuint256The new swap fee value

setMintFee

Set the mint fee within allowed bounds

function setMintFee(uint256 newFee) external;

Parameters

NameTypeDescription
newFeeuint256The new mint fee value

setRedeemFee

Set the redeem fee within allowed bounds

function setRedeemFee(uint256 newFee) external;

Parameters

NameTypeDescription
newFeeuint256The new redeem fee value

setOffPegFeeMultiplier

Set the off-peg fee multiplier within allowed bounds

function setOffPegFeeMultiplier(uint256 newMultiplier) external;

Parameters

NameTypeDescription
newMultiplieruint256The new off-peg fee multiplier value

setExchangeRateFeeFactor

Set the exchange rate fee within allowed bounds

function setExchangeRateFeeFactor(uint256 newFeeFactor) external;

Parameters

NameTypeDescription
newFeeFactoruint256The new exchange rate fee value

setBufferPercent

Set the buffer within allowed bounds

function setBufferPercent(uint256 newBuffer) external;

Parameters

NameTypeDescription
newBufferuint256The new buffer value

setTokenSymbol

Set the token symbol

function setTokenSymbol(string calldata newSymbol) external;

Parameters

NameTypeDescription
newSymbolstringThe new token symbol

setDecayPeriod

Set the decay period

function setDecayPeriod(uint256 newDecayPeriod) external;

Parameters

NameTypeDescription
newDecayPerioduint256The new decay period in seconds

setRateChangeSkipPeriod

Set the rate change skip period

function setRateChangeSkipPeriod(uint256 newSkipPeriod) external;

Parameters

NameTypeDescription
newSkipPerioduint256The new skip period in seconds

updateFeeErrorMargin

Set the fee error margin within allowed bounds

function updateFeeErrorMargin(uint256 newMargin) external;

Parameters

NameTypeDescription
newMarginuint256The new fee error margin value

updateYieldErrorMargin

Set the yield error margin within allowed bounds

function updateYieldErrorMargin(uint256 newMargin) external;

Parameters

NameTypeDescription
newMarginuint256The new yield error margin value

distributeLoss

Distribute any losses incurred

function distributeLoss() external;

pause

Pause the SPA

function pause() external;

unpause

Unpause the SPA

function unpause() external;

cancelRamp

Allows guardians to cancel an ongoing A ramp in emergencies

function cancelRamp() external;

getRegistry

Get the parameter registry used for bounds checking

function getRegistry() external view returns (IParameterRegistry);

Returns

NameTypeDescription
<none>IParameterRegistryThe parameter registry address

getRampAController

Get the RampAController being managed

function getRampAController() external view returns (IRampAController);

Returns

NameTypeDescription
<none>IRampAControllerThe RampAController address

getSpa

Get the SelfPeggingAsset being managed

function getSpa() external view returns (SelfPeggingAsset);

Returns

NameTypeDescription
<none>SelfPeggingAssetThe SelfPeggingAsset address

getSpaToken

Get the SPA token being managed

function getSpaToken() external view returns (SPAToken);

Returns

NameTypeDescription
<none>SPATokenThe SPA token address

Events

RampAInitiated

event RampAInitiated(uint256 oldA, uint256 newA, uint256 endTime);

MinRampTimeUpdated

event MinRampTimeUpdated(uint256 oldTime, uint256 newTime);

SwapFeeUpdated

event SwapFeeUpdated(uint256 oldFee, uint256 newFee);

MintFeeUpdated

event MintFeeUpdated(uint256 oldFee, uint256 newFee);

RedeemFeeUpdated

event RedeemFeeUpdated(uint256 oldFee, uint256 newFee);

OffPegFeeMultiplierUpdated

event OffPegFeeMultiplierUpdated(uint256 oldMultiplier, uint256 newMultiplier);

ExchangeRateFeeFactorUpdated

event ExchangeRateFeeFactorUpdated(uint256 oldFactor, uint256 newFactor);

BufferPercentUpdated

event BufferPercentUpdated(uint256 oldBuffer, uint256 newBuffer);

TokenSymbolUpdated

event TokenSymbolUpdated(string oldSymbol, string newSymbol);

DecayPeriodUpdated

event DecayPeriodUpdated(uint256 oldPeriod, uint256 newPeriod);

RateChangeSkipPeriodUpdated

event RateChangeSkipPeriodUpdated(uint256 oldPeriod, uint256 newPeriod);

FeeErrorMarginUpdated

event FeeErrorMarginUpdated(uint256 oldMargin, uint256 newMargin);

YieldErrorMarginUpdated

event YieldErrorMarginUpdated(uint256 oldMargin, uint256 newMargin);

LossDistributed

event LossDistributed();

ProtocolPaused

event ProtocolPaused();

ProtocolUnpaused

event ProtocolUnpaused();

RampCancelled

event RampCancelled();

TreasuryChanged

event TreasuryChanged(address indexed oldTreasury, address indexed newTreasury);

AdminFeeWithdrawn

event AdminFeeWithdrawn(address indexed to, uint256 amount, uint256 bufferLeft);

IParameterRegistry

Git Source

Functions

setBounds

Updates the bounds for a specific parameter.

Only callable by an authorized governor.

function setBounds(ParamKey key, Bounds calldata newBounds) external;

Parameters

NameTypeDescription
keyParamKeyThe parameter key to update.
newBoundsBoundsThe new bounds structure to apply.

aParams

function aParams() external view returns (Bounds memory);

Returns

NameTypeDescription
<none>BoundsBounds for the 'A' coefficient parameter

swapFeeParams

function swapFeeParams() external view returns (Bounds memory);

Returns

NameTypeDescription
<none>BoundsBounds for the swap fee

mintFeeParams

function mintFeeParams() external view returns (Bounds memory);

Returns

NameTypeDescription
<none>BoundsBounds for the mint fee

redeemFeeParams

function redeemFeeParams() external view returns (Bounds memory);

Returns

NameTypeDescription
<none>BoundsBounds for the redeem fee

offPegParams

function offPegParams() external view returns (Bounds memory);

Returns

NameTypeDescription
<none>BoundsBounds for the off-peg multiplier

exchangeRateFeeParams

function exchangeRateFeeParams() external view returns (Bounds memory);

Returns

NameTypeDescription
<none>BoundsBounds for exchange rate fee changes

decayPeriodParams

function decayPeriodParams() external view returns (Bounds memory);

Returns

NameTypeDescription
<none>BoundsBounds for decay period

rateChangeSkipPeriodParams

function rateChangeSkipPeriodParams() external view returns (Bounds memory);

Returns

NameTypeDescription
<none>BoundsBounds for the rate change skip period

feeErrorMarginParams

function feeErrorMarginParams() external view returns (Bounds memory);

Returns

NameTypeDescription
<none>BoundsBounds for the fee error margin

yieldErrorMarginParams

function yieldErrorMarginParams() external view returns (Bounds memory);

Returns

NameTypeDescription
<none>BoundsBounds for the yield error margin

minRampTimeParams

function minRampTimeParams() external view returns (Bounds memory);

Returns

NameTypeDescription
<none>BoundsBounds for the minimum ramp time

bufferPercentParams

function bufferPercentParams() external view returns (Bounds memory);

Returns

NameTypeDescription
<none>BoundsBounds for the buffer percentage

Events

BoundsUpdated

Emitted when parameter bounds are updated.

event BoundsUpdated(ParamKey key, Bounds oldParams, Bounds newParams);

Parameters

NameTypeDescription
keyParamKeyThe parameter key that was updated.
oldParamsBoundsThe old bounds before the update.
newParamsBoundsThe new bounds after the update.

Errors

ZeroAddress

error ZeroAddress();

Structs

Bounds

Structure representing bounds for a given parameter.

All percentages are expressed in parts-per-million (ppm), i.e., 1e6 = 100%.

struct Bounds {
    uint256 max;
    uint256 min;
    uint64 maxDecreasePct;
    uint64 maxIncreasePct;
}

Properties

NameTypeDescription
maxuint256The maximum hard cap for the parameter value in parameter format.
minuint256The minimum hard cap for the parameter value in parameter format.
maxDecreasePctuint64The maximum decrease allowed per transaction with 1e10 decimal, e.g., 9e9 = -90%.
maxIncreasePctuint64The maximum increase allowed per transaction with 1e10 decimal, e.g., 9e9 = +90%.

Enums

ParamKey

Unique keys identifying different parameter types.

enum ParamKey {
    A,
    SwapFee,
    MintFee,
    RedeemFee,
    OffPeg,
    ExchangeRateFee,
    DecayPeriod,
    RateChangeSkipPeriod,
    FeeErrorMargin,
    YieldErrorMargin,
    MinRampTime,
    BufferPercent
}

IRampAController

Git Source

Interface for the RampAController contract that manages gradual A parameter changes

Functions

setMinRampTime

Sets a new minimum ramp time for A changes

function setMinRampTime(uint256 _newMinRampTime) external;

Parameters

NameTypeDescription
_newMinRampTimeuint256New minimum ramp time in seconds

rampA

Initiates the ramping of A from current value to the target over the specified duration

function rampA(uint256 _futureA, uint256 _futureTime) external;

Parameters

NameTypeDescription
_futureAuint256Target A value
_futureTimeuint256Timestamp when ramping should complete

stopRamp

Stops an ongoing ramp and freezes A at the current value

function stopRamp() external;

minRampTime

Returns the current minimum ramp time required for A changes

function minRampTime() external view returns (uint256);

getA

Returns the current A value based on the ongoing ramp progress or the static value if no ramp

function getA() external view returns (uint256);

Returns

NameTypeDescription
<none>uint256The current A value

isRamping

Checks if the controller is currently in a ramping state

function isRamping() external view returns (bool);

Returns

NameTypeDescription
<none>boolTrue if ramping, false otherwise

initialA

Returns the initial A value for the current/most recent ramp

function initialA() external view returns (uint256);

Returns

NameTypeDescription
<none>uint256The initial A value

futureA

Returns the target A value for the current/most recent ramp

function futureA() external view returns (uint256);

Returns

NameTypeDescription
<none>uint256The target A value

initialATime

Returns the timestamp when the current/most recent ramp started

function initialATime() external view returns (uint256);

Returns

NameTypeDescription
<none>uint256The timestamp

futureATime

Returns the timestamp when the current/most recent ramp will/did complete

function futureATime() external view returns (uint256);

Returns

NameTypeDescription
<none>uint256The timestamp

ISPAToken

Git Source

Inherits: IERC20

Author: Nuts Finance Developer

Interface for SPAToken

Functions

increaseAllowance

Increase the allowance of the spender

function increaseAllowance(address _spender, uint256 _addedValue) external returns (bool);

decreaseAllowance

Decrease the allowance of the spender

function decreaseAllowance(address _spender, uint256 _subtractedValue) external returns (bool);

addTotalSupply

Add the amount to the total supply

function addTotalSupply(uint256 _amount) external;

removeTotalSupply

Remove the amount from the total supply

function removeTotalSupply(uint256 _amount, bool isBuffer, bool withDebt) external;

transferShares

Transfer the shares to the recipient

function transferShares(address _recipient, uint256 _sharesAmount) external returns (uint256);

transferSharesFrom

Transfer the shares from the sender to the recipient

function transferSharesFrom(address _sender, address _recipient, uint256 _sharesAmount) external returns (uint256);

mintShares

Mint the shares to the account

function mintShares(address _account, uint256 _sharesAmount) external;

burnShares

Burn the shares from the account

function burnShares(uint256 _sharesAmount) external;

burnSharesFrom

Burn the shares from the account

function burnSharesFrom(address _account, uint256 _sharesAmount) external;

addBuffer

function addBuffer(uint256 _amount, bool withDebt) external;

withdrawBuffer

function withdrawBuffer(address _to, uint256 _amount) external;

name

Name of the token

function name() external view returns (string memory);

symbol

Symbol of the token

function symbol() external view returns (string memory);

totalShares

Get the total amount of shares

function totalShares() external view returns (uint256);

totalRewards

Get the total amount of rewards

function totalRewards() external view returns (uint256);

sharesOf

Get the total shares of the account

function sharesOf(address _account) external view returns (uint256);

getSharesByPeggedToken

Get the shares corresponding to the amount of pooled eth

function getSharesByPeggedToken(uint256 _ethAmount) external view returns (uint256);

getPeggedTokenByShares

Add the amount of Eth corresponding to the shares

function getPeggedTokenByShares(uint256 _sharesAmount) external view returns (uint256);

IZap

Git Source

Interface for Zap contract

Defines functions to add and remove liquidity with wrapping/unwrapping in one transaction

Functions

zapIn

Add liquidity to SPA and automatically wrap SPA tokens

function zapIn(
    address spa,
    address wspa,
    address receiver,
    uint256 minMintAmount,
    uint256[] calldata amounts
)
    external
    returns (uint256 wspaAmount);

Parameters

NameTypeDescription
spaaddressAddress of the SPA contract
wspaaddressAddress of the wrapped SPA token contract
receiveraddressAddress to receive the wrapped SPA tokens
minMintAmountuint256Minimum amount of SPA tokens to receive
amountsuint256[]Array of token amounts to add

Returns

NameTypeDescription
wspaAmountuint256Amount of wrapped SPA tokens minted

zapOut

Remove liquidity from SPA by unwrapping SPA tokens first

function zapOut(
    address spa,
    address wspa,
    address receiver,
    uint256 wspaAmount,
    uint256[] calldata minAmountsOut,
    bool proportional
)
    external
    returns (uint256[] memory amounts);

Parameters

NameTypeDescription
spaaddressAddress of the SPA contract
wspaaddressAddress of the wrapped SPA token contract
receiveraddressAddress to receive the tokens
wspaAmountuint256Amount of wrapped SPA tokens to redeem
minAmountsOutuint256[]Minimum amounts of tokens to receive
proportionalboolIf true, withdraws proportionally; if false, uses minAmountsOut

Returns

NameTypeDescription
amountsuint256[]Array of token amounts received

zapOutSingle

Unwrap wSPA tokens and redeem a single asset

function zapOutSingle(
    address spa,
    address wspa,
    address receiver,
    uint256 wspaAmount,
    uint256 tokenIndex,
    uint256 minAmountOut
)
    external
    returns (uint256 amount);

Parameters

NameTypeDescription
spaaddressAddress of the SPA contract
wspaaddressAddress of the wrapped SPA token contract
receiveraddressAddress to receive the tokens
wspaAmountuint256Amount of wrapped SPA tokens to redeem
tokenIndexuint256Index of the token to receive
minAmountOutuint256Minimum amount of token to receive

Returns

NameTypeDescription
amountuint256Amount of token received

Events

ZapIn

event ZapIn(
    address indexed spa, address indexed user, address indexed receiver, uint256 wspaAmount, uint256[] inputAmounts
);

ZapOut

event ZapOut(
    address indexed spa,
    address indexed user,
    address indexed receiver,
    uint256 wspaAmount,
    uint256[] outputAmounts,
    bool proportional
);

Contents

Contents

RocketTokenExchangeRateProvider

Git Source

Inherits: IExchangeRateProvider, Initializable, ReentrancyGuardUpgradeable

Rocket Token exchange rate.

State Variables

rocketToken

Rocket Token contract

RocketTokenRETHInterface private rocketToken;

Functions

initialize

Initialize the contract

function initialize(RocketTokenRETHInterface _rocketToken) public initializer;

exchangeRate

Get the exchange rate

function exchangeRate() external view returns (uint256);

exchangeRateDecimals

Get the exchange rate decimals

function exchangeRateDecimals() external pure returns (uint256);

Errors

RocketTokenNotSet

Error thrown when the Rocket Token is not set

error RocketTokenNotSet();

RocketTokenRETHInterface

Git Source

Inherits: IERC20

Functions

getExchangeRate

Get the exchange rate

function getExchangeRate() external view returns (uint256);

ChainlinkCompositeOracleProvider

Git Source

State Variables

PRECISION

Fixed-point precision for internal calculations

uint256 private constant PRECISION = 1e36;

GRACE_PERIOD_TIME

Grace period time after the sequencer is back up

uint256 private constant GRACE_PERIOD_TIME = 3600;

sequencerUptimeFeed

Chainlink feed for the sequencer uptime

AggregatorV3Interface public immutable sequencerUptimeFeed;

configs

Array of 3 configs

Config[] public configs;

Functions

constructor

Contract constructor

constructor(AggregatorV3Interface _sequencerUptimeFeed, Config[] memory _configs);

Parameters

NameTypeDescription
_sequencerUptimeFeedAggregatorV3InterfaceL2 Sequencer uptime feed
_configsConfig[]Array of configs for feeds

price

Get the price of the asset

function price() external view returns (uint256);

Returns

NameTypeDescription
<none>uint256Price of the asset

decimals

Get the decimals of the price

function decimals() external view returns (uint256);

Returns

NameTypeDescription
<none>uint256Decimals of the price

_getCurrentDecimals

Get the current decimals of a config

function _getCurrentDecimals(Config memory config) internal view returns (uint256);

Parameters

NameTypeDescription
configConfigThe config to get decimals for

Returns

NameTypeDescription
<none>uint256The current decimals value

_validateSequencerStatus

Validate the sequencer status

function _validateSequencerStatus() internal view;

Errors

InvalidFeed

Error emitted when feed is invalid

error InvalidFeed();

InvalidStalePeriod

Error emitted when stale period is invalid

error InvalidStalePeriod();

StalePrice

Error emitted when price is stale

error StalePrice();

SequencerDown

Error emitted when sequencer is down

error SequencerDown();

GracePeriodNotOver

Error emitted when grace period is not over

error GracePeriodNotOver();

InvalidFeedPrice

Error emitted when price from feed is invalid

error InvalidFeedPrice();

Structs

Config

struct Config {
    AggregatorV3Interface feed;
    uint256 maxStalePeriod;
    uint256 assetDecimals;
    bool isInverted;
}

ChainlinkOracleProvider

Git Source

State Variables

GRACE_PERIOD_TIME

Grace period time after the sequencer is back up

uint256 private constant GRACE_PERIOD_TIME = 3600;

sequencerUptimeFeed

Chainlink feed for the sequencer uptime

AggregatorV3Interface public immutable sequencerUptimeFeed;

feed

Chainlink feed for the asset

AggregatorV3Interface public immutable feed;

maxStalePeriod

Maximum stale period for the price feed

uint256 public immutable maxStalePeriod;

Functions

constructor

Contract constructor

constructor(AggregatorV3Interface _sequencerUptimeFeed, AggregatorV3Interface _feed, uint256 _maxStalePeriod);

Parameters

NameTypeDescription
_sequencerUptimeFeedAggregatorV3InterfaceL2 Sequencer uptime feed
_feedAggregatorV3Interface
_maxStalePerioduint256

price

Get the price of the asset

function price() external view returns (uint256);

Returns

NameTypeDescription
<none>uint256Price of the asset

decimals

Get the decimals of the price

function decimals() external view returns (uint256);

Returns

NameTypeDescription
<none>uint256Decimals of the price

_validateSequencerStatus

Validate the sequencer status

function _validateSequencerStatus() internal view;

Errors

InvalidFeed

Error emitted when feed is invalid

error InvalidFeed();

InvalidStalePeriod

Error emitted when stale period is invalid

error InvalidStalePeriod();

StalePrice

Error emitted when price is stale

error StalePrice();

SequencerDown

Error emitted when sequencer is down

error SequencerDown();

GracePeriodNotOver

Error emitted when grace period is not over

error GracePeriodNotOver();

ConstantExchangeRateProvider

Git Source

Inherits: IExchangeRateProvider

Constant exchange rate provider.

Functions

exchangeRate

Get the exchange rate

function exchangeRate() external pure returns (uint256);

exchangeRateDecimals

Get the exchange rate decimals

function exchangeRateDecimals() external pure returns (uint256);

ERC4626ExchangeRate

Git Source

Inherits: IExchangeRateProvider

ERC4626 exchange rate.

State Variables

token

ERC4626 token

IERC4626 public token;

Functions

constructor

Initialize the contract

constructor(IERC4626 _token);

exchangeRate

Get the exchange rate

function exchangeRate() external view returns (uint256);

exchangeRateDecimals

Get the exchange rate decimals

function exchangeRateDecimals() external view returns (uint256);

OracleExchangeRate

Git Source

Inherits: IExchangeRateProvider

Oracle exchange rate.

State Variables

oracle

Oracle address

address public oracle;

rateFunc

Rate function signature

bytes public rateFunc;

decimalsFunc

Decimals function signature

bytes public decimalsFunc;

Functions

constructor

Initialize the contract

constructor(address _oracle, bytes memory _rateFunc, bytes memory _decimalsFunc);

exchangeRate

Get the exchange rate

function exchangeRate() external view returns (uint256);

exchangeRateDecimals

Get the exchange rate decimals

function exchangeRateDecimals() external view returns (uint256);

Errors

InternalCallFailed

Error thrown when the internal call failed

error InternalCallFailed();

Contents

MockChainlinkV3Aggregator

Git Source

Inherits: AggregatorV3Interface

State Variables

_decimals

uint8 private _decimals;

_answer

int256 private _answer;

_answeredInRound

uint80 private _answeredInRound;

Functions

constructor

constructor(uint8 decimals_, int256 answer_, uint80 answeredInRound_);

decimals

function decimals() external view override returns (uint8);

description

function description() external pure override returns (string memory);

version

function version() external pure override returns (uint256);

getRoundData

function getRoundData(uint80 _roundId)
    external
    view
    override
    returns (uint80 roundId, int256 answer, uint256 startedAt, uint256 updatedAt, uint80 answeredInRound);

latestRoundData

function latestRoundData()
    external
    view
    override
    returns (uint80 roundId, int256 answer, uint256 startedAt, uint256 updatedAt, uint80 answeredInRound);

MockERC4626Token

Git Source

Inherits: ERC4626Upgradeable

Functions

initialize

function initialize(IERC20 token) public initializer;

MockExchangeRateProvider

Git Source

Inherits: IExchangeRateProvider

Mock exchange rate.

State Variables

rate

uint256 private rate;

decimals

uint256 private decimals;

Functions

constructor

constructor(uint256 _rate, uint256 _decimals);

newRate

function newRate(uint256 _rate) external;

exchangeRate

function exchangeRate() external view returns (uint256);

exchangeRateDecimals

function exchangeRateDecimals() external view returns (uint256);

setExchangeRate

function setExchangeRate(uint256 _rate) external;

MockOracle

Git Source

State Variables

_rate

uint256 internal _rate = 1e18;

Functions

setRate

function setRate(uint256 newRate) external;

rate

function rate() external view returns (uint256);

decimals

function decimals() external pure returns (uint256);

MockToken

Git Source

Inherits: ERC20

Mock ERC20 token.

State Variables

_dec

uint8 private _dec;

Functions

constructor

constructor(string memory _name, string memory _symbol, uint8 _decimals) ERC20(_name, _symbol);

mint

function mint(address account, uint256 amount) public;

burn

function burn(address account, uint256 amount) public;

decimals

function decimals() public view override returns (uint8);

MockTokenERC4626

Git Source

Inherits: ERC20

Mock ERC20 token.

State Variables

_dec

uint8 private _dec;

Functions

constructor

constructor(string memory _name, string memory _symbol, uint8 _decimals) ERC20(_name, _symbol);

mint

function mint(address account, uint256 amount) public;

burn

function burn(address account, uint256 amount) public;

decimals

function decimals() public view override returns (uint8);

totalAssets

function totalAssets() public view returns (uint256);

WETH9

Git Source

State Variables

name

string public name = "Wrapped Ether";

symbol

string public symbol = "WETH";

decimals

uint8 public decimals = 18;

balanceOf

mapping(address => uint256) public balanceOf;

allowance

mapping(address => mapping(address => uint256)) public allowance;

Functions

deposit

function deposit() public payable;

withdraw

function withdraw(uint256 wad) public;

totalSupply

function totalSupply() public view returns (uint256);

approve

function approve(address guy, uint256 wad) public returns (bool);

transfer

function transfer(address dst, uint256 wad) public returns (bool);

transferFrom

function transferFrom(address src, address dst, uint256 wad) public returns (bool);

Events

Approval

event Approval(address indexed src, address indexed guy, uint256 wad);

Transfer

event Transfer(address indexed src, address indexed dst, uint256 wad);

Deposit

event Deposit(address indexed dst, uint256 wad);

Withdrawal

event Withdrawal(address indexed src, uint256 wad);

Errors

InsufficientBalance

error InsufficientBalance();

NoAllowance

error NoAllowance();

Contents

Keeper

Git Source

Inherits: AccessControlUpgradeable, UUPSUpgradeable, IKeeper

Follows Tapio Governance model

Fast-path executor that lets curators adjust parameters within bounds enforced by ParameterRegistry

UUPS upgradeable. Governor is admin, curator and guardian are roles.

State Variables

DENOMINATOR

This is the denominator used for formatting ranges

uint256 private constant DENOMINATOR = 1e10;

PROTOCOL_OWNER_ROLE

bytes32 public constant PROTOCOL_OWNER_ROLE = keccak256("PROTOCOL_OWNER_ROLE");

CURATOR_ROLE

bytes32 public constant CURATOR_ROLE = keccak256("CURATOR_ROLE");

GUARDIAN_ROLE

bytes32 public constant GUARDIAN_ROLE = keccak256("GUARDIAN_ROLE");

GOVERNOR_ROLE

bytes32 public constant GOVERNOR_ROLE = keccak256("GOVERNOR_ROLE");

registry

IParameterRegistry private registry;

rampAController

IRampAController private rampAController;

spa

SelfPeggingAsset private spa;

spaToken

SPAToken private spaToken;

treasury

address public treasury;

Functions

constructor

Note: oz-upgrades-unsafe-allow: constructor

constructor();

initialize

function initialize(
    address _owner,
    address _governor,
    address _curator,
    address _guardian,
    IParameterRegistry _registry,
    IRampAController _rampAController,
    SelfPeggingAsset _spa,
    SPAToken _spaToken
)
    public
    initializer;

rampA

Allows curators to gradually ramp the A coefficient within allowed bounds

function rampA(uint256 newA, uint256 endTime) external override onlyRole(CURATOR_ROLE);

Parameters

NameTypeDescription
newAuint256The target A value
endTimeuint256Timestamp when ramping should complete

setMinRampTime

Set the minimum ramp time

function setMinRampTime(uint256 newMinRampTime) external override onlyRole(GOVERNOR_ROLE);

Parameters

NameTypeDescription
newMinRampTimeuint256is the new minimum ramp time

setSwapFee

Set the swap fee within allowed bounds

function setSwapFee(uint256 newFee) external override onlyRole(GOVERNOR_ROLE);

Parameters

NameTypeDescription
newFeeuint256The new swap fee value

setMintFee

Set the mint fee within allowed bounds

function setMintFee(uint256 newFee) external override onlyRole(GOVERNOR_ROLE);

Parameters

NameTypeDescription
newFeeuint256The new mint fee value

setRedeemFee

Set the redeem fee within allowed bounds

function setRedeemFee(uint256 newFee) external override onlyRole(GOVERNOR_ROLE);

Parameters

NameTypeDescription
newFeeuint256The new redeem fee value

cancelRamp

Allows guardians to cancel an ongoing A ramp in emergencies

function cancelRamp() external override onlyRole(GUARDIAN_ROLE);

setOffPegFeeMultiplier

Set the off-peg fee multiplier within allowed bounds

function setOffPegFeeMultiplier(uint256 newMultiplier) external override onlyRole(GOVERNOR_ROLE);

Parameters

NameTypeDescription
newMultiplieruint256The new off-peg fee multiplier value

setExchangeRateFeeFactor

Set the exchange rate fee within allowed bounds

function setExchangeRateFeeFactor(uint256 newFeeFactor) external override onlyRole(GOVERNOR_ROLE);

Parameters

NameTypeDescription
newFeeFactoruint256The new exchange rate fee value

setBufferPercent

Set the buffer within allowed bounds

function setBufferPercent(uint256 newBuffer) external override onlyRole(GOVERNOR_ROLE);

Parameters

NameTypeDescription
newBufferuint256The new buffer value

setTokenSymbol

Set the token symbol

function setTokenSymbol(string calldata newSymbol) external override onlyRole(GOVERNOR_ROLE);

Parameters

NameTypeDescription
newSymbolstringThe new token symbol

setDecayPeriod

Set the decay period

function setDecayPeriod(uint256 newDecayPeriod) external override onlyRole(GOVERNOR_ROLE);

Parameters

NameTypeDescription
newDecayPerioduint256The new decay period in seconds

setRateChangeSkipPeriod

Set the rate change skip period

function setRateChangeSkipPeriod(uint256 newSkipPeriod) external override onlyRole(GOVERNOR_ROLE);

Parameters

NameTypeDescription
newSkipPerioduint256The new skip period in seconds

updateFeeErrorMargin

Set the fee error margin within allowed bounds

function updateFeeErrorMargin(uint256 newMargin) external override onlyRole(GOVERNOR_ROLE);

Parameters

NameTypeDescription
newMarginuint256The new fee error margin value

updateYieldErrorMargin

Set the yield error margin within allowed bounds

function updateYieldErrorMargin(uint256 newMargin) external override onlyRole(GOVERNOR_ROLE);

Parameters

NameTypeDescription
newMarginuint256The new yield error margin value

distributeLoss

Distribute any losses incurred

function distributeLoss() external override onlyRole(GOVERNOR_ROLE);

setTreasury

Set treasury address that will receive withdrawn SPA tokens from Buffer

function setTreasury(address newTreasury) external onlyRole(GOVERNOR_ROLE);

withdrawAdminFee

Withdraw Buffer through SPAToken and send newly-minted SPA tokens to Treasury

function withdrawAdminFee(uint256 amount) external onlyRole(GOVERNOR_ROLE);

Parameters

NameTypeDescription
amountuint256Amount of tokens to withdraw (18-decimals)

pause

Pause the SPA

function pause() external override onlyRole(GUARDIAN_ROLE);

unpause

Unpause the SPA

function unpause() external override onlyRole(PROTOCOL_OWNER_ROLE);

getRegistry

Get the parameter registry used for bounds checking

function getRegistry() external view override returns (IParameterRegistry);

Returns

NameTypeDescription
<none>IParameterRegistryThe parameter registry address

getRampAController

Get the RampAController being managed

function getRampAController() external view override returns (IRampAController);

Returns

NameTypeDescription
<none>IRampAControllerThe RampAController address

getSpa

Get the SelfPeggingAsset being managed

function getSpa() external view override returns (SelfPeggingAsset);

Returns

NameTypeDescription
<none>SelfPeggingAssetThe SelfPeggingAsset address

getSpaToken

Get the SPA token being managed

function getSpaToken() external view override returns (SPAToken);

Returns

NameTypeDescription
<none>SPATokenThe SPA token address

_authorizeUpgrade

Authorisation to upgrade the implementation of the contract.

function _authorizeUpgrade(address) internal override onlyRole(PROTOCOL_OWNER_ROLE);

checkBounds

Validates if new value is within both absolute and relative bounds

function checkBounds(uint256 newValue, uint256 currentValue, IParameterRegistry.Bounds memory bounds) internal pure;

Parameters

NameTypeDescription
newValueuint256The new value to check
currentValueuint256The current value for relative bounds checking
boundsIParameterRegistry.BoundsThe bounds object containing min, max, and relative change limits

checkRange

Checks if new value is within the allowed relative change from current value

function checkRange(uint256 newValue, uint256 currentValue, IParameterRegistry.Bounds memory bounds) internal pure;

Parameters

NameTypeDescription
newValueuint256The new value to check
currentValueuint256The current value to compare against
boundsIParameterRegistry.BoundsThe bounds object containing relative change limits

Errors

ZeroAddress

error ZeroAddress();

OutOfBounds

error OutOfBounds();

DeltaTooBig

error DeltaTooBig();

RelativeRangeNotSet

error RelativeRangeNotSet();

WrongSymbol

error WrongSymbol();

ParameterRegistry

Git Source

Inherits: IParameterRegistry, Ownable

Stores hard caps and per-transaction relative ranges that bound keeper operations.

Only the Governor (admin role) can modify values. Each SPA has its own ParameterRegistry

State Variables

MIN_MULTIPLIER

uint256 private constant MIN_MULTIPLIER = 1e10;

MAX_A

uint256 private constant MAX_A = 10 ** 6;

MAX_DECREASE_PCT_A

uint64 private constant MAX_DECREASE_PCT_A = 0.9e10;

MAX_INCREASE_PCT_A

uint64 private constant MAX_INCREASE_PCT_A = 9e10;

spa

SPA this registry is connected

SelfPeggingAsset public spa;

bounds

mapping(ParamKey => Bounds) public bounds;

Functions

constructor

constructor(address _governor, address _spa) Ownable(_governor);

setBounds

Updates the bounds for a specific parameter.

Only callable by an authorized governor.

function setBounds(ParamKey key, Bounds calldata newBounds) external onlyOwner;

Parameters

NameTypeDescription
keyParamKeyThe parameter key to update.
newBoundsBoundsThe new bounds structure to apply.

aParams

function aParams() external view returns (Bounds memory);

Returns

NameTypeDescription
<none>BoundsBounds for the 'A' coefficient parameter

swapFeeParams

function swapFeeParams() external view returns (Bounds memory);

Returns

NameTypeDescription
<none>BoundsBounds for the swap fee

mintFeeParams

function mintFeeParams() external view returns (Bounds memory);

Returns

NameTypeDescription
<none>BoundsBounds for the mint fee

redeemFeeParams

function redeemFeeParams() external view returns (Bounds memory);

Returns

NameTypeDescription
<none>BoundsBounds for the redeem fee

offPegParams

function offPegParams() external view returns (Bounds memory);

Returns

NameTypeDescription
<none>BoundsBounds for the off-peg multiplier

exchangeRateFeeParams

function exchangeRateFeeParams() external view returns (Bounds memory);

Returns

NameTypeDescription
<none>BoundsBounds for exchange rate fee changes

decayPeriodParams

function decayPeriodParams() external view returns (Bounds memory);

Returns

NameTypeDescription
<none>BoundsBounds for decay period

rateChangeSkipPeriodParams

function rateChangeSkipPeriodParams() external view returns (Bounds memory);

Returns

NameTypeDescription
<none>BoundsBounds for the rate change skip period

feeErrorMarginParams

function feeErrorMarginParams() external view returns (Bounds memory);

Returns

NameTypeDescription
<none>BoundsBounds for the fee error margin

yieldErrorMarginParams

function yieldErrorMarginParams() external view returns (Bounds memory);

Returns

NameTypeDescription
<none>BoundsBounds for the yield error margin

minRampTimeParams

function minRampTimeParams() external view returns (Bounds memory);

Returns

NameTypeDescription
<none>BoundsBounds for the minimum ramp time

bufferPercentParams

function bufferPercentParams() external view returns (Bounds memory);

Returns

NameTypeDescription
<none>BoundsBounds for the buffer percentage

RampAController

Git Source

Inherits: IRampAController, Initializable, OwnableUpgradeable

Contract for managing gradual changes to A coeff (A) parameter Allows for smooth transitions between different A values.

State Variables

MAX_A

uint256 private constant MAX_A = 10 ** 6;

DEFAULT_RAMP_TIME

uint256 private constant DEFAULT_RAMP_TIME = 30 minutes;

initialA

uint256 public override initialA;

futureA

uint256 public override futureA;

initialATime

uint256 public override initialATime;

futureATime

uint256 public override futureATime;

minRampTime

uint256 public minRampTime;

Functions

constructor

constructor();

initialize

Initializer for RampAController

function initialize(uint256 _initialA, uint256 _minRampTime, address _owner) external initializer;

Parameters

NameTypeDescription
_initialAuint256is the initial value of A
_minRampTimeuint256is min ramp time
_owneraddressis the address of the owner

setMinRampTime

Set the minimum ramp time (default is 30 minutes)

function setMinRampTime(uint256 _minRampTime) external onlyOwner;

Parameters

NameTypeDescription
_minRampTimeuint256is the new minimum ramp time

rampA

Initiate a ramp to a new A value

function rampA(uint256 _futureA, uint256 _futureTime) external override onlyOwner;

Parameters

NameTypeDescription
_futureAuint256is the target value of A
_futureTimeuint256is UNIX timestamp when the ramp should complete

stopRamp

Force-stop ramping A coeff

function stopRamp() external override onlyOwner;

isRamping

Check if ramping in progress

function isRamping() external view override returns (bool);

Returns

NameTypeDescription
<none>booltrue if it is, false otherwise

getA

Public getter which is used in SPA

function getA() public view override returns (uint256);

Returns

NameTypeDescription
<none>uint256the current value of A coeff

Events

RampInitiated

event RampInitiated(uint256 initialA, uint256 futureA, uint256 initialATime, uint256 futureATime);

RampStopped

event RampStopped(uint256 currentA);

MinRampTimeUpdated

event MinRampTimeUpdated(uint256 oldValue, uint256 newValue);

Errors

InvalidFutureTime

error InvalidFutureTime();

RampAlreadyInProgress

error RampAlreadyInProgress();

NoOngoingRamp

error NoOngoingRamp();

AOutOfBounds

error AOutOfBounds();

InsufficientRampTime

error InsufficientRampTime();

Unauthorized

error Unauthorized();

Zap

Git Source

Inherits: IZap, ReentrancyGuard

A helper contract to simplify liquidity provision and removal in Tapio

Allows users to add/remove liquidity with automatic wrapping/unwrapping in 1 tx

SPA and wSPA addresses are passed as parameters to each function

Functions

zapIn

Add liquidity to SPA and automatically wrap SPA tokens

function zapIn(
    address spa,
    address wspa,
    address receiver,
    uint256 minMintAmount,
    uint256[] calldata amounts
)
    external
    nonReentrant
    returns (uint256 wspaAmount);

Parameters

NameTypeDescription
spaaddressAddress of the SPA contract
wspaaddressAddress of the wrapped SPA token contract
receiveraddressAddress to receive the wrapped SPA tokens
minMintAmountuint256Minimum amount of SPA tokens to receive
amountsuint256[]Array of token amounts to add

Returns

NameTypeDescription
wspaAmountuint256Amount of wrapped SPA tokens minted

zapOut

Remove liquidity from SPA by unwrapping SPA tokens first

function zapOut(
    address spa,
    address wspa,
    address receiver,
    uint256 wspaAmount,
    uint256[] calldata minAmountsOut,
    bool proportional
)
    external
    nonReentrant
    returns (uint256[] memory amounts);

Parameters

NameTypeDescription
spaaddressAddress of the SPA contract
wspaaddressAddress of the wrapped SPA token contract
receiveraddressAddress to receive the tokens
wspaAmountuint256Amount of wrapped SPA tokens to redeem
minAmountsOutuint256[]Minimum amounts of tokens to receive
proportionalboolIf true, withdraws proportionally; if false, uses minAmountsOut

Returns

NameTypeDescription
amountsuint256[]Array of token amounts received

zapOutSingle

Unwrap wSPA tokens and redeem a single asset

function zapOutSingle(
    address spa,
    address wspa,
    address receiver,
    uint256 wspaAmount,
    uint256 tokenIndex,
    uint256 minAmountOut
)
    external
    nonReentrant
    returns (uint256 amount);

Parameters

NameTypeDescription
spaaddressAddress of the SPA contract
wspaaddressAddress of the wrapped SPA token contract
receiveraddressAddress to receive the tokens
wspaAmountuint256Amount of wrapped SPA tokens to redeem
tokenIndexuint256Index of the token to receive
minAmountOutuint256Minimum amount of token to receive

Returns

NameTypeDescription
amountuint256Amount of token received

_mint

Call SPA's mint function

function _mint(address spa, uint256[] calldata amounts, uint256 minMintAmount) internal returns (uint256);

_deposit

Call WSPAToken's deposit function

function _deposit(address wspa, uint256 assets, address receiver) internal returns (uint256);

_redeem

Call WSPAToken's redeem function

function _redeem(address wspa, uint256 shares, address receiver) internal returns (uint256);

_redeemProportion

Call SPA's redeemProportion function

function _redeemProportion(
    address spa,
    uint256 amount,
    uint256[] calldata minAmountsOut
)
    internal
    returns (uint256[] memory);

_redeemSingle

Call SPA's redeemSingle function

function _redeemSingle(
    address spa,
    uint256 amount,
    uint256 tokenIndex,
    uint256 minAmountOut
)
    internal
    returns (uint256);

_redeemMulti

Call SPA's redeemMulti function

function _redeemMulti(
    address spa,
    uint256[] calldata amounts,
    uint256 maxRedeemAmount
)
    internal
    returns (uint256[] memory);

_getTokens

Get the tokens from SPA

function _getTokens(address spa) internal view returns (address[] memory);

_getPoolToken

Get the pool token from SPA

function _getPoolToken(address spa) internal view returns (address);

_revertBytes

Helper function to revert with the same error message as the original call

function _revertBytes(bytes memory data) internal pure;

Errors

ZeroAmount

error ZeroAmount();

InvalidParameters

error InvalidParameters();

CallFailed

error CallFailed();

InsufficientAllowance

Git Source

error InsufficientAllowance(uint256 currentAllowance, uint256 amount);

InsufficientBalance

Git Source

error InsufficientBalance(uint256 currentBalance, uint256 amount);

SPAToken

Git Source

Inherits: Initializable, OwnableUpgradeable, ISPAToken

Author: Nuts Finance Developer

ERC20 token minted by the StableSwap pools.

SPA token is ERC20 rebase token minted by StableSwap pools for liquidity providers. SPA token balances are dynamic and represent the holder's share in the total amount of SPA tokens controlled by the protocol. Account shares aren't normalized, so the contract also stores the sum of all shares to calculate each account's token balance which equals to: shares[account] * _totalSupply / _totalShares where the _totalSupply is the total supply of spaToken controlled by the protocol.

State Variables

INFINITE_ALLOWANCE

Constant value representing an infinite allowance.

uint256 internal constant INFINITE_ALLOWANCE = ~uint256(0);

BUFFER_DENOMINATOR

Constant value representing the denominator for the buffer rate.

uint256 public constant BUFFER_DENOMINATOR = 10 ** 10;

NUMBER_OF_DEAD_SHARES

Constant value representing the number of dead shares.

uint256 public constant NUMBER_OF_DEAD_SHARES = 1000;

totalShares

The total amount of shares.

uint256 public totalShares;

totalSupply

The total supply of spaToken

uint256 public totalSupply;

totalRewards

The total amount of rewards

uint256 public totalRewards;

shares

The mapping of account shares.

mapping(address => uint256) public shares;

allowances

The mapping of account allowances.

mapping(address => mapping(address => uint256)) private allowances;

bufferPercent

The buffer rate.

uint256 public bufferPercent;

bufferAmount

The buffer amount.

uint256 public bufferAmount;

tokenName

The token name.

string internal tokenName;

tokenSymbol

The token symbol.

string internal tokenSymbol;

bufferBadDebt

The bad debt of the buffer.

uint256 public bufferBadDebt;

pool

The address of SPA pool.

address public pool;

Functions

constructor

constructor();

initialize

function initialize(
    string memory _name,
    string memory _symbol,
    uint256 _buffer,
    address _keeper,
    address _pool
)
    public
    initializer;

transferShares

Moves _sharesAmount token shares from the caller's account to the _recipient account.

The _sharesAmount argument is the amount of shares, not tokens.

function transferShares(address _recipient, uint256 _sharesAmount) external returns (uint256);

Returns

NameTypeDescription
<none>uint256amount of transferred tokens. Emits a TransferShares event. Emits a Transfer event.

transferSharesFrom

Moves _sharesAmount token shares from the _sender account to the _recipient account.

The _sharesAmount argument is the amount of shares, not tokens.

function transferSharesFrom(address _sender, address _recipient, uint256 _sharesAmount) external returns (uint256);

Returns

NameTypeDescription
<none>uint256amount of transferred tokens. Emits a TransferShares event. Emits a Transfer event. Requirements: - the caller must have allowance for _sender's tokens of at least getPeggedTokenByShares(_sharesAmount).

mintShares

Mints shares for the _account and transfers them to the _account.

function mintShares(address _account, uint256 _tokenAmount) external;

burnShares

Burns shares from the _account.

function burnShares(uint256 _tokenAmount) external;

burnSharesFrom

Burns shares from the _account.

function burnSharesFrom(address _account, uint256 _tokenAmount) external;

transfer

Moves _amount tokens from the caller's account to the _recipientaccount.

The _amount argument is the amount of tokens, not shares.

function transfer(address _recipient, uint256 _amount) external returns (bool);

Returns

NameTypeDescription
<none>boola boolean value indicating whether the operation succeeded. Emits a Transfer event. Emits a TransferShares event.

approve

Sets _amount as the allowance of _spender over the caller's tokens.

The _amount argument is the amount of tokens, not shares.

function approve(address _spender, uint256 _amount) external returns (bool);

Returns

NameTypeDescription
<none>boola boolean value indicating whether the operation succeeded. Emits an Approval event.

transferFrom

Moves _amount tokens from _sender to _recipient using the allowance mechanism. _amount is then deducted from the caller's allowance.

The _amount argument is the amount of tokens, not shares.

function transferFrom(address _sender, address _recipient, uint256 _amount) external returns (bool);

Returns

NameTypeDescription
<none>boola boolean value indicating whether the operation succeeded. Emits a Transfer event. Emits a TransferShares event. Emits an Approval event indicating the updated allowance. Requirements: - the caller must have allowance for _sender's tokens of at least _amount.

increaseAllowance

Atomically increases the allowance granted to _spender by the caller by _addedValue. This is an alternative to approve that can be used as a mitigation for problems described in: https://github.com/OpenZeppelin/openzeppelin-contracts/blob/b709eae01d1da91902d06ace340df6b324e6f049/contracts/token/ERC20/IERC20.sol#L57 Emits an Approval event indicating the updated allowance.

function increaseAllowance(address _spender, uint256 _addedValue) external returns (bool);

decreaseAllowance

Atomically decreases the allowance granted to _spender by the caller by _subtractedValue. This is an alternative to approve that can be used as a mitigation for problems described in: https://github.com/OpenZeppelin/openzeppelin-contracts/blob/b709eae01d1da91902d06ace340df6b324e6f049/contracts/token/ERC20/IERC20.sol#L57 Emits an Approval event indicating the updated allowance.

function decreaseAllowance(address _spender, uint256 _subtractedValue) external returns (bool);

setBuffer

This function is called by the keeper to set the buffer rate.

function setBuffer(uint256 _buffer) external onlyOwner;

setSymbol

This function is called by the keeper to set the token symbol.

function setSymbol(string memory _symbol) external onlyOwner;

addTotalSupply

This function is called only by a stableSwap pool to increase the total supply of SPAToken by the staking rewards and the swap fee.

function addTotalSupply(uint256 _amount) external;

removeTotalSupply

This function is called only by a stableSwap pool to decrease the total supply of SPAToken by lost amount.

function removeTotalSupply(uint256 _amount, bool isBuffer, bool withDebt) external;

Parameters

NameTypeDescription
_amountuint256The amount of lost tokens.
isBufferboolThe flag to indicate whether to use the buffer or not.
withDebtboolThe flag to indicate whether to add the lost amount to the buffer bad debt or not.

addBuffer

This function is called only by a stableSwap pool to increase the buffer amount of SPAToken

function addBuffer(uint256 _amount, bool withDebt) external;

withdrawBuffer

Withdraw _amount from Buffer and mint SPAToken shares to _to Callable only by Governor via Keeper (which is owner)

function withdrawBuffer(address _to, uint256 _amount) external onlyOwner;

Parameters

NameTypeDescription
_toaddressRecipient address that will receive newly–minted shares
_amountuint256Token amount to withdraw

name

Returns the name of the token.

function name() external view returns (string memory);

Returns

NameTypeDescription
<none>stringthe name of the token.

symbol

Returns the symbol of the token.

function symbol() external view returns (string memory);

Returns

NameTypeDescription
<none>stringthe symbol of the token.

balanceOf

Balances are dynamic and equal the _account's share in the amount of the total spaToken controlled by the protocol. See sharesOf.

function balanceOf(address _account) external view returns (uint256);

Returns

NameTypeDescription
<none>uint256the amount of tokens owned by the _account.

allowance

This value changes when approve or transferFrom is called.

function allowance(address _owner, address _spender) external view returns (uint256);

Returns

NameTypeDescription
<none>uint256the remaining number of tokens that _spender is allowed to spend on behalf of _owner through transferFrom. This is zero by default.

sharesOf

function sharesOf(address _account) external view returns (uint256);

Returns

NameTypeDescription
<none>uint256the amount of shares owned by _account.

decimals

Returns the decimals of the token.

function decimals() external pure returns (uint8);

Returns

NameTypeDescription
<none>uint8the number of decimals for getting user representation of a token amount.

getPeggedTokenByShares

function getPeggedTokenByShares(uint256 _sharesAmount) public view returns (uint256);

Returns

NameTypeDescription
<none>uint256the amount of spaToken that corresponds to _sharesAmount token shares.

getSharesByPeggedToken

function getSharesByPeggedToken(uint256 _spaTokenAmount) public view returns (uint256);

Returns

NameTypeDescription
<none>uint256the amount of shares that corresponds to _spaTokenAmount protocol-controlled spaToken.

_transfer

Moves _amount tokens from _sender to _recipient. Emits a Transfer event. Emits a TransferShares event.

function _transfer(address _sender, address _recipient, uint256 _amount) internal;

_approve

Sets _amount as the allowance of _spender over the _owner s tokens. Emits an Approval event.

function _approve(address _owner, address _spender, uint256 _amount) internal;

_spendAllowance

Updates owner s allowance for spender based on spent amount. Does not update the allowance amount in case of infinite allowance. Revert if not enough allowance is available. Might emit an {Approval} event.

function _spendAllowance(address _owner, address _spender, uint256 _amount) internal;

_transferShares

Moves _sharesAmount shares from _sender to _recipient.

function _transferShares(address _sender, address _recipient, uint256 _sharesAmount) internal;

_mintShares

Creates _sharesAmount shares and assigns them to _recipient, increasing the total amount of shares.

function _mintShares(address _recipient, uint256 _tokenAmount) internal returns (uint256 newTotalShares);

_burnShares

Destroys _sharesAmount shares from _account's holdings, decreasing the total amount of shares.

function _burnShares(address _account, uint256 _tokenAmount) internal returns (uint256 newTotalShares);

_emitTransferEvents

Emits Transfer and TransferShares events.

function _emitTransferEvents(address _from, address _to, uint256 _tokenAmount, uint256 _sharesAmount) internal;

_emitTransferAfterMintingShares

Emits Transfer and TransferShares events after minting shares.

function _emitTransferAfterMintingShares(address _to, uint256 _sharesAmount) internal;

_emitTransferAfterBurningShares

Emits Transfer and TransferShares events after burning shares.

function _emitTransferAfterBurningShares(address _from, uint256 _sharesAmount) internal;

_sharesOf

function _sharesOf(address _account) internal view returns (uint256);

Returns

NameTypeDescription
<none>uint256the amount of shares owned by _account.

Events

TransferShares

Emitted when shares are transferred.

event TransferShares(address indexed from, address indexed to, uint256 sharesValue);

RewardsMinted

Emitted when rewards are minted.

event RewardsMinted(uint256 amount, uint256 actualAmount);

SetBufferPercent

Emitted when the buffer rate is set.

event SetBufferPercent(uint256);

BufferIncreased

Emitted when the buffer is increased.

event BufferIncreased(uint256, uint256);

BufferDecreased

Emitted when the buffer is decreased.

event BufferDecreased(uint256, uint256);

BufferWithdrawn

Emitted when Buffer is withdrawn to Treasury

event BufferWithdrawn(address indexed to, uint256 amount, uint256 bufferLeft);

NegativelyRebased

Emitted when there is negative rebase.

event NegativelyRebased(uint256, uint256);

SymbolModified

Emitted when the symbol is modified.

event SymbolModified(string);

Errors

AllowanceBelowZero

Error thrown when the allowance is below zero.

error AllowanceBelowZero();

OutOfRange

Error thrown when array index is out of range.

error OutOfRange();

NoPool

Error thrown when the pool is not the caller.

error NoPool();

InvalidAmount

Error thrown when the amount is invalid.

error InvalidAmount();

InsufficientBuffer

Error thrown when the buffer is insufficient.

error InsufficientBuffer();

ApproveFromZeroAddr

Error thrown when the sender's address is zero.

error ApproveFromZeroAddr();

ApproveToZeroAddr

Error thrown when the recipient's address is zero.

error ApproveToZeroAddr();

ZeroAddress

Error thrown when the address is zero.

error ZeroAddress();

TransferToSPATokenContract

Error thrown when transferring to the spaToken contract.

error TransferToSPATokenContract();

MintToZeroAddr

Error thrown when minting to the zero address.

error MintToZeroAddr();

BurnFromZeroAddr

Error thrown when burning from the zero address.

error BurnFromZeroAddr();

InsufficientSupply

Error thrown when the supply is insufficient.

error InsufficientSupply();

SelfPeggingAsset

Git Source

Inherits: Initializable, ReentrancyGuardUpgradeable, OwnableUpgradeable

Author: Nuts Finance Developer

The SelfPeggingAsset pool provides a way to swap between different tokens

The SelfPeggingAsset contract allows users to trade between different tokens, with prices determined algorithmically based on the current supply and demand of each token

State Variables

FEE_DENOMINATOR

This is the denominator used for calculating transaction fees in the SelfPeggingAsset contract.

uint256 private constant FEE_DENOMINATOR = 10 ** 10;

DEFAULT_FEE_ERROR_MARGIN

This is the maximum error margin for calculating transaction fees in the SelfPeggingAsset contract.

uint256 private constant DEFAULT_FEE_ERROR_MARGIN = 100_000;

DEFAULT_YIELD_ERROR_MARGIN

This is the maximum error margin for calculating transaction yield in the SelfPeggingAsset contract.

uint256 private constant DEFAULT_YIELD_ERROR_MARGIN = 10_000;

MAX_A

This is the maximum value of the amplification coefficient A.

uint256 private constant MAX_A = 10 ** 6;

INITIAL_MINT_MIN

This is minimum initial mint

uint256 private constant INITIAL_MINT_MIN = 100_000;

DEFAULT_DECAY_PERIOD

This is the default decay period

uint256 private constant DEFAULT_DECAY_PERIOD = 5 minutes;

DEFAULT_RATE_CHANGE_SKIP_PERIOD

This is the default rate change skip period

uint256 private constant DEFAULT_RATE_CHANGE_SKIP_PERIOD = 1 days;

tokens

This is an array of addresses representing the tokens currently supported by the SelfPeggingAsset contract.

address[] public tokens;

precisions

This is an array of uint256 values representing the precisions of each token in the SelfPeggingAsset contract. The precision of each token is calculated as 10 ** (18 - token decimals).

uint256[] public precisions;

balances

This is an array of uint256 values representing the current balances of each token in the SelfPeggingAsset contract. The balances are converted to the standard token unit (10 ** 18).

uint256[] public balances;

exchangeRateDecimals

uint256[] public exchangeRateDecimals;

mintFee

This is the fee charged for adding liquidity to the SelfPeggingAsset contract.

uint256 public mintFee;

swapFee

This is the fee charged for trading assets in the SelfPeggingAsset contract. swapFee = swapFee * FEE_DENOMINATOR

uint256 public swapFee;

redeemFee

This is the fee charged for removing liquidity from the SelfPeggingAsset contract. redeemFee = redeemFee * FEE_DENOMINATOR

uint256 public redeemFee;

offPegFeeMultiplier

This is the off peg fee multiplier. offPegFeeMultiplier = offPegFeeMultiplier * FEE_DENOMINATOR

uint256 public offPegFeeMultiplier;

poolToken

This is the address of the ERC20 token contract that represents the SelfPeggingAsset pool token.

ISPAToken public poolToken;

totalSupply

The total supply of pool token minted by the swap. It might be different from the pool token supply as the pool token can have multiple minters.

uint256 public totalSupply;

paused

This is a state variable that represents whether or not the SelfPeggingAsset contract is currently paused.

bool public paused;

A

These is a state variables that represents the amplification coefficient A.

uint256 public A;

rampAController

RampAController contract address for gradual A changes

IRampAController public rampAController;

exchangeRateProviders

Exchange rate provider for the tokens

IExchangeRateProvider[] public exchangeRateProviders;

feeErrorMargin

Fee error margin.

uint256 public feeErrorMargin;

yieldErrorMargin

Yield error margin.

uint256 public yieldErrorMargin;

exchangeRateFeeFactor

The fee factor for rate change fee

uint256 public exchangeRateFeeFactor;

decayPeriod

The time (in seconds) over which the multiplier decays back to 1x after being raised.

uint256 public decayPeriod;

rateChangeSkipPeriod

The time (in seconds) after which the multiplier is skipped when the rate is changed.

uint256 public rateChangeSkipPeriod;

lastActivity

Tracks the last time a transaction occurred in the SelfPeggingAsset contract.

uint256 public lastActivity;

feeStatusByToken

Mapping of token index -> TokenFeeStatus

mapping(uint256 => TokenFeeStatus) public feeStatusByToken;

Functions

syncRamping

modifier syncRamping();

constructor

constructor();

initialize

Initializes the SelfPeggingAsset contract with the given parameters.

function initialize(
    address[] memory _tokens,
    uint256[] memory _precisions,
    uint256[] memory _fees,
    uint256 _offPegFeeMultiplier,
    ISPAToken _poolToken,
    uint256 _A,
    IExchangeRateProvider[] memory _exchangeRateProviders,
    address _rampAController,
    uint256 _exchangeRateFeeFactor,
    address _keeper
)
    public
    initializer;

Parameters

NameTypeDescription
_tokensaddress[]The tokens in the pool.
_precisionsuint256[]The precisions of each token (10 ** (18 - token decimals)).
_feesuint256[]The fees for minting, swapping, and redeeming.
_offPegFeeMultiplieruint256The off peg fee multiplier.
_poolTokenISPATokenThe address of the pool token.
_Auint256The initial value of the amplification coefficient A for the pool.
_exchangeRateProvidersIExchangeRateProvider[]The exchange rate providers for the tokens.
_rampAControlleraddressThe address of the RampAController contract.
_exchangeRateFeeFactoruint256
_keeperaddress

mint

Mints new pool token.

function mint(
    uint256[] calldata _amounts,
    uint256 _minMintAmount
)
    external
    nonReentrant
    syncRamping
    returns (uint256);

Parameters

NameTypeDescription
_amountsuint256[]Unconverted token balances used to mint pool token.
_minMintAmountuint256Minimum amount of pool token to mint.

Returns

NameTypeDescription
<none>uint256The amount of pool tokens minted.

swap

Exchange between two underlying tokens.

function swap(
    uint256 _i,
    uint256 _j,
    uint256 _dx,
    uint256 _minDy
)
    external
    nonReentrant
    syncRamping
    returns (uint256);

Parameters

NameTypeDescription
_iuint256Token index to swap in.
_juint256Token index to swap out.
_dxuint256Unconverted amount of token _i to swap in.
_minDyuint256Minimum token _j to swap out in converted balance.

Returns

NameTypeDescription
<none>uint256Amount of swap out.

redeemProportion

Redeems pool token to underlying tokens proportionally.

function redeemProportion(
    uint256 _amount,
    uint256[] calldata _minRedeemAmounts
)
    external
    nonReentrant
    syncRamping
    returns (uint256[] memory);

Parameters

NameTypeDescription
_amountuint256Amount of pool token to redeem.
_minRedeemAmountsuint256[]Minimum amount of underlying tokens to get.

Returns

NameTypeDescription
<none>uint256[]An array of the amounts of each token to redeem.

redeemSingle

Redeem pool token to one specific underlying token.

function redeemSingle(
    uint256 _amount,
    uint256 _i,
    uint256 _minRedeemAmount
)
    external
    nonReentrant
    syncRamping
    returns (uint256);

Parameters

NameTypeDescription
_amountuint256Amount of pool token to redeem.
_iuint256Index of the token to redeem to.
_minRedeemAmountuint256Minimum amount of the underlying token to redeem to.

Returns

NameTypeDescription
<none>uint256Amount received.

redeemMulti

Redeems underlying tokens.

function redeemMulti(
    uint256[] calldata _amounts,
    uint256 _maxRedeemAmount
)
    external
    nonReentrant
    syncRamping
    returns (uint256[] memory);

Parameters

NameTypeDescription
_amountsuint256[]Amounts of underlying tokens to redeem to.
_maxRedeemAmountuint256Maximum of pool token to redeem.

Returns

NameTypeDescription
<none>uint256[]Amounts received.

setMintFee

Updates the mint fee.

function setMintFee(uint256 _mintFee) external onlyOwner;

Parameters

NameTypeDescription
_mintFeeuint256The new mint fee.

setSwapFee

Updates the swap fee.

function setSwapFee(uint256 _swapFee) external onlyOwner;

Parameters

NameTypeDescription
_swapFeeuint256The new swap fee.

setRedeemFee

Updates the redeem fee.

function setRedeemFee(uint256 _redeemFee) external onlyOwner;

Parameters

NameTypeDescription
_redeemFeeuint256The new redeem fee.

setOffPegFeeMultiplier

Updates the off peg fee multiplier.

function setOffPegFeeMultiplier(uint256 _offPegFeeMultiplier) external onlyOwner;

Parameters

NameTypeDescription
_offPegFeeMultiplieruint256The new off peg fee multiplier.

setExchangeRateFeeFactor

Updates the exchange rate fee factor.

function setExchangeRateFeeFactor(uint256 _exchangeRateFeeFactor) external onlyOwner;

Parameters

NameTypeDescription
_exchangeRateFeeFactoruint256The new exchange rate fee factor.

setDecayPeriod

Updates the decay period.

function setDecayPeriod(uint256 _decayPeriod) external onlyOwner;

Parameters

NameTypeDescription
_decayPerioduint256The new decay period.

setRateChangeSkipPeriod

Updates the rate change skip period.

function setRateChangeSkipPeriod(uint256 _rateChangeSkipPeriod) external onlyOwner;

Parameters

NameTypeDescription
_rateChangeSkipPerioduint256The new rate change skip period.

pause

Pause mint/swap/redeem actions. Can unpause later.

function pause() external onlyOwner;

unpause

Unpause mint/swap/redeem actions.

function unpause() external onlyOwner;

donateD

Update the exchange rate provider for the token.

function donateD(
    uint256[] calldata _amounts,
    uint256 _minDonationAmount
)
    external
    nonReentrant
    syncRamping
    returns (uint256);

updateFeeErrorMargin

update fee error margin.

function updateFeeErrorMargin(uint256 newValue) external onlyOwner;

updateYieldErrorMargin

update yield error margin.

function updateYieldErrorMargin(uint256 newValue) external onlyOwner;

distributeLoss

Distribute losses by rebasing negatively

function distributeLoss() external onlyOwner;

rebase

This function allows to rebase SPAToken by increasing his total supply from the current stableSwap pool by the staking rewards and the swap fee.

function rebase() external syncRamping returns (uint256);

getRedeemSingleAmount

Computes the amount when redeeming pool token to one specific underlying token.

function getRedeemSingleAmount(uint256 _amount, uint256 _i) external view returns (uint256, uint256);

Parameters

NameTypeDescription
_amountuint256Amount of pool token to redeem.
_iuint256Index of the underlying token to redeem to.

Returns

NameTypeDescription
<none>uint256The amount of single token that will be redeemed.
<none>uint256The amount of pool token charged for redemption fee.

getRedeemMultiAmount

Compute the amount of pool token that needs to be redeemed.

function getRedeemMultiAmount(uint256[] calldata _amounts) external view returns (uint256, uint256);

Parameters

NameTypeDescription
_amountsuint256[]Unconverted token balances.

Returns

NameTypeDescription
<none>uint256The amount of pool token that needs to be redeemed.
<none>uint256The amount of pool token charged for redemption fee.

getMintAmount

Compute the amount of pool token that can be minted.

function getMintAmount(uint256[] calldata _amounts) external view returns (uint256, uint256);

Parameters

NameTypeDescription
_amountsuint256[]Unconverted token balances.

Returns

NameTypeDescription
<none>uint256The amount of pool tokens to be minted.
<none>uint256The amount of fees charged.

getSwapAmount

Computes the output amount after the swap.

function getSwapAmount(uint256 _i, uint256 _j, uint256 _dx) external view returns (uint256, uint256);

Parameters

NameTypeDescription
_iuint256Token index to swap in.
_juint256Token index to swap out.
_dxuint256Unconverted amount of token _i to swap in.

Returns

NameTypeDescription
<none>uint256Unconverted amount of token _j to swap out.
<none>uint256The amount of fees charged.

getRedeemProportionAmount

Computes the amounts of underlying tokens when redeeming pool token.

function getRedeemProportionAmount(uint256 _amount) external view returns (uint256[] memory);

Parameters

NameTypeDescription
_amountuint256Amount of pool tokens to redeem.

Returns

NameTypeDescription
<none>uint256[]An array of the amounts of each token to redeem.

getTokens

Returns the array of token addresses in the pool.

function getTokens() external view returns (address[] memory);

getCurrentA

Get the current A value from the controller if set, or use the local value

function getCurrentA() public view returns (uint256);

Returns

NameTypeDescription
<none>uint256The current A value

_updateMultiplierForToken

Updates the fee multiplier for token i if there's a significant rate change.

function _updateMultiplierForToken(uint256 i) internal;

_syncTotalSupply

function _syncTotalSupply() internal;

collectFeeOrYield

Collect fee or yield based on the token balance difference.

function collectFeeOrYield(bool isFee) internal returns (uint256);

Parameters

NameTypeDescription
isFeeboolWhether to collect fee or yield.

Returns

NameTypeDescription
<none>uint256The amount of fee or yield collected.

_currentMultiplier

Computes current multiplier for a given TokenFeeStatus.

function _currentMultiplier(TokenFeeStatus memory st) internal view returns (uint256);

_currentMultiplier

function _currentMultiplier(uint256 index) internal view returns (uint256);

isInactive

Indicates if the pool is inactive based on latest token fee status

function isInactive(uint256 raisedAt) internal view returns (bool);

_volatilityFee

Calculate extra fee from volatility between tokens i, j

function _volatilityFee(uint256 _i, uint256 _j, uint256 _baseFee) internal view returns (uint256);

_volatilityFee

Calculate extra fee from volatility for i

function _volatilityFee(uint256 _i, uint256 _baseFee) internal view returns (uint256);

getUpdatedBalancesAndD

Return the amount of fee that's not collected.

function getUpdatedBalancesAndD() internal view returns (uint256[] memory, uint256);

Returns

NameTypeDescription
<none>uint256[]The balances of underlying tokens.
<none>uint256The total supply of pool tokens.

_updateBalancesForDeposit

Updates token balances for a deposit by adding amounts adjusted for exchange rates and precisions.

function _updateBalancesForDeposit(
    uint256[] memory _balances,
    uint256[] calldata _amounts
)
    internal
    view
    returns (uint256[] memory);

Parameters

NameTypeDescription
_balancesuint256[]Current balances of tokens in the pool.
_amountsuint256[]Amounts of tokens to deposit.

Returns

NameTypeDescription
<none>uint256[]Updated balances after deposit.

_updateBalancesForWithdrawal

Updates token balances for a withdrawal by subtracting amounts adjusted for exchange rates and precisions.

function _updateBalancesForWithdrawal(
    uint256[] memory _balances,
    uint256[] calldata _amounts
)
    internal
    view
    returns (uint256[] memory);

Parameters

NameTypeDescription
_balancesuint256[]Current balances of tokens in the pool.
_amountsuint256[]Amounts of tokens to withdraw.

Returns

NameTypeDescription
<none>uint256[]Updated balances after withdrawal.

_calcSwapFee

Calculates the swap fee based on token balances and dynamic fee adjustment.

function _calcSwapFee(
    uint256 i,
    uint256 j,
    uint256 prevBalanceI,
    uint256 newBalanceI,
    uint256 oldBalanceJ,
    uint256 newBalanceJ,
    uint256 dy
)
    internal
    view
    returns (uint256);

Returns

NameTypeDescription
<none>uint256Fee amount in output token units (token decimals).

_dynamicFee

Calculates the dynamic fee based on liquidity imbalances.

function _dynamicFee(uint256 xpi, uint256 xpj, uint256 _fee) internal view returns (uint256);

Parameters

NameTypeDescription
xpiuint256The liquidity before or first asset liqidity.
xpjuint256The liqduity after or second asset liquidity.
_feeuint256The base fee value.

Returns

NameTypeDescription
<none>uint256The dynamically adjusted fee.

_getD

Computes D given token balances.

function _getD(uint256[] memory _balances, uint256 _A) internal pure returns (uint256);

Parameters

NameTypeDescription
_balancesuint256[]Normalized balance of each token.
_Auint256

Returns

NameTypeDescription
<none>uint256D The SelfPeggingAsset invariant.

_getY

Computes token balance given D.

function _getY(uint256[] memory _balances, uint256 _j, uint256 _D, uint256 _A) internal pure returns (uint256);

Parameters

NameTypeDescription
_balancesuint256[]Converted balance of each token except token with index _j.
_juint256Index of the token to calculate balance.
_Duint256The target D value.
_Auint256

Returns

NameTypeDescription
<none>uint256Converted balance of the token with index _j.

Events

TokenSwapped

This event is emitted when a token swap occurs.

event TokenSwapped(address indexed buyer, uint256 swapAmount, uint256[] amounts, uint256 feeAmount);

Parameters

NameTypeDescription
buyeraddressis the address of the account that made the swap.
swapAmountuint256is the amount of the token swapped by the buyer.
amountsuint256[]is an array containing the amounts of each token received by the buyer.
feeAmountuint256is the amount of transaction fee charged for the swap.

Minted

This event is emitted when liquidity is added to the SelfPeggingAsset contract.

event Minted(address indexed provider, uint256 mintAmount, uint256[] amounts, uint256 feeAmount);

Parameters

NameTypeDescription
provideraddressis the address of the liquidity provider.
mintAmountuint256is the amount of liquidity tokens minted to the provider in exchange for their contribution.
amountsuint256[]is an array containing the amounts of each token contributed by the provider.
feeAmountuint256is the amount of transaction fee charged for the liquidity provision.

Donated

This event is emitted when liquidity is added to the SelfPeggingAsset contract.

event Donated(address indexed provider, uint256 mintAmount, uint256[] amounts);

Parameters

NameTypeDescription
provideraddressis the address of the liquidity provider.
mintAmountuint256is the amount of liquidity tokens minted to the provider in exchange for their contribution.
amountsuint256[]is an array containing the amounts of each token contributed by the provider.

Redeemed

This event is emitted when liquidity is removed from the SelfPeggingAsset contract.

event Redeemed(address indexed provider, uint256 redeemAmount, uint256[] amounts, uint256 feeAmount);

Parameters

NameTypeDescription
provideraddressis the address of the liquidity provider.
redeemAmountuint256is the amount of liquidity tokens redeemed by the provider.
amountsuint256[]is an array containing the amounts of each token received by the provider.
feeAmountuint256is the amount of transaction fee charged for the liquidity provision.

FeeCollected

This event is emitted when transaction fees are collected by the SelfPeggingAsset contract.

event FeeCollected(uint256 feeAmount, uint256 totalSupply);

Parameters

NameTypeDescription
feeAmountuint256is the amount of fee collected.
totalSupplyuint256is the total supply of SPA token.

YieldCollected

This event is emitted when yield is collected by the SelfPeggingAsset contract.

event YieldCollected(uint256 feeAmount, uint256 totalSupply);

Parameters

NameTypeDescription
feeAmountuint256is the amount of yield collected.
totalSupplyuint256is the total supply of SPA token.

RampAControllerUpdated

This event is emitted when the RampAController is set or updated.

event RampAControllerUpdated(address indexed _rampAController);

MintFeeModified

This event is emitted when the mint fee is modified.

event MintFeeModified(uint256 mintFee);

Parameters

NameTypeDescription
mintFeeuint256is the new value of the mint fee.

SwapFeeModified

This event is emitted when the swap fee is modified.

event SwapFeeModified(uint256 swapFee);

Parameters

NameTypeDescription
swapFeeuint256is the new value of the swap fee.

RedeemFeeModified

This event is emitted when the redeem fee is modified.

event RedeemFeeModified(uint256 redeemFee);

Parameters

NameTypeDescription
redeemFeeuint256is the new value of the redeem fee.

OffPegFeeMultiplierModified

This event is emitted when the off peg fee multiplier is modified.

event OffPegFeeMultiplierModified(uint256 offPegFeeMultiplier);

Parameters

NameTypeDescription
offPegFeeMultiplieruint256is the new value of the off peg fee multiplier.

FeeMarginModified

This event is emitted when the fee margin is modified.

event FeeMarginModified(uint256 margin);

Parameters

NameTypeDescription
marginuint256is the new value of the margin.

YieldMarginModified

This event is emitted when the fee margin is modified.

event YieldMarginModified(uint256 margin);

Parameters

NameTypeDescription
marginuint256is the new value of the margin.

ExchangeRateFeeFactorModified

This event is emitted when the exchange rate fee factor is modified.

event ExchangeRateFeeFactorModified(uint256 factor);

Parameters

NameTypeDescription
factoruint256is the new value of the factor.

DecayPeriodModified

This event is emitted when the decay period is modified.

event DecayPeriodModified(uint256 decayPeriod);

Parameters

NameTypeDescription
decayPerioduint256is the new value of the decay period.

RateChangeSkipPeriodModified

This event is emitted when the rate change skip period is modified.

event RateChangeSkipPeriodModified(uint256 rateChangeSkipPeriod);

Parameters

NameTypeDescription
rateChangeSkipPerioduint256is the new value of the rate change skip period.

PoolPaused

This event is emitted when the pool is paused.

event PoolPaused();

PoolUnpaused

This event is emitted when the pool is unpaused.

event PoolUnpaused();

Errors

InputMismatch

Error thrown when the input parameters do not match the expected values.

error InputMismatch();

NoFees

Error thrown when fees are not set

error NoFees();

FeePercentageTooLarge

Error thrown when the fee percentage is too large.

error FeePercentageTooLarge();

TokenNotSet

Error thrown when the token address is not set.

error TokenNotSet();

ExchangeRateProviderNotSet

Error thrown when the exchange rate provider is not set.

error ExchangeRateProviderNotSet();

PrecisionNotSet

Error thrown when the precision is not set.

error PrecisionNotSet();

DuplicateToken

Error thrown when the tokens are duplicates.

error DuplicateToken();

PoolTokenNotSet

Error thrown when the pool token is not set.

error PoolTokenNotSet();

ANotSet

Error thrown when the A value is not set.

error ANotSet();

InvalidAmount

Error thrown when the amount is invalid.

error InvalidAmount();

Paused

Error thrown when the pool is paused.

error Paused();

ZeroAmount

Error thrown when the amount is zero.

error ZeroAmount();

SameToken

Error thrown when the token is the same.

error SameToken();

InvalidIn

Error thrown when the input token is invalid.

error InvalidIn();

InvalidOut

Error thrown when the output token is invalid.

error InvalidOut();

InvalidMins

Error thrown when the amount is invalid.

error InvalidMins();

InvalidToken

Error thrown when the token is invalid.

error InvalidToken();

LimitExceeded

Error thrown when the limit is exceeded.

error LimitExceeded();

NotPaused

Error thrown when the pool is not paused.

error NotPaused();

NoLosses

Error thrown when there is no loss

error NoLosses();

InsufficientDonationAmount

Error thrown donation amount is insufficient

error InsufficientDonationAmount();

InsufficientMintAmount

Error thrown insufficient mint amount

error InsufficientMintAmount(uint256 mintAmount, uint256 minMintAmount);

InsufficientSwapOutAmount

Error thrown insufficient swap out amount

error InsufficientSwapOutAmount(uint256 outAmount, uint256 minOutAmount);

InsufficientRedeemAmount

Error thrown insufficient redeem amount

error InsufficientRedeemAmount(uint256 redeemAmount, uint256 minRedeemAmount);

MaxRedeemAmount

Error thrown when redeem amount is max

error MaxRedeemAmount(uint256 redeemAmount, uint256 maxRedeemAmount);

Structs

TokenFeeStatus

*Data structure for each token's fee status:

  • lastRate: last recorded exchange rate for this token.
  • multiplier: current multiplier (scaled by FEE_DENOMINATOR).
  • raisedAt: timestamp when the multiplier was last raised.*
struct TokenFeeStatus {
    uint256 lastRate;
    uint256 multiplier;
    uint256 raisedAt;
}

SelfPeggingAssetFactory

Git Source

Inherits: UUPSUpgradeable, OwnableUpgradeable

Author: Nuts Finance Developer

The StableSwap Application provides an interface for users to interact with StableSwap pool contracts

The StableSwap Application contract allows users to mint pool tokens, swap between different tokens, and redeem pool tokens to underlying tokens. This contract should never store assets.

State Variables

governor

This is the account that has governor control over the protocol.

address public governor;

mintFee

Default mint fee for the pool.

uint256 public mintFee;

swapFee

Default swap fee for the pool.

uint256 public swapFee;

redeemFee

Default redeem fee for the pool.

uint256 public redeemFee;

offPegFeeMultiplier

Default off peg fee multiplier for the pool.

uint256 public offPegFeeMultiplier;

A

Default A parameter for the pool.

uint256 public A;

selfPeggingAssetBeacon

Beacon for the SelfPeggingAsset implementation.

address public selfPeggingAssetBeacon;

spaTokenBeacon

Beacon for the SPAToken implementation.

address public spaTokenBeacon;

wspaTokenBeacon

Beacon for the WSPAToken implementation.

address public wspaTokenBeacon;

rampAControllerBeacon

Beacon for the RampAController implementation.

address public rampAControllerBeacon;

constantExchangeRateProvider

Constant exchange rate provider.

address public constantExchangeRateProvider;

keeperImplementation

address public keeperImplementation;

minRampTime

Minimum ramp time for the A parameter.

uint256 public minRampTime;

exchangeRateFeeFactor

The exchange rate fee factor.

uint256 public exchangeRateFeeFactor;

bufferPercent

The buffer percent for the SPAToken.

uint256 public bufferPercent;

Functions

constructor

constructor();

initialize

Initializes the StableSwap Application contract.

function initialize(InitializeArgument memory argument) public initializer;

setGovernor

Set the govenance address.

function setGovernor(address _governor) external onlyOwner;

setMintFee

Set the mint fee.

function setMintFee(uint256 _mintFee) external onlyOwner;

setSwapFee

Set the swap fee.

function setSwapFee(uint256 _swapFee) external onlyOwner;

setRedeemFee

Set the redeem fee.

function setRedeemFee(uint256 _redeemFee) external onlyOwner;

setOffPegFeeMultiplier

Set the off peg fee multiplier.

function setOffPegFeeMultiplier(uint256 _offPegFeeMultiplier) external onlyOwner;

setA

Set the A parameter.

function setA(uint256 _A) external onlyOwner;

setMinRampTime

Set the minimum ramp time.

function setMinRampTime(uint256 _minRampTime) external onlyOwner;

setExchangeRateFeeFactor

Set the exchange rate fee factor.

function setExchangeRateFeeFactor(uint256 _exchangeRateFeeFactor) external onlyOwner;

setBufferPercent

Set the buffer percentage.

function setBufferPercent(uint256 _bufferPercent) external onlyOwner;

setKeeperImplementation

Set the keeper implementation.

function setKeeperImplementation(address _keeperImplementation) external onlyOwner;

createPool

Create a new pool.

function createPool(CreatePoolArgument memory argument)
    external
    returns (WSPAToken wspaToken, Keeper keeper, ParameterRegistry parameterRegistry);

_authorizeUpgrade

Authorisation to upgrade the implementation of the contract.

function _authorizeUpgrade(address) internal override onlyOwner;

Events

GovernorModified

This event is emitted when the governor is modified.

event GovernorModified(address governor);

Parameters

NameTypeDescription
governoraddressis the new value of the governor.

PoolCreated

This event is emitted when a new pool is created.

event PoolCreated(
    address poolToken,
    address selfPeggingAsset,
    address wrappedPoolToken,
    address rampAController,
    address parameterRegistry,
    address keeper
);

Parameters

NameTypeDescription
poolTokenaddressis the pool token created.
selfPeggingAssetaddressis the self pegging asset created.
wrappedPoolTokenaddressis the wrapped pool token created.
rampAControlleraddressis the ramp A controller created.
parameterRegistryaddressis the parameter registry created.
keeperaddressis the keeper created.

MintFeeModified

This event is emitted when the mint fee is updated.

event MintFeeModified(uint256 mintFee);

Parameters

NameTypeDescription
mintFeeuint256is the new value of the mint fee.

SwapFeeModified

This event is emitted when the swap fee is updated.

event SwapFeeModified(uint256 swapFee);

Parameters

NameTypeDescription
swapFeeuint256is the new value of the swap fee.

RedeemFeeModified

This event is emitted when the redeem fee is updated.

event RedeemFeeModified(uint256 redeemFee);

Parameters

NameTypeDescription
redeemFeeuint256is the new value of the redeem fee.

OffPegFeeMultiplierModified

This event is emitted when the off peg fee multiplier is updated.

event OffPegFeeMultiplierModified(uint256 offPegFeeMultiplier);

Parameters

NameTypeDescription
offPegFeeMultiplieruint256is the new value of the off peg fee multiplier.

AModified

This event is emitted when the A parameter is updated.

event AModified(uint256 A);

Parameters

NameTypeDescription
Auint256is the new value of the A parameter.

ExchangeRateFeeFactorModified

This event is emitted when the exchange rate fee factor is updated.

event ExchangeRateFeeFactorModified(uint256 exchangeRateFeeFactor);

Parameters

NameTypeDescription
exchangeRateFeeFactoruint256is the new value of the exchange rate fee factor.

MinRampTimeUpdated

This event is emitted when the min ramp time is updated.

event MinRampTimeUpdated(uint256 minRampTime);

Parameters

NameTypeDescription
minRampTimeuint256is the new value of the min ramp time.

BufferPercentUpdated

This event is emitted when the buffer percent is updated.

event BufferPercentUpdated(uint256 bufferPercent);

Parameters

NameTypeDescription
bufferPercentuint256is the new value of the buffer percent.

KeeperImplementationUpdated

This event is emitted when the keeper contract implementation is updated.

event KeeperImplementationUpdated(address keeperImplementation);

Parameters

NameTypeDescription
keeperImplementationaddressis the new address of keeper implementation.

Errors

InvalidAddress

Error thrown when the address is invalid

error InvalidAddress();

InvalidValue

Error thrown when the value is invalid

error InvalidValue();

InvalidOracle

Error thrown when the oracle is invalid

error InvalidOracle();

InvalidFunctionSig

Error thrown when the function signature is invalid

error InvalidFunctionSig();

Structs

InitializeArgument

Parameters for initailizing the factory

struct InitializeArgument {
    address owner;
    address governor;
    uint256 mintFee;
    uint256 swapFee;
    uint256 redeemFee;
    uint256 offPegFeeMultiplier;
    uint256 A;
    uint256 minRampTime;
    address selfPeggingAssetBeacon;
    address spaTokenBeacon;
    address wspaTokenBeacon;
    address rampAControllerBeacon;
    address keeperImplementation;
    address constantExchangeRateProvider;
    uint256 exchangeRateFeeFactor;
    uint256 bufferPercent;
}

CreatePoolArgument

Parameters for creating a new pool

struct CreatePoolArgument {
    address tokenA;
    address tokenB;
    TokenType tokenAType;
    address tokenAOracle;
    bytes tokenARateFunctionSig;
    bytes tokenADecimalsFunctionSig;
    TokenType tokenBType;
    address tokenBOracle;
    bytes tokenBRateFunctionSig;
    bytes tokenBDecimalsFunctionSig;
}

Enums

TokenType

Token type enum

enum TokenType {
    Standard,
    Oracle,
    Rebasing,
    ERC4626
}

WSPAToken

Git Source

Inherits: ERC4626Upgradeable

It's an ERC4626 standard token that represents the account's share of the total supply of SPA tokens. WSPAToken token's balance only changes on transfers, unlike spaToken that is also changed when staking rewards and swap fee are generated. It's a "power user" token for DeFi protocols which don't support rebasable tokens. The contract is also a trustless wrapper that accepts spaToken tokens and mints WSPAToken in return. Then the user unwraps, the contract burns user's WSPAToken and sends user locked SPA tokens in return.

State Variables

spaToken

ISPAToken public spaToken;

Functions

constructor

constructor();

initialize

function initialize(ISPAToken _spaToken) public initializer;

deposit

Deposits spaToken into the vault in exchange for shares.

function deposit(uint256 assets, address receiver) public override returns (uint256 shares);

Parameters

NameTypeDescription
assetsuint256Amount of spaToken to deposit.
receiveraddressAddress to receive the minted shares.

Returns

NameTypeDescription
sharesuint256Amount of shares minted.

mint

Mints shares for a given amount of assets deposited.

function mint(uint256 shares, address receiver) public override returns (uint256 assets);

Parameters

NameTypeDescription
sharesuint256Amount of shares to mint.
receiveraddressAddress to receive the minted shares.

Returns

NameTypeDescription
assetsuint256The amount of spaToken deposited.

withdraw

Withdraws spaToken from the vault in exchange for burning shares.

function withdraw(uint256 assets, address receiver, address owner) public override returns (uint256 shares);

Parameters

NameTypeDescription
assetsuint256Amount of spaToken to withdraw.
receiveraddressAddress to receive the spaToken.
owneraddressAddress whose shares will be burned.

Returns

NameTypeDescription
sharesuint256Burned shares corresponding to the assets withdrawn.

redeem

Redeems shares for spaToken.

function redeem(uint256 shares, address receiver, address owner) public override returns (uint256 assets);

Parameters

NameTypeDescription
sharesuint256Amount of shares to redeem.
receiveraddressAddress to receive the spaToken.
owneraddressAddress whose shares will be burned.

Returns

NameTypeDescription
assetsuint256Amount of spaToken withdrawn.

name

Returns the name of the token.

function name() public view override(ERC20Upgradeable, IERC20Metadata) returns (string memory);

Returns

NameTypeDescription
<none>stringThe name of the token.

symbol

Returns the symbol of the token.

function symbol() public view override(ERC20Upgradeable, IERC20Metadata) returns (string memory);

Returns

NameTypeDescription
<none>stringThe symbol of the token.

convertToShares

Converts an amount of spaToken to the equivalent amount of shares.

function convertToShares(uint256 assets) public view override returns (uint256);

Parameters

NameTypeDescription
assetsuint256Amount of spaToken.

Returns

NameTypeDescription
<none>uint256The equivalent shares.

convertToAssets

Converts an amount of shares to the equivalent amount of spaToken.

function convertToAssets(uint256 shares) public view override returns (uint256);

Parameters

NameTypeDescription
sharesuint256Amount of shares.

Returns

NameTypeDescription
<none>uint256The equivalent spaToken.

maxWithdraw

Returns the maximum amount of assets that can be withdrawn by owner.

function maxWithdraw(address owner) public view override returns (uint256);

Parameters

NameTypeDescription
owneraddressAddress of the account.

Returns

NameTypeDescription
<none>uint256The maximum amount of spaToken that can be withdrawn.

previewDeposit

Simulates the amount of shares that would be minted for a given amount of assets.

function previewDeposit(uint256 assets) public view override returns (uint256);

Parameters

NameTypeDescription
assetsuint256Amount of spaToken to deposit.

Returns

NameTypeDescription
<none>uint256The number of shares that would be minted.

previewMint

Simulates the amount of assets that would be needed to mint a given amount of shares.

function previewMint(uint256 shares) public view override returns (uint256);

Parameters

NameTypeDescription
sharesuint256Amount of shares to mint.

Returns

NameTypeDescription
<none>uint256The number of assets required.

previewRedeem

Simulates the amount of assets that would be withdrawn for a given amount of shares.

function previewRedeem(uint256 shares) public view override returns (uint256);

Parameters

NameTypeDescription
sharesuint256Amount of shares to redeem.

Returns

NameTypeDescription
<none>uint256The number of assets that would be withdrawn.

Errors

ZeroAmount

error ZeroAmount();

InsufficientAllowance

error InsufficientAllowance();