Skip to content

Commit 186ed3d

Browse files
authored
Add support for multiple addresses (#73)
1 parent fc1d2a0 commit 186ed3d

File tree

6 files changed

+100
-44
lines changed

6 files changed

+100
-44
lines changed

CONTRIBUTING.md

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ cd ..
2323
# install deps
2424
pnpm install
2525

26-
pnpm build # this builds whole vscode and can take A LOT of time
26+
pnpm build # this builds whole vscode and can take A LOT of time. If you are having issues, read below
2727
pnpm serve
2828
```
2929

@@ -35,6 +35,13 @@ pnpm serve
3535

3636
- **`pnpm build`** - Builds all packages.
3737

38+
If you are having issues with MacOS and Python try the following:
39+
```
40+
$ brew install sqlite
41+
$ npm config set sqlite /opt/homebrew/opt/sqlite
42+
$ npm config set python python3
43+
```
44+
3845
- **`pnpm watch`** - Starts webpack for `ethereum-extension` in watch mode.
3946

4047
- **`pnpm serve`** - Starts HTTP server with `vscode-host`.

packages/ethereum-viewer/src/contributedCommands.ts

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -50,11 +50,16 @@ export function registerContributedCommands(
5050

5151
const { apiName } = picked;
5252

53-
const info = await openContractSource(context, { fs, address, apiName });
53+
const contractName = await openContractSource(
54+
context,
55+
fs,
56+
apiName,
57+
address
58+
);
5459

5560
renderStatusBarItems({
5661
contractAddress: address,
57-
contractName: info.ContractName || "contract",
62+
contractName,
5863
apiName,
5964
});
6065
},

packages/ethereum-viewer/src/explorer/api-types.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ export function sourceHasSettings(
3131
return s.startsWith("{{");
3232
}
3333

34-
export function sourceHasMulitpleFiles(
34+
export function sourceHasMultipleFiles(
3535
s: SourceCode
3636
): s is SourceCode.MultipleSources {
3737
return s.startsWith("{");

packages/ethereum-viewer/src/explorer/fetchFiles.ts

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -18,12 +18,16 @@ interface FetchFilesOptions {
1818
* If more than 0, we fetch implementation contract and merge its files.
1919
*/
2020
proxyDepth?: number;
21+
/**
22+
* If true multiple files are not prefixed.
23+
*/
24+
skipPrefix?: boolean;
2125
}
2226

2327
export async function fetchFiles(
2428
apiName: ApiName,
2529
contractAddress: string,
26-
{ fetch = _fetch, proxyDepth = 3 }: FetchFilesOptions = {}
30+
{ fetch = _fetch, proxyDepth = 3, skipPrefix = false }: FetchFilesOptions = {}
2731
): Promise<FetchFilesResult> {
2832
const apiUrl = explorerApiUrls[apiName];
2933
const url =
@@ -72,15 +76,15 @@ export async function fetchFiles(
7276
files[path] = content;
7377
}
7478

75-
files = prefixFiles(files, info.ContractName);
76-
} else if (types.sourceHasMulitpleFiles(sourceCode)) {
79+
if (!skipPrefix) files = prefixFiles(files, info.ContractName);
80+
} else if (types.sourceHasMultipleFiles(sourceCode)) {
7781
const parsed = types.parseSourceCode(sourceCode);
7882

7983
for (const [path, { content }] of Object.entries(parsed)) {
8084
files[path] = content;
8185
}
8286

83-
files = prefixFiles(files, info.ContractName);
87+
if (!skipPrefix) files = prefixFiles(files, info.ContractName);
8488
} else {
8589
files[info.ContractName + fileExtension(info)] = sourceCode;
8690
}

packages/ethereum-viewer/src/extension.ts

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -49,15 +49,11 @@ async function main(context: vscode.ExtensionContext) {
4949
apiName,
5050
});
5151

52-
const info = await openContractSource(context, {
53-
fs,
54-
apiName,
55-
address,
56-
});
52+
const contractName = await openContractSource(context, fs, apiName, address);
5753

5854
renderStatusBarItems({
5955
contractAddress: address,
60-
contractName: info.ContractName || "contract",
56+
contractName,
6157
apiName,
6258
});
6359
}

packages/ethereum-viewer/src/openContractSource.ts

Lines changed: 74 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -21,19 +21,17 @@ const IS_ONLINE = true; // Treat this as a toggle for development.
2121
let fileSearchProviderDisposable: Disposable | undefined;
2222
let textSearchProviderDisposable: Disposable | undefined;
2323

24-
export interface OpenContractSourceArgs {
25-
fs: FileSystem;
26-
apiName: explorer.ApiName;
27-
address: string;
28-
}
29-
3024
export async function openContractSource(
3125
context: ExtensionContext,
32-
args: OpenContractSourceArgs
33-
) {
34-
const [entries, info] = await saveContractFilesToFs(args);
35-
36-
const mainFile = getMainContractFile(entries, info);
26+
fs: FileSystem,
27+
apiName: explorer.ApiName,
28+
address: string
29+
): Promise<string> {
30+
const { entries, mainFile, contractName } = await saveContractFilesToFs(
31+
fs,
32+
apiName,
33+
address
34+
);
3735

3836
fileSearchProviderDisposable?.dispose();
3937
fileSearchProviderDisposable = workspace.registerFileSearchProvider(
@@ -51,47 +49,93 @@ export async function openContractSource(
5149

5250
await showTextDocument(mainFile);
5351

54-
return info;
52+
return contractName;
53+
}
54+
55+
async function saveContractFilesToFs(
56+
fs: FileSystem,
57+
apiName: explorer.ApiName,
58+
address: string
59+
) {
60+
if (address.includes(",")) {
61+
const addresses = address.split(",");
62+
const results = await Promise.all(
63+
addresses.map((a) =>
64+
saveSingleContractFilesToFs(fs, apiName, a, {
65+
prefix: a + "/",
66+
allowProxies: false,
67+
includeMainInfo: true,
68+
})
69+
)
70+
);
71+
return {
72+
entries: results.flatMap((r) => r.entries),
73+
mainFile: results[0].mainFile,
74+
contractName: results[0].contractName,
75+
};
76+
}
77+
return saveSingleContractFilesToFs(fs, apiName, address, {
78+
allowProxies: true,
79+
includeMainInfo: false,
80+
});
5581
}
5682

57-
async function saveContractFilesToFs({
58-
fs,
59-
address,
60-
apiName,
61-
}: OpenContractSourceArgs) {
83+
async function saveSingleContractFilesToFs(
84+
fs: FileSystem,
85+
apiName: explorer.ApiName,
86+
address: string,
87+
options: {
88+
prefix?: string;
89+
allowProxies: boolean;
90+
includeMainInfo: boolean;
91+
}
92+
) {
6293
let result: explorer.FetchFilesResult;
6394

6495
// eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
6596
if (IS_ONLINE) {
66-
result = await explorer.fetchFiles(apiName, address);
97+
result = await explorer.fetchFiles(apiName, address, {
98+
proxyDepth: options.allowProxies ? undefined : 0,
99+
skipPrefix: !!options.prefix,
100+
});
67101
} else {
68102
result = fixtures.etherscanResult;
69103
}
70104

105+
const withPrefix = (file: string) =>
106+
options.prefix ? options.prefix + file : file;
107+
71108
const entries = Object.entries(result.files);
72109
for (const [path, content] of entries) {
73-
fs.writeFile(path, content);
110+
fs.writeFile(withPrefix(path), content);
74111
}
75112

76-
return [entries, result.info] as const;
113+
const mainFile = getMainContractFile(entries, result.info);
114+
115+
if (options.includeMainInfo) {
116+
fs.writeFile(withPrefix("main.md"), `Main file: ${mainFile}`);
117+
}
118+
119+
return {
120+
entries,
121+
mainFile: withPrefix(mainFile),
122+
contractName: result.info.ContractName ?? "contract",
123+
};
77124
}
78125

79126
function getMainContractFile(
80-
files: [string, ...unknown[]][],
127+
files: [string, string][],
81128
info: explorer.FetchFilesResult["info"]
82129
): string {
83130
const ext = fileExtension(info);
131+
const name = info.implementation?.ContractName ?? info.ContractName;
84132

85-
let fileToShow =
86-
info.implementation &&
87-
files.find(([path]) =>
88-
path.endsWith(`/${info.implementation!.ContractName}${ext}`)
89-
);
133+
let fileToShow = files.find(([path]) => path.endsWith(`/${name}${ext}`));
90134

91-
if (!fileToShow)
92-
fileToShow = files.find(([path]) =>
93-
path.endsWith(`/${info.ContractName}${ext}`)
94-
);
135+
if (!fileToShow) {
136+
const regexp = new RegExp(`contract\\s+${name}`);
137+
fileToShow = files.find(([path, source]) => regexp.test(source));
138+
}
95139

96140
if (!fileToShow) fileToShow = files.sort(byPathLength)[0];
97141

0 commit comments

Comments
 (0)