Skip to main content

Overview

Stablecoin delegate contracts manage the integration between the Multiliquid Protocol and the counterparty to the swap, either stablecoin issuers (mint/burn) or organizations providing already existing liquidity (balance sheet). A stablecoin delegate contract focuses on one specific stablecoin and routes its operations through that lens. This means the delegate will handle any minting/burning or transfers, contain a custody address that holds RWAs and other stablecoin liquidity, as well as provide administrative functions for whitelisting, fee configuration, and pausability. Base Contract: src/v2/StablecoinDelegateBase.sol

Delegate Types

MintBurnStablecoinDelegate

For stablecoins with native mint/burn capability. Location: src/v2/MintBurnStablecoinDelegate.sol Characteristics:
  • Directly mints stablecoins during RWA → Stablecoin swaps
  • Directly burns stablecoins during Stablecoin → RWA swaps
  • Requires MINTER_ROLE on the stablecoin contract
  • No custody management needed

BalanceSheetStablecoinDelegate

For existing stablecoin liquidity balances without mint/burn integration Location: src/v2/BalanceSheetStablecoinDelegate.sol Characteristics:
  • Transfers stablecoins from custody during RWA → Stablecoin swaps
  • Receives stablecoins to custody during Stablecoin → RWA swaps
  • Manages custody addresses for RWA tokens
  • Requires pre-funded stablecoin reserves

Core Interface

All stablecoin delegates implement IStablecoinDelegateV2:
interface IStablecoinDelegateV2 {
    struct DeployStablecoinParams {
        address vault;
        uint256 vaultAmount;
        address user;
        uint256 userAmount;
        address rwaAddress;
        uint256 rwaAmount;
        bytes metadata;
    }

    struct ReceiveStablecoinParams {
        address user;
        uint256 totalAmount;
        address vault;
        uint256 vaultAmount;
        uint256 redemptionFeeAmt;
        address rwaAddress;
        uint256 rwaAmount;
        bytes metadata;
    }

    struct ExchangeRWAsParams {
        address user;
        address vault;
        uint256 protocolFeeAmt;
        uint256 redemptionFeeAmt;
        address rwaInAddress;
        uint256 rwaInAmount;
        address rwaOutAddress;
        uint256 rwaOutAmount;
        bytes rwaInMetadata;
        bytes rwaOutMetadata;
    }

    struct ExchangeStablecoinsParams {
        address user;
        address vault;
        uint256 protocolFeeAmt;
        uint256 acceptanceFeeAmt;
        uint256 redemptionFeeAmt;
        address stablecoinInAddress;
        uint256 stablecoinInAmount;
        address stablecoinOutAddress;
        uint256 stablecoinOutAmount;
        bytes stablecoinInMetadata;
        bytes stablecoinOutMetadata;
    }

    // Swap operations (called by MultiliquidSwap)
    function deployStablecoin(DeployStablecoinParams calldata params) external returns (bool success);
    function receiveStablecoin(ReceiveStablecoinParams calldata params) external returns (bool success);
    function exchangeRWAs(ExchangeRWAsParams calldata params) external returns (bool success);
    function exchangeStablecoins(ExchangeStablecoinsParams calldata params) external returns (bool success);

    // Whitelist management
    function whitelistStablecoin(address stablecoin, bool accepted) external;
    function whitelistRWA(address rwa, bool accepted) external;

    // Configuration
    function setRWACustodyAddress(address _balanceSheetCustodyAddress) external;
    function setStablecoinCustodyAddress(address _stablecoinCustodyAddress) external;
    function setRWADiscountRate(bytes32 rwaID, uint256 rate) external;
    function setRWARedemptionFee(bytes32 rwaID, uint256 rate) external;
    function setStablecoinAcceptanceFee(address stablecoin, uint256 rate) external;
    function setStablecoinRedemptionFee(address stablecoin, uint256 rate) external;
    
    // Pause controls
    function pause() external;
    function unpause() external;
}

Key Functions

deployStablecoin

Called by MultiliquidSwap during RWA → Stablecoin swaps.
function deployStablecoin(DeployStablecoinParams calldata params)
    external
    onlyRole(MULTILIQUID_SWAP_CONTRACT)
    returns (bool success);
Parameters (DeployStablecoinParams):
  • vault: Address to receive protocol fee
  • vaultAmount: Protocol fee amount
  • user: Address receiving stablecoins
  • userAmount: Stablecoin amount to user
  • rwaAddress: RWA token address
  • rwaAmount: RWA amount being deposited
  • metadata: Optional metadata for the swap
Process:
  1. Validates RWA is whitelisted
  2. Receives RWA tokens from user to custody/issuer
  3. Mints or transfers stablecoins to user
  4. Transfers protocol fee to vault
  5. Returns success status
Access: Only MultiliquidSwap contract

receiveStablecoin

Called by MultiliquidSwap during Stablecoin → RWA swaps.
function receiveStablecoin(ReceiveStablecoinParams calldata params)
    external
    onlyRole(MULTILIQUID_SWAP_CONTRACT)
    returns (bool success);
Parameters (ReceiveStablecoinParams):
  • user: Address receiving RWA tokens
  • totalAmount: Total stablecoin amount (includes fees)
  • vault: Address to receive protocol fee
  • vaultAmount: Protocol fee amount
  • redemptionFeeAmt: Redemption fee charged by issuer
  • rwaAddress: RWA token address
  • rwaAmount: RWA amount to transfer to user
  • metadata: Optional metadata for the swap
