USPD Stabilization Mechanisms
The US Permissionless Dollar (USPD) protocol is designed to maintain its peg to the US Dollar through a series of interconnected economic incentives and automated processes. This document outlines how the system achieves stability under various market conditions.
Core Principle: Overcollateralization
The fundamental principle underpinning USPD’s stability is overcollateralization. Every USPD token in circulation is backed by more than $1 worth of collateral, primarily in the form of staked Ether (stETH). This collateral is managed within individual Stabilizer Positions, each associated with a Stabilizer NFT.
Minting USPD (Stable State)
In a stable state, the system is sufficiently overcollateralized (e.g., individual positions are at least 110% collateralized, with the system average potentially much higher, like 125% or more).
- User Initiates Minting: A user wishes to mint USPD. For example, they want to convert 1 ETH into USPD when ETH is priced at $3000.
- Oracle Price: The user provides a signed price attestation for the current ETH/USD exchange rate (e.g., $3000/ETH) from the
PriceOracle
. - Collateral Allocation: The user calls the
mint
function on theUSPDToken
(which callscUSPDToken.mintShares
), sending their 1 ETH. - Stabilizer Contribution: The
StabilizerNFT
contract identifies an available Stabilizer Position. This position contributes additional collateral (e.g., 0.25 ETH, representing a 25% overcollateralization contribution from the stabilizer for the user’s 1 ETH). - Position Escrow: The user’s 1 ETH and the stabilizer’s 0.25 ETH (both converted to stETH) are locked in a dedicated
PositionEscrow
contract associated with that Stabilizer NFT. - USPD Minted: The user receives $3000 worth of USPD (in the form of
cUSPD
shares, whichUSPDToken
represents as USPD). - Market Interaction: The user can then use their USPD in DeFi applications, such as providing liquidity on Uniswap or lending on Aave.
Maintaining the Peg: Arbitrage and Redemption
The USPD peg to the US Dollar is maintained through arbitrage opportunities and a direct redemption mechanism.
1. Arbitrage on Decentralized Exchanges (DEXs)
- USPD > $1 on DEX: If USPD trades above $1 on a DEX (e.g., $1.02), arbitrageurs are incentivized to:
- Mint new USPD at par value ($1 worth of ETH for 1 USPD via the
mintShares
function). - Sell this newly minted USPD on the DEX for $1.02, profiting from the difference.
- This selling pressure helps drive the USPD price on the DEX back towards $1.
- Mint new USPD at par value ($1 worth of ETH for 1 USPD via the
- USPD < $1 on DEX: If USPD trades below $1 on a DEX (e.g., $0.98), arbitrageurs are incentivized to:
- Buy USPD on the DEX at $0.98.
- Redeem this USPD for $1 worth of stETH via the
cUSPDToken.burnShares
function (if the system is stable). - This buying pressure helps drive the USPD price on the DEX back towards $1.
2. Direct Redemption (cUSPDToken.burnShares
)
When the system is stable (i.e., sufficiently overcollateralized, as checked by StabilizerNFT.unallocateStabilizerFunds
), users can directly redeem their USPD for stETH at the prevailing oracle price (effectively $1 worth of stETH for 1 USPD).
- Process: A user calls
burnShares
oncUSPDToken
(typically viaUSPDToken
). - Collateral Release: The
StabilizerNFT
contract identifies the corresponding collateral inPositionEscrow
contracts. The user’s portion of the stETH collateral is returned to them, and the stabilizer’s overcollateralization portion is released back to their unallocated funds in theirStabilizerEscrow
. - No Slippage: This mechanism provides a guaranteed $1 redemption value (in stETH terms), unlike DEX swaps which can incur slippage, especially for large amounts.
Handling Price Volatility and Instability
The system is designed to handle volatility in the price of ETH (the primary collateral).
Scenario 1: ETH Price Rises
- Increased Collateralization: If the price of ETH rises, the value of the stETH collateral held in
PositionEscrow
contracts increases. This improves the collateralization ratio of individual positions and the overall system health. - Benefit: The system becomes more robust. Stabilizers see their overcollateralization increase, and the risk of liquidation decreases.
Scenario 2: ETH Price Falls - Stabilizer Liquidations
If the price of ETH falls, individual Stabilizer Positions might become undercollateralized.
- Liquidation Threshold: Each Stabilizer Position has a minimum collateralization ratio (e.g., 110%). If a position’s ratio falls below this, it becomes eligible for liquidation. The exact threshold for a specific liquidation can also be influenced by the liquidator’s own Stabilizer NFT ID, allowing for a tiered liquidation system.
- Liquidation Process (
StabilizerNFT.liquidatePosition
):- A liquidator (any user) acquires USPD (e.g., by buying from a DEX or minting new USPD if the system allows).
- The liquidator calls
liquidatePosition
on theStabilizerNFT
contract, specifying the undercollateralized position and providing the USPD to be “burned” against that position’s debt. - The
StabilizerNFT
contract verifies the position is indeed below its liquidation threshold using the current oracle price. - The liquidator’s USPD is burned.
- The liquidator receives stETH from the liquidated position’s collateral. This payout is typically the par value of the burned USPD plus a bonus (e.g., 5%), making liquidation an attractive economic activity.
- Effect: Unhealthy (undercollateralized) positions are removed from the system, and the total supply of USPD is reduced, helping to restore overall system health. The stabilizer whose position was liquidated bears the loss of their overcollateralized portion.
Scenario 3: The Insurance Fund
To further protect the system and incentivize liquidators even when a position is severely undercollateralized:
- Funding: When a position is liquidated and its collateralization ratio is above the liquidator’s payout target (e.g., >105%), the excess collateral (beyond the liquidator’s payout) is sent to an
InsuranceEscrow
contract. - Payout Support: If a liquidated position’s collateral is insufficient to cover the liquidator’s target payout (e.g., position is at 99% collateralized, but liquidator expects 105%), the
InsuranceEscrow
attempts to cover the shortfall, ensuring the liquidator still receives their incentive. - Purpose: The insurance fund acts as a buffer, making liquidations more consistently profitable and thereby encouraging the timely removal of bad debt.
Scenario 4: Extreme Market Conditions (Flash Crash & System Undercollateralization)
In a severe flash crash where the ETH price drops significantly and rapidly, a large number of Stabilizer Positions might become undercollateralized, and the InsuranceEscrow
could be depleted. This could lead to the overall system becoming undercollateralized (e.g., total collateral value < total USPD value).
- Restricted Redemptions: In such a scenario, the
StabilizerNFT.unallocateStabilizerFunds
function (which is called bycUSPDToken.burnShares
) will revert if the system-wide collateralization ratio (checked viaOvercollateralizationReporter
) is below 100%. This prevents direct redemptions at par value, which would exacerbate the undercollateralized state (a “bank run”). - Market-Driven Price Discovery: USPD might trade below $1 on DEXs.
- Liquidation as Primary Recovery:
- Even if the system is globally undercollateralized (e.g., at 95%), liquidating individual Stabilizer Positions remains viable and crucial.
- Arbitrageurs can buy USPD on DEXs at a discount (e.g., $0.90).
- They can then use this discounted USPD to liquidate a Stabilizer Position. If that position, despite being undercollateralized, still holds collateral worth, say, $0.95 for every $1 of USPD debt it backed, the liquidator profits ($0.95 payout - $0.90 cost).
- The stabilizer whose position is liquidated absorbs the loss from their provided overcollateral.
- This process reduces the total USPD supply, helping the system to gradually return to a healthier collateralization ratio as bad debt is cleared.
- System Resilience: The expectation is that even in extreme scenarios, the combination of discounted USPD on secondary markets and the remaining (though diminished) collateral in Stabilizer Positions creates economic incentives for liquidation. This helps the system find a new equilibrium and deleverage. If the ETH price subsequently recovers, the system’s collateralization ratio will improve more rapidly due to the reduced USPD supply.
This multi-layered approach, combining overcollateralization, arbitrage, direct redemptions (in stable times), incentivized liquidations, and an insurance fund, aims to create a resilient stablecoin that can adapt to various market stresses.
Technical Guide: Building a Liquidation Bot
For developers building liquidation bots or monitoring systems, understanding how to programmatically assess Stabilizer Position health is crucial. The health of a Stabilizer Position is determined by its collateralization ratio, which is calculated within the individual PositionEscrow
contract associated with each Stabilizer NFT.
1. Finding Position Escrow Contracts
Each Stabilizer NFT has an associated PositionEscrow
contract that holds the actual collateral. To find the escrow address for a given NFT:
import { createPublicClient, http, getContract } from 'viem';
import { mainnet } from 'viem/chains';
// Create a public client
const publicClient = createPublicClient({
chain: mainnet,
transport: http()
});
// Get the PositionEscrow address for a specific Stabilizer NFT
const positionEscrowAddress = await publicClient.readContract({
address: STABILIZER_NFT_ADDRESS,
abi: stabilizerNFTAbi,
functionName: 'positionEscrows',
args: [tokenId]
});
// Create contract instance for the PositionEscrow
const positionEscrow = getContract({
address: positionEscrowAddress,
abi: positionEscrowAbi,
client: publicClient
});
# Python example using web3.py
from web3 import Web3
stabilizer_nft = w3.eth.contract(address=STABILIZER_NFT_ADDRESS, abi=stabilizer_nft_abi)
position_escrow_address = stabilizer_nft.functions.positionEscrows(token_id).call()
position_escrow = w3.eth.contract(address=position_escrow_address, abi=position_escrow_abi)
2. Calculating Collateralization Ratio
The collateralization ratio determines if a position is eligible for liquidation. Here’s how to calculate it:
import { parseUnits, keccak256, toBytes } from 'viem';
// Get current ETH/USD price from your price oracle
const priceQuery = {
price: parseUnits("3000", 18), // $3000 with 18 decimals
decimals: 18,
dataTimestamp: Math.floor(Date.now() / 1000),
assetPair: keccak256(toBytes("ETH/USD")),
signature: "0x..." // Signed price attestation
};
// Get the collateralization ratio
const ratio = await positionEscrow.read.getCollateralizationRatio([priceQuery]);
// ratio is scaled by 10000, so 11000 = 110.00%
const ratioPercent = Number(ratio) / 100; // Convert to percentage (110.00)
console.log(`Position collateralization ratio: ${ratioPercent}%`);
# Python example
def calculate_collateralization_ratio(position_escrow, eth_usd_price):
price_query = {
'price': int(eth_usd_price * 10**18), # Convert to wei with 18 decimals
'decimals': 18,
'dataTimestamp': int(time.time()),
'assetPair': Web3.keccak(text="ETH/USD"),
'signature': "0x..." # Your signed price attestation
}
ratio = position_escrow.functions.getCollateralizationRatio(price_query).call()
ratio_percent = ratio / 100 # Convert from basis points to percentage
return ratio_percent
3. Determining Liquidation Eligibility
A position becomes eligible for liquidation when its ratio falls below the liquidation threshold. The threshold depends on the liquidator’s NFT ID:
// Calculate liquidation threshold based on liquidator's NFT ID
function calculateLiquidationThreshold(liquidatorTokenId) {
if (liquidatorTokenId === 0) {
return 110.00; // Default threshold (110%)
}
const baseThreshold = 125.00; // 125%
const minThreshold = 110.00; // 110%
const decrement = (liquidatorTokenId - 1) * 0.5; // 0.5% per ID
const calculatedThreshold = baseThreshold - decrement;
return Math.max(calculatedThreshold, minThreshold);
}
// Check if position is liquidatable
const liquidatorTokenId = 5; // Your liquidator NFT ID
const threshold = calculateLiquidationThreshold(liquidatorTokenId);
const currentRatio = Number(await positionEscrow.getCollateralizationRatio(priceQuery)) / 100;
const isLiquidatable = currentRatio < threshold;
console.log(`Position ratio: ${currentRatio}%, Threshold: ${threshold}%, Liquidatable: ${isLiquidatable}`);
4. Getting Position Data for Liquidation
Before executing a liquidation, you need to determine how much can be liquidated:
import { formatEther } from 'viem';
// Get the backed pool shares (liability) of the position
const backedShares = await positionEscrow.read.backedPoolShares();
// Get current stETH balance (collateral)
const stEthBalance = await positionEscrow.read.getCurrentStEthBalance();
console.log(`Position has ${formatEther(backedShares)} backed shares`);
console.log(`Position has ${formatEther(stEthBalance)} stETH collateral`);
// You can liquidate up to the full backed shares amount
const maxLiquidatableShares = backedShares;
5. Monitoring Events for Position Changes
To build an effective liquidation bot, monitor these key events:
import { formatEther } from 'viem';
// Monitor CollateralAdded events on PositionEscrow contracts
const unwatch1 = publicClient.watchContractEvent({
address: positionEscrowAddress,
abi: positionEscrowAbi,
eventName: 'CollateralAdded',
onLogs: (logs) => {
logs.forEach((log) => {
const { amount } = log.args;
console.log(`Collateral added to position ${tokenId}: ${formatEther(amount)} stETH`);
// Recalculate position health
});
}
});
// Monitor CollateralRemoved events
const unwatch2 = publicClient.watchContractEvent({
address: positionEscrowAddress,
abi: positionEscrowAbi,
eventName: 'CollateralRemoved',
onLogs: (logs) => {
logs.forEach((log) => {
const { recipient, amount } = log.args;
console.log(`Collateral removed from position ${tokenId}: ${formatEther(amount)} stETH`);
// Recalculate position health
});
}
});
// Monitor AllocationModified events (changes in backed shares/liability)
const unwatch3 = publicClient.watchContractEvent({
address: positionEscrowAddress,
abi: positionEscrowAbi,
eventName: 'AllocationModified',
onLogs: (logs) => {
logs.forEach((log) => {
const { sharesDelta, newTotalShares } = log.args;
console.log(`Position ${tokenId} allocation changed by ${formatEther(sharesDelta)} shares`);
console.log(`New total backed shares: ${formatEther(newTotalShares)}`);
// Recalculate position health
});
}
});
// Monitor StabilizerNFT events for new positions
const unwatch4 = publicClient.watchContractEvent({
address: STABILIZER_NFT_ADDRESS,
abi: stabilizerNFTAbi,
eventName: 'StabilizerPositionCreated',
onLogs: (logs) => {
logs.forEach((log) => {
const { tokenId, owner } = log.args;
console.log(`New Stabilizer Position created: ${tokenId} owned by ${owner}`);
// Add to monitoring list
});
}
});
# Python event monitoring example
def handle_collateral_added(event):
token_id = event['args']['tokenId'] # You'll need to track this mapping
amount = event['args']['amount']
print(f"Collateral added to position {token_id}: {Web3.fromWei(amount, 'ether')} stETH")
# Trigger position health recalculation
# Set up event filters
collateral_filter = position_escrow.events.CollateralAdded.createFilter(fromBlock='latest')
allocation_filter = position_escrow.events.AllocationModified.createFilter(fromBlock='latest')
# Poll for events in your main loop
for event in collateral_filter.get_new_entries():
handle_collateral_added(event)
This technical foundation enables developers to build sophisticated liquidation bots that can monitor position health in real-time and execute profitable liquidations when positions become undercollateralized.