Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

SyntheticSplitter

Git Source

Inherits: ISyntheticSplitter, Ownable2Step, Pausable, ReentrancyGuard

Title: SyntheticSplitter

Core protocol contract for minting/burning synthetic plDXY tokens.

Accepts USDC collateral to mint equal amounts of plDXY-BEAR + plDXY-BULL tokens. Minted USDC stays local; a permissionless deployToAdapter() pushes excess above the 10% buffer into the yield adapter. Three lifecycle states: ACTIVE → PAUSED → SETTLED.

Note: security-contact: contact@plether.com

Constants

BEAR

SyntheticToken public immutable BEAR;

BULL

SyntheticToken public immutable BULL;

USDC

IERC20 public immutable USDC;

ORACLE

AggregatorV3Interface public immutable ORACLE;

CAP

uint256 public immutable CAP;

USDC_DECIMALS

uint256 private constant USDC_DECIMALS = 6;

USDC_MULTIPLIER

uint256 public constant USDC_MULTIPLIER = 10 ** (18 + 8 - USDC_DECIMALS);

BUFFER_PERCENT

uint256 public constant BUFFER_PERCENT = 10;

ORACLE_TIMEOUT

uint256 public constant ORACLE_TIMEOUT = 24 hours;

TIMELOCK_DELAY

uint256 public constant TIMELOCK_DELAY = 7 days;

HARVEST_REWARD_BPS

uint256 public constant HARVEST_REWARD_BPS = 10;

MIN_SURPLUS_THRESHOLD

uint256 public constant MIN_SURPLUS_THRESHOLD = 50 * 10 ** USDC_DECIMALS;

MIN_DEPLOY_AMOUNT

uint256 public constant MIN_DEPLOY_AMOUNT = 100 * 10 ** USDC_DECIMALS;

SEQUENCER_UPTIME_FEED

AggregatorV3Interface public immutable SEQUENCER_UPTIME_FEED;

SEQUENCER_GRACE_PERIOD

uint256 public constant SEQUENCER_GRACE_PERIOD = 1 hours;

State Variables

yieldAdapter

IERC4626 public yieldAdapter;

pendingAdapter

address public pendingAdapter;

adapterActivationTime

uint256 public adapterActivationTime;

treasury

address public treasury;

staking

address public staking;

pendingFees

FeeConfig public pendingFees;

feesActivationTime

uint256 public feesActivationTime;

lastUnpauseTime

uint256 public lastUnpauseTime;

isLiquidated

bool public isLiquidated;

liquidationTimestamp

uint256 public liquidationTimestamp;

Functions

constructor

Deploys the SyntheticSplitter and creates plDXY-BEAR and plDXY-BULL tokens.

constructor(
    address _oracle,
    address _usdc,
    address _yieldAdapter,
    uint256 _cap,
    address _treasury,
    address _sequencerUptimeFeed
) Ownable(msg.sender);

Parameters

NameTypeDescription
_oracleaddressChainlink-compatible price feed for plDXY basket.
_usdcaddressUSDC token address (6 decimals).
_yieldAdapteraddressERC4626-compliant yield adapter for USDC deposits.
_capuint256Maximum plDXY price (8 decimals). Triggers liquidation when breached.
_treasuryaddressTreasury address for fee distribution.
_sequencerUptimeFeedaddressL2 sequencer uptime feed (address(0) for L1/testnets).

previewMint

Simulates a mint to see required USDC input

function previewMint(
    uint256 mintAmount
) external view returns (uint256 usdcRequired, uint256 depositToAdapter, uint256 keptInBuffer);

Parameters

NameTypeDescription
mintAmountuint256The amount of TokenA/B the user wants to mint

Returns

NameTypeDescription
usdcRequireduint256Total USDC needed from user
depositToAdapteruint256Always 0 (deployment is separate via deployToAdapter())
keptInBufferuint256Amount that will stay in Splitter contract (equals usdcRequired)

mint

Mint plDXY-BEAR and plDXY-BULL tokens by depositing USDC collateral.

function mint(
    uint256 amount
) external nonReentrant whenNotPaused;

Parameters

NameTypeDescription
amountuint256The amount of token pairs to mint (18 decimals).

mintWithPermit

Mint plDXY-BEAR and plDXY-BULL tokens with a USDC permit signature (gasless approval).

function mintWithPermit(
    uint256 amount,
    uint256 deadline,
    uint8 v,
    bytes32 r,
    bytes32 s
) external nonReentrant whenNotPaused;

Parameters

NameTypeDescription
amountuint256The amount of token pairs to mint (18 decimals).
deadlineuint256Unix timestamp after which the permit and transaction revert.
vuint8Signature recovery byte.
rbytes32Signature r component.
sbytes32Signature s component.