Process:
  1. Validates RWA is whitelisted
  2. Burns or receives stablecoins from user
  3. Transfers RWA tokens from custody to user
  4. Handles protocol and redemption fees
  5. Returns success status
Access: Only MultiliquidSwap contract

exchangeRWAs

Called by MultiliquidSwap for RWA-to-RWA swaps (using this stablecoin for pricing).
function exchangeRWAs(ExchangeRWAsParams calldata params)
    external
    onlyRole(MULTILIQUID_SWAP_CONTRACT)
    returns (bool success);
Process:
  1. Receives rwaInAmount of rwaInAddress from user
  2. Transfers rwaOutAmount of rwaOutAddress to user
  3. Collects protocol and redemption fees
  4. Returns success status
Access: Only MultiliquidSwap contract

exchangeStablecoins

Called by MultiliquidSwap for stablecoin-to-stablecoin swaps.
function exchangeStablecoins(ExchangeStablecoinsParams calldata params)
    external
    onlyRole(MULTILIQUID_SWAP_CONTRACT)
    returns (bool success);
Process:
  1. Receives stablecoinInAmount from user
  2. Transfers or mints stablecoinOutAmount to user
  3. Collects acceptance and redemption fees
  4. Returns success status
Access: Only MultiliquidSwap contract

Whitelist Management

whitelistRWA

Add or remove an RWA from this stablecoin’s whitelist.
function whitelistRWA(address rwa, bool accepted) external onlyIssuerAdmin;
Parameters:
  • rwa: Address of the RWA token
  • accepted: true to whitelist, false to remove
Effect: Enables/disables swaps between this stablecoin and the RWA Event:
event RWAWhitelist(address indexed rwa, bool accepted);

whitelistStablecoin

Add or remove another stablecoin for cross-stablecoin swaps.
function whitelistStablecoin(address stablecoin, bool accepted) external onlyIssuerAdmin;
Parameters:
  • stablecoin: Address of the other stablecoin
  • accepted: true to whitelist, false to remove
Effect: Enables/disables swaps between this stablecoin and another stablecoin Event:
event StablecoinWhitelist(address indexed stablecoin, bool accepted);

Fee Configuration

setRWADiscountRate

Set discount rate for a specific RWA.
function setRWADiscountRate(bytes32 rwaID, uint256 rate) external onlyIssuerAdmin;
Parameters:
  • rate: Discount in WAD format (1e18 = 100%)
  • Example: 5% discount = 5e16
Effect: Reduces swap cost when swapping into the RWA

setRWARedemptionFee

Set redemption fee for a specific RWA.
function setRWARedemptionFee(bytes32 rwaID, uint256 rate) external onlyIssuerAdmin;
Parameters:
  • rate: Fee in WAD format (1e18 = 100%)
  • Example: 0.5% fee = 5e15
Effect: Additional fee charged when swapping stablecoin → RWA

Custody Management

Both custody addresses must be set before swap operations can execute (enforced by custodyAddressesSet modifier).

setRWACustodyAddress

Set the custody address for RWA tokens.
function setRWACustodyAddress(address _balanceSheetCustodyAddress) external onlyIssuerAdmin;
Purpose: Defines where RWA tokens are held during swaps Event:
event RWACustodyAddressSet(address indexed balanceSheetCustodyAddress);

setStablecoinCustodyAddress

Set the custody address for stablecoin reserves and fees.
function setStablecoinCustodyAddress(address _stablecoinCustodyAddress) external onlyIssuerAdmin;
Purpose: Defines where stablecoin reserves are held and where redemption/acceptance fees are collected Event:
event StablecoinCustodyAddressSet(address indexed stablecoinCustodyAddress);

Access Control

DEFAULT_ADMIN_ROLE: Can upgrade delegate, manage all roles ISSUER_ADMIN_ROLE: Stablecoin issuer’s administrative role
  • Manage RWA and stablecoin whitelists
  • Set discount rates and redemption fees
  • Configure custody addresses
  • Pause/unpause delegate
MULTILIQUID_SWAP_CONTRACT: Granted to MultiliquidSwap contract
  • Execute swaps
  • Trigger minting/burning
PAUSE_ROLE: Emergency pause capability for Multiliquid protocol
  • Can call pauseMultiliquid() / unpauseMultiliquid() (separate from issuer admin pause)

Events

event RWAWhitelist(address indexed rwa, bool accepted);
event StablecoinWhitelist(address indexed stablecoin, bool accepted);
event RWADiscountRateSet(bytes32 indexed rwaID, uint256 indexed rate);
event RedemptionFeeSet(bytes32 indexed rwaID, uint256 indexed rate);
event StablecoinAcceptanceFeeSet(address indexed stablecoin, uint256 indexed rate);
event StablecoinRedemptionFeeSet(address indexed stablecoin, uint256 indexed rate);
event RWACustodyAddressSet(address indexed balanceSheetCustodyAddress);
event StablecoinCustodyAddressSet(address indexed stablecoinCustodyAddress);

event Paused();
event Unpaused();

Next: RWA Delegate Contracts

Explore optional risk management contracts for Real World Asset tokens