Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Burn using 0xdead to enable taking reserves on L2s #1058

Merged
merged 5 commits into from
Jan 17, 2024
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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 ##
BASE_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
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This wasn't being used anywhere. Had it commented-out in my env file for many months.


## 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
BASE_ETH_RPC_URL: ${{secrets.BASE_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);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

IERC20Token import can be removed

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

hey kirill, do we need to concern about non-standard bridged token? or this can be note to deployer to run integration test before deploying it.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Since AJNA token is already circulating, it should be quite easy to test all success paths on a live L2 deployment with bridged quote, collateral and bwAJNA tokens

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I ran on Base yesterday, and Arbitrum, Optimism, and Polygon PoS today. Renamed variables to be less Base-specific, even though token address is hardcoded in the test.

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("BASE_ETH_RPC_URL"));

// Base L2 bwAJNA token address
_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 testStartAndTakeBaseReserveAuction() 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);
}
}
Loading