SIP-302: Pools (V3)

NetworkEthereum & Optimism
ImplementorDaniel Beal (@dbeal-eth), Leonardo Massazza (@leomassazza), Alejandro Santander (@ajsantander)

Simple Summary

This SIP proposes the creation of pools in Version 3 of the Synthetix protocol. Pools serve as an intermediary by accepting collateral from accounts and providing liquidity to markets.


Governance determines the types of collateral that can be staked by the accounts and delegate to pools. Pools can be created by anyone. Accounts can assign staked collateral to collateral-specific vaults (controlled by pools) by opening staking positions. Accounts can then mint and burn sUSD. The owner of a pool can optionally delegate liquidity among to the markets it backs. The pools and vaults track the debt responsibility of each account based on the sUSD that the account has minted or burned, as well as price fluctuations in the markets that it backs.


By introducing the concept of a pool, we are able to allow stakers to customize their exposure while also allowing stakers to delegate the management of their staking position to others. We envision the creation of a pool that will be managed by the Spartan Council; the official user interface will have stakers delegate their collateral to this pool by default, allowing for a user experience similar to the current version of the protocol. There may also be a pool with no exposure to markets, allowing users to mint and burn USD without exposure to debt from price fluctuations in markets. This should allow the sUSD supply to be increased with little or no risk.

Pools may also serve as the entity for facilitating cross-chain synthesis. Because the proposed architecture for version 3 segments debt into individual markets, we envision relying on an oracle to consolidate liquidity between pools across networks.



The implementation of pools involves the following considerations:

  • Creating Pools
  • Delegating Collateral
  • Minting and Burning sUSD
  • Configuring Staking Positions


Pools create a clean abstraction for provisioning liquidity and sUSD issuance. An alternative approach could involve a separate contract for managing all collateral in the system, another contract to manage minting and burning sUSD, and then allowing accounts to provide liquidity directly to markets. This is not desirable because it adds unnecessary components to the system and significantly increases the implementation complexity of features like delegated staking positions.

It may seem as if we could allow pools to decide which types of collateral are acceptable, rather than configuring this across the entire protocol. This is not an option because we want to allow sUSD to be fungible (regardless of the pool from which it was minted). In other words, we need to prevent the creation of a pool that accepts low quality collateral, exposing all sUSD holders to that risk.

Technical Specification

Staking positions can be represented with the following data structure:

Pools and vaults will implement something similar to the following interfaces:

IPool {
	function createPool(uint requestedPoolId, address owner);
	function nominateNewPoolOwner(address nominatedOwner, uint256 poolId);
    function acceptPoolOwnership(uint256 poolId);
    function renouncePoolNomination(uint256 poolId);
	function setPoolPosition(uint poolId, uint[] calldata markets, uint[] calldata maxDebtShareValues);

IVault {
	function delegateCollateral(uint accountId, uint ppolId, address collateralType, uint amount);
    function mintUSD(uint accountId, uint poolId, address collateralType, uint amount);
    function burnUSD(uint accountId, uint poolId, address collateralType, uint amount);
    function collateralizationRatio(uint accountId, uint poolId, address collateralType) returns (uint);
    function accountPoolDebt(uint accountId, uint poolId, address collateralType) returns (uint);
    function accountPoolCollateralValue(uint accountId, uint poolId, address collateralType) returns (uint);
    function poolDebt(uint poolId, address collateralType) returns (uint);
    function totalDebtShares(uint poolId, address collateralType) returns (uint);
    function debtPerShare(uint poolId, address collateralType) returns (uint);
    function getStakingPosition(bytes32 stakingPositionId) returns (StakingPosition memory stakingPosition);
    function getAccountStakingPositionIds(uint accountId) returns (bytes32[] memory stakingPositionIds);
    function getAccountStakingPositions(uint accountId) returns (StakingPosition[] memory stakingPositions);

Creating Pools
Pools can be created by anyone using the createPool() function. The owner (and only the owner) has the ability to update the pool’s staking position (by calling setPoolPosition()) and nominate a new owner for the pool with nominatePoolOwner(). The nominated owner can call acceptPoolOwnership() to become the owner. An owner can also call renouncePoolOwnership(), effectively making the pool’s position permanent.

Delegating Collateral
Stakers can call the delegateCollateral() function, which will automatically create or update the relevant StakingPosition (specified below) based on the provided parameters. It then triggers the rebalanceMarkets() function to notify each of the markets that the amount of liquidity available has changed. Stakers may only unassign collateral if the resulting C-Ratio is above the Target C-Ratio for that collateral’s type.

struct StakingPosition {
    uint256 accountId;
    address collateralType;
    uint256 poolId;
    uint256 collateralAmount;
    uint256 debtShares;
    uint256 initialVaultDebt;
	uint usdDebt;

The implementation pertaining to collateral management should employ the concept of vault through which the collateral and debt accounted for by pools are tracked seperately by collateral type. In other words, each pool should manage a its own seperate vault for each type of approved collateral. This will ensure that stakers only receive liquidation rewards of the type they are staking and allow staking incentivizes to be configured for specific types of collateral.

Minting and Burning sUSD
Accounts may mint and burn sUSD backed by a collateral type that they have staked. sUSD is an ERC-20 token (with permit functionality) that is accepted by the market manager.

Minting and burning will increase and decrease the usdBalance value, respectively. Stakers may only mint sUSD if the resulting C-Ratio is above the Target C-Ratio for the relevant collateral type.

Configuring Staking Position
The owner of a pool is able to invoke the setPoolPosition() function with an array of markets and corresponding maximum debt share values. The maximum debt share values effectively protects the pool and its members from extreme debt fluctuations and limits the amount of stablecoins that can be minted by a market.

Test Cases

Relevant tests will be developed during implementation.

Configurable Values (Via SCCP)

  • Preferred Pool (uint) - This is the ID of a pool which the Spartan Council prefers that stakers join. This will be the default pool for stakers in the official UI.
  • Approved Pools (uint[]) - This is a list of pools’ IDs owned (or otherwise approved) by the Spartan Council and will be listed in the official UI.

Additionally, governance can add or remove accepted collateral types, each with the following configuration:

  • Token (address) - An ERC-20 contract that represents the collateral.
  • Price Feed (address) - A contract which provides the current value of this asset, denominated in USD.
  • Minimum C-Ratio (uint) - The minimum ratio that the value of this collateral type must maintain in relation to the value of the debt that it backs to avoid becoming subject to liquidation.
  • Target C-Ratio (uint) - The lowest C-Ratio that the protocol allows stakers to reach voluntarily with this collateral type (by minting sUSD, for example).
  • Disabled (bool) - Whether the protocol should accept any more collateral of this type.

Copyright and related rights waived via CC0.