Skip to content

Commit

Permalink
feat!: better eModes (v4) (#629)
Browse files Browse the repository at this point in the history
BREAKING CHANGE:

- The eMode exports on the js side now contain the full eMode configuration with the decoded bitmaps.
- abis are exported via /abis to no longer mix with the addresses
- removing tokenlist from ts exports as there's no good reason to use it from here (integrations work with the toplevel json)
  • Loading branch information
sakulstra authored Oct 9, 2024
1 parent 1296c81 commit f5bf364
Show file tree
Hide file tree
Showing 91 changed files with 3,570 additions and 8,691 deletions.
10 changes: 9 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ import { AaveV2Avalanche } from "@bgd-labs/aave-address-book"; // import specifi
console.log(AaveV2Avalanche.POOL_ADDRESSES_PROVIDER);
// "0xa97684ead0e402dC232d5A977953DF7ECBaB3CDb"

// in addition the chainId of the respecitve addresses is exported alongside
// in addition the chainId of the respective addresses is exported alongside
console.log(AaveV2Avalanche.CHAIN_ID);
// 43114
```
Expand Down Expand Up @@ -106,3 +106,11 @@ b) Adding an address that **cannot be obtained via onchain calls** so it needs t
To achieve an addition here, you need to alter the [additionalAddresses section](https://github.com/bgd-labs/aave-address-book/blob/main/scripts/config.ts#L46) on the pool type and add your address to the respective pools. Additional addresses will currently be exported as type `address`. There's currently no possibility to define a custom type.

In any case you need to run `yarn generate:addresses` afterwards and commit the altered artifacts.

### Troubleshooting

#### Error generating the addresses

This repository will try to use public rpcs.
For some networks they are not very reliable though, therefore you can set `RPC_<NETWORK>` in your .env to use a private rpc.
Check https://github.com/bgd-labs/aave-address-book/blob/main/scripts/clients.ts#L39 for the chain naming convention.
14 changes: 13 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,18 @@
},
"types": "./dist/AaveAddressBook.d.ts",
"default": "./dist/AaveAddressBook.js"
},
"./abis": {
"require": {
"types": "./dist/abis/index.d.ts",
"default": "./dist/abis/index.js"
},
"import": {
"types": "./dist/abis/index.mts",
"default": "./dist/abis/index.mjs"
},
"types": "./dist/abis/index.d.ts",
"default": "./dist/abis/index.js"
}
},
"sideEffects": false,
Expand Down Expand Up @@ -52,7 +64,7 @@
"homepage": "https://github.com/bgd-labs/aave-address-book#readme",
"devDependencies": {
"@bgd-labs/js-utils": "1.4.2",
"@bgd-labs/react-web3-icons": "^1.4.4",
"@bgd-labs/react-web3-icons": "^1.5.3",
"@types/node": "^22.4.1",
"@uniswap/token-lists": "^1.0.0-beta.33",
"ajv": "^8.12.0",
Expand Down
206 changes: 24 additions & 182 deletions safe.csv

Large diffs are not rendered by default.

13 changes: 13 additions & 0 deletions scripts/checks/utils.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import * as addressBook from '../../src/ts/AaveAddressBook';

export function getGovernance(chainId: number) {
for (const [name, lib] of Object.entries(addressBook)) {
if (name.startsWith('GovernanceV3') && lib.CHAIN_ID === chainId) return lib;
}
}

export function getMisc(chainId: number) {
for (const [name, lib] of Object.entries(addressBook)) {
if (name.startsWith('Misc') && lib.CHAIN_ID === chainId) return lib;
}
}
33 changes: 33 additions & 0 deletions scripts/checks/wethGateway.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
import {getContract} from 'viem';
import {CHAIN_ID_CLIENT_MAP} from '../clients';
import {IOwnable_ABI} from '../../src/ts/abis/IOwnable';
import {getGovernance} from './utils';

export async function check(addresses: Record<string, any>) {
if (addresses.WETH_GATEWAY) {
const client = CHAIN_ID_CLIENT_MAP[addresses.CHAIN_ID];
// on testnets owners are usually not governance
if (!client.chain?.testnet) {
const gateway = getContract({
abi: IOwnable_ABI,
address: addresses.WETH_GATEWAY,
client,
});
const owner = await gateway.read.owner();
const governance = getGovernance(addresses.CHAIN_ID);
if (!governance) {
console.log(
'SANITY_GATEWAY: Skipped due to missing governance on chainId: ${addresses.CHAIN_ID}',
);
} else {
const l1Executor = (governance as any).EXECUTOR_LVL_1;
// prettier would be to check against executor lvl_1
if (owner !== l1Executor) {
throw new Error(
`SANITY_GATEWAY: OWNER MISMATCH ${addresses.POOL}.${addresses.WETH_GATEWAY}:${owner} != ${l1Executor}`,
);
}
}
}
}
}
2 changes: 2 additions & 0 deletions scripts/configs/abis.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ export const ABI_INTERFACES = [
'IAToken',
'IDefaultInterestRateStrategy',
'lib/aave-v3-origin/src/contracts/interfaces/IAaveOracle.sol:IAaveOracle',
'lib/aave-v3-origin/src/contracts/rewards/interfaces/IRewardsController.sol:IRewardsController',
'IExecutor',
'ICrossChainController',
'IWithGuardian',
Expand All @@ -35,6 +36,7 @@ export const ABI_INTERFACES = [
'IStakeToken',
'IStataTokenFactory',
'IStataTokenV2',
'lib/aave-v3-origin/src/contracts/helpers/interfaces/IWrappedTokenGatewayV3.sol:IWrappedTokenGatewayV3',
];

/**
Expand Down
10 changes: 10 additions & 0 deletions scripts/configs/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,7 @@ export type ReserveData = {
symbol: string;
UNDERLYING: Hex;
decimals: number;
id: number;
A_TOKEN: Hex;
V_TOKEN: Hex;
INTEREST_RATE_STRATEGY: Hex;
Expand All @@ -89,6 +90,15 @@ export type ReserveData = {
STATA_TOKEN?: Hex;
};

export type EMode = {
label: string;
ltv: number;
liquidationThreshold: number;
liquidationBonus: number;
collateralBitmap: bigint;
borrowableBitmap: bigint;
};

/**
* @dev config for addresses that belong more to a network then to a specific pool
*/
Expand Down
1 change: 0 additions & 1 deletion scripts/generateABIs.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,6 @@ export async function generateABIs(removeExisting: boolean) {
} else {
mkdirSync('./src/ts/abis');
}
const imports: string[] = [];
for (const INTERFACE_PATH of ABI_INTERFACES) {
const {stdout, stderr} = await awaitableExec(`forge inspect ${INTERFACE_PATH} abi`);
const INTERFACE =
Expand Down
3 changes: 2 additions & 1 deletion scripts/generateAddresses.ts
Original file line number Diff line number Diff line change
Expand Up @@ -163,6 +163,8 @@ async function main() {

const abis = generateABIImports();

writeFileSync('./src/ts/abis/index.ts', abis.join('\n'));

const imports = [
governanceNames,
v1Library,
Expand All @@ -172,7 +174,6 @@ async function main() {
govImports,
smImports,
tokenListImports,
abis,
].flat();

const jsExports = imports.map((f) => f.js).flat();
Expand Down
9 changes: 3 additions & 6 deletions scripts/generator/abis.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,14 +6,11 @@ export function generateABIImports() {
const INTERFACE =
INTERFACE_PATH.split(':').length > 1 ? INTERFACE_PATH.split(':')[1] : INTERFACE_PATH;
const varName = `${INTERFACE}_ABI`;
jsExports.push(`export {${varName}} from './abis/${INTERFACE}';`);
jsExports.push(`export {${varName}} from './${INTERFACE}';`);
}
for (const INTERFACE of DOWNLOAD_ABI_INTERFACES) {
const varName = `${INTERFACE.name}_ABI`;
jsExports.push(`export {${varName}} from './abis/${INTERFACE.name}';`);
jsExports.push(`export {${varName}} from './${INTERFACE.name}';`);
}
return {
solidity: [],
js: jsExports,
};
return jsExports;
}
8 changes: 1 addition & 7 deletions scripts/generator/generateTokenList.ts
Original file line number Diff line number Diff line change
Expand Up @@ -167,19 +167,13 @@ export async function generateTokenList(pools: TokenListParams) {
filepath: path,
}),
);
writeFileSync(
`./src/ts/tokenlist.ts`,
await prettier.format(`export const tokenlist = ${JSON.stringify(tokenList)}`, {
filepath: `./src/ts/tokenlist.ts`,
}),
);
}
if (validator.errors) {
console.log(validator.errors);
throw new Error('error creating tokenlist');
}
return {
js: [`export {tokenlist} from './tokenlist';`],
js: [],
solidity: [],
};
}
68 changes: 68 additions & 0 deletions scripts/generator/protocol-v2-generator/fetchPoolAddresses.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
import {Address, Client, getContract, zeroAddress} from 'viem';
import {PoolConfig} from '../../configs/types';
import {bytes32toAddress, getImplementationStorageSlot} from '../utils';
import {ILendingPoolAddressesProvider_ABI} from '../../../src/ts/abis/ILendingPoolAddressesProvider';
import {mainnetAmmV2Pool} from '../../configs/pools/ethereum';

export async function fetchPoolAddresses(client: Client, poolConfig: PoolConfig) {
const addressProviderContract = getContract({
address: poolConfig.POOL_ADDRESSES_PROVIDER,
abi: ILendingPoolAddressesProvider_ABI,
client,
});

const [
POOL,
LENDING_RATE_ORACLE,
POOL_CONFIGURATOR,
ORACLE,
POOL_ADMIN,
EMERGENCY_ADMIN,
AAVE_PROTOCOL_DATA_PROVIDER,
LENDING_POOL_COLLATERAL_MANAGER,
] = await Promise.all([
addressProviderContract.read.getLendingPool(),
addressProviderContract.read.getLendingRateOracle(),
addressProviderContract.read.getLendingPoolConfigurator(),
addressProviderContract.read.getPriceOracle(),
addressProviderContract.read.getPoolAdmin(),
addressProviderContract.read.getEmergencyAdmin(),
addressProviderContract.read.getAddress([
poolConfig.name === mainnetAmmV2Pool.name
? '0x1000000000000000000000000000000000000000000000000000000000000000'
: '0x0100000000000000000000000000000000000000000000000000000000000000',
]),
addressProviderContract.read.getLendingPoolCollateralManager(),
]);

const [POOL_IMPL, POOL_CONFIGURATOR_IMPL] = await Promise.all([
getImplementationStorageSlot(client, POOL),
getImplementationStorageSlot(client, POOL_CONFIGURATOR),
]);

return {
POOL_ADDRESSES_PROVIDER: {
value: poolConfig.POOL_ADDRESSES_PROVIDER,
type: 'ILendingPoolAddressesProvider',
},
POOL: {value: POOL, type: 'ILendingPool'},
POOL_IMPL: bytes32toAddress(POOL_IMPL),
POOL_CONFIGURATOR: {
value: POOL_CONFIGURATOR,
type: 'ILendingPoolConfigurator',
},
POOL_CONFIGURATOR_IMPL: bytes32toAddress(POOL_CONFIGURATOR_IMPL),
ORACLE: {
value: ORACLE,
type: 'IAaveOracle',
},
LENDING_RATE_ORACLE: {value: LENDING_RATE_ORACLE, type: 'ILendingRateOracle'},
AAVE_PROTOCOL_DATA_PROVIDER: {
value: AAVE_PROTOCOL_DATA_PROVIDER,
type: 'IAaveProtocolDataProvider',
},
LENDING_POOL_COLLATERAL_MANAGER,
POOL_ADMIN,
EMERGENCY_ADMIN,
};
}
82 changes: 82 additions & 0 deletions scripts/generator/protocol-v2-generator/fetchTokens.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
import {Address, Client, getContract, zeroAddress} from 'viem';
import {fetchPoolAddresses} from './fetchPoolAddresses';
import {ILendingPool_ABI} from '../../../src/ts/abis/ILendingPool';
import {ReserveData} from '../../configs/types';
import {IERC20Detailed_ABI} from '../../../src/ts/abis/IERC20Detailed';
import {IAaveOracle_ABI} from '../../../src/ts/abis/IAaveOracle';
import {A_TOKEN_V2_ABI} from '../../abi/aToken_v2_abi';
import {INCENTIVES_CONTROLLER_ABI} from '../../abi/incentivesController_abi';

export async function fetchTokens(
client: Client,
poolAddresses: Awaited<ReturnType<typeof fetchPoolAddresses>>,
) {
const poolContract = getContract({
address: poolAddresses.POOL.value,
abi: ILendingPool_ABI,
client,
});
const reserves = await poolContract.read.getReservesList();
const oracleContract = getContract({
address: poolAddresses.ORACLE.value,
abi: IAaveOracle_ABI,
client,
});
const reservesData: ReserveData[] = await Promise.all(
reserves.map(async (reserve) => {
const erc20Contract = getContract({address: reserve, abi: IERC20Detailed_ABI, client});
const [data, symbol, decimals, oracle] = await Promise.all([
poolContract.read.getReserveData([reserve]),
reserve === '0x9f8F72aA9304c8B593d555F12eF6589cC3A579A2'
? 'MKR'
: erc20Contract.read.symbol(),
erc20Contract.read.decimals(),
oracleContract.read.getSourceOfAsset([reserve]),
]);
return {
symbol: reserve === '0x9f8F72aA9304c8B593d555F12eF6589cC3A579A2' ? 'MKR' : symbol,
decimals: decimals,
id: data.id,
UNDERLYING: reserve,
A_TOKEN: data.aTokenAddress,
V_TOKEN: data.variableDebtTokenAddress,
INTEREST_RATE_STRATEGY: data.interestRateStrategyAddress,
ORACLE: oracle,
};
}),
);
return reservesData;
}

export async function inferAdditionalTokenInfo(
client: Client,
reservesData: Awaited<ReturnType<typeof fetchTokens>>,
) {
if (reservesData.length > 0) {
const aTokenContract = getContract({
address: reservesData[0].A_TOKEN,
abi: A_TOKEN_V2_ABI,
client,
});
const DEFAULT_INCENTIVES_CONTROLLER = await aTokenContract.read.getIncentivesController();
const COLLECTOR = await aTokenContract.read.RESERVE_TREASURY_ADDRESS();

let EMISSION_MANAGER: Address = zeroAddress;
try {
const incentivesControllerContract = getContract({
address: DEFAULT_INCENTIVES_CONTROLLER,
abi: INCENTIVES_CONTROLLER_ABI,
client,
});
EMISSION_MANAGER = await incentivesControllerContract.read.EMISSION_MANAGER();
} catch (e) {
console.log(`old version of incentives controller deployed`);
}

return {
COLLECTOR: {value: COLLECTOR, type: 'ICollector'},
DEFAULT_INCENTIVES_CONTROLLER,
EMISSION_MANAGER,
};
}
}
Loading

0 comments on commit f5bf364

Please sign in to comment.