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

post-cantina #633

Merged
merged 99 commits into from
Dec 23, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
99 commits
Select commit Hold shift + click to select a range
aadab33
docs(ifc): fix comments
Rubilmax Dec 5, 2023
a4cb34b
fix(safe-transfer-lib): check for code
Rubilmax Dec 5, 2023
e8edd2c
docs: on all markets
MathisGD Dec 5, 2023
dcb9ff2
docs: minor improvement
MathisGD Dec 5, 2023
f50c709
docs: cantina-23
MathisGD Dec 5, 2023
287fdfd
docs(ifc): fix typo
Rubilmax Dec 5, 2023
d40529a
fix(test): remove useless util
Rubilmax Dec 5, 2023
e4ccec8
Merge pull request #627 from morpho-org/docs/imorpho
MerlinEgalite Dec 5, 2023
a822196
docs(ifc): add edge case
Rubilmax Dec 5, 2023
c842441
docs: cantina-48
MathisGD Dec 5, 2023
4d18f59
docs(ifc): fix supply -> borrow
Rubilmax Dec 5, 2023
af5ea27
docs: cantina-90
MathisGD Dec 5, 2023
9772375
docs(ifc): remove comment
Rubilmax Dec 5, 2023
511fdfb
Merge branch 'docs/imorpho' of github.com:morpho-labs/blue into docs/…
Rubilmax Dec 5, 2023
9346293
Merge pull request #629 from morpho-org/fix/issue-5
MerlinEgalite Dec 5, 2023
9c87b92
chore: minor improvements
MathisGD Dec 6, 2023
4ac8778
fix: add call to irm at market creation
Jean-Grimal Dec 6, 2023
01f9e2b
refactor: create market input validation rule
QGarchery Dec 7, 2023
4b33eef
feat: log bad debt but require via ir
MerlinEgalite Dec 7, 2023
8d81c38
refactor: no need for via ir anymore
MerlinEgalite Dec 7, 2023
e7bfeea
docs: add missing param
MerlinEgalite Dec 7, 2023
289ad5e
fix: liquidation rounding
MathisGD Dec 7, 2023
c02daf8
Update src/Morpho.sol
Jean-Grimal Dec 7, 2023
5349c93
Merge pull request #636 from morpho-org/main
MerlinEgalite Dec 7, 2023
faef77c
Update src/Morpho.sol
Jean-Grimal Dec 7, 2023
44281bd
docs: apply suggestion
MerlinEgalite Dec 7, 2023
4d68d40
Update src/Morpho.sol
Jean-Grimal Dec 7, 2023
d3e785a
docs(shares-math): document borrow share price
Rubilmax Dec 7, 2023
38070e3
docs(shares-math): fix wording
Rubilmax Dec 7, 2023
f4272f9
fix: compilation without via-ir
MathisGD Dec 7, 2023
e14da6e
test: test liquidation fix
MathisGD Dec 7, 2023
c5f6c94
docs(shares-math): change wording
Rubilmax Dec 7, 2023
7ab8eb5
docs(shares-math): capitalize natspec
Rubilmax Dec 7, 2023
53938ce
ci(foundry): use test profile
Rubilmax Dec 7, 2023
f5ecb61
refactor: fix stack too deep
MathisGD Dec 8, 2023
abe3041
Merge remote-tracking branch 'origin/fix/liquidation' into fix/liquid…
MathisGD Dec 8, 2023
bab5dea
no memory vars
adhusson Dec 8, 2023
ed4f0f4
Merge pull request #632 from morpho-org/docs/imorpho
Rubilmax Dec 8, 2023
ff4c0ef
Merge pull request #641 from adhusson/fix/liquidation-no-memory-vars
MathisGD Dec 8, 2023
d7bc725
chore: fmt
MathisGD Dec 8, 2023
867ca89
docs(shares-math): fix wording
Rubilmax Dec 8, 2023
7fdf84a
Merge pull request #637 from morpho-org/refactor/log-bad-debt-assets
MathisGD Dec 10, 2023
d9792e2
fix: issue-431
MathisGD Dec 10, 2023
32ba449
fix: issue-503
MathisGD Dec 10, 2023
6f51034
Merge branch 'post-cantina' of github.com:morpho-labs/blue into fix/i…
Rubilmax Dec 11, 2023
1176e03
feat(irm): skip address(0)
Rubilmax Dec 7, 2023
fc91741
fix(irm): skip before elapsed
Rubilmax Dec 7, 2023
0e0ebdb
test(irm): add irm zero test
Rubilmax Dec 7, 2023
598c43e
fix(lib): skip irm in external lib
Rubilmax Dec 8, 2023
b9fe01c
fix(accrue-interest): skip address(0)
Rubilmax Dec 11, 2023
962b66e
test(irm): fix irm tests
Rubilmax Dec 11, 2023
d10c4e5
docs(shares-math): complete warning
Rubilmax Dec 11, 2023
8a31ef3
Merge pull request #634 from morpho-org/fix/issue-259
MerlinEgalite Dec 11, 2023
dfe479e
docs(shares-math): generalize doc
Rubilmax Dec 11, 2023
87d973a
Merge branch 'post-cantina' of github.com:morpho-labs/blue into feat/…
Rubilmax Dec 11, 2023
c1ed84b
test(hardhat): add idle market tests
Rubilmax Dec 11, 2023
70e2636
fix: cantina-670
MathisGD Dec 11, 2023
915cd56
fix: cantina-686
MathisGD Dec 11, 2023
429912c
fix: cantina-699
MathisGD Dec 11, 2023
936971d
test(forge): fix create market tests
Rubilmax Dec 11, 2023
94c9f57
fix: auth already set
MathisGD Dec 11, 2023
9700691
Merge remote-tracking branch 'origin/post-cantina' into fix/liquidation
MathisGD Dec 11, 2023
691d3ff
test: fix auth already set
MathisGD Dec 11, 2023
2dfed61
Merge pull request #639 from morpho-org/docs/virtual-assets-2
MathisGD Dec 11, 2023
91036d4
test: fix auth already set
MathisGD Dec 11, 2023
7dd997a
test: fix auth already set
MathisGD Dec 11, 2023
dd43449
test: fix auth already set
MathisGD Dec 11, 2023
0a7c460
chore: fmt
MathisGD Dec 11, 2023
51b23e5
Merge remote-tracking branch 'origin/post-cantina' into fix/cantina-13
MathisGD Dec 11, 2023
9bf3dd3
docs: minor improvement
MathisGD Dec 11, 2023
2b052d1
docs: minor improvements
MathisGD Dec 11, 2023
dc76917
Merge pull request #630 from morpho-org/fix/cantina-13
MathisGD Dec 11, 2023
cc70d77
style: naming temp
MathisGD Dec 12, 2023
d61c9da
refactor(liquidate): rename intermediary var
Rubilmax Dec 12, 2023
5c02436
Merge branch 'fix/liquidation' of github.com:morpho-labs/blue into re…
Rubilmax Dec 12, 2023
d960aa8
Merge branch 'post-cantina' of github.com:morpho-labs/blue into feat/…
Rubilmax Dec 12, 2023
a7d3ffd
fix(accrue-interest): update lastUpdate
Rubilmax Dec 12, 2023
5ae9ff2
docs(balances-lib): update comment
Rubilmax Dec 12, 2023
d98b26c
Merge pull request #638 from morpho-org/fix/liquidation
MathisGD Dec 12, 2023
184fc24
Merge pull request #640 from morpho-org/feat/skip-irm-0
MerlinEgalite Dec 12, 2023
75c07c4
fix(foundry.toml): decrease optimization runs
Rubilmax Dec 13, 2023
0147667
Merge pull request #645 from morpho-org/fix/optimization-runs
MathisGD Dec 14, 2023
64dac54
Merge pull request #644 from morpho-org/refactor/liquidation-stack
Rubilmax Dec 18, 2023
54d8af2
fix(test): remove outdated tech
Rubilmax Dec 18, 2023
b48b0cf
Merge pull request #649 from morpho-org/fix/test
MathisGD Dec 18, 2023
acf96da
fix: natspec on borrow and withdraw
Jean-Grimal Dec 18, 2023
1d1a416
fix(authorization): revert already set error
Rubilmax Dec 18, 2023
7b49523
refactor: clear rounding through incentive
QGarchery Dec 18, 2023
94981de
refactor: repay incentive temp variable
QGarchery Dec 18, 2023
fadc8a8
Merge pull request #651 from morpho-org/fix/borrow-withdraw-natspec
MathisGD Dec 19, 2023
c34a801
test(irm): dont fuzz irm
Rubilmax Dec 19, 2023
e1dc2e2
Merge pull request #655 from morpho-org/test/irm
Rubilmax Dec 19, 2023
47aaecf
fix: depth 3 for AccrueInterest
QGarchery Dec 20, 2023
65cf2c0
test: remove useless test
MathisGD Dec 20, 2023
3d55307
test: remove useless test
MathisGD Dec 20, 2023
90fb045
refactor: revert repayIncentive temp variable
QGarchery Dec 20, 2023
5afa588
Merge pull request #653 from morpho-org/refactor/improve-rounding-liq…
MerlinEgalite Dec 20, 2023
b2279f2
docs(authorization): comment already set
Rubilmax Dec 20, 2023
24b4d02
Merge pull request #652 from morpho-org/fix/revert-already-set
MerlinEgalite Dec 20, 2023
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
2 changes: 1 addition & 1 deletion .github/workflows/foundry.yml
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ jobs:
uses: foundry-rs/foundry-toolchain@v1

