Skip to content

Commit d6afde7

Browse files
authored
fix: tooling (#191)
* fix: tooling * fix: update deps
1 parent 80223ad commit d6afde7

File tree

7 files changed

+136
-66
lines changed

7 files changed

+136
-66
lines changed

bun.lockb

3.14 KB
Binary file not shown.

package.json

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@
2929
"@types/object-hash": "^3.0.6",
3030
"prettier": "^3.2.5",
3131
"prettier-plugin-solidity": "^1.4.1",
32-
"tsup": "^8.3.5",
32+
"tsup": "^8.3.6",
3333
"typescript": "^5.4.5",
3434
"vitest": "^2.1.5"
3535
},
@@ -57,10 +57,10 @@
5757
"access": "public"
5858
},
5959
"dependencies": {
60-
"@bgd-labs/aave-address-book": "^4.5.1",
61-
"@bgd-labs/aave-v3-governance-cache": "^1.0.8",
62-
"@bgd-labs/js-utils": "^1.4.6",
63-
"@bgd-labs/rpc-env": "^2.1.1",
60+
"@bgd-labs/aave-address-book": "^4.9.0",
61+
"@bgd-labs/aave-v3-governance-cache": "^1.0.10",
62+
"@bgd-labs/js-utils": "^1.4.7",
63+
"@bgd-labs/rpc-env": "^2.3.2",
6464
"@commander-js/extra-typings": "^12.1.0",
6565
"@inquirer/prompts": "^7.1.0",
6666
"blockstore-core": "^5.0.2",
@@ -72,7 +72,7 @@
7272
"gray-matter": "^4.0.3",
7373
"ipfs-unixfs-importer": "^15.3.1",
7474
"json-bigint": "^1.0.0",
75-
"viem": "^2.21.48",
75+
"viem": "^2.22.21",
7676
"zod": "^3.23.8"
7777
}
7878
}

src/reports/code-diff.ts

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,25 @@
11
import {existsSync} from 'fs';
22
import {execSync} from 'child_process';
3-
import {AaveV3Snapshot, AaveV3Config} from './snapshot-types';
3+
import {ChainId} from '@bgd-labs/rpc-env';
4+
5+
const CHAIN_ID_TO_ETHERSCAN = {
6+
[ChainId.mainnet]: process.env.ETHERSCAN_API_KEY_MAINNET,
7+
[ChainId.polygon]: process.env.ETHERSCAN_API_KEY_POLYGON,
8+
[ChainId.bnb]: process.env.ETHERSCAN_API_KEY_BNB,
9+
[ChainId.base]: process.env.ETHERSCAN_API_KEY_BASE,
10+
[ChainId.arbitrum]: process.env.ETHERSCAN_API_KEY_ARBITRUM,
11+
[ChainId.optimism]: process.env.ETHERSCAN_API_KEY_OPTIMISM,
12+
[ChainId.gnosis]: process.env.ETHERSCAN_API_KEY_GNOSIS,
13+
[ChainId.avalanche]: process.env.ETHERSCAN_API_KEY_AVALANCHE,
14+
[ChainId.zksync]: process.env.ETHERSCAN_API_KEY_ZKSYNC,
15+
[ChainId.scroll]: process.env.ETHERSCAN_API_KEY_SCROLL,
16+
[ChainId.linea]: process.env.ETHERSCAN_API_KEY_LINEA,
17+
};
418

519
export function downloadContract(chainId: number, address: string) {
620
const outPath = `/tmp/${chainId}_${address}`;
721
if (existsSync(outPath)) console.log('skipped download');
8-
const command = `cast source --chain ${chainId} -d ${outPath} ${address}`;
22+
const command = `cast source --chain ${chainId} -d ${outPath} ${address} --etherscan-api-key ${CHAIN_ID_TO_ETHERSCAN[chainId as keyof typeof CHAIN_ID_TO_ETHERSCAN]}`;
923
execSync(command);
1024
return outPath;
1125
}

src/reports/diff-reports.ts

Lines changed: 85 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import {renderReserve, renderReserveDiff} from './reserve';
66
import {AaveV3Reserve, type AaveV3Snapshot} from './snapshot-types';
77
import {renderStrategy, renderStrategyDiff} from './strategy';
88
import {diffCode, downloadContract} from './code-diff';
9+
import {bytes32ToAddress} from '../utils/storageSlots';
910

