# Wharf-hardhat
### AssetPool.sol
* `accumulateRewards()` is missing `onlyLending` modifier, maybe because of tests. But we can add this modifier and keep Alice as a lending address for `AssetPool.test.js`
* No reenterency guard added on deposit/withdraw (maybe we can use on other function calls too depending on their nature)
* `uint256 public totalBorrow;` should be added
* `mapping(address => uint256) public userBorrowed;` can be added for future calculations
* `availableReward()` ❌ calculation should be revised on time based reward index, each address shares will be signed difference from globalIndex to avoid double spending of rewards.
* `transferAsset()` <span style="color:orange">⚠️</span> should keep track of borrows and borrow by address.
* Missing `returnAsset()` for paybacks from `Lending.sol`
* `accumulateReward()` should keep system GlobalIndex for rewards with timestamp, which will help distribute fair reward to everyone
### RateProvider.sol
* `rpow()` from `Compounder.sol` can be used inside `getBorrowRate()` instead of doing `.mul(1e5)`. Unless we are fine with having only 5 decimal places precision
* `rpow()` can be moved to different contract as a acted as a library
* $$ U_{w} $$ is calculated multiple times `mul(borrows).div(available)` and at other place with precision of `mul(1e5)`, I think we should have consistency for precision and think of a way to avoid calculating it again to reduce gas cost
* `uint256 public secondsPerYear` can be a constant `SECONDS_PER_YEAR` and instead of calling it like a function, we can directly call wherever contract have extended it.
### Lending.sol
* `borrow()` ✅
* `payback()` <span style="color:orange">⚠️</span> instead of `IERC20(assetPool.underlyingToken()).safeTransferFrom()`, there should be `returnAsset()` inside `AssetPool.sol` which will allow keeping borrow/supply state of specific address.
* `supplyCollateral()` ✅
* `withdrawCollateral()` ✅
* `liquidate()` <span style="color:orange">⚠️</span> should `preAccrue(debitor)` too and debitor health should be checked after liquidation (*`Good to have, can skip this`*)
> <span style="color:orange">*have to validate burning and reward on liquidation yet*</span>
```sol
function liquidate(
address loanAsset,
address collateralAsset,
address debitor
) external override preAccrue(msg.sender) returns (uint256)
```
* `factor()` ✅ (complexity can be reduced if user `_collateral` and `_loans` are stored in mapping too and will be done in single loop)
* `setCollateralFactor()` ✅ (onlyOwner or governance to be added) (does not support factor in decimal places, only discrete 0-100% and 80.5% is not possible)
* `setInterest()` ✅ (onlyOwner or governance to be added)
* `getCollateral()` ✅
* `getAllCollateral()` ✅
* `getLoan()` ✅ (complexity can be reduced if user `_loans` is stored in mapping too)
* `getAllLoans()` ✅
* `getPrice()` ✅
* `getUnaccruedDebt()` ✅ (complexity will get reduced when `factor()` is getting optimized)
* `accrueInterest()` ✅
* `getCurrentRate()` <span style="color:orange">⚠️</span>❌ Denial of service can be fixed when `getBorrows()` is implemented in `AssetPool.sol`
* No reenterency guard added on borrow and payback, also we should think of others functions that might be victim of reenterency.
* <span style="color:#998523">`_loans` could be converted into mapping (considering the fact we have to iterate through all of loans) to avoid multiple loops</span>
* <span style="color:#998523">Overall there are multiple nested function calls and loops inside calls, we should try to minimize these considering fact that each operation gets converted into approx ~2-3 assembly instructions which might make us run out of gas in some of calculations. (Have to look more in-depth)</span>
---
## Next Steps
* Add Governance/Ownable
* Convert contracts to upgradeable
* Build off-chain liquidation bot
* Treasury Contract
* Wharf-Reserve
---
#### Dependency Graph
```graphviz
digraph G {
graph [ ratio = "auto", page = "100", compound =true, bgcolor = "#2e3e56" ];
node [ style = "filled", fillcolor = "#edad56", color = "#edad56", penwidth =3 ];
edge [ color = "#fcfcfc", penwidth =2, fontname = "helvetica Neue Ultra Light" ];
subgraph "clusterLending" {
graph [ label = "Lending", color = "#445773", fontcolor = "#f0f0f0", style = "rounded", bgcolor = "#445773" ];
"Lending.<Constructor>" [ label = "<Constructor>", color = "#FF9797", fillcolor = "#FF9797" ];
"Lending.preAccrue" [ label = "preAccrue", color = "#1bc6a6", shape =doubleoctagon ];
"Lending.borrow" [ label = "borrow", color = "#ffbdb9", fillcolor = "#ffbdb9" ];
"Lending.payback" [ label = "payback", color = "#ffbdb9", fillcolor = "#ffbdb9" ];
"Lending.supplyCollateral" [ label = "supplyCollateral", color = "#ffbdb9", fillcolor = "#ffbdb9" ];
"Lending.withdrawCollateral" [ label = "withdrawCollateral", color = "#ffbdb9", fillcolor = "#ffbdb9" ];
"Lending.liquidate" [ label = "liquidate", color = "#ffbdb9", fillcolor = "#ffbdb9" ];
"Lending.factor" [ label = "factor" ];
"Lending.setCollateralFactor" [ label = "setCollateralFactor", color = "#ffbdb9", fillcolor = "#ffbdb9" ];
"Lending.setInterest" [ label = "setInterest", color = "#ffbdb9", fillcolor = "#ffbdb9" ];
"Lending.getCollateral" [ label = "getCollateral", color = "#ffbdb9", fillcolor = "#ffbdb9" ];
"Lending.getAllCollateral" [ label = "getAllCollateral", color = "#ffbdb9", fillcolor = "#ffbdb9" ];
"Lending.getLoan" [ label = "getLoan" ];
"Lending.getAllLoans" [ label = "getAllLoans", color = "#ffbdb9", fillcolor = "#ffbdb9" ];
"Lending.getPrice" [ label = "getPrice" ];
"Lending.getUnaccruedDebt" [ label = "getUnaccruedDebt" ];
"Lending.accrueInterest" [ label = "accrueInterest" ];
"Lending.getCurrentRate" [ label = "getCurrentRate" ];
"Lending.type" [ label = "type" ];
"Lending.compound" [ label = "compound" ];
"Lending.getBorrowRate" [ label = "getBorrowRate" ];
"Lending.secondsPerYear" [ label = "secondsPerYear" ];
}
subgraph "clusterContext" {
graph [ label = "Context", color = "#445773", fontcolor = "#f0f0f0", style = "rounded", bgcolor = "#445773" ];
"Context._msgSender" [ label = "_msgSender", color = "#f2c383", fillcolor = "#f2c383" ];
"Context._msgData" [ label = "_msgData", color = "#f2c383", fillcolor = "#f2c383" ];
}
subgraph "clusterIOracle" {
graph [ label = "IOracle (iface)", color = "#445773", fontcolor = "#f0f0f0", style = "rounded", bgcolor = "#445773" ];
"IOracle.getPrice" [ label = "getPrice", color = "#ffbdb9", fillcolor = "#ffbdb9" ];
}
subgraph "clusterAssetPool" {
graph [ label = "AssetPool", color = "#445773", fontcolor = "#f0f0f0", style = "rounded", bgcolor = "#445773" ];
"AssetPool.underlyingToken" [ label = "underlyingToken" ];
"AssetPool.burn" [ label = "burn", color = "#ffbdb9", fillcolor = "#ffbdb9" ];
"AssetPool.transferAsset" [ label = "transferAsset", color = "#ffbdb9", fillcolor = "#ffbdb9" ];
"AssetPool.totalSupply" [ label = "totalSupply" ];
"AssetPool.<Constructor>" [ label = "<Constructor>", color = "#FF9797", fillcolor = "#FF9797" ];
"AssetPool.onlyLending" [ label = "onlyLending", color = "#1bc6a6", shape =doubleoctagon ];
"AssetPool.decimals" [ label = "decimals", color = "#FF9797", fillcolor = "#FF9797" ];
"AssetPool.deposit" [ label = "deposit", color = "#ffbdb9", fillcolor = "#ffbdb9" ];
"AssetPool.withdraw" [ label = "withdraw", color = "#ffbdb9", fillcolor = "#ffbdb9" ];
"AssetPool.availableReward" [ label = "availableReward" ];
"AssetPool.claimReward" [ label = "claimReward", color = "#ffbdb9", fillcolor = "#ffbdb9" ];
"AssetPool._claim" [ label = "_claim" ];
"AssetPool.accumulateReward" [ label = "accumulateReward", color = "#ffbdb9", fillcolor = "#ffbdb9" ];
"AssetPool._mint" [ label = "_mint" ];
"AssetPool.balanceOf" [ label = "balanceOf" ];
"AssetPool._burn" [ label = "_burn" ];
}
subgraph "clusterCompounder" {
graph [ label = "Compounder", color = "#445773", fontcolor = "#f0f0f0", style = "rounded", bgcolor = "#445773" ];
"Compounder.compound" [ label = "compound", color = "#FF9797", fillcolor = "#FF9797" ];
"Compounder.rpow" [ label = "rpow" ];
}
subgraph "clusterRateProvider" {
graph [ label = "RateProvider", color = "#445773", fontcolor = "#f0f0f0", style = "rounded", bgcolor = "#445773" ];
"RateProvider.getBorrowRate" [ label = "getBorrowRate", color = "#FF9797", fillcolor = "#FF9797" ];
"RateProvider.getSupplyRate" [ label = "getSupplyRate", color = "#FF9797", fillcolor = "#FF9797" ];
}
subgraph "clusterrate" {
graph [ label = "rate", color = "#e8726d", fontcolor = "#f0f0f0", style = "rounded,dashed", bgcolor = "#3b4b63" ];
"rate.div" [ label = "div" ];
}
subgraph "clusteramount" {
graph [ label = "amount", color = "#e8726d", fontcolor = "#f0f0f0", style = "rounded,dashed", bgcolor = "#3b4b63" ];
"amount.mul" [ label = "mul" ];
}
subgraph "clustershares" {
graph [ label = "shares", color = "#e8726d", fontcolor = "#f0f0f0", style = "rounded,dashed", bgcolor = "#3b4b63" ];
"shares.mul" [ label = "mul" ];
}
subgraph "clusterp" {
graph [ label = "p", color = "#e8726d", fontcolor = "#f0f0f0", style = "rounded,dashed", bgcolor = "#3b4b63" ];
"p.mul" [ label = "mul" ];
}
subgraph "clusterr" {
graph [ label = "r", color = "#e8726d", fontcolor = "#f0f0f0", style = "rounded,dashed", bgcolor = "#3b4b63" ];
"r.add" [ label = "add" ];
}
subgraph "clusterB1" {
graph [ label = "B1", color = "#e8726d", fontcolor = "#f0f0f0", style = "rounded,dashed", bgcolor = "#3b4b63" ];
"B1.mul" [ label = "mul" ];
}
subgraph "clusterB2" {
graph [ label = "B2", color = "#e8726d", fontcolor = "#f0f0f0", style = "rounded,dashed", bgcolor = "#3b4b63" ];
"B2.mul" [ label = "mul" ];
}
subgraph "clusterborrows" {
graph [ label = "borrows", color = "#e8726d", fontcolor = "#f0f0f0", style = "rounded,dashed", bgcolor = "#3b4b63" ];
"borrows.mul" [ label = "mul" ];
}
subgraph "clusterbw" {
graph [ label = "bw", color = "#e8726d", fontcolor = "#f0f0f0", style = "rounded,dashed", bgcolor = "#3b4b63" ];
"bw.mul" [ label = "mul" ];
}
"Lending.preAccrue";
"Lending.accrueInterest";
"Lending.borrow";
"Lending.factor";
"Lending.payback";
"AssetPool.underlyingToken";
"Lending.withdrawCollateral";
"Lending.liquidate";
"Lending.type";
"Lending.getPrice";
"AssetPool.burn";
"AssetPool.transferAsset";
"Lending.getUnaccruedDebt";
"IOracle.getPrice";
"Lending.getLoan";
"Lending.getCurrentRate";
"Lending.compound";
"AssetPool.totalSupply";
"Lending.getBorrowRate";
"rate.div";
"Lending.secondsPerYear";
"AssetPool.deposit";
"AssetPool._mint";
"amount.mul";
"AssetPool.withdraw";
"AssetPool.availableReward";
"AssetPool._claim";
"AssetPool.balanceOf";
"AssetPool._burn";
"shares.mul";
"AssetPool.claimReward";
"AssetPool.accumulateReward";
"Compounder.compound";
"p.mul";
"Compounder.rpow";
"r.add";
"RateProvider.getBorrowRate";
"B1.mul";
"B2.mul";
"borrows.mul";
"RateProvider.getSupplyRate";
"bw.mul";
"Lending.preAccrue" -> "Lending.accrueInterest" [ color = "#80e097" ];
"Lending.borrow" -> "Lending.factor" [ color = "#80e097" ];
"Lending.payback" -> "AssetPool.underlyingToken" [ color = "white" ];
"Lending.withdrawCollateral" -> "Lending.factor" [ color = "#80e097" ];
"Lending.liquidate" -> "Lending.factor" [ color = "#80e097" ];
"Lending.liquidate" -> "Lending.type" [ color = "#1bc6a6" ];
"Lending.liquidate" -> "Lending.getPrice" [ color = "#80e097" ];
"Lending.liquidate" -> "Lending.getPrice" [ color = "#80e097" ];
"Lending.liquidate" -> "AssetPool.underlyingToken" [ color = "white" ];
"Lending.liquidate" -> "AssetPool.burn" [ color = "white" ];
"Lending.liquidate" -> "AssetPool.transferAsset" [ color = "white" ];
"Lending.factor" -> "Lending.getPrice" [ color = "#80e097" ];
"Lending.factor" -> "Lending.getUnaccruedDebt" [ color = "#80e097" ];
"Lending.factor" -> "Lending.getPrice" [ color = "#80e097" ];
"Lending.getPrice" -> "IOracle.getPrice" [ color = "white" ];
"Lending.getUnaccruedDebt" -> "Lending.getLoan" [ color = "#80e097" ];
"Lending.getUnaccruedDebt" -> "Lending.getCurrentRate" [ color = "#80e097" ];
"Lending.getUnaccruedDebt" -> "Lending.compound" [ color = "#80e097" ];
"Lending.accrueInterest" -> "Lending.getCurrentRate" [ color = "#80e097" ];
"Lending.accrueInterest" -> "Lending.compound" [ color = "#80e097" ];
"Lending.getCurrentRate" -> "AssetPool.totalSupply" [ color = "white" ];
"Lending.getCurrentRate" -> "AssetPool.underlyingToken" [ color = "white" ];
"Lending.getCurrentRate" -> "Lending.getBorrowRate" [ color = "#80e097" ];
"Lending.getCurrentRate" -> "rate.div" [ color = "white" ];
"Lending.getCurrentRate" -> "Lending.secondsPerYear" [ color = "#80e097" ];
"AssetPool.deposit" -> "AssetPool.totalSupply" [ color = "#1bc6a6" ];
"AssetPool.deposit" -> "AssetPool._mint" [ color = "#1bc6a6" ];
"AssetPool.deposit" -> "amount.mul" [ color = "white" ];
"AssetPool.withdraw" -> "AssetPool.availableReward" [ color = "#1bc6a6" ];
"AssetPool.withdraw" -> "AssetPool._claim" [ color = "#1bc6a6" ];
"AssetPool.withdraw" -> "AssetPool.balanceOf" [ color = "#1bc6a6" ];
"AssetPool.withdraw" -> "AssetPool._burn" [ color = "#1bc6a6" ];
"AssetPool.withdraw" -> "amount.mul" [ color = "white" ];
"AssetPool.availableReward" -> "AssetPool.balanceOf" [ color = "#1bc6a6" ];
"AssetPool.availableReward" -> "AssetPool.totalSupply" [ color = "#1bc6a6" ];
"AssetPool.availableReward" -> "shares.mul" [ color = "white" ];
"AssetPool.claimReward" -> "AssetPool.availableReward" [ color = "#1bc6a6" ];
"AssetPool.claimReward" -> "AssetPool._claim" [ color = "#1bc6a6" ];
"AssetPool.burn" -> "AssetPool._burn" [ color = "#1bc6a6" ];
"AssetPool.accumulateReward" -> "AssetPool.totalSupply" [ color = "#1bc6a6" ];
"Compounder.compound" -> "p.mul" [ color = "white" ];
"Compounder.compound" -> "Compounder.rpow" [ color = "#1bc6a6" ];
"Compounder.compound" -> "r.add" [ color = "white" ];
"RateProvider.getBorrowRate" -> "B1.mul" [ color = "white" ];
"RateProvider.getBorrowRate" -> "B2.mul" [ color = "white" ];
"RateProvider.getBorrowRate" -> "borrows.mul" [ color = "white" ];
"RateProvider.getSupplyRate" -> "RateProvider.getBorrowRate" [ color = "#1bc6a6" ];
"RateProvider.getSupplyRate" -> "bw.mul" [ color = "white" ];
rankdir=LR
node [shape=plaintext]
subgraph cluster_01 {
label = "Legend";
key [label=<<table border="0" cellpadding="2" cellspacing="0" cellborder="0">
<tr><td align="right" port="i1">Internal Call</td></tr>
<tr><td align="right" port="i2">External Call</td></tr>
<tr><td align="right" port="i3">Defined Contract</td></tr>
<tr><td align="right" port="i4">Undefined Contract</td></tr>
</table>>]
key2 [label=<<table border="0" cellpadding="2" cellspacing="0" cellborder="0">
<tr><td port="i1"> </td></tr>
<tr><td port="i2"> </td></tr>
<tr><td port="i3" bgcolor="#445773"> </td></tr>
<tr><td port="i4">
<table border="1" cellborder="0" cellspacing="0" cellpadding="7" color="#e8726d">
<tr>
<td></td>
</tr>
</table>
</td></tr>
</table>>]
key:i1:e -> key2:i1:w [color="#1bc6a6"]
key:i2:e -> key2:i2:w [color="white"]
}
}
```