- name: Run Forge tests in ${{ matrix.type }} mode
run: forge test -vvv
run: yarn test:forge -vvv
env:
FOUNDRY_FUZZ_RUNS: ${{ matrix.fuzz-runs }}
FOUNDRY_FUZZ_MAX_TEST_REJECTS: ${{ matrix.max-test-rejects }}
Expand Down
2 changes: 2 additions & 0 deletions certora/confs/AccrueInterest.conf
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,11 @@
],
"verify": "MorphoHarness:certora/specs/AccrueInterest.spec",
"prover_args": [
"-depth 3",
"-smt_hashingScheme plaininjectivity",
"-mediumTimeout 30"
],
"rule_sanity": "basic",
"server": "production",
"msg": "Morpho Blue Accrue Interest"
}
1 change: 1 addition & 0 deletions certora/confs/AssetsAccounting.conf
Original file line number Diff line number Diff line change
Expand Up @@ -4,5 +4,6 @@
],
"verify": "MorphoHarness:certora/specs/AssetsAccounting.spec",
"rule_sanity": "basic",
"server": "production",
"msg": "Morpho Blue Assets Accounting"
}
1 change: 1 addition & 0 deletions certora/confs/ConsistentState.conf
Original file line number Diff line number Diff line change
Expand Up @@ -4,5 +4,6 @@
],
"verify": "MorphoHarness:certora/specs/ConsistentState.spec",
"rule_sanity": "basic",
"server": "production",
"msg": "Morpho Blue Consistent State"
}
1 change: 1 addition & 0 deletions certora/confs/ExactMath.conf
Original file line number Diff line number Diff line change
Expand Up @@ -8,5 +8,6 @@
"-smt_hashingScheme plaininjectivity",
"-mediumTimeout 30"
],
"server": "production",
"msg": "Morpho Blue Exact Math"
}
1 change: 1 addition & 0 deletions certora/confs/Health.conf
Original file line number Diff line number Diff line change
Expand Up @@ -8,5 +8,6 @@
"prover_args": [
"-smt_hashingScheme plaininjectivity"
],
"server": "production",
"msg": "Morpho Blue Health"
}
1 change: 1 addition & 0 deletions certora/confs/LibSummary.conf
Original file line number Diff line number Diff line change
Expand Up @@ -4,5 +4,6 @@
],
"verify": "MorphoHarness:certora/specs/LibSummary.spec",
"rule_sanity": "basic",
"server": "production",
"msg": "Morpho Blue Lib Summary"
}
1 change: 1 addition & 0 deletions certora/confs/Liveness.conf
Original file line number Diff line number Diff line change
Expand Up @@ -4,5 +4,6 @@
],
"verify": "MorphoInternalAccess:certora/specs/Liveness.spec",
"rule_sanity": "basic",
"server": "production",
"msg": "Morpho Blue Liveness"
}
1 change: 1 addition & 0 deletions certora/confs/RatioMath.conf
Original file line number Diff line number Diff line change
Expand Up @@ -9,5 +9,6 @@
"-mediumTimeout 30",
"-timeout 3600"
],
"server": "production",
"msg": "Morpho Blue Ratio Math"
}
1 change: 1 addition & 0 deletions certora/confs/Reentrancy.conf
Original file line number Diff line number Diff line change
Expand Up @@ -7,5 +7,6 @@
"prover_args": [
"-enableStorageSplitting false"
],
"server": "production",
"msg": "Morpho Blue Reentrancy"
}
1 change: 1 addition & 0 deletions certora/confs/Reverts.conf
Original file line number Diff line number Diff line change
Expand Up @@ -4,5 +4,6 @@
],
"verify": "MorphoHarness:certora/specs/Reverts.spec",
"rule_sanity": "basic",
"server": "production",
"msg": "Morpho Blue Reverts"
}
1 change: 1 addition & 0 deletions certora/confs/Transfer.conf
Original file line number Diff line number Diff line change
Expand Up @@ -7,5 +7,6 @@
],
"verify": "TransferHarness:certora/specs/Transfer.spec",
"rule_sanity": "basic",
"server": "production",
"msg": "Morpho Blue Transfer"
}
6 changes: 3 additions & 3 deletions certora/specs/Reverts.spec
Original file line number Diff line number Diff line change
Expand Up @@ -103,14 +103,14 @@ rule setFeeRecipientRevertCondition(env e, address newFeeRecipient) {
assert lastReverted <=> e.msg.value != 0 || e.msg.sender != oldOwner || newFeeRecipient == oldFeeRecipient;
}

