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

Add STETH to Aave V2 #267

Open
wants to merge 63 commits into
base: fat-deployment
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 62 commits
Commits
Show all changes
63 commits
Select commit Hold shift + click to select a range
64215c6
lido: add dependencies for safe math
DmitIv Oct 28, 2021
ef5fce6
lido: add interface of stETH
DmitIv Oct 28, 2021
28af8ed
lido: add contracts for aToken and debtTokens
DmitIv Oct 28, 2021
6eedc59
lido: add mock steth
DmitIv Oct 28, 2021
974a125
lido: set reserve configs
DmitIv Oct 28, 2021
04154f1
lido: add deployment helpers for astETH
DmitIv Oct 28, 2021
f02e29d
lido: update deployment task according to astETH
DmitIv Oct 28, 2021
f0114c6
lido: add tests for astETH
DmitIv Oct 28, 2021
b83de8e
lido: additional testing for depositing
DmitIv Nov 8, 2021
0bb0a79
lido: additional testing for depositing after rebasing
DmitIv Nov 8, 2021
adbcd75
lido: add exploration of the internal balances
DmitIv Nov 8, 2021
12c9111
lido: additional checks for burn math
DmitIv Nov 16, 2021
23f16e6
Disable stETH borrowing
Psirex Dec 20, 2021
47fddd6
Add coverage command for stETH
Psirex Dec 20, 2021
6ae725c
Merge pull request #10 from lidofinance/fix/quantstamp-audit-qsp-2
bulbozaur Dec 20, 2021
5f3aa44
Merge pull request #13 from lidofinance/fix/tests-coverage
bulbozaur Dec 20, 2021
f03c24d
Add specification for lido integration
Psirex Dec 20, 2021
e339538
Rename SPECIFICATION to README
Psirex Dec 20, 2021
7cefeab
Fix _transfer wrong toBalanceBefore value
Psirex Dec 21, 2021
7405c5a
Test StETH integration with mainnet fork
Psirex Jan 11, 2022
be151cc
Add tests for flashloans
Psirex Jan 13, 2022
f0a374c
Add happy path test
Psirex Jan 13, 2022
4f95c1c
Add tests for rebasing
Psirex Jan 14, 2022
a20f9dc
Add edge case for transfer
Psirex Jan 14, 2022
e7218ac
Update multiple deposits test case
Psirex Jan 14, 2022
201c2d5
Remove old tests
Psirex Jan 14, 2022
91ffe71
Change StETHMocked implementation
Psirex Jan 17, 2022
7338e15
Add additional liquidation tests
Psirex Jan 17, 2022
737e927
Fix filename typo
Psirex Jan 17, 2022
1bedda6
Add debt tokens total supply tests
Psirex Jan 17, 2022
85a54de
Update StETHMocked naming and comments
Psirex Jan 17, 2022
6cd8e2b
Merge pull request #14 from lidofinance/mainnet-fork-tests
Psirex Jan 17, 2022
c7f501e
Change mock lib naming to avoid conflicts
Psirex Jan 17, 2022
e3f3bb4
Remove unused contracts
Psirex Jan 19, 2022
936df76
Replace priceOracle contract type in tests
Psirex Jan 19, 2022
ce504c7
Fix readme markup. Remove outdated paragraph
Psirex Jan 19, 2022
d363f67
Remove trailing сommas from reservesConfigs.
Psirex Jan 19, 2022
c2649bb
Remove unused variables from config files
Psirex Jan 19, 2022
7a66ffd
Remove lido from tasks folder
Psirex Jan 19, 2022
4b76799
Fix stETH shares rounding
Psirex Jan 24, 2022
d0dca14
Update AStETH methods naming
Psirex Jan 24, 2022
8738bfd
Version of AStETH with rebasingIndex
Psirex Jan 24, 2022
684394a
Update usage of ether constants in tests
Psirex Jan 24, 2022
8bd0378
Update flashloan tests to check stETH balance
Psirex Jan 25, 2022
8a88b07
Merge pull request #15 from lidofinance/fix/rounding-rebasing-index
Psirex Jan 25, 2022
58b3ab2
Update AStETH flashloan tests asserts
Psirex Jan 25, 2022
5bb8086
Reorganize methods in AStETH contracts
Psirex Jan 25, 2022
1e164bb
Update stETH integration readme
Psirex Jan 25, 2022
832f93b
Fix typos in AStETH contract
Psirex Jan 26, 2022
a662973
Add comments fix naming in helper contracts
Psirex Jan 26, 2022
7f602a6
Use consistent asserts in flashloan test
Psirex Jan 26, 2022
8a8b167
Temporary change file name to fix uppercase typo
Psirex Jan 26, 2022
f123b4c
Fix file name uppercase typo
Psirex Jan 26, 2022
084ac61
Add additional check of the transfer amount
Psirex Jan 30, 2022
411e9db
Update tests checks and comments
Psirex Jan 30, 2022
70c58e0
Put transfer balance validation under the if branch
Psirex Jan 31, 2022
965e22d
Fix typos in tests, improve liquidation test scenario
Psirex Feb 1, 2022
ae7dedf
Add compile command to stETH tests guide in readme
Psirex Feb 1, 2022
d491865
Add test case with all stETH collateral liquidation
Psirex Feb 1, 2022
0f80ed9
Use 0.99 stETH/ETH price ratio in tests
Psirex Feb 1, 2022
eeecf29
Update stETH/ETH price calculations in liquidation tests
Psirex Feb 2, 2022
2a42cb5
Merge pull request #16 from lidofinance/fix/rounding
Psirex Feb 2, 2022
f3b54f8
Add stETH params to markets config
Psirex Feb 18, 2022
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
11 changes: 11 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -119,6 +119,17 @@ docker-compose exec contracts-env bash
npm run test
```

## Test StETH Integration

To run tests for StETH integration use the following commands:

```
npm install
npm run compile
npm run test:steth
npm run test:steth-coverage # to run tests with coverage report
```

## Deployments

For deploying Aave Protocol V2, you can use the available scripts located at `package.json`. For a complete list, run `npm run` to see all the tasks.
Expand Down
276 changes: 276 additions & 0 deletions contracts/mocks/tokens/StETHMocked.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,276 @@
// SPDX-FileCopyrightText: 2020 Lido <[email protected]>
pragma solidity 0.6.12;

/**
* @notice Mock was based on the original StETH contract from the Lido organization
* https://github.com/lidofinance/lido-dao/blob/master/contracts/0.4.24/StETH.sol
* and tries to be as close as possible to the original implementation.
*/
contract StETHMocked {
using LidoSafeMath for uint256;

// use there values like real stETH has
uint256 internal _totalShares = 1608965089698263670456320;
uint256 internal _pooledEther = 1701398689820002221426255;
mapping(address => uint256) private shares;
mapping(address => mapping(address => uint256)) private allowances;

function name() public pure returns (string memory) {
return 'Liquid staked Ether 2.0';
}

function symbol() public pure returns (string memory) {
return 'stETH';
}

function decimals() public pure returns (uint8) {
return 18;
}

function totalSupply() public view returns (uint256) {
return _getTotalPooledEther();
}

function getTotalPooledEther() public view returns (uint256) {
return _getTotalPooledEther();
}

function balanceOf(address _account) public view returns (uint256) {
return getPooledEthByShares(_sharesOf(_account));
}

function transfer(address _recipient, uint256 _amount) public returns (bool) {
_transfer(msg.sender, _recipient, _amount);
return true;
}

function allowance(address _owner, address _spender) public view returns (uint256) {
return allowances[_owner][_spender];
}

function approve(address _spender, uint256 _amount) public returns (bool) {
_approve(msg.sender, _spender, _amount);
return true;
}

function transferFrom(
address _sender,
address _recipient,
uint256 _amount
) public returns (bool) {
uint256 currentAllowance = allowances[_sender][msg.sender];
require(currentAllowance >= _amount, 'TRANSFER_AMOUNT_EXCEEDS_ALLOWANCE');

_transfer(_sender, _recipient, _amount);
_approve(_sender, msg.sender, currentAllowance.sub(_amount));
return true;
}

function increaseAllowance(address _spender, uint256 _addedValue) public returns (bool) {
_approve(msg.sender, _spender, allowances[msg.sender][_spender].add(_addedValue));
return true;
}

function decreaseAllowance(address _spender, uint256 _subtractedValue) public returns (bool) {
uint256 currentAllowance = allowances[msg.sender][_spender];
require(currentAllowance >= _subtractedValue, 'DECREASED_ALLOWANCE_BELOW_ZERO');
_approve(msg.sender, _spender, currentAllowance.sub(_subtractedValue));
return true;
}

function getTotalShares() public view returns (uint256) {
return _getTotalShares();
}

function sharesOf(address _account) public view returns (uint256) {
return _sharesOf(_account);
}

function getSharesByPooledEth(uint256 _ethAmount) public view returns (uint256) {
uint256 totalPooledEther = _getTotalPooledEther();
if (totalPooledEther == 0) {
return 0;
} else {
return _ethAmount.mul(_getTotalShares()).div(totalPooledEther);
}
}

function getPooledEthByShares(uint256 _sharesAmount) public view returns (uint256) {
uint256 totalShares = _getTotalShares();
if (totalShares == 0) {
return 0;
} else {
return _sharesAmount.mul(_getTotalPooledEther()).div(totalShares);
}
}

function mint(address _recipient, uint256 amount) external returns (uint256) {
return _submit(_recipient, amount);
}

function positiveRebase(uint256 amount) external {
_pooledEther = _pooledEther.add(amount);
}

function negativeRebase(uint256 amount) external {
_pooledEther = _pooledEther.sub(amount);
}

function _getTotalPooledEther() internal view returns (uint256) {
return _pooledEther;
}

function _transfer(
address _sender,
address _recipient,
uint256 _amount
) internal {
uint256 _sharesToTransfer = getSharesByPooledEth(_amount);
_transferShares(_sender, _recipient, _sharesToTransfer);
emit Transfer(_sender, _recipient, _amount);
}

function _approve(
address _owner,
address _spender,
uint256 _amount
) internal {
require(_owner != address(0), 'APPROVE_FROM_ZERO_ADDRESS');
require(_spender != address(0), 'APPROVE_TO_ZERO_ADDRESS');

allowances[_owner][_spender] = _amount;
emit Approval(_owner, _spender, _amount);
}

function _getTotalShares() internal view returns (uint256) {
return _totalShares;
}

function _sharesOf(address _account) internal view returns (uint256) {
return shares[_account];
}

function _transferShares(
address _sender,
address _recipient,
uint256 _sharesAmount
) internal {
require(_sender != address(0), 'TRANSFER_FROM_THE_ZERO_ADDRESS');
require(_recipient != address(0), 'TRANSFER_TO_THE_ZERO_ADDRESS');

uint256 currentSenderShares = shares[_sender];
require(_sharesAmount <= currentSenderShares, 'TRANSFER_AMOUNT_EXCEEDS_BALANCE');

shares[_sender] = currentSenderShares.sub(_sharesAmount);
shares[_recipient] = shares[_recipient].add(_sharesAmount);
}

function _mintShares(address _recipient, uint256 _sharesAmount)
internal
returns (uint256 newTotalShares)
{
require(_recipient != address(0), 'MINT_TO_THE_ZERO_ADDRESS');

newTotalShares = _getTotalShares().add(_sharesAmount);
_totalShares = newTotalShares;

shares[_recipient] = shares[_recipient].add(_sharesAmount);
}

function _burnShares(address _account, uint256 _sharesAmount)
internal
returns (uint256 newTotalShares)
{
require(_account != address(0), 'BURN_FROM_THE_ZERO_ADDRESS');

uint256 accountShares = shares[_account];
require(_sharesAmount <= accountShares, 'BURN_AMOUNT_EXCEEDS_BALANCE');

newTotalShares = _getTotalShares().sub(_sharesAmount);
_totalShares = newTotalShares;

shares[_account] = accountShares.sub(_sharesAmount);
}

function _submit(address sender, uint256 deposit) internal returns (uint256) {
require(deposit != 0, 'ZERO_DEPOSIT');

uint256 sharesAmount = getSharesByPooledEth(deposit);
if (sharesAmount == 0) {
sharesAmount = deposit;
}

_mintShares(sender, sharesAmount);
_pooledEther = _pooledEther.add(deposit);
return sharesAmount;
}

event Transfer(address indexed from, address indexed to, uint256 value);
event Approval(address indexed owner, address indexed spender, uint256 value);
}

/**
* @title SafeMath
* @dev Math operations with safety checks that revert on error. Prefix Lido used to not
* conflict with OpenZeppelin SafeMath contract.
*/
library LidoSafeMath {
string private constant ERROR_ADD_OVERFLOW = 'MATH_ADD_OVERFLOW';
string private constant ERROR_SUB_UNDERFLOW = 'MATH_SUB_UNDERFLOW';
string private constant ERROR_MUL_OVERFLOW = 'MATH_MUL_OVERFLOW';
string private constant ERROR_DIV_ZERO = 'MATH_DIV_ZERO';

/**
* @dev Multiplies two numbers, reverts on overflow.
*/
function mul(uint256 _a, uint256 _b) internal pure returns (uint256) {
if (_a == 0) {
return 0;
}

uint256 c = _a * _b;
require(c / _a == _b, ERROR_MUL_OVERFLOW);

return c;
}

/**
* @dev Integer division of two numbers truncating the quotient, reverts on division by zero.
*/
function div(uint256 _a, uint256 _b) internal pure returns (uint256) {
require(_b > 0, ERROR_DIV_ZERO); // Solidity only automatically asserts when dividing by 0
uint256 c = _a / _b;
// assert(_a == _b * c + _a % _b); // There is no case in which this doesn't hold

return c;
}

/**
* @dev Subtracts two numbers, reverts on overflow (i.e. if subtrahend is greater than minuend).
*/
function sub(uint256 _a, uint256 _b) internal pure returns (uint256) {
require(_b <= _a, ERROR_SUB_UNDERFLOW);
uint256 c = _a - _b;

return c;
}

/**
* @dev Adds two numbers, reverts on overflow.
*/
function add(uint256 _a, uint256 _b) internal pure returns (uint256) {
uint256 c = _a + _b;
require(c >= _a, ERROR_ADD_OVERFLOW);

return c;
}

/**
* @dev Divides two numbers and returns the remainder (unsigned integer modulo),
* reverts when dividing by zero.
*/
function mod(uint256 a, uint256 b) internal pure returns (uint256) {
require(b != 0, ERROR_DIV_ZERO);
return a % b;
}
}
2 changes: 1 addition & 1 deletion contracts/protocol/tokenization/StableDebtToken.sol
Original file line number Diff line number Diff line change
Expand Up @@ -103,7 +103,7 @@ contract StableDebtToken is IStableDebtToken, DebtTokenBase {
address onBehalfOf,
uint256 amount,
uint256 rate
) external override onlyLendingPool returns (bool) {
) external virtual override onlyLendingPool returns (bool) {
MintLocalVars memory vars;

if (user != onBehalfOf) {
Expand Down
2 changes: 1 addition & 1 deletion contracts/protocol/tokenization/VariableDebtToken.sol
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ contract VariableDebtToken is DebtTokenBase, IVariableDebtToken {
address onBehalfOf,
uint256 amount,
uint256 index
) external override onlyLendingPool returns (bool) {
) external virtual override onlyLendingPool returns (bool) {
if (user != onBehalfOf) {
_decreaseBorrowAllowance(onBehalfOf, user, amount);
}
Expand Down
Loading