Oracle System

Overview

The oracle system provides critical price data for cross-chain vaults and performance tracking. It enables accurate fee calculation, share price updates, and yield tracking across multiple chains.

Price Oracle Integration

Oracle Setup

function setOracle(
    uint64 chainId,
    address oracle
) external onlyRoles(ADMIN_ROLE)

Process Flow:

  1. Admin configures chain-specific oracle

  2. Oracle starts tracking vault share prices

  3. Updates trigger fee calculations

Price Updates

function harvest(Harvest[] calldata harvests) external updateWatermark {
    uint256 duration = block.timestamp - lastReport;
    uint256 sharePrice_ = sharePrice();
    
    for (uint256 i = 0; i < harvests.length; i++) {
        Harvest memory _vault = harvests[i];
        
        // Get latest price from oracle
        VaultReport memory report = vault.oracle.getLatestSharePrice(
            _vault.chainId,
            _vault.vaultAddress
        );
        
        // Update cached price
        vaults[superformId].lastReportedSharePrice = uint192(report.sharePrice);
        
        // Calculate yield
        uint256 totalAssetsAfter = vault.convertToAssets(sharesBalance, true);
        int256 vaultDelta = int256(totalAssetsAfter) - int256(totalAssetsBefore);
        
        // Process fees if profitable
        if (vaultDelta > 0) {
            _processPerformanceFees(vaultDelta, sharePrice_, duration);
        }
    }
}

Price Validation

Staleness Check

error StaleSharePrice();

function convertToAssets(
    VaultData memory self,
    uint256 shares,
    bool revertIfStale
) internal view returns (uint256) {
    if (self.chainId != _chainId()) {
        VaultReport memory report = self.oracle.getLatestSharePrice(
            self.chainId, 
            self.vaultAddress
        );
        
        if (revertIfStale && 
            report.lastUpdate + ORACLE_STALENESS_TOLERANCE < block.timestamp) {
            revert StaleSharePrice();
        }
        
        return report.sharePrice * shares / 10 ** self.decimals;
    }
}

Price Update Frequency

  • Maximum staleness: 8 hours (ORACLE_STALENESS_TOLERANCE)

  • Updates trigger fee assessments

  • Staleness affects operations

Oracle Rewards

Fee Distribution

function _assessOracleFees(
    address oracleFeeReceiver,
    uint256 duration
) private {
    uint256 oracleFees = (totalAssets() * duration * oracleFee) 
        / SECS_PER_YEAR 
        / MAX_BPS;
        
    uint256 oracleFeeShares = convertToShares(oracleFees);
    _mint(oracleFeeReceiver, oracleFeeShares);
}

Reward Configuration

function setOracleFee(
    uint16 _oracleFee
) external onlyRoles(ADMIN_ROLE) {
    oracleFee = _oracleFee;
    emit SetOracleFee(_oracleFee);
}

Share Price Tracking

Price Cache

struct VaultData {
    uint192 lastReportedSharePrice;   // Cached share price
    ISharePriceOracle oracle;         // Price oracle
}

Price Updates

function sharePrice() public view returns (uint256) {
    if (data.chainId != _chainId()) {
        VaultReport memory report = data.oracle.getLatestSharePrice(
            data.chainId,
            data.vaultAddress
        );
        return report.sharePrice;
    } else {
        return ERC4626(data.vaultAddress).convertToAssets(10 ** data.decimals);
    }
}

Security Considerations

Price Manipulation Protection

  • Staleness checks

  • Multiple oracle support

  • Price deviation limits

Cross-chain Security

  • Chain-specific oracles

  • Independent price validation

  • Timeout mechanisms

Integration Example

// Setup oracle for chain
vault.setOracle(
    137,                    // Polygon chain ID
    polygonOracleAddress    // Chain-specific oracle
);

// Update prices and process fees
vault.harvest([
    Harvest({
        chainId: 137,
        vaultAddress: polygonVault
    })
]);
  • See Asset Management for fee calculations

  • See Core Operations for price impact

  • See Settlement Mechanics for value calculations

Last updated