_mintCore

function _mintCore(
    uint256 amount
) internal;

previewBurn

Simulates a burn to see USDC return

function previewBurn(
    uint256 burnAmount
) external view returns (uint256 usdcRefund, uint256 withdrawnFromAdapter);

Parameters

NameTypeDescription
burnAmountuint256The amount of TokenA/B the user wants to burn

Returns

NameTypeDescription
usdcRefunduint256Total USDC user will receive
withdrawnFromAdapteruint256Amount pulled from Yield Source to cover shortage

burn

Burn plDXY-BEAR and plDXY-BULL tokens to redeem USDC collateral.

function burn(
    uint256 amount
) external nonReentrant;

Parameters

NameTypeDescription
amountuint256The amount of token pairs to burn (18 decimals).

_withdrawFromAdapter

Withdraws USDC from yield adapter with redeem fallback.

function _withdrawFromAdapter(
    uint256 amount
) internal;

Parameters

NameTypeDescription
amountuint256USDC amount to withdraw (6 decimals).

triggerLiquidation

Locks the protocol into liquidated state when price >= CAP.

Permissionless. Prevents system revival if price drops after breach.

function triggerLiquidation() external nonReentrant;

emergencyRedeem

Emergency redemption when protocol is liquidated (price >= CAP).

Only burns plDXY-BEAR tokens at CAP price. plDXY-BULL becomes worthless.

function emergencyRedeem(
    uint256 amount
) external nonReentrant;

Parameters

NameTypeDescription
amountuint256The amount of plDXY-BEAR tokens to redeem (18 decimals).

ejectLiquidity

Emergency exit: withdraws all funds from yield adapter.

Bypasses timelock. Auto-pauses protocol. Use if adapter is compromised.

function ejectLiquidity() external onlyOwner;

withdrawFromAdapter

Withdraws a specific amount from yield adapter while paused.

Requires protocol to be paused. Use for gradual liquidity extraction when full ejectLiquidity() fails due to adapter liquidity constraints.

function withdrawFromAdapter(
    uint256 amount
) external nonReentrant onlyOwner;

Parameters

NameTypeDescription
amountuint256Desired USDC amount to withdraw. Capped by adapter’s maxWithdraw.

deployToAdapter

Deploys excess local USDC to the yield adapter.

Permissionless keeper function. Pushes USDC above the 10% buffer target into the adapter. Returns 0 silently when nothing to deploy (keeper-friendly).

function deployToAdapter() external nonReentrant whenNotPaused returns (uint256 deployed);

Returns

NameTypeDescription
deployeduint256Amount of USDC deployed to the adapter.

_deployExcess

Pushes local USDC above the 10% buffer target into the yield adapter.

function _deployExcess() internal;

previewHarvest

Previews yield harvest amounts and eligibility.

function previewHarvest()
    external
    view
    returns (
        bool canHarvest,
        uint256 totalSurplus,
        uint256 callerReward,
        uint256 treasuryShare,
        uint256 stakingShare
    );

Returns

NameTypeDescription
canHarvestboolTrue if surplus exceeds MIN_SURPLUS_THRESHOLD.
totalSurplusuint256Available surplus (total assets - liabilities).
callerRewarduint256Caller incentive (0.1% of harvest).
treasuryShareuint256Treasury allocation (20% of remaining).
stakingShareuint256Staking allocation (80% of remaining).

harvestYield

Permissionless yield harvesting with automatic redeployment.

Pays surplus from local buffer first, only hits adapter for the remainder. After distribution, deploys any remaining excess to the adapter. Distributes: 0.1% to caller, 20% of remaining to treasury, 80% of remaining to staking.

function harvestYield() external nonReentrant whenNotPaused;

_checkLiveness

Enforces 7-day cooldown after unpause for governance actions.

function _checkLiveness() internal view;

proposeFeeReceivers

Propose new fee receiver addresses (7-day timelock).

function proposeFeeReceivers(
    address _treasury,
    address _staking
) external onlyOwner;

Parameters

NameTypeDescription
_treasuryaddressNew treasury address.
_stakingaddressNew staking address (can be zero to send all to treasury).

finalizeFeeReceivers

Finalize pending fee receiver change after timelock expires.

function finalizeFeeReceivers() external onlyOwner;

proposeAdapter

Propose a new yield adapter (7-day timelock).

function proposeAdapter(
    address _newAdapter
) external onlyOwner;

Parameters

NameTypeDescription
_newAdapteraddressAddress of the new ERC4626-compliant adapter.

finalizeAdapter

