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

dev-277: refactor minter caps #146

Merged
merged 15 commits into from
Apr 24, 2024
Merged
Binary file modified bun.lockb
Binary file not shown.
4 changes: 2 additions & 2 deletions foundry.toml
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,9 @@ fs_permissions = [{ access = "read-write", path = "./" }]
ffi = true
solc = '0.8.23'
evm_version = 'paris'
via_ir = false
via_ir = true
optimizer = true
optimizer_runs = 10000
optimizer_runs = 1000
remappings = [
'@openzeppelin/=lib/kresko-foundry-helpers/lib/openzeppelin-contracts/',
'@oz-upgradeable/=lib/kresko-foundry-helpers/lib/openzeppelin-contracts-upgradeable/contracts/',
Expand Down
15 changes: 15 additions & 0 deletions justfile
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,21 @@ hasBun := `bun --help | grep -q 'Usage: bun' && echo true || echo false`
hasFoundry := `forge --version | grep -q 'forge' && echo true || echo false`
hasPM2 := `bunx pm2 | grep -q 'usage: pm2' && echo true || echo false`

@deploy script sig:
forge script $1 --sig "$2()" --ffi --broadcast \
--chain arbitrum \
--fork-url "$RPC_ARBITRUM_INFURA" \
--verify

@resume script sig:
forge script $1 --sig "$2()" --ffi --broadcast \
--chain arbitrum \
--skip-simulation \
--rpc-url "$RPC_ARBITRUM_INFURA" \
--verify \
--resume


deploy-local:
forge script src/contracts/scripts/deploy/Deploy.s.sol:Deploy \
--sig $(cast calldata "deploy(string,string,uint32,bool,bool)" "localhost" "MNEMONIC_DEVNET" 0 true false) \
Expand Down
1 change: 1 addition & 0 deletions out/foundry/deploy/42161/minter-caps-update-latest.json
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
{"MinterMintFacet":{"address":"0x919999B03ca6B1E5F2CA7dC4031A0edD96FEFcb6","newSelectors":1,"oldSelectors":1},"MinterStateFacet":{"address":"0x97515a953227C6771229A4F15B92B064574789f1","newSelectors":10,"oldSelectors":9},"Payload9":{"address":"0xf1160543C721bcc8b0c57469979edf0eAdC18620","ctor":"0x"},"ViewDataFacet":{"address":"0x29451Fa9Eb20Cf1CE23C7C1b5B754EFBB8564862","newSelectors":9,"oldSelectors":9},"diamondCut-MinterLogicUpdate":{"calldata":"0x1f931c1c0000000000000000000000000000000000000000000000000000000000000060000000000000000000000000f1160543c721bcc8b0c57469979edf0eadc186200000000000000000000000000000000000000000000000000000000000000920000000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000c00000000000000000000000000000000000000000000000000000000000000160000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000003a0000000000000000000000000000000000000000000000000000000000000056000000000000000000000000000000000000000000000000000000000000007000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000001f2358af300000000000000000000000000000000000000000000000000000000000000000000000000000000919999b03ca6b1e5f2ca7dc4031a0edd96fefcb6000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000001f2358af3000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000009eca7f1f300000000000000000000000000000000000000000000000000000000e7499689000000000000000000000000000000000000000000000000000000009842ad9700000000000000000000000000000000000000000000000000000000e87b1dfa000000000000000000000000000000000000000000000000000000004b94b15800000000000000000000000000000000000000000000000000000000557ff65c00000000000000000000000000000000000000000000000000000000e9364e3e00000000000000000000000000000000000000000000000000000000c015681300000000000000000000000000000000000000000000000000000000c7dc1d640000000000000000000000000000000000000000000000000000000000000000000000000000000097515a953227c6771229a4f15b92b064574789f100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000060000000000000000000000000000000000000000000000000000000000000000aeca7f1f300000000000000000000000000000000000000000000000000000000e7499689000000000000000000000000000000000000000000000000000000009842ad9700000000000000000000000000000000000000000000000000000000e87b1dfa000000000000000000000000000000000000000000000000000000004b94b15800000000000000000000000000000000000000000000000000000000557ff65c00000000000000000000000000000000000000000000000000000000e9364e3e00000000000000000000000000000000000000000000000000000000c0156813000000000000000000000000000000000000000000000000000000005e88142800000000000000000000000000000000000000000000000000000000c7dc1d64000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000009cff9fda500000000000000000000000000000000000000000000000000000000ad1e72d700000000000000000000000000000000000000000000000000000000caf0340d00000000000000000000000000000000000000000000000000000000d5854f8d00000000000000000000000000000000000000000000000000000000a244df97000000000000000000000000000000000000000000000000000000000baf4ae20000000000000000000000000000000000000000000000000000000015a4352600000000000000000000000000000000000000000000000000000000ecc0dbc300000000000000000000000000000000000000000000000000000000e4073f6b0000000000000000000000000000000000000000000000000000000000000000000000000000000029451fa9eb20cf1ce23c7c1b5b754efbb8564862000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000009cff9fda500000000000000000000000000000000000000000000000000000000ad1e72d700000000000000000000000000000000000000000000000000000000caf0340d00000000000000000000000000000000000000000000000000000000d5854f8d00000000000000000000000000000000000000000000000000000000a244df97000000000000000000000000000000000000000000000000000000000baf4ae20000000000000000000000000000000000000000000000000000000015a4352600000000000000000000000000000000000000000000000000000000ecc0dbc300000000000000000000000000000000000000000000000000000000e4073f6b0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000048129fc1c00000000000000000000000000000000000000000000000000000000","to":"0x0000000000177abD99485DCaea3eFaa91db3fe72"}}
44 changes: 44 additions & 0 deletions src/contracts/core/common/funcs/Assets.sol
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,9 @@ import {safePrice, SDIPrice} from "common/funcs/Prices.sol";
import {cs} from "common/State.sol";
import {PercentageMath} from "libs/PercentageMath.sol";
import {ms} from "minter/MState.sol";
import {scdp} from "scdp/SState.sol";
import {IERC20} from "kresko-lib/token/IERC20.sol";
import {IKISS} from "kiss/interfaces/IKISS.sol";

library Assets {
using WadRay for uint256;
Expand Down Expand Up @@ -263,4 +266,45 @@ library Assets {
}
return _maybeRebasedAmount;
}

/**
* @notice Validate that the minter debt limit is not exceeded.
* @param _asset Asset struct of the asset being minted.
* @param _krAsset Address of the kresko asset being minted.
* @param _mintAmount Amount of the kresko asset being minted.
* @dev Reverts if the minter debt limit is exceeded.
*/
function validateMinterDebtLimit(Asset storage _asset, address _krAsset, uint256 _mintAmount) internal view {
uint256 supply = getMinterSupply(_asset, _krAsset);
uint256 newSupply = supply + _mintAmount;
if (newSupply > _asset.maxDebtMinter) {
revert Errors.EXCEEDS_ASSET_MINTING_LIMIT(Errors.id(_krAsset), newSupply, _asset.maxDebtMinter);
}
}

/**
* @notice Get the minter supply for a given kresko asset.
* @param _asset Asset struct of the asset being minted.
* @param _krAsset Address of the kresko asset being minted.
* @return minterSupply Minter supply for the kresko asset.
*/
function getMinterSupply(Asset storage _asset, address _krAsset) internal view returns (uint256) {
if (_asset.anchor == _krAsset) {
return _getMinterSupplyKiss(_krAsset);
}
return _getMinterSupplyKrAsset(_krAsset, _asset.anchor);
}

function _getMinterSupplyKrAsset(address _assetAddr, address _anchor) private view returns (uint256) {
IKreskoAssetAnchor anchor = IKreskoAssetAnchor(_anchor);
uint256 supply = anchor.totalSupply() - anchor.balanceOf(_assetAddr) - scdp().assetData[_assetAddr].debt;
if (supply == 0) return 0;
return anchor.convertToAssets(supply);
}

function _getMinterSupplyKiss(address _assetAddr) private view returns (uint256) {
return
IERC20(_assetAddr).totalSupply() -
(IERC20(IKISS(_assetAddr).vKISS()).balanceOf(_assetAddr) + scdp().assetData[_assetAddr].debt);
}
}
6 changes: 2 additions & 4 deletions src/contracts/core/minter/facets/MinterMintFacet.sol
Original file line number Diff line number Diff line change
Expand Up @@ -46,15 +46,13 @@ contract MinterMintFacet is IMinterMintFacet, Modifiers {

if (!asset.isMarketOpen()) revert Errors.MARKET_CLOSED(Errors.id(_args.krAsset), asset.ticker.toString());

uint256 newSupply = IKreskoAsset(_args.krAsset).totalSupply() + _args.amount;
if (newSupply > asset.maxDebtMinter) {
revert Errors.EXCEEDS_ASSET_MINTING_LIMIT(Errors.id(_args.krAsset), newSupply, asset.maxDebtMinter);
}
asset.validateMinterDebtLimit(_args.krAsset, _args.amount);

// If there is a fee for opening a position, handle it
if (asset.openFee > 0) {
handleMinterFee(asset, _args.account, _args.amount, Enums.MinterFee.Open);
}

uint256 existingDebt = s.accountDebtAmount(_args.account, _args.krAsset, asset);

// The synthetic asset debt position must be greater than the minimum debt position value
Expand Down
4 changes: 4 additions & 0 deletions src/contracts/core/minter/facets/MinterStateFacet.sol
Original file line number Diff line number Diff line change
Expand Up @@ -70,4 +70,8 @@ contract MinterStateFacet is IMinterStateFacet {
) external view returns (uint256 value, uint256 adjustedValue, uint256 price) {
return debtAmountToValues(cs().assets[_krAsset], _amount);
}

function getMinterSupply(address _krAsset) external view returns (uint256) {
return cs().assets[_krAsset].getMinterSupply(_krAsset);
}
}
3 changes: 3 additions & 0 deletions src/contracts/core/minter/interfaces/IMinterStateFacet.sol
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,9 @@ interface IMinterStateFacet {
/// @notice get all meaningful protocol parameters
function getParametersMinter() external view returns (MinterParams memory);

/// @notice Gets the supply originating from the Minter for @param _asset.
function getMinterSupply(address _asset) external view returns (uint256);

/**
* @notice Gets the USD value for a single collateral asset and amount.
* @param _collateralAsset The address of the collateral asset.
Expand Down
45 changes: 0 additions & 45 deletions src/contracts/core/periphery/DataV1.sol
Original file line number Diff line number Diff line change
Expand Up @@ -165,7 +165,6 @@ contract DataV1 is IDataV1 {

function getAccount(PythView calldata _prices, address _account) external view returns (DAccount memory result) {
result.protocol = DIAMOND.viewAccountData(_prices, _account);
result.protocol.minter.debts = kissFix(_account, _prices);
result.vault.addr = VAULT;
result.vault.name = IERC20(VAULT).name();
result.vault.amount = IERC20(VAULT).balanceOf(_account);
Expand All @@ -179,50 +178,6 @@ contract DataV1 is IDataV1 {
result.chainId = block.chainid;
}

function kissFix(address _account, PythView calldata _prices) internal view returns (View.Position[] memory result) {
IKresko kr = IKresko(address(DIAMOND));

View.AssetView[] memory assets = DIAMOND.viewProtocolData(_prices).assets;
address[] memory mintedAssets = kr.getAccountMintedAssets(_account);

View.Position[] memory found = new View.Position[](assets.length);
uint256 count;
for (uint256 i; i < assets.length; i++) {
View.AssetView memory asset = assets[i];
if (asset.config.isMinterMintable) {
found[i] = _getMinterPos(_account, asset, kr, mintedAssets);
++count;
}
}

result = new View.Position[](count);
for (uint256 j; j < found.length; j++) {
if (found[j].addr != address(0)) result[--count] = found[j];
}
}

function _getMinterPos(
address _account,
View.AssetView memory _asset,
IKresko _kr,
address[] memory _mintedAssets
) internal view returns (View.Position memory) {
uint256 debtAmount = _kr.getAccountDebtAmount(_account, _asset.addr);
uint256 val = debtAmount.wadMul(_asset.price);
return
View.Position({
addr: _asset.addr,
symbol: _asset.symbol,
amount: debtAmount,
amountAdj: 0,
val: val,
valAdj: val.percentMul(_asset.config.kFactor),
index: _mintedAssets.findIndex(_asset.addr),
price: _asset.price,
config: _asset.config
});
}

function getBalances(
PythView calldata _prices,
address _account,
Expand Down
1 change: 1 addition & 0 deletions src/contracts/core/periphery/ViewData.sol
Original file line number Diff line number Diff line change
Expand Up @@ -235,6 +235,7 @@ library ViewFuncs {
synthwrap: synthwrap,
name: token.name(),
tSupply: token.totalSupply(),
mSupply: asset.isMinterMintable ? asset.getMinterSupply(addr) : 0,
price: uint256(price.answer),
isMarketOpen: asset.isMarketOpen(),
priceRaw: price,
Expand Down
1 change: 1 addition & 0 deletions src/contracts/core/periphery/ViewTypes.sol
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,7 @@ library View {
address addr;
bool isMarketOpen;
uint256 tSupply;
uint256 mSupply;
uint256 price;
Asset config;
}
Expand Down
39 changes: 39 additions & 0 deletions src/contracts/scripts/MinterCap.s.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

import {ArbScript} from "scripts/utils/ArbScript.s.sol";
import {Help, Log} from "kresko-lib/utils/Libs.s.sol";
import {ProtocolUpgrader} from "scripts/utils/ProtocolUpgrader.s.sol";
import {deployPayload} from "scripts/payloads/Payloads.sol";
import {Task0009} from "scripts/tasks/Task0009.s.sol";
import {DataV1} from "periphery/DataV1.sol";

// solhint-disable no-empty-blocks, reason-string, state-visibility

contract MinterCapLogicUpdate is ProtocolUpgrader, ArbScript {
using Log for *;
using Help for *;

address sender;

function setUp() public virtual {
vm.createSelectFork("arbitrum");
initUpgrader(kreskoAddr, factoryAddr, CreateMode.Create2);
}

function payload0009() public output("minter-caps-update") {
broadcastWith(safe);
createFacetCut("MinterMintFacet");
createFacetCut("MinterStateFacet");
createFacetCut("ViewDataFacet");
initializer.initContract = deployPayload(type(Task0009).creationCode, "", 9);
initializer.initData = abi.encodeWithSelector(Task0009.initialize.selector);
executeCuts("MinterLogicUpdate", false);
}

function afterRun() public {
useMnemonic("MNEMONIC");
broadcastWith(getAddr(0));
dataV1 = new DataV1(kreskoAddr, vaultAddr, kissAddr, address(quoter), kreskianAddr, questAddr);
}
}
18 changes: 18 additions & 0 deletions src/contracts/scripts/tasks/Task0009.s.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
import {ArbDeployAddr} from "kresko-lib/info/ArbDeployAddr.sol";
import {Arrays} from "libs/Arrays.sol";
import {cs} from "common/State.sol";
import {ms} from "minter/MState.sol";

contract Task0009 is ArbDeployAddr {
using Arrays for address[];

function initialize() public {
require(cs().assets[kissAddr].maxDebtMinter != 0, "zero");
require(cs().assets[kissAddr].maxDebtMinter == 140_000 ether, "already-initialized");

cs().assets[kissAddr].maxDebtMinter = 60_000 ether;
ms().krAssets.pushUnique(kissAddr);
}
}
Loading
Loading