Skip to content

Commit

Permalink
Merge pull request #21 from GenerationSoftware/gen-633-allow-liquidat…
Browse files Browse the repository at this point in the history
…ion-pairs-to-be-discoverable

Update ILiquidationSource Integration
  • Loading branch information
trmid committed Sep 27, 2023
2 parents b8fc696 + f2ba1d1 commit 362af85
Show file tree
Hide file tree
Showing 6 changed files with 102 additions and 116 deletions.
4 changes: 2 additions & 2 deletions .gitmodules
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
[submodule "lib/pt-v5-prize-pool"]
path = lib/pt-v5-prize-pool
url = https://github.com/generationsoftware/pt-v5-prize-pool
branch = prod-deploy-1
branch = main
[submodule "lib/prb-math"]
path = lib/prb-math
url = https://github.com/PaulRBerg/prb-math
Expand All @@ -17,4 +17,4 @@
[submodule "lib/pt-v5-liquidator-interfaces"]
path = lib/pt-v5-liquidator-interfaces
url = https://github.com/generationsoftware/pt-v5-liquidator-interfaces
branch = prod-deploy-1
branch = main
70 changes: 35 additions & 35 deletions src/VaultBooster.sol
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ error OnlyLiquidationPair();
/// @notice Emitted when the liquidator attempts to liquidate more than the available balance
error InsufficientAvailableBalance(uint256 amountOut, uint256 available);

/// @notice Emitted when the liquidator attempts to liquidate for a token other than the prize token
/// @notice Emitted when the liquidator attempts to liquidate for a token other than the prize token
error UnsupportedTokenIn();