Finalize adapter migration after timelock. Migrates all funds atomically.

function finalizeAdapter() external nonReentrant onlyOwner;

pause

Pause the protocol. Blocks minting and harvesting.

function pause() external onlyOwner;

unpause

Unpause the protocol. Starts 7-day governance cooldown.

function unpause() external onlyOwner;

rescueToken

Rescue accidentally sent tokens. Cannot rescue core assets.

function rescueToken(
    address token,
    address to
) external onlyOwner;

Parameters

NameTypeDescription
tokenaddressThe ERC20 token to rescue.
toaddressThe recipient address.

currentStatus

Returns the current protocol lifecycle status.

function currentStatus() external view override returns (Status);

Returns

NameTypeDescription
<none>StatusThe current Status enum value (ACTIVE, PAUSED, or SETTLED).

getSystemStatus

Returns comprehensive system metrics for dashboards.

function getSystemStatus() external view returns (SystemStatus memory status);

Returns

NameTypeDescription
statusSystemStatusStruct containing price, collateral ratio, and liquidity data.

_getTotalLiabilities

Calculates total liabilities based on BEAR supply at CAP price.

function _getTotalLiabilities() internal view returns (uint256);

_getTotalAssets

Calculates total assets (local USDC + adapter value).

function _getTotalAssets() internal view returns (uint256);

_requireSolventIfPaused

Reverts if paused and insolvent (assets < liabilities).

function _requireSolventIfPaused() internal view;

_getOraclePrice

Oracle price validation using OracleLib.

function _getOraclePrice() internal view returns (uint256);

Events

Minted

event Minted(address indexed user, uint256 amount);

Burned

event Burned(address indexed user, uint256 amount);

AdapterProposed

event AdapterProposed(address indexed newAdapter, uint256 activationTime);

AdapterMigrated

event AdapterMigrated(address indexed oldAdapter, address indexed newAdapter, uint256 transferredAmount);

LiquidationTriggered

event LiquidationTriggered(uint256 price);

EmergencyRedeemed

event EmergencyRedeemed(address indexed user, uint256 amount);

YieldHarvested

event YieldHarvested(uint256 totalSurplus, uint256 treasuryAmt, uint256 stakingAmt);

FeesProposed

event FeesProposed(address indexed treasury, address indexed staking, uint256 activationTime);

FeesUpdated

event FeesUpdated(address indexed treasury, address indexed staking);

EmergencyEjected

event EmergencyEjected(uint256 amountRecovered);

DeployedToAdapter

event DeployedToAdapter(address indexed caller, uint256 amount);

AdapterWithdrawn

event AdapterWithdrawn(uint256 requested, uint256 withdrawn);

TokenRescued

event TokenRescued(address indexed token, address indexed to, uint256 amount);

Errors

Splitter__ZeroAddress

error Splitter__ZeroAddress();

Splitter__InvalidCap

error Splitter__InvalidCap();

Splitter__ZeroAmount

error Splitter__ZeroAmount();

Splitter__ZeroRefund

error Splitter__ZeroRefund();

Splitter__AdapterNotSet

error Splitter__AdapterNotSet();

Splitter__LiquidationActive

error Splitter__LiquidationActive();

Splitter__NotLiquidated

error Splitter__NotLiquidated();

Splitter__TimelockActive

error Splitter__TimelockActive();

Splitter__InvalidProposal

error Splitter__InvalidProposal();

Splitter__NoSurplus

error Splitter__NoSurplus();

Splitter__GovernanceLocked

error Splitter__GovernanceLocked();

Splitter__InsufficientHarvest

error Splitter__InsufficientHarvest();

Splitter__AdapterWithdrawFailed

error Splitter__AdapterWithdrawFailed();

Splitter__Insolvent

error Splitter__Insolvent();

Splitter__NotPaused

error Splitter__NotPaused();

Splitter__CannotRescueCoreAsset

error Splitter__CannotRescueCoreAsset();

Splitter__MigrationLostFunds

error Splitter__MigrationLostFunds();

Splitter__InvalidAdapter

error Splitter__InvalidAdapter();

Splitter__PermitFailed

error Splitter__PermitFailed();

Structs

FeeConfig

struct FeeConfig {
    address treasuryAddr;
    address stakingAddr;
}

SystemStatus

struct SystemStatus {
    uint256 currentPrice;
    uint256 capPrice;
    bool liquidated;
    bool isPaused;
    uint256 totalAssets; // Local + Adapter
    uint256 totalLiabilities; // Bear Supply * CAP
    uint256 collateralRatio; // Basis points
    uint256 adapterAssets; // USDC value held in yield adapter
}