// Check the revert condition for the createMarket function.
rule createMarketRevertCondition(env e, MorphoHarness.MarketParams marketParams) {
// Check that createMarket reverts when its input are not validated.
rule createMarketInputValidation(env e, MorphoHarness.MarketParams marketParams) {
MorphoHarness.Id id = libId(marketParams);
bool irmEnabled = isIrmEnabled(marketParams.irm);
bool lltvEnabled = isLltvEnabled(marketParams.lltv);
bool wasCreated = isCreated(id);
createMarket@withrevert(e, marketParams);
assert lastReverted <=> e.msg.value != 0 || !irmEnabled || !lltvEnabled || wasCreated;
assert e.msg.value != 0 || !irmEnabled || !lltvEnabled || wasCreated => lastReverted;
}

// Check that supply reverts when its input are not validated.
Expand Down
2 changes: 1 addition & 1 deletion foundry.toml
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
names = true
sizes = true
via-ir = true
optimizer_runs = 4294967295
optimizer_runs = 999999 # Etherscan does not support verifying contracts with more optimization runs.

[profile.default.invariant]
runs = 8
Expand Down
82 changes: 48 additions & 34 deletions src/Morpho.sol
Original file line number Diff line number Diff line change
Expand Up @@ -158,6 +158,9 @@ contract Morpho is IMorphoStaticTyping {
idToMarketParams[id] = marketParams;

emit EventsLib.CreateMarket(id, marketParams);

// Call to initialize the IRM in case it is stateful.
if (marketParams.irm != address(0)) IIrm(marketParams.irm).borrowRate(marketParams, market[id]);
}

/* SUPPLY MANAGEMENT */
Expand Down Expand Up @@ -354,28 +357,29 @@ contract Morpho is IMorphoStaticTyping {

_accrueInterest(marketParams, id);

uint256 collateralPrice = IOracle(marketParams.oracle).price();
{
uint256 collateralPrice = IOracle(marketParams.oracle).price();

require(!_isHealthy(marketParams, id, borrower, collateralPrice), ErrorsLib.HEALTHY_POSITION);
require(!_isHealthy(marketParams, id, borrower, collateralPrice), ErrorsLib.HEALTHY_POSITION);

uint256 repaidAssets;
{
// The liquidation incentive factor is min(maxLiquidationIncentiveFactor, 1/(1 - cursor*(1 - lltv))).
uint256 liquidationIncentiveFactor = UtilsLib.min(
MAX_LIQUIDATION_INCENTIVE_FACTOR,
WAD.wDivDown(WAD - LIQUIDATION_CURSOR.wMulDown(WAD - marketParams.lltv))
);

if (seizedAssets > 0) {
repaidAssets =
seizedAssets.mulDivUp(collateralPrice, ORACLE_PRICE_SCALE).wDivUp(liquidationIncentiveFactor);
repaidShares = repaidAssets.toSharesDown(market[id].totalBorrowAssets, market[id].totalBorrowShares);
uint256 seizedAssetsQuoted = seizedAssets.mulDivUp(collateralPrice, ORACLE_PRICE_SCALE);

repaidShares = seizedAssetsQuoted.wDivUp(liquidationIncentiveFactor).toSharesUp(
market[id].totalBorrowAssets, market[id].totalBorrowShares
);
} else {
repaidAssets = repaidShares.toAssetsUp(market[id].totalBorrowAssets, market[id].totalBorrowShares);
seizedAssets =
repaidAssets.wMulDown(liquidationIncentiveFactor).mulDivDown(ORACLE_PRICE_SCALE, collateralPrice);
seizedAssets = repaidShares.toAssetsDown(market[id].totalBorrowAssets, market[id].totalBorrowShares)
.wMulDown(liquidationIncentiveFactor).mulDivDown(ORACLE_PRICE_SCALE, collateralPrice);
}
}
uint256 repaidAssets = repaidShares.toAssetsUp(market[id].totalBorrowAssets, market[id].totalBorrowShares);

position[id][borrower].borrowShares -= repaidShares.toUint128();
market[id].totalBorrowShares -= repaidShares.toUint128();
Expand All @@ -384,23 +388,26 @@ contract Morpho is IMorphoStaticTyping {
position[id][borrower].collateral -= seizedAssets.toUint128();

uint256 badDebtShares;
uint256 badDebtAssets;
if (position[id][borrower].collateral == 0) {
badDebtShares = position[id][borrower].borrowShares;
uint256 badDebt = UtilsLib.min(
badDebtAssets = UtilsLib.min(
market[id].totalBorrowAssets,
badDebtShares.toAssetsUp(market[id].totalBorrowAssets, market[id].totalBorrowShares)
);

market[id].totalBorrowAssets -= badDebt.toUint128();
market[id].totalSupplyAssets -= badDebt.toUint128();
market[id].totalBorrowAssets -= badDebtAssets.toUint128();
market[id].totalSupplyAssets -= badDebtAssets.toUint128();
market[id].totalBorrowShares -= badDebtShares.toUint128();
position[id][borrower].borrowShares = 0;
}

IERC20(marketParams.collateralToken).safeTransfer(msg.sender, seizedAssets);

// `repaidAssets` may be greater than `totalBorrowAssets` by 1.
emit EventsLib.Liquidate(id, msg.sender, borrower, repaidAssets, repaidShares, seizedAssets, badDebtShares);
emit EventsLib.Liquidate(
id, msg.sender, borrower, repaidAssets, repaidShares, seizedAssets, badDebtAssets, badDebtShares
);

IERC20(marketParams.collateralToken).safeTransfer(msg.sender, seizedAssets);

if (data.length > 0) IMorphoLiquidateCallback(msg.sender).onMorphoLiquidate(repaidAssets, data);

Expand All @@ -413,10 +420,12 @@ contract Morpho is IMorphoStaticTyping {

/// @inheritdoc IMorphoBase
function flashLoan(address token, uint256 assets, bytes calldata data) external {
IERC20(token).safeTransfer(msg.sender, assets);
require(assets != 0, ErrorsLib.ZERO_ASSETS);

emit EventsLib.FlashLoan(msg.sender, token, assets);

IERC20(token).safeTransfer(msg.sender, assets);

IMorphoFlashLoanCallback(msg.sender).onMorphoFlashLoan(assets, data);

IERC20(token).safeTransferFrom(msg.sender, address(this), assets);
Expand All @@ -426,18 +435,21 @@ contract Morpho is IMorphoStaticTyping {

/// @inheritdoc IMorphoBase
function setAuthorization(address authorized, bool newIsAuthorized) external {
require(newIsAuthorized != isAuthorized[msg.sender][authorized], ErrorsLib.ALREADY_SET);

isAuthorized[msg.sender][authorized] = newIsAuthorized;

emit EventsLib.SetAuthorization(msg.sender, msg.sender, authorized, newIsAuthorized);
}

/// @inheritdoc IMorphoBase
function setAuthorizationWithSig(Authorization memory authorization, Signature calldata signature) external {
/// Do not check whether authorization is already set because the nonce increment is a desired side effect.
require(block.timestamp <= authorization.deadline, ErrorsLib.SIGNATURE_EXPIRED);
require(authorization.nonce == nonce[authorization.authorizer]++, ErrorsLib.INVALID_NONCE);

bytes32 hashStruct = keccak256(abi.encode(AUTHORIZATION_TYPEHASH, authorization));
bytes32 digest = keccak256(abi.encodePacked("\x19\x01", DOMAIN_SEPARATOR, hashStruct));
bytes32 digest = keccak256(bytes.concat("\x19\x01", DOMAIN_SEPARATOR, hashStruct));
address signatory = ecrecover(digest, signature.v, signature.r, signature.s);

require(signatory != address(0) && authorization.authorizer == signatory, ErrorsLib.INVALID_SIGNATURE);
Expand Down Expand Up @@ -470,25 +482,27 @@ contract Morpho is IMorphoStaticTyping {
/// @dev Assumes that the inputs `marketParams` and `id` match.
function _accrueInterest(MarketParams memory marketParams, Id id) internal {
uint256 elapsed = block.timestamp - market[id].lastUpdate;

if (elapsed == 0) return;

uint256 borrowRate = IIrm(marketParams.irm).borrowRate(marketParams, market[id]);
uint256 interest = market[id].totalBorrowAssets.wMulDown(borrowRate.wTaylorCompounded(elapsed));
market[id].totalBorrowAssets += interest.toUint128();
market[id].totalSupplyAssets += interest.toUint128();

uint256 feeShares;
if (market[id].fee != 0) {
uint256 feeAmount = interest.wMulDown(market[id].fee);
// The fee amount is subtracted from the total supply in this calculation to compensate for the fact
// that total supply is already increased by the full interest (including the fee amount).
feeShares = feeAmount.toSharesDown(market[id].totalSupplyAssets - feeAmount, market[id].totalSupplyShares);
position[id][feeRecipient].supplyShares += feeShares;
market[id].totalSupplyShares += feeShares.toUint128();
}
if (marketParams.irm != address(0)) {
uint256 borrowRate = IIrm(marketParams.irm).borrowRate(marketParams, market[id]);
uint256 interest = market[id].totalBorrowAssets.wMulDown(borrowRate.wTaylorCompounded(elapsed));
market[id].totalBorrowAssets += interest.toUint128();
market[id].totalSupplyAssets += interest.toUint128();

uint256 feeShares;
if (market[id].fee != 0) {
uint256 feeAmount = interest.wMulDown(market[id].fee);
// The fee amount is subtracted from the total supply in this calculation to compensate for the fact
// that total supply is already increased by the full interest (including the fee amount).
feeShares =
feeAmount.toSharesDown(market[id].totalSupplyAssets - feeAmount, market[id].totalSupplyShares);
position[id][feeRecipient].supplyShares += feeShares;
market[id].totalSupplyShares += feeShares.toUint128();
}

emit EventsLib.AccrueInterest(id, borrowRate, interest, feeShares);
emit EventsLib.AccrueInterest(id, borrowRate, interest, feeShares);
}

// Safe "unchecked" cast.
market[id].lastUpdate = uint128(block.timestamp);
Expand Down
5 changes: 3 additions & 2 deletions src/interfaces/IIrm.sol
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,12 @@ import {MarketParams, Market} from "./IMorpho.sol";
/// @custom:contact [email protected]
/// @notice Interface that Interest Rate Models (IRMs) used by Morpho must implement.
interface IIrm {
/// @notice Returns the borrow rate of the market `marketParams`.
/// @notice Returns the borrow rate per second (scaled by WAD) of the market `marketParams`.
/// @dev Assumes that `market` corresponds to `marketParams`.
function borrowRate(MarketParams memory marketParams, Market memory market) external returns (uint256);

/// @notice Returns the borrow rate of the market `marketParams` without modifying any storage.
/// @notice Returns the borrow rate per second (scaled by WAD) of the market `marketParams` without modifying any
/// storage.
/// @dev Assumes that `market` corresponds to `marketParams`.
function borrowRateView(MarketParams memory marketParams, Market memory market) external view returns (uint256);
}
31 changes: 17 additions & 14 deletions src/interfaces/IMorpho.sol
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,7 @@ interface IMorphoBase {
/// @notice Whether the `lltv` is enabled.
function isLltvEnabled(uint256 lltv) external view returns (bool);

/// @notice Whether `authorized` is authorized to modify `authorizer`'s positions.
/// @notice Whether `authorized` is authorized to modify `authorizer`'s position on all markets.
/// @dev Anyone is authorized to modify their own positions, regardless of this variable.
function isAuthorized(address authorizer, address authorized) external view returns (bool);

Expand All @@ -91,6 +91,7 @@ interface IMorphoBase {
function enableLltv(uint256 lltv) external;

/// @notice Sets the `newFee` for the given market `marketParams`.
/// @param newFee The new fee, scaled by WAD.
/// @dev Warning: The recipient can be the zero address.
function setFee(MarketParams memory marketParams, uint256 newFee) external;

Expand Down Expand Up @@ -129,12 +130,12 @@ interface IMorphoBase {

/// @notice Supplies `assets` or `shares` on behalf of `onBehalf`, optionally calling back the caller's
/// `onMorphoSupply` function with the given `data`.
/// @dev Either `assets` or `shares` should be zero. Most usecases should rely on `assets` as an input so the caller
/// is guaranteed to have `assets` tokens pulled from their balance, but the possibility to mint a specific amount
/// of shares is given for full compatibility and precision.
/// @dev If the supply of a market gets depleted, the supply share price instantly resets to
/// `VIRTUAL_ASSETS`:`VIRTUAL_SHARES`.
/// @dev Either `assets` or `shares` should be zero. Most use cases should rely on `assets` as an input so the
/// caller is guaranteed to have `assets` tokens pulled from their balance, but the possibility to mint a specific
/// amount of shares is given for full compatibility and precision.
/// @dev Supplying a large amount can revert for overflow.
/// @dev Supplying an amount of shares may lead to supply more or fewer assets than expected due to slippage.
/// Consider using the `assets` parameter to avoid this.
/// @param marketParams The market to supply assets to.
/// @param assets The amount of assets to supply.
/// @param shares The amount of shares to mint.
Expand All @@ -150,7 +151,7 @@ interface IMorphoBase {
bytes memory data
) external returns (uint256 assetsSupplied, uint256 sharesSupplied);

/// @notice Withdraws `assets` or `shares` on behalf of `onBehalf` to `receiver`.
/// @notice Withdraws `assets` or `shares` on behalf of `onBehalf` and sends the assets to `receiver`.
/// @dev Either `assets` or `shares` should be zero. To withdraw max, pass the `shares`'s balance of `onBehalf`.
/// @dev `msg.sender` must be authorized to manage `onBehalf`'s positions.
/// @dev Withdrawing an amount corresponding to more shares than supplied will revert for underflow.
Expand All @@ -171,14 +172,14 @@ interface IMorphoBase {
address receiver
) external returns (uint256 assetsWithdrawn, uint256 sharesWithdrawn);

/// @notice Borrows `assets` or `shares` on behalf of `onBehalf` to `receiver`.
/// @dev Either `assets` or `shares` should be zero. Most usecases should rely on `assets` as an input so the caller
/// is guaranteed to borrow `assets` of tokens, but the possibility to mint a specific amount of shares is given for
/// full compatibility and precision.
/// @dev If the borrow of a market gets depleted, the borrow share price instantly resets to
/// `VIRTUAL_ASSETS`:`VIRTUAL_SHARES`.
/// @notice Borrows `assets` or `shares` on behalf of `onBehalf` and sends the assets to `receiver`.
/// @dev Either `assets` or `shares` should be zero. Most use cases should rely on `assets` as an input so the
/// caller is guaranteed to borrow `assets` of tokens, but the possibility to mint a specific amount of shares is
/// given for full compatibility and precision.
/// @dev `msg.sender` must be authorized to manage `onBehalf`'s positions.
/// @dev Borrowing a large amount can revert for overflow.
/// @dev Borrowing an amount of shares may lead to borrow fewer assets than expected due to slippage.
/// Consider using the `assets` parameter to avoid this.
/// @param marketParams The market to borrow assets from.
/// @param assets The amount of assets to borrow.
/// @param shares The amount of shares to mint.
Expand All @@ -200,6 +201,7 @@ interface IMorphoBase {
/// @dev Repaying an amount corresponding to more shares than borrowed will revert for underflow.
/// @dev It is advised to use the `shares` input when repaying the full position to avoid reverts due to conversion
/// roundings between shares and assets.
/// @dev An attacker can front-run a repay with a small repay making the transaction revert for underflow.
/// @param marketParams The market to repay assets to.
/// @param assets The amount of assets to repay.
/// @param shares The amount of shares to burn.
Expand All @@ -226,7 +228,7 @@ interface IMorphoBase {
function supplyCollateral(MarketParams memory marketParams, uint256 assets, address onBehalf, bytes memory data)
external;

/// @notice Withdraws `assets` of collateral on behalf of `onBehalf` to `receiver`.
/// @notice Withdraws `assets` of collateral on behalf of `onBehalf` and sends the assets to `receiver`.
/// @dev `msg.sender` must be authorized to manage `onBehalf`'s positions.
/// @dev Withdrawing an amount corresponding to more collateral than supplied will revert for underflow.
/// @param marketParams The market to withdraw collateral from.
Expand All @@ -242,6 +244,7 @@ interface IMorphoBase {
/// @dev Either `seizedAssets` or `repaidShares` should be zero.
/// @dev Seizing more than the collateral balance will underflow and revert without any error message.
/// @dev Repaying more than the borrow balance will underflow and revert without any error message.
/// @dev An attacker can front-run a liquidation with a small repay making the transaction revert for underflow.
/// @param marketParams The market of the position.
/// @param borrower The owner of the position.
/// @param seizedAssets The amount of collateral to seize.
Expand Down
3 changes: 3 additions & 0 deletions src/libraries/ErrorsLib.sol
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,9 @@ library ErrorsLib {
/// @notice Thrown when the market is already created.
string internal constant MARKET_ALREADY_CREATED = "market already created";

/// @notice Thrown when a token to transfer doesn't have code.
string internal constant NO_CODE = "no code";

/// @notice Thrown when the market is not created.
string internal constant MARKET_NOT_CREATED = "market not created";

Expand Down
Loading
Loading