1011
function hasDiff(input: Record<string, any>): boolean {
1112
if (!input) return false;
@@ -23,72 +24,83 @@ export async function diffReports<A extends AaveV3Snapshot, B extends AaveV3Snap
2324
post: B,
2425
) {
2526
const chainId = pre.chainId;
27+
// if raw is present, it already is a diff, so no need to diff it
28+
let raw;
29+
if (post.raw) {
30+
raw = {...post.raw};
31+
delete post.raw;
32+
}
2633
const diffResult = diff(pre, post);
2734
const diffResultWithoutUnchanged = diff(pre, post, true);
35+
if (raw) {
36+
diffResultWithoutUnchanged.raw = raw as any;
37+
}
2838

2939
// create report
3040
let content = '';
31-
const reservesAdded = Object.keys(diffResult.reserves)
32-
.map((reserveKey) => {
33-
// to being present on reserve level % trueish means reserve was added
34-
if ((diffResult.reserves[reserveKey] as any).to) {
35-
let report = renderReserve((diffResult.reserves[reserveKey] as any).to, chainId);
36-
report += renderStrategy(post.strategies[reserveKey]);
37-
report += `| interestRate | ![ir](${getStrategyImageUrl(post.strategies[reserveKey])}) |\n`;
41+
if (diffResult.reserves) {
42+
const reservesAdded = Object.keys(diffResult.reserves)
43+
.map((reserveKey) => {
44+
// to being present on reserve level % trueish means reserve was added
45+
if ((diffResult.reserves[reserveKey] as any).to) {
46+
let report = renderReserve((diffResult.reserves[reserveKey] as any).to, chainId);
47+
report += renderStrategy(post.strategies[reserveKey]);
48+
report += `| interestRate | ![ir](${getStrategyImageUrl(post.strategies[reserveKey])}) |\n`;
3849

39-
return report;
40-
}
41-
})
42-
.filter((i) => i);
43-
const reservesRemoved = Object.keys(diffResult.reserves)
44-
.map((reserveKey) => {
45-
// from being present on reserve level % trueish means reserve was removed
46-
if ((diffResult.reserves[reserveKey] as any).from) {
47-
return renderReserve((diffResult.reserves[reserveKey] as any).from, chainId);
48-
}
49-
})
50-
.filter((i) => i);
51-
const reservesAltered = Object.keys(diffResult.reserves)
52-
.map((reserveKey) => {
53-
// "from" being present on reserses key means reserve was removed
54-
if (!(diffResult.reserves[reserveKey] as any).hasOwnProperty('from')) {
55-
const hasChangedReserveProperties = hasDiff(diffResult.reserves[reserveKey]);
56-
const preIr = getStrategyImageUrl(pre.strategies[reserveKey]);
57-
const postIr = getStrategyImageUrl(post.strategies[reserveKey]);
58-
const hasChangedIr = preIr !== postIr;
59-
if (!hasChangedReserveProperties && !hasChangedIr) return;
60-
// diff reserve
61-
let report = renderReserveDiff(diffResult.reserves[reserveKey] as any, chainId);
62-
// diff irs
63-
if (hasChangedIr) {
64-
report += renderStrategyDiff(
65-
diff(pre.strategies[reserveKey], post.strategies[reserveKey]) as any,
66-
);
67-
report += `| interestRate | ![before](${preIr}) | ![after](${postIr}) |`;
50+
return report;
6851
}
52+
})
53+
.filter((i) => i);
54+
const reservesRemoved = Object.keys(diffResult.reserves)
55+
.map((reserveKey) => {
56+
// from being present on reserve level % trueish means reserve was removed
57+
if ((diffResult.reserves[reserveKey] as any).from) {
58+
return renderReserve((diffResult.reserves[reserveKey] as any).from, chainId);
59+
}
60+
})
61+
.filter((i) => i);
62+
const reservesAltered = Object.keys(diffResult.reserves)
63+
.map((reserveKey) => {
64+
// "from" being present on reserses key means reserve was removed
65+
if (!(diffResult.reserves[reserveKey] as any).hasOwnProperty('from')) {
66+
const hasChangedReserveProperties = hasDiff(diffResult.reserves[reserveKey]);
67+
const preIr = getStrategyImageUrl(pre.strategies[reserveKey]);
68+
const postIr = getStrategyImageUrl(post.strategies[reserveKey]);
69+
const hasChangedIr = preIr !== postIr;
70+
if (!hasChangedReserveProperties && !hasChangedIr) return;
71+
// diff reserve
72+
let report = renderReserveDiff(diffResult.reserves[reserveKey] as any, chainId);
73+
// diff irs
74+
if (hasChangedIr) {
75+
report += renderStrategyDiff(
76+
diff(pre.strategies[reserveKey], post.strategies[reserveKey]) as any,
77+
);
78+
report += `| interestRate | ![before](${preIr}) | ![after](${postIr}) |`;
79+
}
6980

70-
return report;
81+
return report;
82+
}
83+
})
84+
.filter((i) => i);
85+
if (reservesAdded.length || reservesRemoved.length || reservesAltered.length) {
86+
content += '## Reserve changes\n\n';
87+
if (reservesAdded.length) {
88+
content += `### ${reservesAdded.length > 1 ? 'Reserve' : 'Reserves'} added\n\n`;
89+
content += reservesAdded.join('\n\n');
90+
content += '\n\n';
7191
}
72-
})
73-
.filter((i) => i);
74-
if (reservesAdded.length || reservesRemoved.length || reservesAltered.length) {
75-
content += '## Reserve changes\n\n';
76-
if (reservesAdded.length) {
77-
content += `### ${reservesAdded.length > 1 ? 'Reserve' : 'Reserves'} added\n\n`;
78-
content += reservesAdded.join('\n\n');
79-
content += '\n\n';
80-
}
8192

82-
if (reservesAltered.length) {
83-
content += `### ${reservesAltered.length > 1 ? 'Reserve' : 'Reserves'} altered\n\n`;
84-
content += reservesAltered.join('\n\n');
85-
content += '\n\n';
86-
}
93+
if (reservesAltered.length) {
94+
content += `### ${reservesAltered.length > 1 ? 'Reserve' : 'Reserves'} altered\n\n`;
95+
content += reservesAltered.join('\n\n');
96+
content += '\n\n';
97+
}
8798

88-
if (reservesRemoved.length) {
89-
content += `### ${reservesRemoved.length > 1 ? 'Reserve' : 'Reserves'} removed\n\n`;
90-
content += reservesRemoved.join('\n\n');
91-
content += '\n\n';
99+
if (reservesRemoved.length) {
100+
content += `### ${reservesRemoved.length > 1 ? 'Reserve' : 'Reserves'} removed\n\n`;
101+
content += reservesRemoved.join('\n\n');
102+
content += '\n\n';
103+
}
92104
}
93105
}
94106

@@ -114,6 +126,24 @@ export async function diffReports<A extends AaveV3Snapshot, B extends AaveV3Snap
114126
}
115127
}
116128

129+
if (raw) {
130+
// ERC1967 slot https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/proxy/ERC1967/ERC1967Utils.sol#L21C53-L21C119
131+
const erc1967Slot = '0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc';
132+
Object.keys(raw).map((contract) => {
133+
if (raw[contract].stateDiff[erc1967Slot]) {
134+
const fromAddress = bytes32ToAddress(raw[contract].stateDiff[erc1967Slot].previousValue);
135+
const toAddress = bytes32ToAddress(raw[contract].stateDiff[erc1967Slot].newValue);
136+
const from = downloadContract(pre.chainId, fromAddress);
137+
const to = downloadContract(pre.chainId, toAddress);
138+
const result = diffCode(from, to);
139+
writeFileSync(
140+
`./diffs/${pre.chainId}_${contract}_${fromAddress}_${toAddress}.diff`,
141+
result,
142+
);
143+
}
144+
});
145+
}
146+
117147
try {
118148
if (diffResultWithoutUnchanged.poolConfig) {
119149
for (const key of Object.keys(diffResult.poolConfig)) {

src/reports/snapshot-types.ts

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
1-
import {zkSync} from 'viem/chains';
1+
import {Address} from 'viem';
2+
import {zksync} from 'viem/chains';
23
import {z} from 'zod';
34

45
export const aaveV3ConfigSchema = z.object({
@@ -95,7 +96,7 @@ export const CHAIN_ID = {
9596
BNB: 56,
9697
GNOSIS: 100,
9798
CELO: 42220,
98-
ZKSYNC: zkSync.id,
99+
ZKSYNC: zksync.id,
99100
} as const;
100101

101102
const zodChainId = z.nativeEnum(CHAIN_ID);
@@ -108,6 +109,19 @@ export const aaveV3SnapshotSchema = z.object({
108109
eModes: z.record(aaveV3EmodeSchema),
109110
poolConfig: aaveV3ConfigSchema,
110111
chainId: zodChainId,
112+
raw: z
113+
.record(
114+
z.string(),
115+
z.object({
116+
label: z.string().nullable(),
117+
balanceDiff: z.string().nullable(),
118+
stateDiff: z.record(
119+
z.string(),
120+
z.object({previousValue: z.string(), newValue: z.string()}),
121+
),
122+
}),
123+
)
124+
.optional(),
111125
});
112126

113127
export const aDIReceiverConfigSchema = z.object({

src/utils/storageSlots.spec.ts

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import {describe, expect, it} from 'vitest';
2-
import {setBits} from './storageSlots';
2+
import {bytes32ToAddress, setBits} from './storageSlots';
33

44
describe('solidityUtils', () => {
55
it('setBits', async () => {
@@ -8,4 +8,10 @@ describe('solidityUtils', () => {
88
expect(setBits('0b111', 1n, 3n, 0n)).toBe(1n);
99
expect(setBits('0b111', 0n, 3n, 0n)).toBe(0n);
1010
});
11+
12+
it('extracts address', () => {
13+
expect(
14+
bytes32ToAddress('0x0000000000000000000000004816b2c2895f97fb918f1ae7da403750a0ee372e'),
15+
).toBe('0x4816b2C2895f97fB918f1aE7Da403750a0eE372e');
16+
});
1117
});

src/utils/storageSlots.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,11 @@ import {
33
concat,
44
encodeAbiParameters,
55
fromHex,
6+
getAddress,
67
keccak256,
78
pad,
89
parseAbiParameters,
10+
slice,
911
toBytes,
1012
toHex,
1113
trim,
@@ -133,3 +135,7 @@ export function bitMapToIndexes(bitmap: bigint) {
133135
}
134136
return reserveIndexes;
135137
}
138+
139+
export function bytes32ToAddress(bytes32: Hex) {
140+
return getAddress(slice(bytes32, 12, 32));
141+
}

0 commit comments

Comments
 (0)