-
Notifications
You must be signed in to change notification settings - Fork 45
/
WalletBalanceProvider.sol
108 lines (91 loc) · 3.77 KB
/
WalletBalanceProvider.sol
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
// SPDX-License-Identifier: BUSL-1.1
pragma solidity ^0.8.10;
import {Address} from '../dependencies/openzeppelin/contracts/Address.sol';
import {IERC20} from '../dependencies/openzeppelin/contracts/IERC20.sol';
import {IPoolAddressesProvider} from '../interfaces/IPoolAddressesProvider.sol';
import {IPool} from '../interfaces/IPool.sol';
import {GPv2SafeERC20} from '../dependencies/gnosis/contracts/GPv2SafeERC20.sol';
import {ReserveConfiguration} from '../protocol/libraries/configuration/ReserveConfiguration.sol';
import {DataTypes} from '../protocol/libraries/types/DataTypes.sol';
/**
* @title WalletBalanceProvider contract
* @author Aave, influenced by https://github.com/wbobeirne/eth-balance-checker/blob/master/contracts/BalanceChecker.sol
* @notice Implements a logic of getting multiple tokens balance for one user address
* @dev NOTE: THIS CONTRACT IS NOT USED WITHIN THE AAVE PROTOCOL. It's an accessory contract used to reduce the number of calls
* towards the blockchain from the Aave backend.
**/
contract WalletBalanceProvider {
using Address for address payable;
using Address for address;
using GPv2SafeERC20 for IERC20;
using ReserveConfiguration for DataTypes.ReserveConfigurationMap;
address constant MOCK_ETH_ADDRESS = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE;
/**
@dev Fallback function, don't accept any ETH
**/
receive() external payable {
//only contracts can send ETH to the core
require(msg.sender.isContract(), '22');
}
/**
@dev Check the token balance of a wallet in a token contract
Returns the balance of the token for user. Avoids possible errors:
- return 0 on non-contract address
**/
function balanceOf(address user, address token) public view returns (uint256) {
if (token == MOCK_ETH_ADDRESS) {
return user.balance; // ETH balance
// check if token is actually a contract
} else if (token.isContract()) {
return IERC20(token).balanceOf(user);
}
revert('INVALID_TOKEN');
}
/**
* @notice Fetches, for a list of _users and _tokens (ETH included with mock address), the balances
* @param users The list of users
* @param tokens The list of tokens
* @return And array with the concatenation of, for each user, his/her balances
**/
function batchBalanceOf(
address[] calldata users,
address[] calldata tokens
) external view returns (uint256[] memory) {
uint256[] memory balances = new uint256[](users.length * tokens.length);
for (uint256 i = 0; i < users.length; i++) {
for (uint256 j = 0; j < tokens.length; j++) {
balances[i * tokens.length + j] = balanceOf(users[i], tokens[j]);
}
}
return balances;
}
/**
@dev provides balances of user wallet for all reserves available on the pool
*/
function getUserWalletBalances(
address provider,
address user
) external view returns (address[] memory, uint256[] memory) {
IPool pool = IPool(IPoolAddressesProvider(provider).getPool());
address[] memory reserves = pool.getReservesList();
address[] memory reservesWithEth = new address[](reserves.length + 1);
for (uint256 i = 0; i < reserves.length; i++) {
reservesWithEth[i] = reserves[i];
}
reservesWithEth[reserves.length] = MOCK_ETH_ADDRESS;
uint256[] memory balances = new uint256[](reservesWithEth.length);
for (uint256 j = 0; j < reserves.length; j++) {
DataTypes.ReserveConfigurationMap memory configuration = pool.getConfiguration(
reservesWithEth[j]
);
(bool isActive, , , ) = configuration.getFlags();
if (!isActive) {
balances[j] = 0;
continue;
}
balances[j] = balanceOf(user, reservesWithEth[j]);
}
balances[reserves.length] = balanceOf(user, MOCK_ETH_ADDRESS);
return (reservesWithEth, balances);
}
}