Skip to content

Commit

Permalink
fix: issue-83
Browse files Browse the repository at this point in the history
  • Loading branch information
fann95 committed Nov 2, 2023
1 parent bf84623 commit 3c17a39
Show file tree
Hide file tree
Showing 4 changed files with 110 additions and 44 deletions.
57 changes: 42 additions & 15 deletions contracts/LiquidityBorrowingManager.sol
Original file line number Diff line number Diff line change
Expand Up @@ -124,6 +124,8 @@ contract LiquidityBorrowingManager is
event EmergencyLoanClosure(address borrower, address lender, bytes32 borrowingKey);
/// Indicates that the protocol has collected fee tokens
event CollectProtocol(address recipient, address[] tokens, uint256[] amounts);
/// Indicates that the lender has collected fee tokens
event CollectLoansFees(address recipient, address[] tokens, uint256[] amounts);
/// Indicates that the daily interest rate for holding token(for specific pair) has been updated
event UpdateHoldTokenDailyRate(address saleToken, address holdToken, uint256 value);
/// Indicates that a borrower has increased their collateral balance for a loan
Expand Down Expand Up @@ -188,23 +190,23 @@ contract LiquidityBorrowingManager is
* @param tokens An array of addresses representing the tokens for which fees will be collected.
*/
function collectProtocol(address recipient, address[] calldata tokens) external onlyOwner {
uint256[] memory amounts = new uint256[](tokens.length);
for (uint256 i; i < tokens.length; ) {
address token = tokens[i];
uint256 amount = platformsFeesInfo[token] / Constants.COLLATERAL_BALANCE_PRECISION;
if (amount > 0) {
platformsFeesInfo[token] = 0;
amounts[i] = amount;
Vault(VAULT_ADDRESS).transferToken(token, recipient, amount);
}
unchecked {
++i;
}
}
uint256[] memory amounts = _collect(platformsFeesInfo, recipient, tokens);

emit CollectProtocol(recipient, tokens, amounts);
}

/**
* @notice This function allows the caller to collect their own loan fees for multiple tokens
* and transfer them to themselves.
* @param tokens An array of addresses representing the tokens for which fees will be collected.
*/
function collectLoansFees(address[] calldata tokens) external {
mapping(address => uint256) storage collection = loansFeesInfo[msg.sender];
uint256[] memory amounts = _collect(collection, msg.sender, tokens);

emit CollectLoansFees(msg.sender, tokens, amounts);
}

