Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Compoundv3 USDT Plugin #1213

Merged
merged 23 commits into from
Oct 30, 2024
Merged
Show file tree
Hide file tree
Changes from 11 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions common/configuration.ts
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,7 @@ export interface ITokens {
cUSDCv3?: string
wcUSDCv3?: string
cUSDbCv3?: string
cUSDTv3?: string
ONDO?: string
sFRAX?: string
sDAI?: string
Expand Down Expand Up @@ -233,6 +234,7 @@ export const networkConfig: { [key: string]: INetworkConfig } = {
apxETH: '0x9Ba021B0a9b958B5E75cE9f6dff97C7eE52cb3E6',
cUSDCv3: '0xc3d688B66703497DAA19211EEdff47f25384cdc3',
wcUSDCv3: '0x27F2f159Fe990Ba83D57f39Fd69661764BEbf37a',
cUSDTv3: '0x3Afdc9BCA9213A35503b077a6072F3D0d5AB0840',
ONDO: '0xfAbA6f8e4a5E8Ab82F62fe7C39859FA577269BE3',
sFRAX: '0xA663B02CF0a4b149d2aD41910CB81e23e1c41c32',
sDAI: '0x83f20f44975d03b1b09e64809b757c47f942beea',
Expand Down Expand Up @@ -553,6 +555,7 @@ export const networkConfig: { [key: string]: INetworkConfig } = {
USDC: '0xaf88d065e77c8cc2239327c5edb3a432268e5831',
USDT: '0xfd086bc7cd5c481dcc9c85ebe478a1c0b69fcbb9',
cUSDCv3: '0x9c4ec768c28520B50860ea7a15bd7213a9fF58bf',
cUSDTv3: '0xd98Be00b5D27fc98112BdE293e487f8D4cA57d07',
WETH: '0x82af49447d8a07e3bd95bd0d56f35241523fbab1',
WBTC: '0x2f2a2543B76A4166549F7aaB2e75Bef0aefC5B0f',
aArbUSDCn: '0x724dc807b04555b71ed48a6896b6f41593b8c637', // aArbUSDCn wraps USDC!
Expand Down
4 changes: 2 additions & 2 deletions contracts/facade/FacadeMonitor.sol
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import "../interfaces/IRToken.sol";
import "../libraries/Fixed.sol";
import "../p1/RToken.sol";
import "../plugins/assets/compoundv2/DEPRECATED_CTokenWrapper.sol";
import "../plugins/assets/compoundv3/ICusdcV3Wrapper.sol";
import "../plugins/assets/compoundv3/ICFiatV3Wrapper.sol";
import "../plugins/assets/stargate/StargateRewardableWrapper.sol";
import { StaticATokenV3LM } from "../plugins/assets/aave-v3/vendor/StaticATokenV3LM.sol";
import "../plugins/assets/morpho-aave/MorphoAaveV2TokenisedDeposit.sol";
Expand Down Expand Up @@ -174,7 +174,7 @@ contract FacadeMonitor is Initializable, OwnableUpgradeable, UUPSUpgradeable, IF
backingBalance = (cTokenBal * exchangeRate) / 1e18;
availableLiquidity = underlying.balanceOf(address(cToken));
} else if (collType == CollPluginType.COMPOUND_V3) {
ICusdcV3Wrapper cTokenV3Wrapper = ICusdcV3Wrapper(address(erc20));
ICFiatV3Wrapper cTokenV3Wrapper = ICFiatV3Wrapper(address(erc20));
CometInterface cTokenV3 = CometInterface(address(cTokenV3Wrapper.underlyingComet()));
IERC20 underlying = IERC20(cTokenV3.baseToken());

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,62 +5,67 @@ import "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
import "./vendor/CometInterface.sol";
import "./WrappedERC20.sol";
import "./vendor/ICometRewards.sol";
import "./ICusdcV3Wrapper.sol";
import "./ICFiatV3Wrapper.sol";
import "./CometHelpers.sol";

/**
* @title CusdcV3Wrapper
* @notice Wrapper for cUSDCV3 / COMET that acts as a stable-balance ERC20, instead of rebasing
* token. {comet} will be used as the unit for the underlying token, and {wComet} will be used
* as the unit for wrapped tokens.
* @title CFiatV3Wrapper
* @notice Wrapper for Compound V3 fiat coins such as cUSDCv3, cUSDTv3 / COMET that acts
* as a stable-balance ERC20, instead of rebasing token. {comet} will be used as the unit
* for the underlying token, and {wComet} will be used as the unit for wrapped tokens.
*/
contract CusdcV3Wrapper is ICusdcV3Wrapper, WrappedERC20, CometHelpers {
contract CFiatV3Wrapper is ICFiatV3Wrapper, WrappedERC20, CometHelpers {
using SafeERC20 for IERC20;

/// From cUSDCv3, used in principal <> present calculations
uint256 public constant TRACKING_INDEX_SCALE = 1e15;
/// From cUSDCv3, scaling factor for USDC rewards
uint256 public constant RESCALE_FACTOR = 1e12;

CometInterface public immutable underlyingComet;
ICometRewards public immutable rewardsAddr;
IERC20 public immutable rewardERC20;
uint256 public immutable trackingIndexScale;
uint256 public immutable rescaleFactor;
uint8 internal immutable cometDecimals;

mapping(address => uint64) public baseTrackingIndex; // uint64 for consistency with CometHelpers
mapping(address => uint256) public baseTrackingAccrued; // uint256 to avoid overflow in L:199
mapping(address => uint256) public rewardsClaimed;

constructor(
address cusdcv3,
address ctokenv3,
address rewardsAddr_,
address rewardERC20_
) WrappedERC20("Wrapped cUSDCv3", "wcUSDCv3") {
if (cusdcv3 == address(0)) revert ZeroAddress();
address rewardERC20_,
string memory name,
string memory symbol
) WrappedERC20(name, symbol) {
if (ctokenv3 == address(0)) revert ZeroAddress();

rewardsAddr = ICometRewards(rewardsAddr_);
rewardERC20 = IERC20(rewardERC20_);
underlyingComet = CometInterface(cusdcv3);
underlyingComet = CometInterface(ctokenv3);
cometDecimals = underlyingComet.decimals();
// for principal <> present calculations
trackingIndexScale = underlyingComet.trackingIndexScale();
// scaling factor for rewards
rescaleFactor = 10**(18 - cometDecimals);
}

/// @return number of decimals
function decimals() public pure override(IERC20Metadata, WrappedERC20) returns (uint8) {
return 6;
function decimals() public view override(IERC20Metadata, WrappedERC20) returns (uint8) {
return cometDecimals;
}

/// @param amount {Comet} The amount of cUSDCv3 to deposit
/// @param amount {Comet} The amount of cTokenV3 to deposit
function deposit(uint256 amount) external {
_deposit(msg.sender, msg.sender, msg.sender, amount);
}

/// @param dst The dst to deposit into
/// @param amount {Comet} The amount of cUSDCv3 to deposit
/// @param amount {Comet} The amount of cTokenV3 to deposit
function depositTo(address dst, uint256 amount) external {
_deposit(msg.sender, msg.sender, dst, amount);
}

/// @param src The address to deposit from
/// @param dst The address to deposit to
/// @param amount {Comet} The amount of cUSDCv3 to deposit
/// @param amount {Comet} The amount of cTokenV3 to deposit
function depositFrom(
address src,
address dst,
Expand All @@ -70,11 +75,11 @@ contract CusdcV3Wrapper is ICusdcV3Wrapper, WrappedERC20, CometHelpers {
}

/// Only called internally to run the deposit logic
/// Takes `amount` fo cUSDCv3 from `src` and deposits to `dst` account in the wrapper.
/// Takes `amount` fo cTokenV3 from `src` and deposits to `dst` account in the wrapper.
/// @param operator The address calling the contract (msg.sender)
/// @param src The address to deposit from
/// @param dst The address to deposit to
/// @param amount {Comet} The amount of cUSDCv3 to deposit
/// @param amount {Comet} The amount of cTokenv3 to deposit
function _deposit(
address operator,
address src,
Expand Down Expand Up @@ -102,7 +107,7 @@ contract CusdcV3Wrapper is ICusdcV3Wrapper, WrappedERC20, CometHelpers {
_mint(dst, uint104(wrapperPostPrinc - wrapperPrePrinc));
}

/// @param amount {Comet} The amount of cUSDCv3 to withdraw
/// @param amount {Comet} The amount of cTokenV3 to withdraw
function withdraw(uint256 amount) external {
_withdraw(msg.sender, msg.sender, msg.sender, amount);
}
Expand Down Expand Up @@ -195,7 +200,7 @@ contract CusdcV3Wrapper is ICusdcV3Wrapper, WrappedERC20, CometHelpers {

accrueAccount(src);
uint256 claimed = rewardsClaimed[src];
uint256 accrued = baseTrackingAccrued[src] * RESCALE_FACTOR;
uint256 accrued = baseTrackingAccrued[src] * rescaleFactor;
uint256 owed;
if (accrued > claimed) {
owed = accrued - claimed;
Expand Down Expand Up @@ -260,10 +265,10 @@ contract CusdcV3Wrapper is ICusdcV3Wrapper, WrappedERC20, CometHelpers {
uint256 indexDelta = uint256(trackingSupplyIndex - baseTrackingIndex[account]);
uint256 newBaseTrackingAccrued = baseTrackingAccrued[account] +
(safe104(balanceOf(account)) * indexDelta) /
TRACKING_INDEX_SCALE;
trackingIndexScale;

uint256 claimed = rewardsClaimed[account];
uint256 accrued = newBaseTrackingAccrued * RESCALE_FACTOR;
uint256 accrued = newBaseTrackingAccrued * rescaleFactor;
uint256 owed = accrued > claimed ? accrued - claimed : 0;

return owed;
Expand All @@ -289,7 +294,7 @@ contract CusdcV3Wrapper is ICusdcV3Wrapper, WrappedERC20, CometHelpers {
(, uint64 trackingSupplyIndex) = getSupplyIndices();
uint256 indexDelta = uint256(trackingSupplyIndex - baseTrackingIndex[account]);

baseTrackingAccrued[account] += (safe104(accountBal) * indexDelta) / TRACKING_INDEX_SCALE;
baseTrackingAccrued[account] += (safe104(accountBal) * indexDelta) / trackingIndexScale;
baseTrackingIndex[account] = trackingSupplyIndex;
}

Expand Down
14 changes: 7 additions & 7 deletions contracts/plugins/assets/compoundv3/CTokenV3Collateral.sol
Original file line number Diff line number Diff line change
Expand Up @@ -7,14 +7,14 @@ import "@chainlink/contracts/src/v0.8/interfaces/AggregatorV3Interface.sol";
import "../../../libraries/Fixed.sol";
import "../AppreciatingFiatCollateral.sol";
import "../OracleLib.sol";
import "./ICusdcV3Wrapper.sol";
import "./ICFiatV3Wrapper.sol";
import "./vendor/IComet.sol";

/**
* @title CTokenV3Collateral
* @notice Collateral plugin for Compound V3,
* tok = wcUSDC
* ref = USDC
* tok = wcToken (wcUSDC, wcUSDT, etc)
* ref = USDC/USDT/etc
* tar = USD
* UoA = USD
*/
Expand All @@ -31,8 +31,8 @@ contract CTokenV3Collateral is AppreciatingFiatCollateral {
AppreciatingFiatCollateral(config, revenueHiding)
{
require(config.defaultThreshold != 0, "defaultThreshold zero");
comp = ICusdcV3Wrapper(address(config.erc20)).rewardERC20();
comet = IComet(address(ICusdcV3Wrapper(address(erc20)).underlyingComet()));
comp = ICFiatV3Wrapper(address(config.erc20)).rewardERC20();
comet = IComet(address(ICFiatV3Wrapper(address(erc20)).underlyingComet()));
cometDecimals = comet.decimals();
}

Expand All @@ -46,7 +46,7 @@ contract CTokenV3Collateral is AppreciatingFiatCollateral {
function underlyingRefPerTok() public view virtual override returns (uint192) {
return
shiftl_toFix(
ICusdcV3Wrapper(address(erc20)).exchangeRate(),
ICFiatV3Wrapper(address(erc20)).exchangeRate(),
-int8(cometDecimals),
FLOOR
);
Expand All @@ -55,7 +55,7 @@ contract CTokenV3Collateral is AppreciatingFiatCollateral {
/// Refresh exchange rates and update default status.
/// @dev Should not need to override: can handle collateral with variable refPerTok()
function refresh() public virtual override {
ICusdcV3Wrapper(address(erc20)).accrue();
ICFiatV3Wrapper(address(erc20)).accrue();

CollateralStatus oldStatus = status();

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import "./vendor/CometInterface.sol";
import "./IWrappedERC20.sol";
import "../../../interfaces/IRewardable.sol";

interface ICusdcV3Wrapper is IWrappedERC20, IRewardable {
interface ICFiatV3Wrapper is IWrappedERC20, IRewardable {
struct UserBasic {
uint104 principal;
uint64 baseTrackingIndex;
Expand Down
2 changes: 1 addition & 1 deletion contracts/plugins/assets/compoundv3/WrappedERC20.sol
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,7 @@ abstract contract WrappedERC20 is IWrappedERC20 {
/**
* @dev Returns the decimals places of the token.
*/
function decimals() public pure virtual returns (uint8) {
function decimals() public view virtual returns (uint8) {
return 18;
}

Expand Down
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
// SPDX-License-Identifier: BlueOak-1.0.0
pragma solidity 0.8.19;

import "../assets/compoundv3/CusdcV3Wrapper.sol";
import "../assets/compoundv3/ICusdcV3Wrapper.sol";
import "../assets/compoundv3/CFiatV3Wrapper.sol";
import "../assets/compoundv3/ICFiatV3Wrapper.sol";

interface ICusdcV3WrapperMock is ICusdcV3Wrapper {
interface ICFiatV3WrapperMock is ICFiatV3Wrapper {
function setMockExchangeRate(bool setMock, uint256 mockValue) external;
}

contract CusdcV3WrapperMock {
contract CFiatV3WrapperMock {
uint256[20] private __gap;
address internal mockTarget;
mapping(bytes4 => bool) internal isMocking;
Expand All @@ -33,7 +33,7 @@ contract CusdcV3WrapperMock {
if (isMocking[this.exchangeRate.selector]) {
return mockExchangeRate_;
} else {
return CusdcV3Wrapper(mockTarget).exchangeRate();
return CFiatV3Wrapper(mockTarget).exchangeRate();
}
}

Expand Down
8 changes: 5 additions & 3 deletions scripts/addresses/1-tmp-assets-collateral.json
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,8 @@
"ETHx": "0x73a36258E6A48D0095D1997Fec7F51e191B4Ec81",
"apxETH": "0x05ffDaAA2aF48e1De1CE34d633db018a28e3B3F5",
"sUSDe": "0x35081Ca24319835e5f759163F7e75eaB753e0b7E",
"pyUSD": "0xa5cde4fB1132daF8f4a0D3140859271208d944E9"
"pyUSD": "0xa5cde4fB1132daF8f4a0D3140859271208d944E9",
"cUSDTv3": "0x753142cc768C05Ea66A1b92622aFE148Ad44Cb30"
},
"erc20s": {
"stkAAVE": "0x4da27a545c0c5B758a6BA100e3a049001de870f5",
Expand Down Expand Up @@ -125,6 +126,7 @@
"ETHx": "0xA35b1B31Ce002FBF2058D22F30f95D405200A15b",
"apxETH": "0x9Ba021B0a9b958B5E75cE9f6dff97C7eE52cb3E6",
"sUSDe": "0x9D39A5DE30e57443BfF2A8307A4256c8797A3497",
"pyUSD": "0x6c3ea9036406852006290770bedfcaba0e23a0e8"
"pyUSD": "0x6c3ea9036406852006290770bedfcaba0e23a0e8",
"cUSDTv3": "0xbeD348315d7327Cd81d26338c11976674825bb14"
}
}
}
6 changes: 4 additions & 2 deletions scripts/addresses/mainnet-4.0.0/1-tmp-assets-collateral.json
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
{
"assets": {},
"collateral": {
"ETHx": "0x73a36258E6A48D0095D1997Fec7F51e191B4Ec81"
"ETHx": "0x73a36258E6A48D0095D1997Fec7F51e191B4Ec81",
"cUSDTv3": "0x753142cc768C05Ea66A1b92622aFE148Ad44Cb30"
},
"erc20s": {
"ETHx": "0xA35b1B31Ce002FBF2058D22F30f95D405200A15b"
"ETHx": "0xA35b1B31Ce002FBF2058D22F30f95D405200A15b",
"cUSDTv3": "0xbeD348315d7327Cd81d26338c11976674825bb14"
}
}
2 changes: 2 additions & 0 deletions scripts/deploy.ts
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,7 @@ async function main() {
'phase2-assets/collaterals/deploy_rocket_pool_reth_collateral.ts',
'phase2-assets/collaterals/deploy_flux_finance_collateral.ts',
'phase2-assets/collaterals/deploy_ctokenv3_usdc_collateral.ts',
'phase2-assets/collaterals/deploy_ctokenv3_usdt_collateral.ts',
'phase2-assets/collaterals/deploy_convex_3pool_collateral.ts',
'phase2-assets/collaterals/deploy_convex_paypool_collateral.ts',
'phase2-assets/collaterals/deploy_convex_crvusd_usdc_collateral.ts',
Expand Down Expand Up @@ -114,6 +115,7 @@ async function main() {
'phase2-assets/collaterals/deploy_aave_v3_usdc.ts',
'phase2-assets/collaterals/deploy_aave_v3_usdt.ts',
'phase2-assets/collaterals/deploy_ctokenv3_usdc_collateral.ts',
'phase2-assets/collaterals/deploy_ctokenv3_usdt_collateral.ts',
'phase2-assets/collaterals/deploy_convex_crvusd_usdc_collateral.ts',
'phase2-assets/collaterals/deploy_convex_crvusd_usdt_collateral.ts',
'phase2-assets/collaterals/deploy_usdm.ts',
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -47,11 +47,13 @@ async function main() {

/******** Deploy CompoundV3 USDC - cUSDbCv3 **************************/

const WrapperFactory: ContractFactory = await hre.ethers.getContractFactory('CusdcV3Wrapper')
const WrapperFactory: ContractFactory = await hre.ethers.getContractFactory('CFiatV3Wrapper')
const erc20 = await WrapperFactory.deploy(
networkConfig[chainId].tokens.cUSDbCv3,
networkConfig[chainId].COMET_REWARDS,
networkConfig[chainId].tokens.COMP
networkConfig[chainId].tokens.COMP,
'Wrapped cUSDbCv3',
'wcUSDbCv3'
)
await erc20.deployed()

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -42,11 +42,13 @@ async function main() {

/******** Deploy CompoundV3 USDC - cUSDCv3 **************************/

const WrapperFactory: ContractFactory = await hre.ethers.getContractFactory('CusdcV3Wrapper')
const WrapperFactory: ContractFactory = await hre.ethers.getContractFactory('CFiatV3Wrapper')
const erc20 = await WrapperFactory.deploy(
networkConfig[chainId].tokens.cUSDCv3,
networkConfig[chainId].COMET_REWARDS,
networkConfig[chainId].tokens.COMP
networkConfig[chainId].tokens.COMP,
'Wrapped cUSDCv3',
'wcUSDCv3'
)
await erc20.deployed()

Expand Down
Loading
Loading