Skip to content

Commit

Permalink
Burn using 0xdead to enable taking reserves on L2s (#1058)
Browse files Browse the repository at this point in the history
* replace burn call, which doesn't exist  on L2s

* added a Base L2 unit test for reserve auction

* Fix testPurchaseWithFlashLoan, failing due to recent increase in WETH price against USDC

* renamed the L2 ETH_RPC_URL

* rename test

---------

Co-authored-by: prateek105 <[email protected]>
  • Loading branch information
EdNoepel and prateek105 authored Jan 17, 2024
1 parent 2d6bbcb commit d07146c
Show file tree
Hide file tree
Showing 5 changed files with 92 additions and 9 deletions.
10 changes: 5 additions & 5 deletions .env.example
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,12 @@ ALCHEMY_API_KEY=
## Infura API key ##
WEB3_INFURA_PROJECT_ID=

## Ethereum node endpoint ##
## Mainnet Ethereum node endpoint ##
ETH_RPC_URL=

## Base L2 node endpoint ##
L2_ETH_RPC_URL=

## EOA Contract Deployer ##
ETH_FROM=

Expand All @@ -21,8 +24,5 @@ ETH_GAS=15000000
## Solidity Compiler Version ##
SOLC_VERSION=0.8.18

## AJNA token address for target chain ##
AJNA_TOKEN=0xaadebCF61AA7Da0573b524DE57c67aDa797D46c5

## path to the JSON keystore file for your deployment account ##
DEPLOY_KEY=
DEPLOY_KEY=
1 change: 1 addition & 0 deletions .github/workflows/forge-test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ on: [push]
env:
FOUNDRY_PROFILE: ci
ETH_RPC_URL: ${{secrets.ETH_RPC_URL}} ## Loads environment from secrets
L2_ETH_RPC_URL: ${{secrets.L2_ETH_RPC_URL}}

jobs:
check:
Expand Down
6 changes: 3 additions & 3 deletions src/base/Pool.sol
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,8 @@ abstract contract Pool is Clone, ReentrancyGuard, Multicall, IPool {
uint256 internal constant QUOTE_ADDRESS = 41;
/// @dev Immutable quote token scale arg offset.
uint256 internal constant QUOTE_SCALE = 61;
/// @dev Address used to burn AJNA tokens
address internal constant BURN_ADDRESS = 0x000000000000000000000000000000000000dEaD;

/***********************/
/*** State Variables ***/
Expand Down Expand Up @@ -433,9 +435,7 @@ abstract contract Pool is Clone, ReentrancyGuard, Multicall, IPool {
);

// burn required number of ajna tokens to take quote from reserves
IERC20(_getArgAddress(AJNA_ADDRESS)).safeTransferFrom(msg.sender, address(this), ajnaRequired);

IERC20Token(_getArgAddress(AJNA_ADDRESS)).burn(ajnaRequired);
IERC20(_getArgAddress(AJNA_ADDRESS)).safeTransferFrom(msg.sender, BURN_ADDRESS, ajnaRequired);

// transfer quote token to caller
_transferQuoteToken(msg.sender, amount_);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ contract PurchaseQuoteWithExternalLiquidityTest is Test {
address internal _lender;

function setUp() external {
vm.createSelectFork(vm.envString("ETH_RPC_URL"));
vm.createSelectFork(vm.envString("ETH_RPC_URL"), 18800000);
_ajnaPool = ERC20Pool(new ERC20PoolFactory(AJNA).deployPool(WETH, USDC, 0.05 * 10**18));
_lender = makeAddr("lender");

Expand Down
82 changes: 82 additions & 0 deletions tests/forge/unit/ERC20Pool/ERC20PoolReserveAuction.t.sol
Original file line number Diff line number Diff line change
@@ -1,14 +1,17 @@
// SPDX-License-Identifier: UNLICENSED
pragma solidity 0.8.18;

import "@std/Test.sol";
import '@openzeppelin/contracts/token/ERC20/ERC20.sol';

import { ERC20HelperContract } from './ERC20DSTestPlus.sol';
import { FlashloanBorrower, SomeDefiStrategy } from '../../utils/FlashloanBorrower.sol';
import { Token } from '../../utils/Tokens.sol';

import 'src/libraries/helpers/PoolHelper.sol';
import 'src/ERC20Pool.sol';
import 'src/ERC20PoolFactory.sol';
import 'src/PoolInfoUtils.sol';

import { IPoolErrors } from 'src/interfaces/pool/IPool.sol';

Expand Down Expand Up @@ -322,3 +325,82 @@ contract ERC20PoolReserveAuctionNoFundsTest is ERC20HelperContract {
}

}

contract L2ERC20PoolReserveAuctionTest is Test {
ERC20PoolFactory internal _poolFactory;
ERC20Pool internal _pool;
ERC20 internal _ajna;
Token internal _collateral;
Token internal _quote;
PoolInfoUtils internal _poolInfo;
address internal _borrower;
address internal _lender;
address internal _bidder;

function setUp() public {
vm.createSelectFork(vm.envString("L2_ETH_RPC_URL"));

// L2 bwAJNA token address (example is for Base)
_ajna = ERC20(0xf0f326af3b1Ed943ab95C29470730CC8Cf66ae47);
_collateral = new Token("Collateral", "C");
_quote = new Token("Quote", "Q");
_poolFactory = new ERC20PoolFactory(address(_ajna));
_pool = ERC20Pool(_poolFactory.deployPool(address(_collateral), address(_quote), 0.05 * 1e18));
_poolInfo = new PoolInfoUtils();

_borrower = makeAddr("borrower");
_lender = makeAddr("lender");
_bidder = makeAddr("bidder");

// mint tokens
deal(address(_collateral), _borrower, 10 * 1e18);
deal(address(_quote), _borrower, 100 * 1e18);
deal(address(_quote), _lender, 10_000 * 1e18);
deal(address(_ajna), _bidder, 10 * 1e18);

// add liquidity
changePrank(_lender);
_quote.approve(address(_pool), type(uint256).max);
_pool.addQuoteToken(1_000 * 1e18, 2500, block.timestamp);

// draw debt
changePrank(_borrower);
_collateral.approve(address(_pool), type(uint256).max);
_pool.drawDebt(address(_borrower), 300 * 1e18, 7000, 1 * 1e18);
}

function testStartAndTakeL2ReserveAuction() external {
// skip time to accumulate interest
skip(26 weeks);

// repay debt
changePrank(_borrower);
_quote.approve(address(_pool), type(uint256).max);
_pool.repayDebt(address(_borrower), 400 * 1e18, 1 * 1e18, address(_borrower), 7000);

// check token balances and confirm reserves are claimable
assertEq(_quote.balanceOf(address(_bidder)), 0);
assertEq(_ajna.balanceOf(address(_bidder)), 10 * 1e18);
assertEq(_ajna.balanceOf(address(_pool)), 0);
(, uint256 claimableReserves, , ,) = _poolInfo.poolReservesInfo(address(_pool));
assertEq(claimableReserves, 1.471235273731403306 * 1e18);

// kick reserve auction
changePrank(_bidder);
_pool.kickReserveAuction();
(, , uint256 remaining, ,) = _poolInfo.poolReservesInfo(address(_pool));
assertEq(remaining, 1.471235273731403306 * 1e18);

// take all at reasonable price
skip(32 hours);
(, , , uint256 auctionPrice,) = _poolInfo.poolReservesInfo(address(_pool));
assertEq(auctionPrice, 0.158255207587128891 * 1e18);
_ajna.approve(address(_pool), type(uint256).max);
_pool.takeReserves(2 * 1e18);

// check token balances ensuring AJNA was burned
assertEq(_quote.balanceOf(address(_bidder)), 1.471235273731403306 * 1e18);
assertEq(_ajna.balanceOf(address(_bidder)), 9.767169356346130372 * 1e18);
assertEq(_ajna.balanceOf(address(_pool)), 0);
}
}

0 comments on commit d07146c

Please sign in to comment.