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

Сomet with extended asset list #904

Open
wants to merge 23 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
23 commits
Select commit Hold shift + click to select a range
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
15 changes: 13 additions & 2 deletions .github/workflows/enact-migration.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -106,7 +106,7 @@ jobs:
run_id: ${{ github.event.inputs.run_id }}
name: ${{ github.event.inputs.network }}-${{ github.event.inputs.deployment }}-${{ github.event.inputs.migration }}
path: deployments/${{ github.event.inputs.network }}/${{ github.event.inputs.deployment }}/artifacts/
if: github.event.inputs.run_id != ''
if: github.event.inputs.run_id != '' && github.event.inputs.run_id != 0

- name: Run Enact Migration
run: |
Expand All @@ -129,7 +129,18 @@ jobs:
GOV_NETWORK_PROVIDER: ${{ fromJSON('["", "http://localhost:8685"]')[github.event.inputs.eth_pk == '' && env.GOV_NETWORK != ''] }}
GOV_NETWORK: ${{ env.GOV_NETWORK }}
REMOTE_ACCOUNTS: ${{ fromJSON('["", "true"]')[github.event.inputs.eth_pk == ''] }}
if: github.event.inputs.impersonateAccount != ''
if: github.event.inputs.impersonateAccount != '' && github.event.inputs.run_id != 0
- name: Run Prepare and Enact Migration (impersonate)
run: |
yarn hardhat migrate --network ${{ github.event.inputs.network }} --deployment ${{ github.event.inputs.deployment }} --prepare --enact --overwrite ${{ fromJSON('["", "--simulate"]')[github.event.inputs.simulate == 'true'] }} ${{ fromJSON('["", "--no-enacted"]')[github.event.inputs.no_enacted == 'true'] }} ${{ github.event.inputs.migration }} --impersonate ${{ github.event.inputs.impersonateAccount }}
env:
DEBUG: true
ETH_PK: "${{ inputs.eth_pk }}"
NETWORK_PROVIDER: ${{ fromJSON('["", "http://localhost:8585"]')[github.event.inputs.eth_pk == ''] }}
GOV_NETWORK_PROVIDER: ${{ fromJSON('["", "http://localhost:8685"]')[github.event.inputs.eth_pk == '' && env.GOV_NETWORK != ''] }}
GOV_NETWORK: ${{ env.GOV_NETWORK }}
REMOTE_ACCOUNTS: ${{ fromJSON('["", "true"]')[github.event.inputs.eth_pk == ''] }}
if: github.event.inputs.impersonateAccount != '' && github.event.inputs.run_id == 0
- name: Commit changes
if: ${{ github.event.inputs.simulate == 'false' }}
run: |
Expand Down
131 changes: 131 additions & 0 deletions contracts/AssetList.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,131 @@
// SPDX-License-Identifier: BUSL-1.1
pragma solidity 0.8.15;

import "./IPriceFeed.sol";
import "./IERC20NonStandard.sol";
import "./CometMainInterface.sol";
import "./CometCore.sol";

