Smart Contracts
All 9 UPD smart contracts — their purpose, interfaces, deploy order, and roles.
Smart Contracts
UPD consists of 9 smart contracts. All written in Solidity 0.8.29, deployed with Foundry.
Deploy Order
The contracts must be deployed in this order (no circular dependencies):
1. PriceOracle
2. UPDToken
3. PositionEscrow (impl)
4. StabilizerEscrow (impl)
5. StabilizerNFT
6. OvercollateralizationReporter
7. InsuranceEscrow
8. BridgeEscrow
9. sUPD (stub)Contracts
UPDToken
Role: Standard ERC20 for the $1 stablecoin.
interface IUPDToken is IERC20, IERC20Permit {
function mint(address to, uint256 amount) external; // onlyRole(MINTER_ROLE)
function burn(address from, uint256 amount) external; // onlyRole(BURNER_ROLE)
}StabilizerNFT holds both MINTER_ROLE and BURNER_ROLE. No other address can mint or burn. No blacklist function exists.
StabilizerNFT
Role: Orchestrates minting, burning, collateral allocation, and liquidation.
interface IStabilizerNFT {
function mint(address to, uint256 ethAmount, PriceAttestation calldata price)
external payable returns (uint256 updMinted);
function burn(address from, uint256 updAmount, PriceAttestation calldata price)
external returns (uint256 stEthReturned);
function liquidate(uint256 stabilizerTokenId) external;
function getPosition(uint256 tokenId) external view returns (Position memory);
function utilizationOf(uint256 tokenId) external view returns (uint256 bps);
}Uses two external Solidity libraries:
LinkedListLib— sorted doubly-linked list for priority ordering (deployed separately, DELEGATECALL)CollateralMathLib— pure math for allocation ratios and liquidation thresholds (internal)
PositionEscrow
Role: Holds stETH backing for a specific Stabilizer's active UPD position.
One PositionEscrow is created (by clone) per Stabilizer.
StabilizerEscrow
Role: Holds unallocated stETH per Stabilizer — collateral deposited but not yet backing UPD.
PriceOracle
Role: Validates signed ETH/USD price attestations from Chainlink and Uniswap V3.
interface IPriceOracle {
function validate(PriceAttestation calldata attestation)
external view returns (uint256 price);
}UUPS upgradeable — can add new price sources without redeploying the full system.
OvercollateralizationReporter
Role: Tracks the system-wide collateralization ratio on-chain.
interface IOvercollateralizationReporter {
function collateralizationRatio() external view returns (uint256 bps);
function isSystemSolvent() external view returns (bool);
}InsuranceEscrow
Role: Emergency buffer for undercollateralization events. Funded by protocol fees or manual injection.
BridgeEscrow
Role: Lock/release mechanism for L1↔L2 bridging of UPD.
sUPD
Role: Yield-bearing staked UPD wrapper. Receives yield via injectYield(). Currently a stub.
ABIs
import {
UPD_TOKEN_ABI,
STABILIZER_NFT_ABI,
PRICE_ORACLE_ABI,
POSITION_ESCROW_ABI,
STABILIZER_ESCROW_ABI,
OVERCOLLATERALIZATION_REPORTER_ABI,
INSURANCE_ESCROW_ABI,
BRIDGE_ESCROW_ABI,
SUPD_ABI,
} from '@permissionless-technologies/upd-sdk/contracts'Contract Addresses
Addresses are available in the SDK for each supported chain:
import { getContractAddresses } from '@permissionless-technologies/upd-sdk/contracts'
const addresses = getContractAddresses(chainId)
// { updToken, stabilizerNFT, priceOracle, ... }Library Contracts
LinkedListLib and CollateralMathLib are deployed as standalone library contracts.
LinkedListLib uses DELEGATECALL (external library) for real bytecode savings.
CollateralMathLib is internal (inlined at compile time).