/**
* @notice This function is used to update the daily rate for holding token for specific pair.
* @dev Only the daily rate operator can call this function.
Expand Down Expand Up @@ -324,16 +326,21 @@ contract LiquidityBorrowingManager is

/**
* @dev Returns the fees information for multiple tokens in an array.
* @param feesOwner The address of the owner of the fees OR address(0) for returns platformsFeesInfo.
* @param tokens An array of token addresses for which the fees are to be retrieved.
* @return fees An array containing the fees for each token.
*/
function getPlatformsFeesInfo(
function getFeesInfo(
address feesOwner,
address[] calldata tokens
) external view returns (uint256[] memory fees) {
fees = new uint256[](tokens.length);
mapping(address => uint256) storage collection = feesOwner == address(0)
? platformsFeesInfo
: loansFeesInfo[msg.sender];
for (uint256 i; i < tokens.length; ) {
address token = tokens[i];
uint256 amount = platformsFeesInfo[token] / Constants.COLLATERAL_BALANCE_PRECISION;
uint256 amount = collection[token] / Constants.COLLATERAL_BALANCE_PRECISION;
fees[i] = amount;
unchecked {
++i;
Expand Down Expand Up @@ -1099,4 +1106,24 @@ contract LiquidityBorrowingManager is
}
}
}

function _collect(
mapping(address => uint256) storage collection,
address recipient,
address[] calldata tokens
) private returns (uint256[] memory amounts) {
amounts = new uint256[](tokens.length);
for (uint256 i; i < tokens.length; ) {
address token = tokens[i];
uint256 amount = collection[token] / Constants.COLLATERAL_BALANCE_PRECISION;
if (amount > 0) {
collection[token] = 0;
amounts[i] = amount;
Vault(VAULT_ADDRESS).transferToken(token, recipient, amount);
}
unchecked {
++i;
}
}
}
}
7 changes: 5 additions & 2 deletions contracts/abstract/LiquidityManager.sol
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,9 @@ abstract contract LiquidityManager is ApproveSwapAndPay {
*/
IQuoterV2 public immutable underlyingQuoterV2;

/// msg.sender => token => FeesAmt
mapping(address => mapping(address => uint256)) internal loansFeesInfo;

/**
* @dev Contract constructor.
* @param _underlyingPositionManagerAddress Address of the underlying position manager contract.
Expand Down Expand Up @@ -403,9 +406,9 @@ abstract contract LiquidityManager is ApproveSwapAndPay {
params.totalfeesOwed,
cache.holdTokenDebt,
params.totalBorrowedAmount
) / Constants.COLLATERAL_BALANCE_PRECISION;
);

Vault(VAULT_ADDRESS).transferToken(cache.holdToken, creditor, liquidityOwnerReward);
loansFeesInfo[creditor][cache.holdToken] += liquidityOwnerReward;
}

unchecked {
Expand Down
79 changes: 57 additions & 22 deletions docs/LiquidityBorrowingManager.md
Original file line number Diff line number Diff line change
Expand Up @@ -153,6 +153,22 @@ This function is used to check the daily rate collateral for a specific borrowin
| balance | int256 | The balance of the daily rate collateral. |
| estimatedLifeTime | uint256 | The estimated lifetime of the collateral in seconds. |

### collectLoansFees

```solidity
function collectLoansFees(address[] tokens) external nonpayable
```

This function allows the caller to collect their own loan fees for multiple tokens and transfer them to themselves.



#### Parameters

| Name | Type | Description |
|---|---|---|
| tokens | address[] | An array of addresses representing the tokens for which fees will be collected. |

### collectProtocol

```solidity
Expand Down Expand Up @@ -294,6 +310,29 @@ function getBorrowingKeysForTokenId(uint256 tokenId) external view returns (byte
|---|---|---|
| borrowingKeys | bytes32[] | An array of borrowing keys. |

### getFeesInfo

```solidity
function getFeesInfo(address feesOwner, address[] tokens) external view returns (uint256[] fees)
```



*Returns the fees information for multiple tokens in an array.*

#### Parameters

| Name | Type | Description |
|---|---|---|
| feesOwner | address | The address of the owner of the fees OR address(0) for returns platformsFeesInfo. |
| tokens | address[] | An array of token addresses for which the fees are to be retrieved. |

#### Returns

| Name | Type | Description |
|---|---|---|
| fees | uint256[] | An array containing the fees for each token. |

### getHoldTokenDailyRateInfo

```solidity
Expand Down Expand Up @@ -408,28 +447,6 @@ Get information about loans associated with a borrowing key
|---|---|---|
| loans | LiquidityManager.LoanInfo[] | An array containing LoanInfo structs representing the loans associated with the borrowing key |

### getPlatformsFeesInfo

```solidity
function getPlatformsFeesInfo(address[] tokens) external view returns (uint256[] fees)
```



*Returns the fees information for multiple tokens in an array.*

#### Parameters

| Name | Type | Description |
|---|---|---|
| tokens | address[] | An array of token addresses for which the fees are to be retrieved. |

#### Returns

| Name | Type | Description |
|---|---|---|
| fees | uint256[] | An array containing the fees for each token. |

### holdTokenInfo

```solidity
Expand Down Expand Up @@ -792,6 +809,24 @@ Indicates that a borrower has made a new loan
| liquidationBonus | uint256 | undefined |
| dailyRatePrepayment | uint256 | undefined |

### CollectLoansFees

```solidity
event CollectLoansFees(address recipient, address[] tokens, uint256[] amounts)
```

Indicates that the lender has collected fee tokens



#### Parameters

| Name | Type | Description |
|---|---|---|
| recipient | address | undefined |
| tokens | address[] | undefined |
| amounts | uint256[] | undefined |

### CollectProtocol

```solidity
Expand Down
11 changes: 6 additions & 5 deletions test/WagmiLeverageTests.ts
Original file line number Diff line number Diff line change
Expand Up @@ -347,7 +347,7 @@ describe("WagmiLeverageTests", () => {

const prevBalanceLender = await WBTC.balanceOf(alice.address);
const prevBalance = await WBTC.balanceOf(bob.address);
const prevPlatformsFees = (await borrowingManager.getPlatformsFeesInfo([WBTC_ADDRESS]))[0];
const prevPlatformsFees = (await borrowingManager.getFeesInfo(constants.AddressZero, [WBTC_ADDRESS]))[0];

//query amount of collateral available
const borrowingsInfo = await borrowingManager.borrowingsInfo(borrowingKey);
Expand All @@ -362,9 +362,10 @@ describe("WagmiLeverageTests", () => {
await borrowingManager.connect(bob).repay(repayParams, deadline);

const newBalance = await WBTC.balanceOf(bob.address);
const newBalanceLender = await WBTC.balanceOf(alice.address);
const newPlatformsFees = (await borrowingManager.getPlatformsFeesInfo([WBTC_ADDRESS]))[0];
const newPlatformsFees = (await borrowingManager.getFeesInfo(constants.AddressZero, [WBTC_ADDRESS]))[0];
expect(newPlatformsFees).to.be.equal(prevPlatformsFees.add(200));//+20% of MINIMUM_AMOUNT
await borrowingManager.connect(alice).collectLoansFees([WBTC_ADDRESS]);
const newBalanceLender = await WBTC.balanceOf(alice.address);
expect(newBalanceLender).to.be.equal(prevBalanceLender.add(800));//+80% of MINIMUM_AMOUNT
expect(newBalance).to.be.equal(prevBalance.add(liquidationBonus).add(dailyCollateral.sub(1000)));//- MINIMUM_AMOUNT
});
Expand Down Expand Up @@ -1554,15 +1555,15 @@ describe("WagmiLeverageTests", () => {

it("collect protocol fees should be successful", async () => {
const aliceBalanceBefore = await getERC20Balance(WETH_ADDRESS, alice.address);
let fees = await borrowingManager.getPlatformsFeesInfo([USDT_ADDRESS, WETH_ADDRESS]);
let fees = await borrowingManager.getFeesInfo(constants.AddressZero, [USDT_ADDRESS, WETH_ADDRESS]);
expect(fees[0]).to.be.equal(0);
expect(fees[1]).to.be.gt(0);
await expect(borrowingManager.connect(alice).collectProtocol(alice.address, [USDT_ADDRESS, WETH_ADDRESS])).to.be
.reverted;
await borrowingManager.connect(owner).collectProtocol(alice.address, [USDT_ADDRESS, WETH_ADDRESS]);
const aliceBalanceAfter = await getERC20Balance(WETH_ADDRESS, alice.address);
expect(aliceBalanceAfter).to.be.equal(aliceBalanceBefore.add(fees[1]));
fees = await borrowingManager.getPlatformsFeesInfo([USDT_ADDRESS, WETH_ADDRESS]);
fees = await borrowingManager.getFeesInfo(constants.AddressZero, [USDT_ADDRESS, WETH_ADDRESS]);
expect(fees[1]).to.be.equal(0);
});

Expand Down

0 comments on commit 3c17a39

Please sign in to comment.