/**
* @title Compound's Asset List
* @author Compound
*/
contract AssetList {
/// @dev The decimals required for a price feed
uint8 internal constant PRICE_FEED_DECIMALS = 8;

/// @dev The scale for factors
uint64 internal constant FACTOR_SCALE = 1e18;

/// @dev The max value for a collateral factor (1)
uint64 internal constant MAX_COLLATERAL_FACTOR = FACTOR_SCALE;

uint256[] internal assets_a;
uint256[] internal assets_b;

/// @notice The number of assets this contract actually supports
uint8 public immutable numAssets;

constructor(CometConfiguration.AssetConfig[] memory assetConfigs) {
uint8 _numAssets = uint8(assetConfigs.length);
numAssets = _numAssets;
uint256[] memory _assets_a = new uint256[](_numAssets);
uint256[] memory _assets_b = new uint256[](_numAssets);
for (uint i = 0; i < _numAssets; ) {
(uint256 asset_a, uint256 asset_b) = getPackedAssetInternal(assetConfigs, i);
_assets_a[i] = asset_a;
_assets_b[i] = asset_b;
unchecked { i++; }
}
assets_a = _assets_a;
assets_b = _assets_b;
}

/**
* @dev Checks and gets the packed asset info for storage
*/
function getPackedAssetInternal(CometConfiguration.AssetConfig[] memory assetConfigs, uint i) internal view returns (uint256, uint256) {
CometConfiguration.AssetConfig memory assetConfig;
if (i < assetConfigs.length) {
assembly {
assetConfig := mload(add(add(assetConfigs, 0x20), mul(i, 0x20)))
}
} else {
return (0, 0);
}
address asset = assetConfig.asset;
address priceFeed = assetConfig.priceFeed;
uint8 decimals_ = assetConfig.decimals;

// Short-circuit if asset is nil
if (asset == address(0)) {
return (0, 0);
}

// Sanity check price feed and asset decimals
if (IPriceFeed(priceFeed).decimals() != PRICE_FEED_DECIMALS) revert CometMainInterface.BadDecimals();
if (IERC20NonStandard(asset).decimals() != decimals_) revert CometMainInterface.BadDecimals();

// Ensure collateral factors are within range
if (assetConfig.borrowCollateralFactor >= assetConfig.liquidateCollateralFactor) revert CometMainInterface.BorrowCFTooLarge();
if (assetConfig.liquidateCollateralFactor > MAX_COLLATERAL_FACTOR) revert CometMainInterface.LiquidateCFTooLarge();

unchecked {
// Keep 4 decimals for each factor
uint64 descale = FACTOR_SCALE / 1e4;
uint16 borrowCollateralFactor = uint16(assetConfig.borrowCollateralFactor / descale);
uint16 liquidateCollateralFactor = uint16(assetConfig.liquidateCollateralFactor / descale);
uint16 liquidationFactor = uint16(assetConfig.liquidationFactor / descale);

// Be nice and check descaled values are still within range
if (borrowCollateralFactor >= liquidateCollateralFactor) revert CometMainInterface.BorrowCFTooLarge();

// Keep whole units of asset for supply cap
uint64 supplyCap = uint64(assetConfig.supplyCap / (10 ** decimals_));

uint256 word_a = (uint160(asset) << 0 |
uint256(borrowCollateralFactor) << 160 |
uint256(liquidateCollateralFactor) << 176 |
uint256(liquidationFactor) << 192);
uint256 word_b = (uint160(priceFeed) << 0 |
uint256(decimals_) << 160 |
uint256(supplyCap) << 168);

return (word_a, word_b);
}
}

/**
* @notice Get the i-th asset info, according to the order they were passed in originally
* @param i The index of the asset info to get
* @return The asset info object
*/
function getAssetInfo(uint8 i) public view returns (CometCore.AssetInfo memory) {
if (i >= numAssets) revert CometMainInterface.BadAsset();

uint256 word_a = assets_a[i];
uint256 word_b = assets_b[i];

address asset = address(uint160(word_a & type(uint160).max));
uint64 rescale = FACTOR_SCALE / 1e4;
uint64 borrowCollateralFactor = uint64(((word_a >> 160) & type(uint16).max) * rescale);
uint64 liquidateCollateralFactor = uint64(((word_a >> 176) & type(uint16).max) * rescale);
uint64 liquidationFactor = uint64(((word_a >> 192) & type(uint16).max) * rescale);

address priceFeed = address(uint160(word_b & type(uint160).max));
uint8 decimals_ = uint8(((word_b >> 160) & type(uint8).max));
uint64 scale = uint64(10 ** decimals_);
uint128 supplyCap = uint128(((word_b >> 168) & type(uint64).max) * scale);

return CometCore.AssetInfo({
offset: i,
asset: asset,
priceFeed: priceFeed,
scale: scale,
borrowCollateralFactor: borrowCollateralFactor,
liquidateCollateralFactor: liquidateCollateralFactor,
liquidationFactor: liquidationFactor,
supplyCap: supplyCap
});
}
}
17 changes: 17 additions & 0 deletions contracts/AssetListFactory.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
// SPDX-License-Identifier: BUSL-1.1
pragma solidity 0.8.15;

import "./AssetList.sol";

/**
* @title Compound's Asset List Factory
* @author Compound
*/
contract AssetListFactory {
event AssetListCreated(address indexed assetList, CometCore.AssetConfig[] assetConfigs);

function createAssetList(CometCore.AssetConfig[] memory assetConfigs) external returns (address assetList) {
assetList = address(new AssetList(assetConfigs));
emit AssetListCreated(assetList, assetConfigs);
}
}
2 changes: 1 addition & 1 deletion contracts/CometExt.sol
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ contract CometExt is CometExtInterface {
function baseIndexScale() override external pure returns (uint64) { return BASE_INDEX_SCALE; }
function factorScale() override external pure returns (uint64) { return FACTOR_SCALE; }
function priceScale() override external pure returns (uint64) { return PRICE_SCALE; }
function maxAssets() override external pure returns (uint8) { return MAX_ASSETS; }
function maxAssets() override virtual external pure returns (uint8) { return MAX_ASSETS; }

/**
* @notice Aggregate variables tracked for the entire market
Expand Down
23 changes: 23 additions & 0 deletions contracts/CometExtAssetList.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
// SPDX-License-Identifier: BUSL-1.1
pragma solidity 0.8.15;

import "./CometExt.sol";

contract CometExtAssetList is CometExt {

/// @notice The address of the asset list factory
address immutable public assetListFactory;

/**
* @notice Construct a new protocol instance
* @param config The mapping of initial/constant parameters
* @param assetListFactoryAddress The address of the asset list factory
**/
constructor(ExtConfiguration memory config, address assetListFactoryAddress) CometExt(config) {
assetListFactory = assetListFactoryAddress;
}

uint8 internal constant MAX_ASSETS_FOR_ASSET_LIST = 24;

function maxAssets() override external pure returns (uint8) { return MAX_ASSETS_FOR_ASSET_LIST; }
}
Loading