UPD — Universal Private DollarSmart Contracts

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).

On this page