/// @notice Emitted when a withdraw of zero amount is initiated.
Expand Down Expand Up @@ -76,21 +76,13 @@ contract VaultBooster is Ownable, ILiquidationSource {
/// @param token The token that they deposited
/// @param from The account that deposited the tokens
/// @param amount The amount that was deposited.
event Deposited(
IERC20 indexed token,
address indexed from,
uint256 amount
);
event Deposited(IERC20 indexed token, address indexed from, uint256 amount);

/// @notice Emitted when tokens are withdrawn by the owner
/// @param token The token that was withdrawn
/// @param from The account that withdraw the tokens
/// @param amount The amount of tokens that were withdrawn
event Withdrawn(
IERC20 indexed token,
address indexed from,
uint256 amount
);
event Withdrawn(IERC20 indexed token, address indexed from, uint256 amount);

/// @notice Emitted when tokens are liquidated
/// @param token The token that was sold
Expand All @@ -109,17 +101,14 @@ contract VaultBooster is Ownable, ILiquidationSource {
/// @notice Emitted when boost tokens are accrued
/// @param token The token that accrued
/// @param availableBoostBalance The new available balance
event BoostAccrued(
IERC20 indexed token,
uint256 availableBoostBalance
);
event BoostAccrued(IERC20 indexed token, uint256 availableBoostBalance);

/// @notice The prize pool that this booster will contribute to
PrizePool public immutable prizePool;

/// @notice The prize pool's twab controller; copied here to save gas
TwabController public immutable twabController;

/// @notice The vault that the VaultBooster is boosting
address public immutable vault;

Expand All @@ -130,11 +119,7 @@ contract VaultBooster is Ownable, ILiquidationSource {
/// @param _prizePool The prize pool to contribute to
/// @param _vault The vault to boost
/// @param _owner The owner of the VaultBooster contract
constructor(
PrizePool _prizePool,
address _vault,
address _owner
) Ownable() {
constructor(PrizePool _prizePool, address _vault, address _owner) Ownable() {
if (address(0) == _vault) revert VaultZeroAddress();
if (address(0) == _owner) revert OwnerZeroAddress();
_transferOwnership(_owner);
Expand Down Expand Up @@ -183,6 +168,9 @@ contract VaultBooster is Ownable, ILiquidationSource {
lastAccruedAt: uint48(block.timestamp)
});

/// @dev See ILiquidationSource.LiquidationPairSet
emit LiquidationPairSet(address(_token), _liquidationPair);

emit SetBoost(
_token,
_liquidationPair,
Expand All @@ -193,11 +181,11 @@ contract VaultBooster is Ownable, ILiquidationSource {
);
}

/// @notice Deposits tokens into this contract.
/// @notice Deposits tokens into this contract.
/// @dev Useful because it ensures `accrue` is called before depositing
/// @param _token The token to deposit
/// @param _amount The amount to deposit
function deposit(IERC20 _token, uint256 _amount) onlyBoosted(_token) external {
function deposit(IERC20 _token, uint256 _amount) external onlyBoosted(_token) {
if (0 == _amount) revert ZeroAmountDeposit();
_accrue(_token);
_token.safeTransferFrom(msg.sender, address(this), _amount);
Expand Down Expand Up @@ -228,9 +216,7 @@ contract VaultBooster is Ownable, ILiquidationSource {
emit Withdrawn(_token, msg.sender, _amount);
}

/// @notice Returns the available amount of tokens for a boost
/// @param _tokenOut The token whose boost should be checked
/// @return The available amount boost tokens
/// @inheritdoc ILiquidationSource
function liquidatableBalanceOf(address _tokenOut) external override returns (uint256) {
return _accrue(IERC20(_tokenOut));
}
Expand Down Expand Up @@ -260,14 +246,28 @@ contract VaultBooster is Ownable, ILiquidationSource {
address tokenIn,
uint256 amountIn,
bytes calldata transferTokensOutData
) external onlyPrizeToken(tokenIn) onlyLiquidationPair(abi.decode(transferTokensOutData, (address))) {
)
external
onlyPrizeToken(tokenIn)
onlyLiquidationPair(abi.decode(transferTokensOutData, (address)))
{
prizePool.contributePrizeTokens(vault, amountIn);
}

/// @notice Returns the liquidation target for the given input tokens. Input must be the prize token, and it always returns the prize pool.
/// @param _tokenIn The token that will be received. Revert if it isn't the prize token.
/// @return The address of the prize pool
function targetOf(address _tokenIn) external view override onlyPrizeToken(_tokenIn) returns (address) {
/// @inheritdoc ILiquidationSource
function isLiquidationPair(
address tokenOut,
address liquidationPair
) external view returns (bool) {
return liquidationPair == _boosts[IERC20(tokenOut)].liquidationPair;
}

/// @inheritdoc ILiquidationSource
/// @dev Reverts if `_tokenIn` isn't the prize token.
/// @dev Always returns the prize pool address.
function targetOf(
address _tokenIn
) external view override onlyPrizeToken(_tokenIn) returns (address) {
return address(prizePool);
}

Expand Down Expand Up @@ -303,9 +303,10 @@ contract VaultBooster is Ownable, ILiquidationSource {
uint32(boost.lastAccruedAt),
uint32(block.timestamp)
);
deltaAmount += convert(boost.multiplierOfTotalSupplyPerSecond.intoUD60x18()
.mul(convert(deltaTime))
.mul(convert(totalSupply))
deltaAmount += convert(
boost.multiplierOfTotalSupplyPerSecond.intoUD60x18().mul(convert(deltaTime)).mul(
convert(totalSupply)
)
);
}
uint256 actualBalance = _tokenOut.balanceOf(address(this));
Expand Down Expand Up @@ -339,5 +340,4 @@ contract VaultBooster is Ownable, ILiquidationSource {
}
_;
}

}
90 changes: 47 additions & 43 deletions test/VaultBooster.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -3,31 +3,16 @@ pragma solidity 0.8.19;

import "forge-std/Test.sol";

import {
VaultBooster,
Boost,
UD60x18,
UD2x18,
OnlyLiquidationPair,
UnsupportedTokenIn,
InsufficientAvailableBalance,
ZeroAmountWithdraw,
ZeroAmountDeposit,
VaultZeroAddress,
OwnerZeroAddress,
CannotDepositWithoutBoost,
TokenZeroAddress,
LiquidationPairZeroAddress,
InsufficientAvailableBalance
} from "../src/VaultBooster.sol";
import { VaultBooster, Boost, UD60x18, UD2x18, OnlyLiquidationPair, UnsupportedTokenIn, InsufficientAvailableBalance, ZeroAmountWithdraw, ZeroAmountDeposit, VaultZeroAddress, OwnerZeroAddress, CannotDepositWithoutBoost, TokenZeroAddress, LiquidationPairZeroAddress, InsufficientAvailableBalance } from "../src/VaultBooster.sol";

import { IFlashSwapCallback } from "pt-v5-liquidator-interfaces/IFlashSwapCallback.sol";
import { PrizePool, TwabController, IERC20 } from "pt-v5-prize-pool/PrizePool.sol";

/// @dev See the "Writing Tests" section in the Foundry Book if this is your first time with Forge.
/// https://book.getfoundry.sh/forge/writing-tests
contract VaultBoosterTest is Test {

event LiquidationPairSet(address indexed tokenOut, address indexed liquidationPair);

event SetBoost(
IERC20 indexed _token,
address indexed _liquidationPair,
Expand All @@ -37,17 +22,9 @@ contract VaultBoosterTest is Test {
uint48 lastAccruedAt
);

event Deposited(
IERC20 indexed _token,
address indexed _from,
uint256 _amount
);
event Deposited(IERC20 indexed _token, address indexed _from, uint256 _amount);

event Withdrawn(
IERC20 indexed _token,
address indexed _from,
uint256 _amount
);
event Withdrawn(IERC20 indexed _token, address indexed _from, uint256 _amount);

event Liquidated(
IERC20 indexed token,
Expand All @@ -57,10 +34,7 @@ contract VaultBoosterTest is Test {
uint256 availableBoostBalance
);

event BoostAccrued(
IERC20 indexed token,
uint256 availableBoostBalance
);
event BoostAccrued(IERC20 indexed token, uint256 availableBoostBalance);

VaultBooster booster;

Expand All @@ -79,8 +53,16 @@ contract VaultBoosterTest is Test {
vault = makeAddr("vault");
prizePool = PrizePool(makeAddr("prizePool"));
twabController = TwabController(makeAddr("twabController"));
vm.mockCall(address(prizePool), abi.encodeWithSelector(prizePool.twabController.selector), abi.encode(twabController));
vm.mockCall(address(prizePool), abi.encodeWithSelector(prizePool.prizeToken.selector), abi.encode(prizeToken));
vm.mockCall(
address(prizePool),
abi.encodeWithSelector(prizePool.twabController.selector),
abi.encode(twabController)
);
vm.mockCall(
address(prizePool),
abi.encodeWithSelector(prizePool.prizeToken.selector),
abi.encode(prizeToken)
);

booster = new VaultBooster(prizePool, vault, address(this));
}
Expand Down Expand Up @@ -108,6 +90,8 @@ contract VaultBoosterTest is Test {
}

function testSetBoost() public {
vm.expectEmit();
emit LiquidationPairSet(address(boostToken), address(liquidationPair));
vm.expectEmit(true, true, true, true);
emit SetBoost(
boostToken,
Expand All @@ -127,7 +111,11 @@ contract VaultBoosterTest is Test {
}

function testSetBoost_available() public {
vm.mockCall(address(boostToken), abi.encodeWithSelector(IERC20.balanceOf.selector, address(booster)), abi.encode(1e18));
vm.mockCall(
address(boostToken),
abi.encodeWithSelector(IERC20.balanceOf.selector, address(booster)),
abi.encode(1e18)
);
booster.setBoost(boostToken, liquidationPair, UD2x18.wrap(0.001e18), 0.03e18, 1e18);
Boost memory boost = booster.getBoost(boostToken);
assertEq(boost.available, 1e18);
Expand All @@ -150,10 +138,22 @@ contract VaultBoosterTest is Test {
assertEq(boost.available, 0.5e18);
}

function testIsLiquidationPair() public {
assertEq(booster.isLiquidationPair(address(boostToken), address(liquidationPair)), false);
booster.setBoost(boostToken, liquidationPair, UD2x18.wrap(0.001e18), 0.03e18, 0);
assertEq(booster.isLiquidationPair(address(boostToken), address(liquidationPair)), true);
assertEq(booster.isLiquidationPair(address(boostToken), address(1)), false);
assertEq(booster.isLiquidationPair(address(1), address(liquidationPair)), false);
}

function testDeposit_success() public {
mockBoostTokenBalance(1e18);
booster.setBoost(boostToken, liquidationPair, UD2x18.wrap(0), 0, 1e18);
vm.mockCall(address(boostToken), abi.encodeWithSelector(IERC20.transferFrom.selector, address(this), address(booster), 2e18), abi.encode(true));
vm.mockCall(
address(boostToken),
abi.encodeWithSelector(IERC20.transferFrom.selector, address(this), address(booster), 2e18),
abi.encode(true)
);
vm.warp(1 days);

vm.expectEmit(true, true, true, true);
Expand All @@ -167,7 +167,11 @@ contract VaultBoosterTest is Test {
function testDeposit_ZeroAmountDeposit() public {
mockBoostTokenBalance(1e18);
booster.setBoost(boostToken, liquidationPair, UD2x18.wrap(0), 0, 1e18);
vm.mockCall(address(boostToken), abi.encodeWithSelector(IERC20.transferFrom.selector, address(this), address(booster), 2e18), abi.encode(true));
vm.mockCall(
address(boostToken),
abi.encodeWithSelector(IERC20.transferFrom.selector, address(this), address(booster), 2e18),
abi.encode(true)
);
vm.warp(1 days);

vm.expectRevert(abi.encodeWithSelector(ZeroAmountDeposit.selector));
Expand Down Expand Up @@ -367,10 +371,7 @@ contract VaultBoosterTest is Test {
function testVerifyTokensIn() public {
vm.mockCall(
address(prizePool),
abi.encodeCall(
prizePool.contributePrizeTokens,
(address(vault), 1000e18)
),
abi.encodeCall(prizePool.contributePrizeTokens, (address(vault), 1000e18)),
abi.encode(0)
);

Expand Down Expand Up @@ -399,7 +400,10 @@ contract VaultBoosterTest is Test {
/** =========== MOCKS ============= */

function mockBoostTokenBalance(uint256 _balance) public {
vm.mockCall(address(boostToken), abi.encodeWithSelector(IERC20.balanceOf.selector, address(booster)), abi.encode(_balance));
vm.mockCall(
address(boostToken),
abi.encodeWithSelector(IERC20.balanceOf.selector, address(booster)),
abi.encode(_balance)
);
}

}
Loading

0 comments on commit 362af85

Please sign in to comment.