-
Notifications
You must be signed in to change notification settings - Fork 111
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Co-authored-by: Taylor Brent <[email protected]>
- Loading branch information
1 parent
de7b0fe
commit 9598658
Showing
16 changed files
with
790 additions
and
6 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,31 @@ | ||
# Mountain USDM Collateral Plugin | ||
|
||
## Summary | ||
|
||
This plugin allows `wUSDM` holders to use their tokens as collateral in the Reserve Protocol. | ||
|
||
`wUSDM` is an unowned, immutable, ERC4626-wrapper around the USDM token. | ||
|
||
Since it is ERC4626, the redeemable USDM amount can be obtained by dividing `wUSDM.totalAssets()` by `wUSDM.totalSupply()`. | ||
|
||
`USDM` contract: <https://etherscan.io/address/0x59d9356e565ab3a36dd77763fc0d87feaf85508c#code> | ||
|
||
`wUSDM` contract: <https://etherscan.io/address/0x57f5e098cad7a3d1eed53991d4d66c45c9af7812#code> | ||
|
||
## Oracles - Important! | ||
|
||
A Chronicle oracle <https://chroniclelabs.org/> is available for `wUSDM`, Even though Chronicle oracles provide a compatible interface for reading prices, they require the reading contract to be **whitelisted** by Chronicle. It is important to provide the Chronicle team the collateral plugin address as soon as it is deployed to the network so they can whitelist it. This has to be done **before** the plugin is used by any RToken. | ||
|
||
## Implementation | ||
|
||
### Units | ||
|
||
| tok | ref | target | UoA | | ||
| ----- | ---- | ------ | --- | | ||
| wUSDM | USDM | USD | USD | | ||
|
||
### Functions | ||
|
||
#### refPerTok {ref/tok} | ||
|
||
`return shiftl_toFix(erc4626.convertToAssets(oneShare), -refDecimals)` |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,59 @@ | ||
// SPDX-License-Identifier: BlueOak-1.0.0 | ||
pragma solidity 0.8.19; | ||
|
||
import "../../../libraries/Fixed.sol"; | ||
import "../ERC4626FiatCollateral.sol"; | ||
|
||
/** | ||
* @title USDM Collateral | ||
* @notice Collateral plugin for USDM (Mountain Protocol) | ||
* tok = wUSDM (ERC4626 vault) | ||
* ref = USDM | ||
* tar = USD | ||
* UoA = USD | ||
* | ||
* Note: Uses a Chronicle Oracle, which requires the plugin address to be whitelisted | ||
*/ | ||
|
||
contract USDMCollateral is ERC4626FiatCollateral { | ||
using OracleLib for AggregatorV3Interface; | ||
using FixLib for uint192; | ||
|
||
// solhint-disable no-empty-blocks | ||
|
||
/// @param config.chainlinkFeed - {UoA/tok} - Chronicle oracle - Requires whitelisting! | ||
constructor(CollateralConfig memory config, uint192 revenueHiding) | ||
ERC4626FiatCollateral(config, revenueHiding) | ||
{ | ||
require(config.defaultThreshold != 0, "defaultThreshold zero"); | ||
} | ||
|
||
/// Can revert, used by other contract functions in order to catch errors | ||
/// Should not return FIX_MAX for low | ||
/// Should only return FIX_MAX for high if low is 0 | ||
/// @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 | ||
virtual | ||
override | ||
returns ( | ||
uint192 low, | ||
uint192 high, | ||
uint192 pegPrice | ||
) | ||
{ | ||
// {UoA/tok} | ||
uint192 p = chainlinkFeed.price(oracleTimeout); | ||
uint192 err = p.mul(oracleError, CEIL); | ||
|
||
low = p - err; | ||
high = p + err; | ||
// assert(low <= high); obviously true just by inspection | ||
|
||
// {target/ref} = {UoA/ref} = {UoA/tok} / {ref/tok} | ||
pegPrice = p.div(underlyingRefPerTok()); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,59 @@ | ||
// SPDX-License-Identifier: MIT | ||
pragma solidity ^0.8.19; | ||
|
||
/// Toll (whitelist) | ||
interface IToll { | ||
/// @notice Thrown by protected function if caller not tolled. | ||
/// @param caller The caller's address. | ||
error NotTolled(address caller); | ||
|
||
/// @notice Emitted when toll granted to address. | ||
/// @param caller The caller's address. | ||
/// @param who The address toll got granted to. | ||
event TollGranted(address indexed caller, address indexed who); | ||
|
||
/// @notice Grants address `who` toll. | ||
/// @dev Only callable by auth'ed address. | ||
/// @param who The address to grant toll. | ||
function kiss(address who) external; | ||
|
||
/// @notice Renounces address `who`'s toll. | ||
/// @dev Only callable by auth'ed address. | ||
/// @param who The address to renounce toll. | ||
function diss(address who) external; | ||
|
||
/// @notice Returns whether address `who` is tolled. | ||
/// @param who The address to check. | ||
/// @return True if `who` is tolled, false otherwise. | ||
function tolled(address who) external view returns (bool); | ||
} | ||
|
||
/** | ||
* @title IChronicle | ||
* | ||
* @notice Interface for Chronicle Protocol's oracle products | ||
*/ | ||
interface IChronicle is IToll { | ||
/// @notice Returns the oracle's current value. | ||
/// @dev Reverts if no value set. | ||
/// @return value The oracle's current value. | ||
function read() external view returns (uint256 value); | ||
|
||
/// @notice Returns the oracle's current value and its age. | ||
/// @dev Reverts if no value set. | ||
/// @return value The oracle's current value. | ||
/// @return age The value's age. | ||
function readWithAge() external view returns (uint256 value, uint256 age); | ||
|
||
/// Chainlink compatibility | ||
function latestRoundData() | ||
external | ||
view | ||
returns ( | ||
uint80 roundId, | ||
int256 answer, | ||
uint256 startedAt, | ||
uint256 updatedAt, | ||
uint80 answeredInRound | ||
); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,30 @@ | ||
{ | ||
"assets": { | ||
"COMP": "0x6882560A919714A742afd2A2a0af6b4D8d20cF22", | ||
"ARB": "0x21fBa52dA03e1F964fa521532f8B8951fC212055" | ||
}, | ||
"collateral": { | ||
"DAI": "0x6FE56A3EEa3fEc93601a94D26bEa1876bD48192F", | ||
"USDC": "0xa96aE05dFa869F4FCC4142E8D4E4F2706FEe2B57", | ||
"USDT": "0x3Ac8F000D75a2EA4a9a36c6844410926bc0c32f7", | ||
"saArbUSDCn": "0x7be9Bc50734820516693A376238Cc6Bf029BA682", | ||
"saArbUSDT": "0x529D7e23Ce63efdcE41dA2a41296Fd7399157F5b", | ||
"cUSDCv3": "0x8a5DfEa5cdA35AB374ac558951A3dF1437A6FcA6", | ||
"cvxCrvUSDUSDT": "0xf729b03AcbD60c8aF9B449d51444445815a56d0e", | ||
"cvxCrvUSDUSDC": "0x57547D29cf0D5B4d31c6c71Ec73b3A8c8416ade6", | ||
"wUSDM": "0xA185a9fd314b61f33F740760a59cc46b31297e30" | ||
}, | ||
"erc20s": { | ||
"COMP": "0x354A6dA3fcde098F8389cad84b0182725c6C91dE", | ||
"DAI": "0xDA10009cBd5D07dd0CeCc66161FC93D7c9000da1", | ||
"USDC": "0xaf88d065e77c8cc2239327c5edb3a432268e5831", | ||
"USDT": "0xfd086bc7cd5c481dcc9c85ebe478a1c0b69fcbb9", | ||
"saArbUSDCn": "0x030cDeCBDcA6A34e8De3f49d1798d5f70E3a3414", | ||
"saArbUSDT": "0xffef97179f58a582dEf73e6d2e4BcD2BDC8ca128", | ||
"cUSDCv3": "0xd54804250E9C561AEa9Dee34e9cf2342f767ACC5", | ||
"ARB": "0x912ce59144191c1204e64559fe8253a0e49e6548", | ||
"cvxCrvUSDUSDT": "0xf74d4C9b0F49fb70D8Ff6706ddF39e3a16D61E67", | ||
"cvxCrvUSDUSDC": "0xBFEE9F3E015adC754066424AEd535313dc764116", | ||
"wUSDM": "0x57f5e098cad7a3d1eed53991d4d66c45c9af7812" | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,38 @@ | ||
{ | ||
"prerequisites": { | ||
"RSR": "0xCa5Ca9083702c56b481D1eec86F1776FDbd2e594", | ||
"RSR_FEED": "0xcfF9349ec6d027f20fC9360117fef4a1Ad38B488", | ||
"GNOSIS_EASY_AUCTION": "0xcD033976a011F41D2AB6ef47984041568F818E73" | ||
}, | ||
"tradingLib": "0x348644F24FA34c40a8E3C4Cf9aF14f8a96aD63fC", | ||
"cvxMiningLib": "", | ||
"facade": "0x387A0C36681A22F728ab54426356F4CAa6bB48a9", | ||
"facets": { | ||
"actFacet": "0xE774CCF1431c3DEe7Fa4c20f67534b61289CAa45", | ||
"readFacet": "0x15175d35F3d88548B49600B4ee8067253A2e4e66" | ||
}, | ||
"facadeWriteLib": "0x042D85e9eb1F4372ffA362240E0630229CaA1904", | ||
"basketLib": "0x53f1Df4E5591Ae35Bf738742981669c3767241FA", | ||
"facadeWrite": "0xe2B652E538543d02f985A5E422645A704633956d", | ||
"deployer": "0xfd7eb6B208E1fa7B14E26A1fb10fFC17Cf695d68", | ||
"rsrAsset": "0x7182e3A6E29936C8B14c4fa6f63a62D0b1D0f767", | ||
"implementations": { | ||
"main": "0xf7a9D27c3B60c78c6F6e2c2d6ED6E8B94b352461", | ||
"trading": { | ||
"gnosisTrade": "0xD42620d04fCe65B1F5E8Facc894a2e34D764FEc9", | ||
"dutchTrade": "0x8b4374005291B8FCD14C4E947604b2FB3C660A73" | ||
}, | ||
"components": { | ||
"assetRegistry": "0xA9df960Af018178C0138CD5780c768A0a0A7e61f", | ||
"backingManager": "0xD85Fac03804a3e44D29c494f3761D11A2262cBBe", | ||
"basketHandler": "0x157b0C032192F5714BD68bf33dF96C122EA5e1d6", | ||
"broker": "0xa24E0D3E77Ec4849A288C72F9d9bC4dF84B26558", | ||
"distributor": "0x5Ef74A083Ac932b5f050bf41cDe1F67c659b4b88", | ||
"furnace": "0x8A11D590B32186E1236B5E75F2d8D72c280dc880", | ||
"rsrTrader": "0xaeCa35F0cB9d12D68adC4d734D4383593F109654", | ||
"rTokenTrader": "0xaeCa35F0cB9d12D68adC4d734D4383593F109654", | ||
"rToken": "0xC8f487B34251Eb76761168B70Dc10fA38B0Bd90b", | ||
"stRSR": "0x437b525F96A2Da0A4b165efe27c61bea5c8d3CD4" | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
106 changes: 106 additions & 0 deletions
106
scripts/deployment/phase2-assets/collaterals/deploy_usdm.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,106 @@ | ||
import fs from 'fs' | ||
import hre from 'hardhat' | ||
import { getChainId } from '../../../../common/blockchain-utils' | ||
import { arbitrumL2Chains, networkConfig } from '../../../../common/configuration' | ||
import { fp } from '../../../../common/numbers' | ||
import { expect } from 'chai' | ||
import { CollateralStatus } from '../../../../common/constants' | ||
import { | ||
getDeploymentFile, | ||
getAssetCollDeploymentFilename, | ||
IAssetCollDeployments, | ||
getDeploymentFilename, | ||
fileExists, | ||
} from '../../common' | ||
import { USDMCollateral } from '../../../../typechain' | ||
import { ContractFactory } from 'ethers' | ||
import { | ||
DEFAULT_THRESHOLD, | ||
DELAY_UNTIL_DEFAULT, | ||
PRICE_TIMEOUT, | ||
ORACLE_TIMEOUT, | ||
ORACLE_ERROR, | ||
} from '../../../../test/plugins/individual-collateral/mountain/constants' | ||
|
||
async function main() { | ||
// ==== Read Configuration ==== | ||
const [deployer] = await hre.ethers.getSigners() | ||
|
||
const chainId = await getChainId(hre) | ||
|
||
console.log(`Deploying Collateral to network ${hre.network.name} (${chainId}) | ||
with burner account: ${deployer.address}`) | ||
|
||
if (!networkConfig[chainId]) { | ||
throw new Error(`Missing network configuration for ${hre.network.name}`) | ||
} | ||
|
||
// Get phase1 deployment | ||
const phase1File = getDeploymentFilename(chainId) | ||
if (!fileExists(phase1File)) { | ||
throw new Error(`${phase1File} doesn't exist yet. Run phase 1`) | ||
} | ||
// Check previous step completed | ||
const assetCollDeploymentFilename = getAssetCollDeploymentFilename(chainId) | ||
const assetCollDeployments = <IAssetCollDeployments>getDeploymentFile(assetCollDeploymentFilename) | ||
|
||
const deployedCollateral: string[] = [] | ||
|
||
/******** Deploy USDM Collateral - wUSDM **************************/ | ||
let collateral: USDMCollateral | ||
|
||
// Only on Arbitrum for now | ||
if (arbitrumL2Chains.includes(hre.network.name)) { | ||
const USDMCollateralFactory: ContractFactory = await hre.ethers.getContractFactory( | ||
'USDMCollateral' | ||
) | ||
|
||
collateral = <USDMCollateral>await USDMCollateralFactory.connect(deployer).deploy( | ||
{ | ||
priceTimeout: PRICE_TIMEOUT.toString(), | ||
chainlinkFeed: networkConfig[chainId].chainlinkFeeds.wUSDM, | ||
oracleError: ORACLE_ERROR.toString(), // 1% | ||
erc20: networkConfig[chainId].tokens.wUSDM, | ||
maxTradeVolume: fp('1e6').toString(), // $1m, | ||
oracleTimeout: ORACLE_TIMEOUT.toString(), // 24 hr | ||
targetName: hre.ethers.utils.formatBytes32String('USD'), | ||
defaultThreshold: DEFAULT_THRESHOLD.toString(), | ||
delayUntilDefault: DELAY_UNTIL_DEFAULT.toString(), // 24h | ||
}, | ||
fp('1e-6') | ||
) | ||
} else { | ||
throw new Error(`Unsupported chainId: ${chainId}`) | ||
} | ||
|
||
await collateral.deployed() | ||
|
||
console.log( | ||
`Deployed USDM (wUSDM) Collateral to ${hre.network.name} (${chainId}): ${collateral.address}` | ||
) | ||
// await (await collateral.refresh()).wait() | ||
// expect(await collateral.status()).to.equal(CollateralStatus.SOUND) | ||
|
||
console.log( | ||
'🚨 The wUSDM collateral requires chronicle to whitelist the collateral plugin after deployment 🚨' | ||
) | ||
|
||
console.log( | ||
'🚨 After that, we need to return to this plugin and refresh() it and confirm it is SOUND 🚨' | ||
) | ||
|
||
assetCollDeployments.collateral.wUSDM = collateral.address | ||
assetCollDeployments.erc20s.wUSDM = networkConfig[chainId].tokens.wUSDM | ||
deployedCollateral.push(collateral.address.toString()) | ||
|
||
fs.writeFileSync(assetCollDeploymentFilename, JSON.stringify(assetCollDeployments, null, 2)) | ||
|
||
console.log(`Deployed collateral to ${hre.network.name} (${chainId}) | ||
New deployments: ${deployedCollateral} | ||
Deployment file: ${assetCollDeploymentFilename}`) | ||
} | ||
|
||
main().catch((error) => { | ||
console.error(error) | ||
process.exitCode = 1 | ||
}) |
Oops, something went wrong.