Skip to content

Commit c581b33

Browse files
shiyasmohdsaihaj
andauthoredMay 20, 2024··
feat: auto fetch contract name from address (#1664)
* feat: auto fetch contract name from address * fix: lint fix * Create shaggy-ligers-carry.md --------- Co-authored-by: Saihajpreet Singh <saihajpreet.singh@gmail.com>
1 parent 8f6ee24 commit c581b33

File tree

4 files changed

+90
-7
lines changed

4 files changed

+90
-7
lines changed
 

‎.changeset/shaggy-ligers-carry.md

+5
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"@graphprotocol/graph-cli": minor
3+
---
4+
5+
auto fetch contract name from address

‎packages/cli/src/command-helpers/abi.ts

+43
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,19 @@ export const loadStartBlockForContract = async (
4444
},
4545
);
4646

47+
export const loadContractNameForAddress = async (
48+
network: string,
49+
address: string,
50+
): Promise<string> =>
51+
await withSpinner(
52+
`Fetching Contract Name`,
53+
`Failed to fetch Contract Name`,
54+
`Warnings while fetching contract name from Etherscan`,
55+
async () => {
56+
return getContractNameForAddress(network, address);
57+
},
58+
);
59+
4760
export const fetchDeployContractTransactionFromEtherscan = async (
4861
network: string,
4962
address: string,
@@ -111,6 +124,36 @@ export const fetchTransactionByHashFromRPC = async (
111124
}
112125
};
113126

127+
export const fetchSourceCodeFromEtherscan = async (
128+
network: string,
129+
address: string,
130+
): Promise<any> => {
131+
const scanApiUrl = getEtherscanLikeAPIUrl(network);
132+
const result = await fetch(
133+
`${scanApiUrl}?module=contract&action=getsourcecode&address=${address}`,
134+
);
135+
const json = await result.json();
136+
if (json.status === '1') {
137+
return json;
138+
}
139+
throw new Error('Failed to fetch contract source code');
140+
};
141+
142+
export const getContractNameForAddress = async (
143+
network: string,
144+
address: string,
145+
): Promise<string> => {
146+
try {
147+
const contractSourceCode = await fetchSourceCodeFromEtherscan(network, address);
148+
const contractName = contractSourceCode.result[0].ContractName;
149+
logger('Successfully getContractNameForAddress. contractName: %s', contractName);
150+
return contractName;
151+
} catch (error) {
152+
logger('Failed to fetch getContractNameForAddress: %O', error);
153+
throw new Error(error?.message);
154+
}
155+
};
156+
114157
export const getStartBlockForContract = async (
115158
network: string,
116159
address: string,

‎packages/cli/src/commands/add.ts

+24-1
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import { CLIError } from '@oclif/core/lib/errors';
55
import {
66
loadAbiFromBlockScout,
77
loadAbiFromEtherscan,
8+
loadContractNameForAddress,
89
loadStartBlockForContract,
910
} from '../command-helpers/abi';
1011
import * as DataSourcesExtractor from '../command-helpers/data-sources';
@@ -64,7 +65,7 @@ export default class AddCommand extends Command {
6465
args: { address, 'subgraph-manifest': manifestPath },
6566
flags: {
6667
abi,
67-
'contract-name': contractName,
68+
'contract-name': contractNameFlag,
6869
'merge-entities': mergeEntities,
6970
'network-file': networksFile,
7071
'start-block': startBlockFlag,
@@ -78,6 +79,7 @@ export default class AddCommand extends Command {
7879
const result = manifest.result.asMutable();
7980

8081
let startBlock = startBlockFlag;
82+
let contractName = contractNameFlag;
8183

8284
const entities = getEntities(manifest);
8385
const contractNames = getContractNames(manifest);
@@ -119,6 +121,27 @@ export default class AddCommand extends Command {
119121
}
120122
}
121123

124+
try {
125+
contractName = await loadContractNameForAddress(network, address);
126+
} catch (error) {
127+
// not asking user to do prompt in test environment
128+
if (process.env.NODE_ENV !== 'test') {
129+
const { contractName: userInputContractName } = await prompt.ask<{ contractName: string }>([
130+
{
131+
type: 'input',
132+
name: 'contractName',
133+
message: 'Contract Name',
134+
initial: 'Contract',
135+
validate: value => value && value.length > 0,
136+
result(value) {
137+
return value;
138+
},
139+
},
140+
]);
141+
contractName = userInputContractName;
142+
}
143+
}
144+
122145
await writeABI(ethabi, contractName);
123146

124147
const { collisionEntities, onlyCollisions, abiData } = updateEventNamesOnCollision(

‎packages/cli/src/commands/init.ts

+18-6
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import { Args, Command, Flags, ux } from '@oclif/core';
77
import {
88
loadAbiFromBlockScout,
99
loadAbiFromEtherscan,
10+
loadContractNameForAddress,
1011
loadStartBlockForContract,
1112
} from '../command-helpers/abi';
1213
import { initNetworksConfig } from '../command-helpers/network';
@@ -717,6 +718,18 @@ async function processInitForm(
717718
initStartBlock = Number(startBlock).toString();
718719
}
719720
}
721+
722+
// If contract name is not set, try to load it.
723+
if (!initContractName) {
724+
// Load contract name for this contract
725+
const contractName = await retryWithPrompt(() =>
726+
loadContractNameForAddress(network, value),
727+
);
728+
if (contractName) {
729+
initContractName = contractName;
730+
}
731+
}
732+
720733
return value;
721734
},
722735
},
@@ -813,6 +826,10 @@ async function processInitForm(
813826
initial: initContractName || 'Contract' || isSubstreams,
814827
skip: () => initFromExample !== undefined || !protocolInstance.hasContract(),
815828
validate: value => value && value.length > 0,
829+
result(value) {
830+
if (initContractName) return initContractName;
831+
return value;
832+
},
816833
},
817834
]);
818835

@@ -1314,11 +1331,6 @@ async function addAnotherContract(
13141331
this.log(`✖ ${error}`);
13151332
}
13161333

1317-
const contractName = await ux.prompt('\nContract Name', {
1318-
required: true,
1319-
default: 'Contract',
1320-
});
1321-
13221334
// Get the cwd before process.chdir in order to switch back in the end of command execution
13231335
const cwd = process.cwd();
13241336

@@ -1327,7 +1339,7 @@ async function addAnotherContract(
13271339
process.chdir(directory);
13281340
}
13291341

1330-
const commandLine = [contract, '--contract-name', contractName];
1342+
const commandLine = [contract];
13311343

13321344
await AddCommand.run(commandLine);
13331345
} catch (e) {

0 commit comments

Comments
 (0)
Please sign in to comment.