diff --git a/common/configuration.ts b/common/configuration.ts index d5164fa63..4930e41ba 100644 --- a/common/configuration.ts +++ b/common/configuration.ts @@ -115,6 +115,10 @@ export interface ITokens { // Mountain USDM?: string wUSDM?: string + + // Anzen + USDZ?: string + sUSDz?: string } export type ITokensKeys = Array @@ -256,6 +260,8 @@ export const networkConfig: { [key: string]: INetworkConfig } = { sdUSDCUSDCPlus: '0x9bbF31E99F30c38a5003952206C31EEa77540BeF', USDe: '0x4c9edd5852cd905f086c759e8383e09bff1e68b3', sUSDe: '0x9D39A5DE30e57443BfF2A8307A4256c8797A3497', + USDz: '0xA469B7Ee9ee773642b3e93E842e5D9b5BaA10067', + sUSDz: '0x547213367cfB08ab418E7b54d7883b2C2AA27Fd7', }, chainlinkFeeds: { RSR: '0x759bBC1be8F90eE6457C44abc7d443842a976d02', @@ -513,6 +519,8 @@ export const networkConfig: { [key: string]: INetworkConfig } = { sUSDbC: '0x4c80e24119cfb836cdf0a6b53dc23f04f7e652ca', wstETH: '0xc1CBa3fCea344f92D9239c08C0568f6F2F0ee452', STG: '0xE3B53AF74a4BF62Ae5511055290838050bf764Df', + USDz: '0x04D5ddf5f3a8939889F11E97f8c4BB48317F1938', + sUSDz: '0xe31eE12bDFDD0573D634124611e85338e2cBF0cF', }, chainlinkFeeds: { DAI: '0x591e79239a7d679378ec8c847e5038150364c78f', // 0.3%, 24hr @@ -529,6 +537,8 @@ export const networkConfig: { [key: string]: INetworkConfig } = { stETHETH: '0xf586d0728a47229e747d824a939000Cf21dEF5A0', // 0.5%, 24h ETHUSD: '0x71041dddad3595F9CEd3DcCFBe3D1F4b0a16Bb70', // 0.15%, 20min wstETHstETH: '0xB88BAc61a4Ca37C43a3725912B1f472c9A5bc061', // 0.5%, 24h + USDz: '0xe25969e2Fa633a0C027fAB8F30Fc9C6A90D60B48', // 0.5%, 24hr + sUSDzUSDzexr: '0xD89c7fFB39C44b17EAecd8717a75A36c19C07582', // 0.5%, 24hr }, GNOSIS_EASY_AUCTION: '0xb1875Feaeea32Bbb02DE83D81772e07E37A40f02', // mock COMET_REWARDS: '0x123964802e6ABabBE1Bc9547D72Ef1B69B00A6b1', diff --git a/contracts/plugins/assets/anzen/L2USDzFiatCollateral.sol b/contracts/plugins/assets/anzen/L2USDzFiatCollateral.sol new file mode 100644 index 000000000..c8eaf8747 --- /dev/null +++ b/contracts/plugins/assets/anzen/L2USDzFiatCollateral.sol @@ -0,0 +1,91 @@ +// SPDX-License-Identifier: BlueOak-1.0.0 +pragma solidity 0.8.19; + +import "@openzeppelin/contracts/utils/math/Math.sol"; +import "../../../libraries/Fixed.sol"; +import "../AppreciatingFiatCollateral.sol"; +import "../OracleLib.sol"; + +/** + * @title USDz Fiat Collateral for L2s (like Base) + * @notice Collateral plugin for USDz (Anzen Finance) + * tok = sUSDz (wrapped USDz, ERC4626 vault on Ethereum Mainnet) + * ref = USDz + * tar = USD + * UoA = USD + */ + +contract L2USDzFiatCollateral is AppreciatingFiatCollateral { + using OracleLib for AggregatorV3Interface; + using FixLib for uint192; + + // Here we include them directly and ignore the parent class' chainlinkFeed entirely. + + AggregatorV3Interface public immutable targetPerRefChainlinkFeed; // {tar/ref} + uint48 public immutable targetPerRefChainlinkTimeout; // {s} + + AggregatorV3Interface public immutable refPerTokenChainlinkFeed; // {ref/tok} + uint48 public immutable refPerTokenChainlinkTimeout; // {s} + + /// @param config.chainlinkFeed - ignored + /// @param config.oracleTimeout - ignored + /// @param config.oracleError {1} Should be the oracle error for UoA/tok + constructor( + CollateralConfig memory config, + uint192 revenueHiding, + AggregatorV3Interface _targetPerRefChainlinkFeed, + uint48 _targetPerRefChainlinkTimeout, + AggregatorV3Interface _refPerTokenChainlinkFeed, + uint48 _refPerTokenChainlinkTimeout + ) AppreciatingFiatCollateral(config, revenueHiding) { + require(config.defaultThreshold != 0, "defaultThreshold zero"); + + require(address(_targetPerRefChainlinkFeed) != address(0), "targetPerRefFeed missing"); + require(_targetPerRefChainlinkTimeout != 0, "targetPerRefTimeout zero"); + require(address(_refPerTokenChainlinkFeed) != address(0), "refPerTokenFeed missing"); + require(_refPerTokenChainlinkTimeout != 0, "refPerTokenTimeout zero"); + + targetPerRefChainlinkFeed = _targetPerRefChainlinkFeed; + targetPerRefChainlinkTimeout = _targetPerRefChainlinkTimeout; + + refPerTokenChainlinkFeed = _refPerTokenChainlinkFeed; + refPerTokenChainlinkTimeout = _refPerTokenChainlinkTimeout; + maxOracleTimeout = uint48( + Math.max( + Math.max(maxOracleTimeout, _targetPerRefChainlinkTimeout), + Math.max(maxOracleTimeout, _refPerTokenChainlinkTimeout) + ) + ); + } + + /// Can revert, used by other contract functions in order to catch errors + /// @return low {UoA/tok} The low price estimate + /// @return high {UoA/tok} The high price estimate + /// @return pegPrice {target/ref} The actual price observed in the peg + function tryPrice() + external + view + override + returns ( + uint192 low, + uint192 high, + uint192 pegPrice + ) + { + // {tar/ref} Get current market peg ({eth/steth}) + pegPrice = targetPerRefChainlinkFeed.price(targetPerRefChainlinkTimeout); + + // {UoA/tok} = {tar/ref} * {ref/tok} + uint192 p = pegPrice.mul(underlyingRefPerTok()); + uint192 err = p.mul(oracleError, CEIL); + + high = p + err; + low = p - err; + // assert(low <= high); obviously true just by inspection + } + + /// @return {ref/tok} Quantity of whole reference units per whole collateral tokens + function underlyingRefPerTok() public view override returns (uint192) { + return refPerTokenChainlinkFeed.price(refPerTokenChainlinkTimeout); + } +} \ No newline at end of file diff --git a/contracts/plugins/assets/anzen/README.md b/contracts/plugins/assets/anzen/README.md new file mode 100644 index 000000000..50592f86d --- /dev/null +++ b/contracts/plugins/assets/anzen/README.md @@ -0,0 +1,33 @@ +# Anzen USDz Collateral Plugin + +## Summary + +`USDz` is a stablecoin backed by a diversified portfolio of private credit assets, specifically over-collateralized asset-backed securities. These assets are rigorously underwritten in partnership with Percent, a US licensed broker-dealer that has structured and serviced over $1.7 billion in credit deals since 2018. The protocol deploys capital alongside institutional fiat investors, ensuring a robust and secure backing for USDz. + +The diversified credit portfolio underlying USDz provides a consistent income stream that can support sustainable rewards emissions for `sUSDz(Staked USDz)`. This design allows USDz to be a reliable store of value based on its stable RWA backing, with the added benefit of consistent rewards emissions that are uncorrelated to crypto price movements. + +`sUSDz` is a high-yield ERC4626 vault, most similar to the DAI savings module. This plugin allows `sUSDz` holders to use their tokens as collateral in the Reserve Protocol. + +Since it is ERC4626, the redeemable USDz amount can be obtained by dividing `sUSDz.totalAssets()` by `sUSDz.totalSupply()`. + +`USDz` contract: + - + - + +`sUSDz` contract: + - + - + +## Implementation + +### Units + +| tok | ref | target | UoA | +| ----- | ---- | ------ | --- | +| sUSDz | USDz | USD | USD | + +### Functions + +#### refPerTok {ref/tok} + +`return shiftl_toFix(erc4626.convertToAssets(oneShare), -refDecimals)` \ No newline at end of file diff --git a/contracts/plugins/assets/anzen/USDzFiatCollateral.sol b/contracts/plugins/assets/anzen/USDzFiatCollateral.sol new file mode 100644 index 000000000..04b64224d --- /dev/null +++ b/contracts/plugins/assets/anzen/USDzFiatCollateral.sol @@ -0,0 +1,25 @@ +// SPDX-License-Identifier: BlueOak-1.0.0 +pragma solidity 0.8.19; + +import { CollateralConfig } from "../AppreciatingFiatCollateral.sol"; +import { ERC4626FiatCollateral } from "../ERC4626FiatCollateral.sol"; + +/** + * @title USDz Fiat Collateral + * @notice Collateral plugin for USDz (Anzen Finance) + * tok = sUSDz (ERC4626 vault) + * ref = USDz + * tar = USD + * UoA = USD + */ + +contract USDzFiatCollateral is ERC4626FiatCollateral { + /// config.erc20 must be sUSDz + /// @param config.chainlinkFeed Feed units: {UoA/ref} + /// @param revenueHiding {1} A value like 1e-6 that represents the maximum refPerTok to hide + constructor(CollateralConfig memory config, uint192 revenueHiding) + ERC4626FiatCollateral(config, revenueHiding) + { + require(config.defaultThreshold != 0, "defaultThreshold zero"); + } +} \ No newline at end of file