Skip to content

Commit

Permalink
Merge pull request #13 from clober-dex/refactor/use-debt-amount
Browse files Browse the repository at this point in the history
Feat/Combine `maxPayInterest` and `minEarnInterest` to `interestThreshold`
  • Loading branch information
JhChoy authored Nov 29, 2023
2 parents 36725d4 + 836ea47 commit 0e2f406
Show file tree
Hide file tree
Showing 8 changed files with 85 additions and 118 deletions.
34 changes: 15 additions & 19 deletions contracts/BorrowController.sol
Original file line number Diff line number Diff line change
Expand Up @@ -55,10 +55,9 @@ contract BorrowController is IBorrowController, Controller, IPositionLocker {
}
LoanPosition memory position = _loanPositionManager.getPosition(positionId);

uint256 maxPayInterest;
uint256 minEarnInterest;
(position.collateralAmount, position.debtAmount, position.expiredWith, maxPayInterest, minEarnInterest) =
abi.decode(data, (uint256, uint256, Epoch, uint256, uint256));
int256 interestThreshold;
(position.collateralAmount, position.debtAmount, position.expiredWith, interestThreshold) =
abi.decode(data, (uint256, uint256, Epoch, int256));

(Coupon[] memory couponsToMint, Coupon[] memory couponsToBurn, int256 collateralDelta, int256 debtDelta) =
_loanPositionManager.adjustPosition(
Expand All @@ -73,9 +72,9 @@ contract BorrowController is IBorrowController, Controller, IPositionLocker {
_wrapCoupons(couponsToMint);
}

if (swapParams.inToken == position.collateralToken) {
if (swapParams.inSubstitute == position.collateralToken) {
_swap(position.collateralToken, position.debtToken, swapParams.amount, swapParams.data);
} else if (swapParams.inToken == position.debtToken) {
} else if (swapParams.inSubstitute == position.debtToken) {
_swap(position.debtToken, position.collateralToken, swapParams.amount, swapParams.data);
}

Expand All @@ -85,8 +84,7 @@ contract BorrowController is IBorrowController, Controller, IPositionLocker {
couponsToMint,
couponsToBurn,
debtDelta < 0 ? uint256(-debtDelta) : 0,
maxPayInterest,
minEarnInterest
interestThreshold
);

if (collateralDelta > 0) {
Expand All @@ -110,15 +108,15 @@ contract BorrowController is IBorrowController, Controller, IPositionLocker {
address collateralToken,
address debtToken,
uint256 collateralAmount,
uint256 borrowAmount,
uint256 maxPayInterest,
uint256 debtAmount,
int256 maxPayInterest,
Epoch expiredWith,
SwapParams calldata swapParams,
ERC20PermitParams calldata collateralPermitParams
) external payable nonReentrant wrapETH {
collateralPermitParams.tryPermit(_getUnderlyingToken(collateralToken), msg.sender, address(this));

bytes memory lockData = abi.encode(collateralAmount, borrowAmount, expiredWith, maxPayInterest, 0);
bytes memory lockData = abi.encode(collateralAmount, debtAmount, expiredWith, maxPayInterest);
lockData = abi.encode(0, msg.sender, swapParams, abi.encode(collateralToken, debtToken, lockData));
bytes memory result = _loanPositionManager.lock(lockData);
uint256 positionId = abi.decode(result, (uint256));
Expand All @@ -131,9 +129,8 @@ contract BorrowController is IBorrowController, Controller, IPositionLocker {
function adjustPosition(
uint256 positionId,
uint256 collateralAmount,
uint256 borrowAmount,
uint256 maxPayInterest,
uint256 minEarnInterest,
uint256 debtAmount,
int256 interestThreshold,
Epoch expiredWith,
SwapParams calldata swapParams,
PermitSignature calldata positionPermitParams,
Expand All @@ -146,10 +143,10 @@ contract BorrowController is IBorrowController, Controller, IPositionLocker {
debtPermitParams.tryPermit(_getUnderlyingToken(position.debtToken), msg.sender, address(this));

position.collateralAmount = collateralAmount;
position.debtAmount = borrowAmount;
position.debtAmount = debtAmount;
position.expiredWith = expiredWith;

_loanPositionManager.lock(_encodeAdjustData(positionId, position, maxPayInterest, minEarnInterest, swapParams));
_loanPositionManager.lock(_encodeAdjustData(positionId, position, interestThreshold, swapParams));

_burnAllSubstitute(position.collateralToken, msg.sender);
_burnAllSubstitute(position.debtToken, msg.sender);
Expand Down Expand Up @@ -178,11 +175,10 @@ contract BorrowController is IBorrowController, Controller, IPositionLocker {
function _encodeAdjustData(
uint256 id,
LoanPosition memory p,
uint256 maxPay,
uint256 minEarn,
int256 interestThreshold,
SwapParams memory swapParams
) internal view returns (bytes memory) {
bytes memory data = abi.encode(p.collateralAmount, p.debtAmount, p.expiredWith, maxPay, minEarn);
bytes memory data = abi.encode(p.collateralAmount, p.debtAmount, p.expiredWith, interestThreshold);
return abi.encode(id, msg.sender, swapParams, data);
}
}
17 changes: 7 additions & 10 deletions contracts/DepositController.sol
Original file line number Diff line number Diff line change
Expand Up @@ -50,10 +50,8 @@ contract DepositController is IDepositController, Controller, IPositionLocker {
}
BondPosition memory position = _bondPositionManager.getPosition(positionId);

uint256 maxPayInterest;
uint256 minEarnInterest;
(position.amount, position.expiredWith, maxPayInterest, minEarnInterest) =
abi.decode(data, (uint256, Epoch, uint256, uint256));
int256 interestThreshold;
(position.amount, position.expiredWith, interestThreshold) = abi.decode(data, (uint256, Epoch, int256));
(Coupon[] memory couponsToMint, Coupon[] memory couponsToBurn, int256 amountDelta) =
_bondPositionManager.adjustPosition(positionId, position.amount, position.expiredWith);
if (amountDelta < 0) _bondPositionManager.withdrawToken(position.asset, address(this), uint256(-amountDelta));
Expand All @@ -68,8 +66,7 @@ contract DepositController is IDepositController, Controller, IPositionLocker {
couponsToMint,
couponsToBurn,
amountDelta > 0 ? uint256(amountDelta) : 0,
maxPayInterest,
minEarnInterest
interestThreshold
);

if (amountDelta > 0) {
Expand All @@ -88,11 +85,11 @@ contract DepositController is IDepositController, Controller, IPositionLocker {
address asset,
uint256 amount,
uint16 lockEpochs,
uint256 minEarnInterest,
int256 minEarnInterest,
ERC20PermitParams calldata tokenPermitParams
) external payable nonReentrant wrapETH {
tokenPermitParams.tryPermit(_getUnderlyingToken(asset), msg.sender, address(this));
bytes memory lockData = abi.encode(amount, EpochLibrary.current().add(lockEpochs - 1), 0, minEarnInterest);
bytes memory lockData = abi.encode(amount, EpochLibrary.current().add(lockEpochs - 1), -minEarnInterest);
bytes memory result = _bondPositionManager.lock(abi.encode(0, msg.sender, abi.encode(asset, lockData)));
uint256 id = abi.decode(result, (uint256));

Expand All @@ -104,13 +101,13 @@ contract DepositController is IDepositController, Controller, IPositionLocker {
function withdraw(
uint256 positionId,
uint256 withdrawAmount,
uint256 maxPayInterest,
int256 maxPayInterest,
PermitSignature calldata positionPermitParams
) external nonReentrant onlyPositionOwner(positionId) {
positionPermitParams.tryPermit(_bondPositionManager, positionId, address(this));
BondPosition memory position = _bondPositionManager.getPosition(positionId);

bytes memory lockData = abi.encode(position.amount - withdrawAmount, position.expiredWith, maxPayInterest, 0);
bytes memory lockData = abi.encode(position.amount - withdrawAmount, position.expiredWith, maxPayInterest);
_bondPositionManager.lock(abi.encode(positionId, msg.sender, lockData));

_burnAllSubstitute(position.asset, msg.sender);
Expand Down
11 changes: 5 additions & 6 deletions contracts/interfaces/IBorrowController.sol
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import {Epoch} from "../libraries/Epoch.sol";

interface IBorrowController is IController {
struct SwapParams {
address inToken;
address inSubstitute;
uint256 amount;
bytes data;
}
Expand All @@ -20,8 +20,8 @@ interface IBorrowController is IController {
address collateralToken,
address debtToken,
uint256 collateralAmount,
uint256 borrowAmount,
uint256 maxPayInterest,
uint256 debtAmount,
int256 maxPayInterest,
Epoch expiredWith,
SwapParams calldata swapParams,
ERC20PermitParams calldata collateralPermitParams
Expand All @@ -30,9 +30,8 @@ interface IBorrowController is IController {
function adjustPosition(
uint256 positionId,
uint256 collateralAmount,
uint256 borrowAmount,
uint256 maxPayInterest,
uint256 minEarnInterest,
uint256 debtAmount,
int256 interestThreshold,
Epoch expiredWith,
SwapParams calldata swapParams,
PermitSignature calldata positionPermitParams,
Expand Down
4 changes: 2 additions & 2 deletions contracts/interfaces/IDepositController.sol
Original file line number Diff line number Diff line change
Expand Up @@ -12,14 +12,14 @@ interface IDepositController is IController {
address token,
uint256 amount,
uint16 lockEpochs,
uint256 minEarnInterest,
int256 minEarnInterest,
ERC20PermitParams calldata tokenPermitParams
) external payable;

function withdraw(
uint256 positionId,
uint256 withdrawAmount,
uint256 maxPayInterest,
int256 maxPayInterest,
PermitSignature calldata positionPermitParams
) external;

Expand Down
55 changes: 22 additions & 33 deletions contracts/libraries/Controller.sol
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import {IERC20Permit} from "@openzeppelin/contracts/token/ERC20/extensions/IERC2
import {ERC1155Holder} from "@openzeppelin/contracts/token/ERC1155/utils/ERC1155Holder.sol";
import {Ownable2Step} from "@openzeppelin/contracts/access/Ownable2Step.sol";
import {Ownable} from "@openzeppelin/contracts/access/Ownable.sol";
import {SafeCast} from "@openzeppelin/contracts/utils/math/SafeCast.sol";

import {CloberMarketSwapCallbackReceiver} from "../external/clober/CloberMarketSwapCallbackReceiver.sol";
import {CloberMarketFactory} from "../external/clober/CloberMarketFactory.sol";
Expand All @@ -33,6 +34,7 @@ abstract contract Controller is
Ownable2Step,
ReentrancyGuard
{
using SafeCast for uint256;
using SafeERC20 for IERC20;
using CouponKeyLibrary for CouponKey;
using CouponLibrary for Coupon;
Expand Down Expand Up @@ -64,17 +66,15 @@ abstract contract Controller is
Coupon[] memory couponsToMint,
Coupon[] memory couponsToBurn,
uint256 amountToPay,
uint256 maxPayInterest,
uint256 leftRequiredInterest
int256 remainingInterest
) internal {
if (couponsToBurn.length > 0) {
Coupon memory lastCoupon = couponsToBurn[couponsToBurn.length - 1];
assembly {
mstore(couponsToBurn, sub(mload(couponsToBurn), 1))
}
bytes memory data = abi.encode(
user, lastCoupon, couponsToMint, couponsToBurn, amountToPay, maxPayInterest, leftRequiredInterest
);
bytes memory data =
abi.encode(user, lastCoupon, couponsToMint, couponsToBurn, amountToPay, remainingInterest);
assembly {
mstore(couponsToBurn, add(mload(couponsToBurn), 1))
}
Expand All @@ -87,17 +87,16 @@ abstract contract Controller is
assembly {
mstore(couponsToMint, sub(mload(couponsToMint), 1))
}
bytes memory data = abi.encode(
user, lastCoupon, couponsToMint, couponsToBurn, amountToPay, maxPayInterest, leftRequiredInterest
);
bytes memory data =
abi.encode(user, lastCoupon, couponsToMint, couponsToBurn, amountToPay, remainingInterest);
assembly {
mstore(couponsToMint, add(mload(couponsToMint), 1))
}

CloberOrderBook market = CloberOrderBook(_couponMarkets[lastCoupon.id()]);
market.marketOrder(address(this), 0, 0, lastCoupon.amount, 2, data);
} else {
if (leftRequiredInterest > 0) revert ControllerSlippage();
if (remainingInterest < 0) revert ControllerSlippage();
_ensureBalance(token, user, amountToPay);
}
}
Expand All @@ -115,32 +114,22 @@ abstract contract Controller is
address asset = CloberOrderBook(msg.sender).quoteToken();
address user;
Coupon memory lastCoupon;
unchecked {
Coupon[] memory couponsToMint;
Coupon[] memory couponsToBurn;
uint256 amountToPay;
uint256 maxPayInterest;
uint256 leftRequiredInterest;
(user, lastCoupon, couponsToMint, couponsToBurn, amountToPay, maxPayInterest, leftRequiredInterest) =
abi.decode(data, (address, Coupon, Coupon[], Coupon[], uint256, uint256, uint256));

if (asset == inputToken) {
if (maxPayInterest < inputAmount) revert ControllerSlippage();
maxPayInterest -= inputAmount;
amountToPay += inputAmount;
} else {
if (leftRequiredInterest > outputAmount) {
leftRequiredInterest -= outputAmount;
} else {
leftRequiredInterest = 0;
}
}

_executeCouponTrade(
user, asset, couponsToMint, couponsToBurn, amountToPay, maxPayInterest, leftRequiredInterest
);
Coupon[] memory couponsToMint;
Coupon[] memory couponsToBurn;
uint256 amountToPay;
int256 remainingInterest;
(user, lastCoupon, couponsToMint, couponsToBurn, amountToPay, remainingInterest) =
abi.decode(data, (address, Coupon, Coupon[], Coupon[], uint256, int256));

if (asset == inputToken) {
remainingInterest -= inputAmount.toInt256();
amountToPay += inputAmount;
} else {
remainingInterest += outputAmount.toInt256();
}

_executeCouponTrade(user, asset, couponsToMint, couponsToBurn, amountToPay, remainingInterest);

// transfer input tokens
if (inputAmount > 0) IERC20(inputToken).safeTransfer(msg.sender, inputAmount);
uint256 couponBalance = IERC20(inputToken).balanceOf(address(this));
Expand Down
Loading

0 comments on commit 0e2f406

Please sign in to comment.