Skip to content
This repository was archived by the owner on Apr 26, 2024. It is now read-only.

Commit f5f7203

Browse files
authored
Append eth address to src if same name in discovered contracts (#110)
* Append eth address to src if same name in discovered contracts * Add tests for new source folder naming * Make single discovery save files correctly * Bump version, fix typo
1 parent 0095ece commit f5f7203

File tree

7 files changed

+257
-70
lines changed

7 files changed

+257
-70
lines changed

README.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,6 @@ We use a tool called [changesets](https://github.com/changesets/changesets) to m
55
When you make a change and you wish to publish that change to NPM you should commit all the changes and follow these steps:
66

77
- run `yarn changeset` and mark the packages you wish to publish, select what kind of a change it is (major,minor,patch) and provide the summary of the changes
8-
- now run `yarn changeset versions`, this will change the generated `.changeset/file.md` into an entry into `CHANGELOG.md` and `package.json` in changed packages
8+
- now run `yarn changeset version`, this will change the generated `.changeset/file.md` into an entry into `CHANGELOG.md` and `package.json` in changed packages
99

1010
After your PR with changed `CHANGELOG.md` and `package.json` is merged into `main`, a CI step will run which will try to publish all change changes.

packages/discovery/CHANGELOG.md

+6
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,11 @@
11
# @l2beat/discovery
22

3+
## 0.28.3
4+
5+
### Patch Changes
6+
7+
- Append address to source folders if names clash
8+
39
## 0.28.2
410

511
### Patch Changes

packages/discovery/package.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
{
22
"name": "@l2beat/discovery",
33
"description": "L2Beat discovery - engine & tooling utilized for keeping an eye on L2s",
4-
"version": "0.28.2",
4+
"version": "0.28.3",
55
"main": "dist/index.js",
66
"types": "dist/index.d.ts",
77
"bin": {

packages/discovery/src/cli/singleDiscoveryCommand.ts

+8-32
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,13 @@
11
import { Logger } from '@l2beat/backend-tools'
22
import { execSync } from 'child_process'
33
import { providers } from 'ethers'
4-
import { writeFile } from 'fs/promises'
5-
import { mkdirp } from 'mkdirp'
6-
import { dirname } from 'path'
4+
import path from 'path'
75
import { rimraf } from 'rimraf'
86

97
import { DiscoveryCliConfig } from '../config/config.discovery'
108
import { DiscoveryConfig } from '../discovery/config/DiscoveryConfig'
119
import { DiscoveryLogger } from '../discovery/DiscoveryLogger'
12-
import { getSourceName } from '../discovery/output/saveDiscoveryResult'
13-
import { toDiscoveryOutput } from '../discovery/output/toDiscoveryOutput'
10+
import { saveDiscoveryResult } from '../discovery/output/saveDiscoveryResult'
1411
import { discover as discovery } from '../discovery/runDiscovery'
1512
import { EtherscanLikeClient } from '../utils/EtherscanLikeClient'
1613
import { HttpClient } from '../utils/HttpClient'
@@ -53,34 +50,12 @@ export async function singleDiscoveryCommand(
5350
chainConfig.rpcGetLogsMaxRange,
5451
)
5552

56-
const discoveryOutput = toDiscoveryOutput(
57-
projectConfig.name,
58-
projectConfig.chainId,
59-
projectConfig.hash,
60-
blockNumber,
61-
results,
62-
)
63-
64-
const root = `./cache/single-discovery`
65-
await mkdirp(root)
53+
const rootFolder = `./cache/single-discovery`
54+
await rimraf(rootFolder)
6655

67-
const jsonFilePath = `${root}/discovered.json`
68-
await writeFile(jsonFilePath, JSON.stringify(discoveryOutput, null, 2))
69-
70-
await rimraf(`${root}/code`)
71-
for (const result of results) {
72-
if (result.type === 'EOA') {
73-
continue
74-
}
75-
for (const [i, files] of result.sources.entries()) {
76-
for (const [file, content] of Object.entries(files)) {
77-
const codebase = getSourceName(i, result.sources.length)
78-
const path = `${root}/code/${result.name}${codebase}/${file}`
79-
await mkdirp(dirname(path))
80-
await writeFile(path, content)
81-
}
82-
}
83-
}
56+
await saveDiscoveryResult(results, projectConfig, blockNumber, {
57+
rootFolder,
58+
})
8459

8560
logger.info(
8661
'Opening discovered.json in the browser, please use firefox or other browser with JSON viewer extension',
@@ -89,5 +64,6 @@ export async function singleDiscoveryCommand(
8964
'The discovered.json & code can be found in "./cache/single-discovery"',
9065
)
9166

67+
const jsonFilePath = path.join(rootFolder, 'discovered.json')
9268
execSync(`open ${jsonFilePath}`)
9369
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,171 @@
1+
import { expect } from 'earl'
2+
import { map } from 'lodash'
3+
4+
import { EthereumAddress } from '../../utils/EthereumAddress'
5+
import { UnixTime } from '../../utils/UnixTime'
6+
import { AnalyzedContract } from '../analysis/AddressAnalyzer'
7+
import { getSourceOutputPath } from './saveDiscoveryResult'
8+
9+
describe(getSourceOutputPath.name, () => {
10+
const genAnalyzedContract = (name: string): AnalyzedContract => ({
11+
type: 'Contract' as const,
12+
name,
13+
address: EthereumAddress.random(),
14+
derivedName: undefined,
15+
errors: {},
16+
values: {},
17+
isVerified: true,
18+
deploymentTimestamp: new UnixTime(1234),
19+
deploymentBlockNumber: 9876,
20+
upgradeability: { type: 'immutable' },
21+
implementations: [],
22+
abis: {},
23+
sources: [],
24+
})
25+
26+
const contractA = genAnalyzedContract('A')
27+
const contractB1 = genAnalyzedContract('B')
28+
const contractB2 = genAnalyzedContract('B')
29+
const allContracts = [contractA, contractB1, contractB2]
30+
31+
it('adds address suffix if names clash', () => {
32+
const allContractNames = map(allContracts, (c) => c.name)
33+
const root = '/.code'
34+
const pathA = getSourceOutputPath(
35+
'a.sol',
36+
0,
37+
1,
38+
contractA.name,
39+
contractA.address,
40+
root,
41+
allContractNames,
42+
)
43+
const pathB1 = getSourceOutputPath(
44+
'b.sol',
45+
0,
46+
1,
47+
contractB1.name,
48+
contractB1.address,
49+
root,
50+
allContractNames,
51+
)
52+
const pathB2 = getSourceOutputPath(
53+
'b.sol',
54+
0,
55+
1,
56+
contractB2.name,
57+
contractB2.address,
58+
root,
59+
allContractNames,
60+
)
61+
62+
expect(pathA).toEqual(`${root}/A/a.sol`)
63+
expect(pathB1).toEqual(`${root}/B-${contractB1.address.toString()}/b.sol`)
64+
expect(pathB2).toEqual(`${root}/B-${contractB2.address.toString()}/b.sol`)
65+
})
66+
67+
it('adds proxy/implementation suffixes', () => {
68+
const allContractNames = map(allContracts, (c) => c.name)
69+
const root = '/.code'
70+
const pathA_proxy = getSourceOutputPath(
71+
'a1.sol',
72+
0,
73+
2,
74+
contractA.name,
75+
contractA.address,
76+
root,
77+
allContractNames,
78+
)
79+
const pathA_impl = getSourceOutputPath(
80+
'a2.sol',
81+
1,
82+
2,
83+
contractA.name,
84+
contractA.address,
85+
root,
86+
allContractNames,
87+
)
88+
89+
expect(pathA_proxy).toEqual(`${root}/A/proxy/a1.sol`)
90+
expect(pathA_impl).toEqual(`${root}/A/implementation/a2.sol`)
91+
})
92+
93+
it('adds proxy and numbered implementation suffixes', () => {
94+
const allContractNames = map(allContracts, (c) => c.name)
95+
const sourcesCount = 3
96+
const root = '/.code'
97+
const pathA_proxy = getSourceOutputPath(
98+
'a1.sol',
99+
0,
100+
sourcesCount,
101+
contractA.name,
102+
contractA.address,
103+
root,
104+
allContractNames,
105+
)
106+
const pathA_impl1 = getSourceOutputPath(
107+
'a2.sol',
108+
1,
109+
sourcesCount,
110+
contractA.name,
111+
contractA.address,
112+
root,
113+
allContractNames,
114+
)
115+
const pathA_impl2 = getSourceOutputPath(
116+
'a3.sol',
117+
2,
118+
sourcesCount,
119+
contractA.name,
120+
contractA.address,
121+
root,
122+
allContractNames,
123+
)
124+
125+
expect(pathA_proxy).toEqual(`${root}/A/proxy/a1.sol`)
126+
expect(pathA_impl1).toEqual(`${root}/A/implementation-1/a2.sol`)
127+
expect(pathA_impl2).toEqual(`${root}/A/implementation-2/a3.sol`)
128+
})
129+
130+
it('properly handles mix of name clashes and implementations', () => {
131+
const allContractNames = map(allContracts, (c) => c.name)
132+
const sourcesCount = 3
133+
const root = '/.code'
134+
const pathB1_proxy = getSourceOutputPath(
135+
'b11.sol',
136+
0,
137+
sourcesCount,
138+
contractB1.name,
139+
contractB1.address,
140+
root,
141+
allContractNames,
142+
)
143+
const pathB1_impl1 = getSourceOutputPath(
144+
'b12.sol',
145+
1,
146+
sourcesCount,
147+
contractB1.name,
148+
contractB1.address,
149+
root,
150+
allContractNames,
151+
)
152+
const pathB1_impl2 = getSourceOutputPath(
153+
'b13.sol',
154+
2,
155+
sourcesCount,
156+
contractB1.name,
157+
contractB1.address,
158+
root,
159+
allContractNames,
160+
)
161+
expect(pathB1_proxy).toEqual(
162+
`${root}/B-${contractB1.address.toString()}/proxy/b11.sol`,
163+
)
164+
expect(pathB1_impl1).toEqual(
165+
`${root}/B-${contractB1.address.toString()}/implementation-1/b12.sol`,
166+
)
167+
expect(pathB1_impl2).toEqual(
168+
`${root}/B-${contractB1.address.toString()}/implementation-2/b13.sol`,
169+
)
170+
})
171+
})

0 commit comments

Comments
 (0)