@graphprotocol/graph-cli 0.37.3-alpha-20230112195908-6a078ea → 0.37.3-alpha-20230112205341-caa8660
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +2 -1
- package/dist/command-helpers/studio.js +6 -5
- package/dist/command-helpers/studio.test.js +0 -3
- package/dist/commands/init.js +58 -43
- package/dist/protocols/contract.js +2 -0
- package/dist/protocols/near/contract.js +1 -0
- package/dist/subgraph.js +4 -4
- package/dist/validation/index.js +5 -6
- package/package.json +1 -1
- package/src/command-helpers/abi.ts +1 -1
- package/src/command-helpers/studio.test.ts +0 -3
- package/src/command-helpers/studio.ts +13 -8
- package/src/command-helpers/subgraph.ts +3 -5
- package/src/commands/build.ts +1 -1
- package/src/commands/deploy.ts +1 -1
- package/src/commands/{init.js → init.ts} +203 -74
- package/src/protocols/contract.ts +9 -0
- package/src/protocols/ethereum/contract.ts +3 -1
- package/src/protocols/index.ts +6 -2
- package/src/protocols/near/contract.ts +4 -4
- package/src/subgraph.ts +1 -1
- package/src/validation/contract.ts +3 -2
- package/src/validation/index.ts +1 -6
package/CHANGELOG.md
CHANGED
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
# @graphprotocol/graph-cli
|
|
2
2
|
|
|
3
|
-
## 0.37.3-alpha-
|
|
3
|
+
## 0.37.3-alpha-20230112205341-caa8660
|
|
4
4
|
|
|
5
5
|
### Patch Changes
|
|
6
6
|
|
|
7
7
|
- [#1020](https://github.com/graphprotocol/graph-cli/pull/1020) [`6184688`](https://github.com/graphprotocol/graph-cli/commit/6184688d7e6efaae49a722410befd28da0af87b0) Thanks [@saihaj](https://github.com/saihaj)! - dependencies updates:
|
|
8
8
|
- Updated dependency [`immutable@4.2.1` ↗︎](https://www.npmjs.com/package/immutable/v/4.2.1) (from `3.8.2`, in `dependencies`)
|
|
9
|
+
- Removed dependency [`dockerode@2.5.8` ↗︎](https://www.npmjs.com/package/dockerode/v/2.5.8) (from `dependencies`)
|
|
9
10
|
|
|
10
11
|
## 0.37.2
|
|
11
12
|
|
|
@@ -1,13 +1,14 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.validateStudioNetwork = exports.allowedStudioNetworks = void 0;
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
const validateStudioNetwork = ({ studio, product, network }) => {
|
|
4
|
+
exports.allowedStudioNetworks = ['mainnet', 'rinkeby', 'goerli', 'gnosis'];
|
|
5
|
+
const validateStudioNetwork = ({ studio, product, network, }) => {
|
|
7
6
|
let isStudio = studio || product === 'subgraph-studio';
|
|
8
|
-
let isAllowedNetwork = allowedStudioNetworks.includes(
|
|
7
|
+
let isAllowedNetwork = exports.allowedStudioNetworks.includes(
|
|
8
|
+
// @ts-expect-error we're checking if the network is allowed
|
|
9
|
+
network);
|
|
9
10
|
if (isStudio && !isAllowedNetwork) {
|
|
10
|
-
throw new Error(`The Subgraph Studio only allows subgraphs for these networks: ${allowedStudioNetworks.join(', ')}`);
|
|
11
|
+
throw new Error(`The Subgraph Studio only allows subgraphs for these networks: ${exports.allowedStudioNetworks.join(', ')}`);
|
|
11
12
|
}
|
|
12
13
|
};
|
|
13
14
|
exports.validateStudioNetwork = validateStudioNetwork;
|
|
@@ -19,7 +19,6 @@ describe('Version Command Helpers', () => {
|
|
|
19
19
|
test("And it's NOT an allowed network", () => {
|
|
20
20
|
expect(() => (0, studio_1.validateStudioNetwork)({
|
|
21
21
|
product: 'subgraph-studio',
|
|
22
|
-
// @ts-expect-error for tests sake
|
|
23
22
|
network: 'celo',
|
|
24
23
|
})).toThrow(new Error(`The Subgraph Studio only allows subgraphs for these networks: ${studio_1.allowedStudioNetworks.join(', ')}`));
|
|
25
24
|
});
|
|
@@ -33,9 +32,7 @@ describe('Version Command Helpers', () => {
|
|
|
33
32
|
});
|
|
34
33
|
test("And it's NOT an allowed network", () => {
|
|
35
34
|
expect(() => (0, studio_1.validateStudioNetwork)({
|
|
36
|
-
// @ts-expect-error for tests sake
|
|
37
35
|
product: 'hosted-service',
|
|
38
|
-
// @ts-expect-error for tests sake
|
|
39
36
|
network: 'celo',
|
|
40
37
|
})).not.toThrow(new Error(`The Subgraph Studio only allows subgraphs for these networks: ${studio_1.allowedStudioNetworks.join(', ')}`));
|
|
41
38
|
});
|
package/dist/commands/init.js
CHANGED
|
@@ -29,9 +29,8 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
29
29
|
const chalk_1 = __importDefault(require("chalk"));
|
|
30
30
|
const os_1 = __importDefault(require("os"));
|
|
31
31
|
const path_1 = __importDefault(require("path"));
|
|
32
|
-
const toolbox = __importStar(require("gluegun/toolbox"));
|
|
33
32
|
const fs_1 = __importDefault(require("fs"));
|
|
34
|
-
const
|
|
33
|
+
const graphCli = __importStar(require("../cli"));
|
|
35
34
|
const subgraph_1 = require("../command-helpers/subgraph");
|
|
36
35
|
const DataSourcesExtractor = __importStar(require("../command-helpers/data-sources"));
|
|
37
36
|
const studio_1 = require("../command-helpers/studio");
|
|
@@ -101,7 +100,7 @@ const processInitForm = async (toolbox, { protocol, product, studio, node, abi,
|
|
|
101
100
|
message: 'Protocol',
|
|
102
101
|
choices: protocolChoices,
|
|
103
102
|
skip: protocolChoices.includes(protocol),
|
|
104
|
-
result: value => {
|
|
103
|
+
result: (value) => {
|
|
105
104
|
protocol = protocol || value;
|
|
106
105
|
protocolInstance = new protocols_1.default(protocol);
|
|
107
106
|
return protocol;
|
|
@@ -119,7 +118,7 @@ const processInitForm = async (toolbox, { protocol, product, studio, node, abi,
|
|
|
119
118
|
product === 'hosted-service' ||
|
|
120
119
|
studio !== undefined ||
|
|
121
120
|
node !== undefined,
|
|
122
|
-
result: value => {
|
|
121
|
+
result: (value) => {
|
|
123
122
|
// For now we only support NEAR subgraphs in the Hosted Service
|
|
124
123
|
if (protocol === 'near') {
|
|
125
124
|
// Can be overwritten because the question will be skipped (product === undefined)
|
|
@@ -138,7 +137,7 @@ const processInitForm = async (toolbox, { protocol, product, studio, node, abi,
|
|
|
138
137
|
name: 'subgraphName',
|
|
139
138
|
message: () => product == 'subgraph-studio' || studio ? 'Subgraph slug' : 'Subgraph name',
|
|
140
139
|
initial: subgraphName,
|
|
141
|
-
validate: name => {
|
|
140
|
+
validate: (name) => {
|
|
142
141
|
try {
|
|
143
142
|
(0, subgraph_1.validateSubgraphName)(name, { allowSimpleName });
|
|
144
143
|
return true;
|
|
@@ -152,7 +151,7 @@ const processInitForm = async (toolbox, { protocol, product, studio, node, abi,
|
|
|
152
151
|
$ graph init ${name} --allow-simple-name`;
|
|
153
152
|
}
|
|
154
153
|
},
|
|
155
|
-
result: value => {
|
|
154
|
+
result: (value) => {
|
|
156
155
|
subgraphName = value;
|
|
157
156
|
return value;
|
|
158
157
|
},
|
|
@@ -162,7 +161,7 @@ const processInitForm = async (toolbox, { protocol, product, studio, node, abi,
|
|
|
162
161
|
name: 'directory',
|
|
163
162
|
message: 'Directory to create the subgraph in',
|
|
164
163
|
initial: () => directory || (0, subgraph_1.getSubgraphBasename)(subgraphName),
|
|
165
|
-
validate: value => toolbox.filesystem.exists(value || directory || (0, subgraph_1.getSubgraphBasename)(subgraphName))
|
|
164
|
+
validate: (value) => toolbox.filesystem.exists(value || directory || (0, subgraph_1.getSubgraphBasename)(subgraphName))
|
|
166
165
|
? 'Directory already exists'
|
|
167
166
|
: true,
|
|
168
167
|
},
|
|
@@ -172,13 +171,16 @@ const processInitForm = async (toolbox, { protocol, product, studio, node, abi,
|
|
|
172
171
|
message: () => `${protocolInstance.displayName()} network`,
|
|
173
172
|
choices: () => {
|
|
174
173
|
initDebug('Generating list of available networks for protocol "%s" (%M)', protocol, availableNetworks.get(protocol));
|
|
175
|
-
return
|
|
174
|
+
return (
|
|
175
|
+
// @ts-expect-error TODO: wait what?
|
|
176
|
+
availableNetworks
|
|
176
177
|
.get(protocol) // Get networks related to the chosen protocol.
|
|
177
|
-
|
|
178
|
+
// @ts-expect-error TODO: wait what?
|
|
179
|
+
.toArray()); // Needed because of gluegun. It can't even receive a JS iterable.
|
|
178
180
|
},
|
|
179
181
|
skip: fromExample !== undefined,
|
|
180
182
|
initial: network || 'mainnet',
|
|
181
|
-
result: value => {
|
|
183
|
+
result: (value) => {
|
|
182
184
|
network = value;
|
|
183
185
|
return value;
|
|
184
186
|
},
|
|
@@ -214,7 +216,8 @@ const processInitForm = async (toolbox, { protocol, product, studio, node, abi,
|
|
|
214
216
|
if (protocolInstance.hasABIs() && !abi) {
|
|
215
217
|
try {
|
|
216
218
|
if (network === 'poa-core') {
|
|
217
|
-
|
|
219
|
+
// TODO: this variable is never used anywhere, what happens?
|
|
220
|
+
// abiFromBlockScout = await loadAbiFromBlockScout(ABI, network, value)
|
|
218
221
|
}
|
|
219
222
|
else {
|
|
220
223
|
abiFromEtherscan = await (0, abi_1.loadAbiFromEtherscan)(ABI, network, value);
|
|
@@ -238,7 +241,7 @@ const processInitForm = async (toolbox, { protocol, product, studio, node, abi,
|
|
|
238
241
|
return true;
|
|
239
242
|
}
|
|
240
243
|
try {
|
|
241
|
-
abiFromFile =
|
|
244
|
+
abiFromFile = loadAbiFromFile(toolbox, ABI, value);
|
|
242
245
|
return true;
|
|
243
246
|
}
|
|
244
247
|
catch (e) {
|
|
@@ -252,8 +255,8 @@ const processInitForm = async (toolbox, { protocol, product, studio, node, abi,
|
|
|
252
255
|
message: 'Contract Name',
|
|
253
256
|
initial: contractName || 'Contract',
|
|
254
257
|
skip: () => fromExample !== undefined || !protocolInstance.hasContract(),
|
|
255
|
-
validate: value => value && value.length > 0,
|
|
256
|
-
result: value => {
|
|
258
|
+
validate: (value) => value && value.length > 0,
|
|
259
|
+
result: (value) => {
|
|
257
260
|
contractName = value;
|
|
258
261
|
return value;
|
|
259
262
|
},
|
|
@@ -264,22 +267,28 @@ const processInitForm = async (toolbox, { protocol, product, studio, node, abi,
|
|
|
264
267
|
message: 'Index contract events as entities',
|
|
265
268
|
initial: true,
|
|
266
269
|
skip: () => !!indexEvents,
|
|
267
|
-
result: value => {
|
|
270
|
+
result: (value) => {
|
|
268
271
|
indexEvents = value;
|
|
269
272
|
return value;
|
|
270
273
|
},
|
|
271
274
|
},
|
|
272
275
|
];
|
|
273
276
|
try {
|
|
274
|
-
let answers = await toolbox.prompt.ask(
|
|
275
|
-
|
|
277
|
+
let answers = await toolbox.prompt.ask(
|
|
278
|
+
// @ts-expect-error questions do somehow fit
|
|
279
|
+
questions);
|
|
280
|
+
return {
|
|
281
|
+
...answers,
|
|
282
|
+
abi: (abiFromEtherscan || abiFromFile),
|
|
283
|
+
protocolInstance,
|
|
284
|
+
};
|
|
276
285
|
}
|
|
277
286
|
catch (e) {
|
|
278
287
|
return undefined;
|
|
279
288
|
}
|
|
280
289
|
};
|
|
281
|
-
const loadAbiFromFile =
|
|
282
|
-
let exists =
|
|
290
|
+
const loadAbiFromFile = (toolbox, ABI, filename) => {
|
|
291
|
+
let exists = toolbox.filesystem.exists(filename);
|
|
283
292
|
if (!exists) {
|
|
284
293
|
throw Error('File does not exist.');
|
|
285
294
|
}
|
|
@@ -290,14 +299,14 @@ const loadAbiFromFile = async (ABI, filename) => {
|
|
|
290
299
|
throw Error('Not sure what this path points to.');
|
|
291
300
|
}
|
|
292
301
|
else {
|
|
293
|
-
return
|
|
302
|
+
return ABI.load('Contract', filename);
|
|
294
303
|
}
|
|
295
304
|
};
|
|
296
305
|
exports.default = {
|
|
297
306
|
description: 'Creates a new subgraph with basic scaffolding',
|
|
298
307
|
run: async (toolbox) => {
|
|
299
308
|
// Obtain tools
|
|
300
|
-
|
|
309
|
+
const { print, system } = toolbox;
|
|
301
310
|
// Read CLI parameters
|
|
302
311
|
let { protocol, product, studio, node, g, abi, allowSimpleName, fromContract, contractName, fromExample, h, help, indexEvents, network, } = toolbox.parameters.options;
|
|
303
312
|
node = node || g;
|
|
@@ -334,15 +343,15 @@ exports.default = {
|
|
|
334
343
|
return;
|
|
335
344
|
}
|
|
336
345
|
// Detect git
|
|
337
|
-
let git =
|
|
346
|
+
let git = system.which('git');
|
|
338
347
|
if (git === null) {
|
|
339
348
|
print.error(`Git was not found on your system. Please install 'git' so it is in $PATH.`);
|
|
340
349
|
process.exitCode = 1;
|
|
341
350
|
return;
|
|
342
351
|
}
|
|
343
352
|
// Detect Yarn and/or NPM
|
|
344
|
-
let yarn =
|
|
345
|
-
let npm =
|
|
353
|
+
let yarn = system.which('yarn');
|
|
354
|
+
let npm = system.which('npm');
|
|
346
355
|
if (!yarn && !npm) {
|
|
347
356
|
print.error(`Neither Yarn nor NPM were found on your system. Please install one of them.`);
|
|
348
357
|
process.exitCode = 1;
|
|
@@ -371,7 +380,8 @@ exports.default = {
|
|
|
371
380
|
const ABI = protocolInstance.getABI();
|
|
372
381
|
if (abi) {
|
|
373
382
|
try {
|
|
374
|
-
|
|
383
|
+
// @ts-expect-error TODO: how does this even work when the filename is expected?
|
|
384
|
+
abi = loadAbiFromFile(ABI, abi);
|
|
375
385
|
}
|
|
376
386
|
catch (e) {
|
|
377
387
|
print.error(`Failed to load ABI: ${e.message}`);
|
|
@@ -480,12 +490,12 @@ const revalidateSubgraphName = async (toolbox, subgraphName, { allowSimpleName }
|
|
|
480
490
|
return false;
|
|
481
491
|
}
|
|
482
492
|
};
|
|
483
|
-
const initRepository = async (toolbox, directory) => await (0, spinner_1.withSpinner)(`Initialize subgraph repository`, `Failed to initialize subgraph repository`, `Warnings while initializing subgraph repository`, async (
|
|
493
|
+
const initRepository = async (toolbox, directory) => await (0, spinner_1.withSpinner)(`Initialize subgraph repository`, `Failed to initialize subgraph repository`, `Warnings while initializing subgraph repository`, async () => {
|
|
484
494
|
// Remove .git dir in --from-example mode; in --from-contract, we're
|
|
485
495
|
// starting from an empty directory
|
|
486
496
|
let gitDir = path_1.default.join(directory, '.git');
|
|
487
497
|
if (toolbox.filesystem.exists(gitDir)) {
|
|
488
|
-
|
|
498
|
+
toolbox.filesystem.remove(gitDir);
|
|
489
499
|
}
|
|
490
500
|
await toolbox.system.run('git init', { cwd: directory });
|
|
491
501
|
await toolbox.system.run('git add --all', { cwd: directory });
|
|
@@ -504,18 +514,18 @@ const npmLinkToLocalCli = async (toolbox, directory) => {
|
|
|
504
514
|
await toolbox.system.run('npm link @graphprotocol/graph-cli', { cwd: directory });
|
|
505
515
|
}
|
|
506
516
|
};
|
|
507
|
-
const installDependencies = async (toolbox, directory, installCommand) => await (0, spinner_1.withSpinner)(`Install dependencies with ${toolbox.print.colors.muted(installCommand)}`, `Failed to install dependencies`, `Warnings while installing dependencies`, async (
|
|
517
|
+
const installDependencies = async (toolbox, directory, installCommand) => await (0, spinner_1.withSpinner)(`Install dependencies with ${toolbox.print.colors.muted(installCommand)}`, `Failed to install dependencies`, `Warnings while installing dependencies`, async () => {
|
|
508
518
|
// Links to local graph-cli if we're running the automated tests
|
|
509
519
|
await npmLinkToLocalCli(toolbox, directory);
|
|
510
520
|
await toolbox.system.run(installCommand, { cwd: directory });
|
|
511
521
|
return true;
|
|
512
522
|
});
|
|
513
|
-
const runCodegen = async (toolbox, directory, codegenCommand) => await (0, spinner_1.withSpinner)(`Generate ABI and schema types with ${toolbox.print.colors.muted(codegenCommand)}`, `Failed to generate code from ABI and GraphQL schema`, `Warnings while generating code from ABI and GraphQL schema`, async (
|
|
523
|
+
const runCodegen = async (toolbox, directory, codegenCommand) => await (0, spinner_1.withSpinner)(`Generate ABI and schema types with ${toolbox.print.colors.muted(codegenCommand)}`, `Failed to generate code from ABI and GraphQL schema`, `Warnings while generating code from ABI and GraphQL schema`, async () => {
|
|
514
524
|
await toolbox.system.run(codegenCommand, { cwd: directory });
|
|
515
525
|
return true;
|
|
516
526
|
});
|
|
517
|
-
const printNextSteps = (toolbox, { subgraphName, directory }, { commands }) => {
|
|
518
|
-
|
|
527
|
+
const printNextSteps = (toolbox, { subgraphName, directory }, { commands, }) => {
|
|
528
|
+
const { print } = toolbox;
|
|
519
529
|
let relativeDir = path_1.default.relative(process.cwd(), directory);
|
|
520
530
|
// Print instructions
|
|
521
531
|
print.success(`
|
|
@@ -531,10 +541,10 @@ Subgraph ${print.colors.blue(subgraphName)} created in ${print.colors.blue(relat
|
|
|
531
541
|
|
|
532
542
|
Make sure to visit the documentation on https://thegraph.com/docs/ for further information.`);
|
|
533
543
|
};
|
|
534
|
-
const initSubgraphFromExample = async (toolbox, { fromExample, allowSimpleName, subgraphName, directory, studio, product }, { commands }) => {
|
|
544
|
+
const initSubgraphFromExample = async (toolbox, { fromExample, allowSimpleName, subgraphName, directory, studio, product, }, { commands, }) => {
|
|
535
545
|
let { filesystem, print, system } = toolbox;
|
|
536
546
|
// Fail if the subgraph name is invalid
|
|
537
|
-
if (!revalidateSubgraphName(toolbox, subgraphName, { allowSimpleName })) {
|
|
547
|
+
if (!revalidateSubgraphName(toolbox, subgraphName, { allowSimpleName: !!allowSimpleName })) {
|
|
538
548
|
process.exitCode = 1;
|
|
539
549
|
return;
|
|
540
550
|
}
|
|
@@ -545,7 +555,7 @@ const initSubgraphFromExample = async (toolbox, { fromExample, allowSimpleName,
|
|
|
545
555
|
return;
|
|
546
556
|
}
|
|
547
557
|
// Clone the example subgraph repository
|
|
548
|
-
let cloned = await (0, spinner_1.withSpinner)(`Cloning example subgraph`, `Failed to clone example subgraph`, `Warnings while cloning example subgraph`, async (
|
|
558
|
+
let cloned = await (0, spinner_1.withSpinner)(`Cloning example subgraph`, `Failed to clone example subgraph`, `Warnings while cloning example subgraph`, async () => {
|
|
549
559
|
// Create a temporary directory
|
|
550
560
|
const prefix = path_1.default.join(os_1.default.tmpdir(), 'example-subgraph-');
|
|
551
561
|
const tmpDir = fs_1.default.mkdtempSync(prefix);
|
|
@@ -555,7 +565,7 @@ const initSubgraphFromExample = async (toolbox, { fromExample, allowSimpleName,
|
|
|
555
565
|
if (fromExample === undefined || fromExample === true) {
|
|
556
566
|
fromExample = DEFAULT_EXAMPLE_SUBGRAPH;
|
|
557
567
|
}
|
|
558
|
-
const exampleSubgraphPath = path_1.default.join(tmpDir, fromExample);
|
|
568
|
+
const exampleSubgraphPath = path_1.default.join(tmpDir, String(fromExample));
|
|
559
569
|
if (!filesystem.exists(exampleSubgraphPath)) {
|
|
560
570
|
return { result: false, error: `Example not found: ${fromExample}` };
|
|
561
571
|
}
|
|
@@ -589,7 +599,7 @@ const initSubgraphFromExample = async (toolbox, { fromExample, allowSimpleName,
|
|
|
589
599
|
return;
|
|
590
600
|
}
|
|
591
601
|
// Update package.json to match the subgraph name
|
|
592
|
-
let prepared = await (0, spinner_1.withSpinner)(`Update subgraph name and commands in package.json`, `Failed to update subgraph name and commands in package.json`, `Warnings while updating subgraph name and commands in package.json`, async (
|
|
602
|
+
let prepared = await (0, spinner_1.withSpinner)(`Update subgraph name and commands in package.json`, `Failed to update subgraph name and commands in package.json`, `Warnings while updating subgraph name and commands in package.json`, async () => {
|
|
593
603
|
try {
|
|
594
604
|
// Load package.json
|
|
595
605
|
let pkgJsonFilename = filesystem.path(directory, 'package.json');
|
|
@@ -638,7 +648,7 @@ const initSubgraphFromExample = async (toolbox, { fromExample, allowSimpleName,
|
|
|
638
648
|
}
|
|
639
649
|
printNextSteps(toolbox, { subgraphName, directory }, { commands });
|
|
640
650
|
};
|
|
641
|
-
const initSubgraphFromContract = async (toolbox, { protocolInstance, allowSimpleName, subgraphName, directory, abi, network, contract, indexEvents, contractName, node, studio, product, }, { commands, addContract }) => {
|
|
651
|
+
const initSubgraphFromContract = async (toolbox, { protocolInstance, allowSimpleName, subgraphName, directory, abi, network, contract, indexEvents, contractName, node, studio, product, }, { commands, addContract, }) => {
|
|
642
652
|
let { print } = toolbox;
|
|
643
653
|
// Fail if the subgraph name is invalid
|
|
644
654
|
if (!revalidateSubgraphName(toolbox, subgraphName, { allowSimpleName })) {
|
|
@@ -651,7 +661,10 @@ const initSubgraphFromContract = async (toolbox, { protocolInstance, allowSimple
|
|
|
651
661
|
process.exitCode = 1;
|
|
652
662
|
return;
|
|
653
663
|
}
|
|
654
|
-
if (protocolInstance.hasABIs() &&
|
|
664
|
+
if (protocolInstance.hasABIs() &&
|
|
665
|
+
((0, schema_1.abiEvents)(abi).size === 0 ||
|
|
666
|
+
// @ts-expect-error TODO: the abiEvents result is expected to be a List, how's it an array?
|
|
667
|
+
(0, schema_1.abiEvents)(abi).length === 0)) {
|
|
655
668
|
// Fail if the ABI does not contain any events
|
|
656
669
|
print.error(`ABI does not contain any events`);
|
|
657
670
|
process.exitCode = 1;
|
|
@@ -721,7 +734,7 @@ const initSubgraphFromContract = async (toolbox, { protocolInstance, allowSimple
|
|
|
721
734
|
const addAnotherContract = async (toolbox, { protocolInstance, directory }) => {
|
|
722
735
|
const addContractConfirmation = await toolbox.prompt.confirm('Add another contract?');
|
|
723
736
|
if (addContractConfirmation) {
|
|
724
|
-
let abiFromFile;
|
|
737
|
+
let abiFromFile = false;
|
|
725
738
|
let ProtocolContract = protocolInstance.getContract();
|
|
726
739
|
let questions = [
|
|
727
740
|
{
|
|
@@ -739,7 +752,7 @@ const addAnotherContract = async (toolbox, { protocolInstance, directory }) => {
|
|
|
739
752
|
name: 'localAbi',
|
|
740
753
|
message: 'Provide local ABI path?',
|
|
741
754
|
choices: ['yes', 'no'],
|
|
742
|
-
result: value => {
|
|
755
|
+
result: (value) => {
|
|
743
756
|
abiFromFile = value === 'yes' ? true : false;
|
|
744
757
|
return abiFromFile;
|
|
745
758
|
},
|
|
@@ -755,13 +768,15 @@ const addAnotherContract = async (toolbox, { protocolInstance, directory }) => {
|
|
|
755
768
|
name: 'contractName',
|
|
756
769
|
message: 'Contract Name',
|
|
757
770
|
initial: 'Contract',
|
|
758
|
-
validate: value => value && value.length > 0,
|
|
771
|
+
validate: (value) => value && value.length > 0,
|
|
759
772
|
},
|
|
760
773
|
];
|
|
761
774
|
// Get the cwd before process.chdir in order to switch back in the end of command execution
|
|
762
775
|
const cwd = process.cwd();
|
|
763
776
|
try {
|
|
764
|
-
let { abi, contract, contractName } = await toolbox.prompt.ask(
|
|
777
|
+
let { abi, contract, contractName } = await toolbox.prompt.ask(
|
|
778
|
+
// @ts-expect-error questions do somehow fit
|
|
779
|
+
questions);
|
|
765
780
|
if (fs_1.default.existsSync(directory)) {
|
|
766
781
|
process.chdir(directory);
|
|
767
782
|
}
|
|
@@ -774,7 +789,7 @@ const addAnotherContract = async (toolbox, { protocolInstance, directory }) => {
|
|
|
774
789
|
commandLine.push('--abi', abi);
|
|
775
790
|
}
|
|
776
791
|
}
|
|
777
|
-
await
|
|
792
|
+
await graphCli.run(commandLine);
|
|
778
793
|
}
|
|
779
794
|
catch (e) {
|
|
780
795
|
toolbox.print.error(e);
|
package/dist/subgraph.js
CHANGED
|
@@ -32,7 +32,7 @@ const path_1 = __importDefault(require("path"));
|
|
|
32
32
|
const yaml_1 = __importDefault(require("yaml"));
|
|
33
33
|
const types_1 = require("yaml/types");
|
|
34
34
|
const graphql = __importStar(require("graphql/language"));
|
|
35
|
-
const
|
|
35
|
+
const validation = __importStar(require("./validation"));
|
|
36
36
|
const debug_1 = __importDefault(require("./debug"));
|
|
37
37
|
let subgraphDebug = (0, debug_1.default)('graph-cli:subgraph');
|
|
38
38
|
const throwCombinedError = (filename, errors) => {
|
|
@@ -72,11 +72,11 @@ class Subgraph {
|
|
|
72
72
|
return definition.name.value === 'SubgraphManifest';
|
|
73
73
|
});
|
|
74
74
|
// Validate the subgraph manifest using this schema
|
|
75
|
-
return
|
|
75
|
+
return validation.validateManifest(data, rootType, schema, protocol, { resolveFile });
|
|
76
76
|
}
|
|
77
77
|
static validateSchema(manifest, { resolveFile }) {
|
|
78
78
|
let filename = resolveFile(manifest.getIn(['schema', 'file']));
|
|
79
|
-
const validationErrors =
|
|
79
|
+
const validationErrors = validation.validateSchema(filename);
|
|
80
80
|
let errors;
|
|
81
81
|
if (validationErrors.size > 0) {
|
|
82
82
|
errors = validationErrors.groupBy(error => error.get('entity')).sort();
|
|
@@ -154,7 +154,7 @@ At least one such handler must be defined.`,
|
|
|
154
154
|
if (!protocol.hasContract()) {
|
|
155
155
|
return immutable_1.default.List();
|
|
156
156
|
}
|
|
157
|
-
return
|
|
157
|
+
return validation.validateContractValues(manifest, protocol);
|
|
158
158
|
}
|
|
159
159
|
// Validate that data source names are unique, so they don't overwrite each other.
|
|
160
160
|
static validateUniqueDataSourceNames(manifest) {
|
package/dist/validation/index.js
CHANGED
|
@@ -1,11 +1,10 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.validateContract = exports.validateContractValues = exports.validateManifest = exports.validateSchema = void 0;
|
|
3
4
|
const schema_1 = require("./schema");
|
|
5
|
+
Object.defineProperty(exports, "validateSchema", { enumerable: true, get: function () { return schema_1.validateSchema; } });
|
|
4
6
|
const manifest_1 = require("./manifest");
|
|
7
|
+
Object.defineProperty(exports, "validateManifest", { enumerable: true, get: function () { return manifest_1.validateManifest; } });
|
|
5
8
|
const contract_1 = require("./contract");
|
|
6
|
-
exports.
|
|
7
|
-
|
|
8
|
-
validateManifest: manifest_1.validateManifest,
|
|
9
|
-
validateContractValues: contract_1.validateContractValues,
|
|
10
|
-
validateContract: contract_1.validateContract,
|
|
11
|
-
};
|
|
9
|
+
Object.defineProperty(exports, "validateContractValues", { enumerable: true, get: function () { return contract_1.validateContractValues; } });
|
|
10
|
+
Object.defineProperty(exports, "validateContract", { enumerable: true, get: function () { return contract_1.validateContract; } });
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@graphprotocol/graph-cli",
|
|
3
|
-
"version": "0.37.3-alpha-
|
|
3
|
+
"version": "0.37.3-alpha-20230112205341-caa8660",
|
|
4
4
|
"license": "(Apache-2.0 OR MIT)",
|
|
5
5
|
"description": "CLI for building for and deploying to The Graph",
|
|
6
6
|
"main": "dist/cli.js",
|
|
@@ -37,7 +37,6 @@ describe('Version Command Helpers', () => {
|
|
|
37
37
|
expect(() =>
|
|
38
38
|
validateStudioNetwork({
|
|
39
39
|
product: 'subgraph-studio',
|
|
40
|
-
// @ts-expect-error for tests sake
|
|
41
40
|
network: 'celo',
|
|
42
41
|
}),
|
|
43
42
|
).toThrow(
|
|
@@ -69,9 +68,7 @@ describe('Version Command Helpers', () => {
|
|
|
69
68
|
test("And it's NOT an allowed network", () => {
|
|
70
69
|
expect(() =>
|
|
71
70
|
validateStudioNetwork({
|
|
72
|
-
// @ts-expect-error for tests sake
|
|
73
71
|
product: 'hosted-service',
|
|
74
|
-
// @ts-expect-error for tests sake
|
|
75
72
|
network: 'celo',
|
|
76
73
|
}),
|
|
77
74
|
).not.toThrow(
|
|
@@ -1,12 +1,19 @@
|
|
|
1
|
-
const allowedStudioNetworks = ['mainnet', 'rinkeby', 'goerli', 'gnosis'] as const
|
|
1
|
+
export const allowedStudioNetworks = ['mainnet', 'rinkeby', 'goerli', 'gnosis'] as const
|
|
2
2
|
|
|
3
|
-
const validateStudioNetwork = ({
|
|
4
|
-
studio
|
|
5
|
-
product
|
|
6
|
-
network
|
|
3
|
+
export const validateStudioNetwork = ({
|
|
4
|
+
studio,
|
|
5
|
+
product,
|
|
6
|
+
network,
|
|
7
|
+
}: {
|
|
8
|
+
studio?: string | boolean
|
|
9
|
+
product?: string
|
|
10
|
+
network: string
|
|
7
11
|
}) => {
|
|
8
12
|
let isStudio = studio || product === 'subgraph-studio'
|
|
9
|
-
let isAllowedNetwork = allowedStudioNetworks.includes(
|
|
13
|
+
let isAllowedNetwork = allowedStudioNetworks.includes(
|
|
14
|
+
// @ts-expect-error we're checking if the network is allowed
|
|
15
|
+
network,
|
|
16
|
+
)
|
|
10
17
|
|
|
11
18
|
if (isStudio && !isAllowedNetwork) {
|
|
12
19
|
throw new Error(
|
|
@@ -16,5 +23,3 @@ const validateStudioNetwork = ({ studio, product, network }:{
|
|
|
16
23
|
)
|
|
17
24
|
}
|
|
18
25
|
}
|
|
19
|
-
|
|
20
|
-
export { allowedStudioNetworks, validateStudioNetwork }
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
const validateSubgraphName = (
|
|
1
|
+
export const validateSubgraphName = (
|
|
2
2
|
name: string,
|
|
3
|
-
{ allowSimpleName }: { allowSimpleName
|
|
3
|
+
{ allowSimpleName }: { allowSimpleName?: boolean },
|
|
4
4
|
) => {
|
|
5
5
|
if (allowSimpleName) {
|
|
6
6
|
return name
|
|
@@ -16,9 +16,7 @@ You can bypass this check with --allow-simple-name.`)
|
|
|
16
16
|
}
|
|
17
17
|
}
|
|
18
18
|
|
|
19
|
-
const getSubgraphBasename = (name: string) => {
|
|
19
|
+
export const getSubgraphBasename = (name: string) => {
|
|
20
20
|
let segments = name.split('/', 2)
|
|
21
21
|
return segments[segments.length - 1]
|
|
22
22
|
}
|
|
23
|
-
|
|
24
|
-
export { validateSubgraphName, getSubgraphBasename }
|
package/src/commands/build.ts
CHANGED
|
@@ -118,7 +118,7 @@ export default {
|
|
|
118
118
|
}
|
|
119
119
|
|
|
120
120
|
if (network) {
|
|
121
|
-
let identifierName = protocol.getContract()
|
|
121
|
+
let identifierName = protocol.getContract()!.identifierName()
|
|
122
122
|
await updateSubgraphNetwork(toolbox, manifest, network, networkFile, identifierName)
|
|
123
123
|
}
|
|
124
124
|
|
package/src/commands/deploy.ts
CHANGED
|
@@ -252,7 +252,7 @@ export default {
|
|
|
252
252
|
}
|
|
253
253
|
|
|
254
254
|
if (network) {
|
|
255
|
-
let identifierName = protocol.getContract()
|
|
255
|
+
let identifierName = protocol.getContract()!.identifierName()
|
|
256
256
|
await updateSubgraphNetwork(toolbox, manifest, network, networkFile, identifierName)
|
|
257
257
|
}
|
|
258
258
|
|
|
@@ -1,22 +1,24 @@
|
|
|
1
1
|
import chalk from 'chalk'
|
|
2
2
|
import os from 'os'
|
|
3
3
|
import path from 'path'
|
|
4
|
-
import
|
|
4
|
+
import { GluegunToolbox } from 'gluegun'
|
|
5
5
|
import fs from 'fs'
|
|
6
|
-
import graphCli from '../cli'
|
|
6
|
+
import * as graphCli from '../cli'
|
|
7
7
|
import { getSubgraphBasename, validateSubgraphName } from '../command-helpers/subgraph'
|
|
8
8
|
import * as DataSourcesExtractor from '../command-helpers/data-sources'
|
|
9
9
|
import { validateStudioNetwork } from '../command-helpers/studio'
|
|
10
10
|
import { initNetworksConfig } from '../command-helpers/network'
|
|
11
|
-
import { withSpinner
|
|
11
|
+
import { withSpinner } from '../command-helpers/spinner'
|
|
12
12
|
import { fixParameters } from '../command-helpers/gluegun'
|
|
13
13
|
import { chooseNodeUrl } from '../command-helpers/node'
|
|
14
14
|
import { loadAbiFromEtherscan, loadAbiFromBlockScout } from '../command-helpers/abi'
|
|
15
15
|
import { generateScaffold, writeScaffold } from '../command-helpers/scaffold'
|
|
16
16
|
import { abiEvents } from '../scaffold/schema'
|
|
17
17
|
import { validateContract } from '../validation'
|
|
18
|
-
import Protocol from '../protocols'
|
|
18
|
+
import Protocol, { ProtocolName } from '../protocols'
|
|
19
19
|
import debug from '../debug'
|
|
20
|
+
import EthereumABI from '../protocols/ethereum/abi'
|
|
21
|
+
import { ContractCtor } from '../protocols/contract'
|
|
20
22
|
|
|
21
23
|
const protocolChoices = Array.from(Protocol.availableProtocols().keys())
|
|
22
24
|
const availableNetworks = Protocol.availableNetworks()
|
|
@@ -51,22 +53,22 @@ ${chalk.dim('Options for --from-contract:')}
|
|
|
51
53
|
${chalk.dim.underline('Ethereum:')}
|
|
52
54
|
|
|
53
55
|
--abi <path> Path to the contract ABI (default: download from Etherscan)
|
|
54
|
-
--network <${availableNetworks.get('ethereum')
|
|
56
|
+
--network <${availableNetworks.get('ethereum')!.join('|')}>
|
|
55
57
|
Selects the network the contract is deployed to
|
|
56
58
|
|
|
57
59
|
${chalk.dim.underline('NEAR:')}
|
|
58
60
|
|
|
59
|
-
--network <${availableNetworks.get('near')
|
|
61
|
+
--network <${availableNetworks.get('near')!.join('|')}>
|
|
60
62
|
Selects the network the contract is deployed to
|
|
61
63
|
|
|
62
64
|
${chalk.dim.underline('Cosmos:')}
|
|
63
65
|
|
|
64
|
-
--network <${availableNetworks.get('cosmos')
|
|
66
|
+
--network <${availableNetworks.get('cosmos')!.join('|')}>
|
|
65
67
|
Selects the network the contract is deployed to
|
|
66
68
|
`
|
|
67
69
|
|
|
68
70
|
const processInitForm = async (
|
|
69
|
-
toolbox,
|
|
71
|
+
toolbox: GluegunToolbox,
|
|
70
72
|
{
|
|
71
73
|
protocol,
|
|
72
74
|
product,
|
|
@@ -81,13 +83,41 @@ const processInitForm = async (
|
|
|
81
83
|
network,
|
|
82
84
|
subgraphName,
|
|
83
85
|
contractName,
|
|
86
|
+
}: {
|
|
87
|
+
protocol: ProtocolName
|
|
88
|
+
product: string
|
|
89
|
+
studio: string
|
|
90
|
+
node: string
|
|
91
|
+
abi: EthereumABI
|
|
92
|
+
allowSimpleName: boolean
|
|
93
|
+
directory: string
|
|
94
|
+
contract: string
|
|
95
|
+
indexEvents: boolean
|
|
96
|
+
fromExample: string | boolean
|
|
97
|
+
network: string
|
|
98
|
+
subgraphName: string
|
|
99
|
+
contractName: string
|
|
84
100
|
},
|
|
85
|
-
)
|
|
86
|
-
|
|
101
|
+
): Promise<
|
|
102
|
+
| {
|
|
103
|
+
abi: EthereumABI
|
|
104
|
+
protocolInstance: Protocol
|
|
105
|
+
subgraphName: string
|
|
106
|
+
directory: string
|
|
107
|
+
studio: string
|
|
108
|
+
product: string
|
|
109
|
+
network: string
|
|
110
|
+
contract: string
|
|
111
|
+
indexEvents: boolean
|
|
112
|
+
contractName: string
|
|
113
|
+
}
|
|
114
|
+
| undefined
|
|
115
|
+
> => {
|
|
116
|
+
let abiFromEtherscan: EthereumABI | undefined = undefined
|
|
87
117
|
let abiFromFile = undefined
|
|
88
|
-
let protocolInstance
|
|
89
|
-
let ProtocolContract
|
|
90
|
-
let ABI
|
|
118
|
+
let protocolInstance!: Protocol
|
|
119
|
+
let ProtocolContract: ContractCtor
|
|
120
|
+
let ABI: typeof EthereumABI
|
|
91
121
|
|
|
92
122
|
let questions = [
|
|
93
123
|
{
|
|
@@ -96,7 +126,7 @@ const processInitForm = async (
|
|
|
96
126
|
message: 'Protocol',
|
|
97
127
|
choices: protocolChoices,
|
|
98
128
|
skip: protocolChoices.includes(protocol),
|
|
99
|
-
result: value => {
|
|
129
|
+
result: (value: string) => {
|
|
100
130
|
protocol = protocol || value
|
|
101
131
|
protocolInstance = new Protocol(protocol)
|
|
102
132
|
return protocol
|
|
@@ -115,7 +145,7 @@ const processInitForm = async (
|
|
|
115
145
|
product === 'hosted-service' ||
|
|
116
146
|
studio !== undefined ||
|
|
117
147
|
node !== undefined,
|
|
118
|
-
result: value => {
|
|
148
|
+
result: (value: string | undefined) => {
|
|
119
149
|
// For now we only support NEAR subgraphs in the Hosted Service
|
|
120
150
|
if (protocol === 'near') {
|
|
121
151
|
// Can be overwritten because the question will be skipped (product === undefined)
|
|
@@ -127,7 +157,7 @@ const processInitForm = async (
|
|
|
127
157
|
allowSimpleName = true
|
|
128
158
|
}
|
|
129
159
|
|
|
130
|
-
product = value
|
|
160
|
+
product = value as any
|
|
131
161
|
return value
|
|
132
162
|
},
|
|
133
163
|
},
|
|
@@ -137,7 +167,7 @@ const processInitForm = async (
|
|
|
137
167
|
message: () =>
|
|
138
168
|
product == 'subgraph-studio' || studio ? 'Subgraph slug' : 'Subgraph name',
|
|
139
169
|
initial: subgraphName,
|
|
140
|
-
validate: name => {
|
|
170
|
+
validate: (name: string) => {
|
|
141
171
|
try {
|
|
142
172
|
validateSubgraphName(name, { allowSimpleName })
|
|
143
173
|
return true
|
|
@@ -150,7 +180,7 @@ const processInitForm = async (
|
|
|
150
180
|
$ graph init ${name} --allow-simple-name`
|
|
151
181
|
}
|
|
152
182
|
},
|
|
153
|
-
result: value => {
|
|
183
|
+
result: (value: string) => {
|
|
154
184
|
subgraphName = value
|
|
155
185
|
return value
|
|
156
186
|
},
|
|
@@ -160,7 +190,7 @@ const processInitForm = async (
|
|
|
160
190
|
name: 'directory',
|
|
161
191
|
message: 'Directory to create the subgraph in',
|
|
162
192
|
initial: () => directory || getSubgraphBasename(subgraphName),
|
|
163
|
-
validate: value =>
|
|
193
|
+
validate: (value: string) =>
|
|
164
194
|
toolbox.filesystem.exists(value || directory || getSubgraphBasename(subgraphName))
|
|
165
195
|
? 'Directory already exists'
|
|
166
196
|
: true,
|
|
@@ -173,16 +203,20 @@ const processInitForm = async (
|
|
|
173
203
|
initDebug(
|
|
174
204
|
'Generating list of available networks for protocol "%s" (%M)',
|
|
175
205
|
protocol,
|
|
176
|
-
availableNetworks.get(protocol),
|
|
206
|
+
availableNetworks.get(protocol as any),
|
|
177
207
|
)
|
|
178
|
-
return
|
|
179
|
-
|
|
180
|
-
|
|
208
|
+
return (
|
|
209
|
+
// @ts-expect-error TODO: wait what?
|
|
210
|
+
availableNetworks
|
|
211
|
+
.get(protocol) // Get networks related to the chosen protocol.
|
|
212
|
+
// @ts-expect-error TODO: wait what?
|
|
213
|
+
.toArray()
|
|
214
|
+
) // Needed because of gluegun. It can't even receive a JS iterable.
|
|
181
215
|
},
|
|
182
216
|
|
|
183
217
|
skip: fromExample !== undefined,
|
|
184
218
|
initial: network || 'mainnet',
|
|
185
|
-
result: value => {
|
|
219
|
+
result: (value: string) => {
|
|
186
220
|
network = value
|
|
187
221
|
return value
|
|
188
222
|
},
|
|
@@ -196,12 +230,12 @@ const processInitForm = async (
|
|
|
196
230
|
type: 'input',
|
|
197
231
|
name: 'contract',
|
|
198
232
|
message: () => {
|
|
199
|
-
ProtocolContract = protocolInstance.getContract()
|
|
233
|
+
ProtocolContract = protocolInstance.getContract()!
|
|
200
234
|
return `Contract ${ProtocolContract.identifierName()}`
|
|
201
235
|
},
|
|
202
236
|
skip: () => fromExample !== undefined || !protocolInstance.hasContract(),
|
|
203
237
|
initial: contract,
|
|
204
|
-
validate: async value => {
|
|
238
|
+
validate: async (value: string) => {
|
|
205
239
|
if (fromExample !== undefined || !protocolInstance.hasContract()) {
|
|
206
240
|
return true
|
|
207
241
|
}
|
|
@@ -211,7 +245,7 @@ const processInitForm = async (
|
|
|
211
245
|
|
|
212
246
|
return valid ? true : error
|
|
213
247
|
},
|
|
214
|
-
result: async value => {
|
|
248
|
+
result: async (value: string) => {
|
|
215
249
|
if (fromExample !== undefined) {
|
|
216
250
|
return value
|
|
217
251
|
}
|
|
@@ -222,9 +256,10 @@ const processInitForm = async (
|
|
|
222
256
|
if (protocolInstance.hasABIs() && !abi) {
|
|
223
257
|
try {
|
|
224
258
|
if (network === 'poa-core') {
|
|
225
|
-
|
|
259
|
+
// TODO: this variable is never used anywhere, what happens?
|
|
260
|
+
// abiFromBlockScout = await loadAbiFromBlockScout(ABI, network, value)
|
|
226
261
|
} else {
|
|
227
|
-
abiFromEtherscan = await loadAbiFromEtherscan(ABI, network
|
|
262
|
+
abiFromEtherscan = await loadAbiFromEtherscan(ABI, network!, value)
|
|
228
263
|
}
|
|
229
264
|
} catch (e) {}
|
|
230
265
|
}
|
|
@@ -240,13 +275,13 @@ const processInitForm = async (
|
|
|
240
275
|
!protocolInstance.hasABIs() ||
|
|
241
276
|
fromExample !== undefined ||
|
|
242
277
|
abiFromEtherscan !== undefined,
|
|
243
|
-
validate: async value => {
|
|
278
|
+
validate: async (value: string) => {
|
|
244
279
|
if (fromExample || abiFromEtherscan || !protocolInstance.hasABIs()) {
|
|
245
280
|
return true
|
|
246
281
|
}
|
|
247
282
|
|
|
248
283
|
try {
|
|
249
|
-
abiFromFile =
|
|
284
|
+
abiFromFile = loadAbiFromFile(toolbox, ABI, value)
|
|
250
285
|
return true
|
|
251
286
|
} catch (e) {
|
|
252
287
|
return e.message
|
|
@@ -259,8 +294,8 @@ const processInitForm = async (
|
|
|
259
294
|
message: 'Contract Name',
|
|
260
295
|
initial: contractName || 'Contract',
|
|
261
296
|
skip: () => fromExample !== undefined || !protocolInstance.hasContract(),
|
|
262
|
-
validate: value => value && value.length > 0,
|
|
263
|
-
result: value => {
|
|
297
|
+
validate: (value: string) => value && value.length > 0,
|
|
298
|
+
result: (value: string) => {
|
|
264
299
|
contractName = value
|
|
265
300
|
return value
|
|
266
301
|
},
|
|
@@ -271,7 +306,7 @@ const processInitForm = async (
|
|
|
271
306
|
message: 'Index contract events as entities',
|
|
272
307
|
initial: true,
|
|
273
308
|
skip: () => !!indexEvents,
|
|
274
|
-
result: value => {
|
|
309
|
+
result: (value: boolean) => {
|
|
275
310
|
indexEvents = value
|
|
276
311
|
return value
|
|
277
312
|
},
|
|
@@ -279,15 +314,26 @@ const processInitForm = async (
|
|
|
279
314
|
]
|
|
280
315
|
|
|
281
316
|
try {
|
|
282
|
-
let answers = await toolbox.prompt.ask(
|
|
283
|
-
|
|
317
|
+
let answers = await toolbox.prompt.ask(
|
|
318
|
+
// @ts-expect-error questions do somehow fit
|
|
319
|
+
questions,
|
|
320
|
+
)
|
|
321
|
+
return {
|
|
322
|
+
...(answers as any), // necessary answers are here
|
|
323
|
+
abi: (abiFromEtherscan || abiFromFile)!,
|
|
324
|
+
protocolInstance,
|
|
325
|
+
}
|
|
284
326
|
} catch (e) {
|
|
285
327
|
return undefined
|
|
286
328
|
}
|
|
287
329
|
}
|
|
288
330
|
|
|
289
|
-
const loadAbiFromFile =
|
|
290
|
-
|
|
331
|
+
const loadAbiFromFile = (
|
|
332
|
+
toolbox: GluegunToolbox,
|
|
333
|
+
ABI: typeof EthereumABI,
|
|
334
|
+
filename: string,
|
|
335
|
+
) => {
|
|
336
|
+
let exists = toolbox.filesystem.exists(filename)
|
|
291
337
|
|
|
292
338
|
if (!exists) {
|
|
293
339
|
throw Error('File does not exist.')
|
|
@@ -296,15 +342,15 @@ const loadAbiFromFile = async (ABI, filename) => {
|
|
|
296
342
|
} else if (exists === 'other') {
|
|
297
343
|
throw Error('Not sure what this path points to.')
|
|
298
344
|
} else {
|
|
299
|
-
return
|
|
345
|
+
return ABI.load('Contract', filename)
|
|
300
346
|
}
|
|
301
347
|
}
|
|
302
348
|
|
|
303
349
|
export default {
|
|
304
350
|
description: 'Creates a new subgraph with basic scaffolding',
|
|
305
|
-
run: async toolbox => {
|
|
351
|
+
run: async (toolbox: GluegunToolbox) => {
|
|
306
352
|
// Obtain tools
|
|
307
|
-
|
|
353
|
+
const { print, system } = toolbox
|
|
308
354
|
|
|
309
355
|
// Read CLI parameters
|
|
310
356
|
let {
|
|
@@ -360,7 +406,7 @@ export default {
|
|
|
360
406
|
}
|
|
361
407
|
|
|
362
408
|
// Detect git
|
|
363
|
-
let git =
|
|
409
|
+
let git = system.which('git')
|
|
364
410
|
if (git === null) {
|
|
365
411
|
print.error(
|
|
366
412
|
`Git was not found on your system. Please install 'git' so it is in $PATH.`,
|
|
@@ -370,8 +416,8 @@ export default {
|
|
|
370
416
|
}
|
|
371
417
|
|
|
372
418
|
// Detect Yarn and/or NPM
|
|
373
|
-
let yarn =
|
|
374
|
-
let npm =
|
|
419
|
+
let yarn = system.which('yarn')
|
|
420
|
+
let npm = system.which('npm')
|
|
375
421
|
if (!yarn && !npm) {
|
|
376
422
|
print.error(
|
|
377
423
|
`Neither Yarn nor NPM were found on your system. Please install one of them.`,
|
|
@@ -415,7 +461,8 @@ export default {
|
|
|
415
461
|
const ABI = protocolInstance.getABI()
|
|
416
462
|
if (abi) {
|
|
417
463
|
try {
|
|
418
|
-
|
|
464
|
+
// @ts-expect-error TODO: how does this even work when the filename is expected?
|
|
465
|
+
abi = loadAbiFromFile(ABI, abi)
|
|
419
466
|
} catch (e) {
|
|
420
467
|
print.error(`Failed to load ABI: ${e.message}`)
|
|
421
468
|
process.exitCode = 1
|
|
@@ -520,7 +567,11 @@ export default {
|
|
|
520
567
|
},
|
|
521
568
|
}
|
|
522
569
|
|
|
523
|
-
const revalidateSubgraphName = async (
|
|
570
|
+
const revalidateSubgraphName = async (
|
|
571
|
+
toolbox: GluegunToolbox,
|
|
572
|
+
subgraphName: string,
|
|
573
|
+
{ allowSimpleName }: { allowSimpleName: boolean },
|
|
574
|
+
) => {
|
|
524
575
|
// Fail if the subgraph name is invalid
|
|
525
576
|
try {
|
|
526
577
|
validateSubgraphName(subgraphName, { allowSimpleName })
|
|
@@ -536,17 +587,17 @@ const revalidateSubgraphName = async (toolbox, subgraphName, { allowSimpleName }
|
|
|
536
587
|
}
|
|
537
588
|
}
|
|
538
589
|
|
|
539
|
-
const initRepository = async (toolbox, directory) =>
|
|
590
|
+
const initRepository = async (toolbox: GluegunToolbox, directory: string) =>
|
|
540
591
|
await withSpinner(
|
|
541
592
|
`Initialize subgraph repository`,
|
|
542
593
|
`Failed to initialize subgraph repository`,
|
|
543
594
|
`Warnings while initializing subgraph repository`,
|
|
544
|
-
async
|
|
595
|
+
async () => {
|
|
545
596
|
// Remove .git dir in --from-example mode; in --from-contract, we're
|
|
546
597
|
// starting from an empty directory
|
|
547
598
|
let gitDir = path.join(directory, '.git')
|
|
548
599
|
if (toolbox.filesystem.exists(gitDir)) {
|
|
549
|
-
|
|
600
|
+
toolbox.filesystem.remove(gitDir)
|
|
550
601
|
}
|
|
551
602
|
await toolbox.system.run('git init', { cwd: directory })
|
|
552
603
|
await toolbox.system.run('git add --all', { cwd: directory })
|
|
@@ -562,18 +613,22 @@ const initRepository = async (toolbox, directory) =>
|
|
|
562
613
|
// This requires that the command `npm link` is called
|
|
563
614
|
// on the root directory of this repository, as described here:
|
|
564
615
|
// https://docs.npmjs.com/cli/v7/commands/npm-link.
|
|
565
|
-
const npmLinkToLocalCli = async (toolbox, directory) => {
|
|
616
|
+
const npmLinkToLocalCli = async (toolbox: GluegunToolbox, directory: string) => {
|
|
566
617
|
if (process.env.GRAPH_CLI_TESTS) {
|
|
567
618
|
await toolbox.system.run('npm link @graphprotocol/graph-cli', { cwd: directory })
|
|
568
619
|
}
|
|
569
620
|
}
|
|
570
621
|
|
|
571
|
-
const installDependencies = async (
|
|
622
|
+
const installDependencies = async (
|
|
623
|
+
toolbox: GluegunToolbox,
|
|
624
|
+
directory: string,
|
|
625
|
+
installCommand: string,
|
|
626
|
+
) =>
|
|
572
627
|
await withSpinner(
|
|
573
628
|
`Install dependencies with ${toolbox.print.colors.muted(installCommand)}`,
|
|
574
629
|
`Failed to install dependencies`,
|
|
575
630
|
`Warnings while installing dependencies`,
|
|
576
|
-
async
|
|
631
|
+
async () => {
|
|
577
632
|
// Links to local graph-cli if we're running the automated tests
|
|
578
633
|
await npmLinkToLocalCli(toolbox, directory)
|
|
579
634
|
|
|
@@ -582,19 +637,35 @@ const installDependencies = async (toolbox, directory, installCommand) =>
|
|
|
582
637
|
},
|
|
583
638
|
)
|
|
584
639
|
|
|
585
|
-
const runCodegen = async (
|
|
640
|
+
const runCodegen = async (
|
|
641
|
+
toolbox: GluegunToolbox,
|
|
642
|
+
directory: string,
|
|
643
|
+
codegenCommand: string,
|
|
644
|
+
) =>
|
|
586
645
|
await withSpinner(
|
|
587
646
|
`Generate ABI and schema types with ${toolbox.print.colors.muted(codegenCommand)}`,
|
|
588
647
|
`Failed to generate code from ABI and GraphQL schema`,
|
|
589
648
|
`Warnings while generating code from ABI and GraphQL schema`,
|
|
590
|
-
async
|
|
649
|
+
async () => {
|
|
591
650
|
await toolbox.system.run(codegenCommand, { cwd: directory })
|
|
592
651
|
return true
|
|
593
652
|
},
|
|
594
653
|
)
|
|
595
654
|
|
|
596
|
-
const printNextSteps = (
|
|
597
|
-
|
|
655
|
+
const printNextSteps = (
|
|
656
|
+
toolbox: GluegunToolbox,
|
|
657
|
+
{ subgraphName, directory }: { subgraphName: string; directory: string },
|
|
658
|
+
{
|
|
659
|
+
commands,
|
|
660
|
+
}: {
|
|
661
|
+
commands: {
|
|
662
|
+
install: string
|
|
663
|
+
codegen: string
|
|
664
|
+
deploy: string
|
|
665
|
+
}
|
|
666
|
+
},
|
|
667
|
+
) => {
|
|
668
|
+
const { print } = toolbox
|
|
598
669
|
|
|
599
670
|
let relativeDir = path.relative(process.cwd(), directory)
|
|
600
671
|
|
|
@@ -616,14 +687,38 @@ Make sure to visit the documentation on https://thegraph.com/docs/ for further i
|
|
|
616
687
|
}
|
|
617
688
|
|
|
618
689
|
const initSubgraphFromExample = async (
|
|
619
|
-
toolbox,
|
|
620
|
-
{
|
|
621
|
-
|
|
690
|
+
toolbox: GluegunToolbox,
|
|
691
|
+
{
|
|
692
|
+
fromExample,
|
|
693
|
+
allowSimpleName,
|
|
694
|
+
subgraphName,
|
|
695
|
+
directory,
|
|
696
|
+
studio,
|
|
697
|
+
product,
|
|
698
|
+
}: {
|
|
699
|
+
fromExample: string | boolean
|
|
700
|
+
allowSimpleName?: boolean
|
|
701
|
+
subgraphName: string
|
|
702
|
+
directory: string
|
|
703
|
+
studio: string
|
|
704
|
+
product: string
|
|
705
|
+
},
|
|
706
|
+
{
|
|
707
|
+
commands,
|
|
708
|
+
}: {
|
|
709
|
+
commands: {
|
|
710
|
+
install: string
|
|
711
|
+
codegen: string
|
|
712
|
+
deploy: string
|
|
713
|
+
}
|
|
714
|
+
},
|
|
622
715
|
) => {
|
|
623
716
|
let { filesystem, print, system } = toolbox
|
|
624
717
|
|
|
625
718
|
// Fail if the subgraph name is invalid
|
|
626
|
-
if (
|
|
719
|
+
if (
|
|
720
|
+
!revalidateSubgraphName(toolbox, subgraphName, { allowSimpleName: !!allowSimpleName })
|
|
721
|
+
) {
|
|
627
722
|
process.exitCode = 1
|
|
628
723
|
return
|
|
629
724
|
}
|
|
@@ -640,7 +735,7 @@ const initSubgraphFromExample = async (
|
|
|
640
735
|
`Cloning example subgraph`,
|
|
641
736
|
`Failed to clone example subgraph`,
|
|
642
737
|
`Warnings while cloning example subgraph`,
|
|
643
|
-
async
|
|
738
|
+
async () => {
|
|
644
739
|
// Create a temporary directory
|
|
645
740
|
const prefix = path.join(os.tmpdir(), 'example-subgraph-')
|
|
646
741
|
const tmpDir = fs.mkdtempSync(prefix)
|
|
@@ -655,7 +750,7 @@ const initSubgraphFromExample = async (
|
|
|
655
750
|
fromExample = DEFAULT_EXAMPLE_SUBGRAPH
|
|
656
751
|
}
|
|
657
752
|
|
|
658
|
-
const exampleSubgraphPath = path.join(tmpDir, fromExample)
|
|
753
|
+
const exampleSubgraphPath = path.join(tmpDir, String(fromExample))
|
|
659
754
|
|
|
660
755
|
if (!filesystem.exists(exampleSubgraphPath)) {
|
|
661
756
|
return { result: false, error: `Example not found: ${fromExample}` }
|
|
@@ -700,7 +795,7 @@ const initSubgraphFromExample = async (
|
|
|
700
795
|
`Update subgraph name and commands in package.json`,
|
|
701
796
|
`Failed to update subgraph name and commands in package.json`,
|
|
702
797
|
`Warnings while updating subgraph name and commands in package.json`,
|
|
703
|
-
async
|
|
798
|
+
async () => {
|
|
704
799
|
try {
|
|
705
800
|
// Load package.json
|
|
706
801
|
let pkgJsonFilename = filesystem.path(directory, 'package.json')
|
|
@@ -758,7 +853,7 @@ const initSubgraphFromExample = async (
|
|
|
758
853
|
}
|
|
759
854
|
|
|
760
855
|
const initSubgraphFromContract = async (
|
|
761
|
-
toolbox,
|
|
856
|
+
toolbox: GluegunToolbox,
|
|
762
857
|
{
|
|
763
858
|
protocolInstance,
|
|
764
859
|
allowSimpleName,
|
|
@@ -772,8 +867,31 @@ const initSubgraphFromContract = async (
|
|
|
772
867
|
node,
|
|
773
868
|
studio,
|
|
774
869
|
product,
|
|
870
|
+
}: {
|
|
871
|
+
protocolInstance: Protocol
|
|
872
|
+
allowSimpleName: boolean
|
|
873
|
+
subgraphName: string
|
|
874
|
+
directory: string
|
|
875
|
+
abi: EthereumABI
|
|
876
|
+
network: string
|
|
877
|
+
contract: string
|
|
878
|
+
indexEvents: boolean
|
|
879
|
+
contractName: string
|
|
880
|
+
node: string
|
|
881
|
+
studio: string
|
|
882
|
+
product: string
|
|
883
|
+
},
|
|
884
|
+
{
|
|
885
|
+
commands,
|
|
886
|
+
addContract,
|
|
887
|
+
}: {
|
|
888
|
+
commands: {
|
|
889
|
+
install: string
|
|
890
|
+
codegen: string
|
|
891
|
+
deploy: string
|
|
892
|
+
}
|
|
893
|
+
addContract: boolean
|
|
775
894
|
},
|
|
776
|
-
{ commands, addContract },
|
|
777
895
|
) => {
|
|
778
896
|
let { print } = toolbox
|
|
779
897
|
|
|
@@ -790,7 +908,12 @@ const initSubgraphFromContract = async (
|
|
|
790
908
|
return
|
|
791
909
|
}
|
|
792
910
|
|
|
793
|
-
if (
|
|
911
|
+
if (
|
|
912
|
+
protocolInstance.hasABIs() &&
|
|
913
|
+
(abiEvents(abi).size === 0 ||
|
|
914
|
+
// @ts-expect-error TODO: the abiEvents result is expected to be a List, how's it an array?
|
|
915
|
+
abiEvents(abi).length === 0)
|
|
916
|
+
) {
|
|
794
917
|
// Fail if the ABI does not contain any events
|
|
795
918
|
print.error(`ABI does not contain any events`)
|
|
796
919
|
process.exitCode = 1
|
|
@@ -837,7 +960,7 @@ const initSubgraphFromContract = async (
|
|
|
837
960
|
}
|
|
838
961
|
|
|
839
962
|
if (protocolInstance.hasContract()) {
|
|
840
|
-
let identifierName = protocolInstance.getContract()
|
|
963
|
+
let identifierName = protocolInstance.getContract()!.identifierName()
|
|
841
964
|
let networkConf = await initNetworksConfig(toolbox, directory, identifierName)
|
|
842
965
|
if (networkConf !== true) {
|
|
843
966
|
process.exitCode = 1
|
|
@@ -873,19 +996,22 @@ const initSubgraphFromContract = async (
|
|
|
873
996
|
printNextSteps(toolbox, { subgraphName, directory }, { commands })
|
|
874
997
|
}
|
|
875
998
|
|
|
876
|
-
const addAnotherContract = async (
|
|
999
|
+
const addAnotherContract = async (
|
|
1000
|
+
toolbox: GluegunToolbox,
|
|
1001
|
+
{ protocolInstance, directory }: { protocolInstance: Protocol; directory: string },
|
|
1002
|
+
) => {
|
|
877
1003
|
const addContractConfirmation = await toolbox.prompt.confirm('Add another contract?')
|
|
878
1004
|
|
|
879
1005
|
if (addContractConfirmation) {
|
|
880
|
-
let abiFromFile
|
|
881
|
-
let ProtocolContract = protocolInstance.getContract()
|
|
1006
|
+
let abiFromFile: boolean = false
|
|
1007
|
+
let ProtocolContract = protocolInstance.getContract()!
|
|
882
1008
|
|
|
883
1009
|
let questions = [
|
|
884
1010
|
{
|
|
885
1011
|
type: 'input',
|
|
886
1012
|
name: 'contract',
|
|
887
1013
|
message: () => `Contract ${ProtocolContract.identifierName()}`,
|
|
888
|
-
validate: async value => {
|
|
1014
|
+
validate: async (value: string) => {
|
|
889
1015
|
// Validate whether the contract is valid
|
|
890
1016
|
const { valid, error } = validateContract(value, ProtocolContract)
|
|
891
1017
|
return valid ? true : error
|
|
@@ -896,7 +1022,7 @@ const addAnotherContract = async (toolbox, { protocolInstance, directory }) => {
|
|
|
896
1022
|
name: 'localAbi',
|
|
897
1023
|
message: 'Provide local ABI path?',
|
|
898
1024
|
choices: ['yes', 'no'],
|
|
899
|
-
result: value => {
|
|
1025
|
+
result: (value: string) => {
|
|
900
1026
|
abiFromFile = value === 'yes' ? true : false
|
|
901
1027
|
return abiFromFile
|
|
902
1028
|
},
|
|
@@ -912,7 +1038,7 @@ const addAnotherContract = async (toolbox, { protocolInstance, directory }) => {
|
|
|
912
1038
|
name: 'contractName',
|
|
913
1039
|
message: 'Contract Name',
|
|
914
1040
|
initial: 'Contract',
|
|
915
|
-
validate: value => value && value.length > 0,
|
|
1041
|
+
validate: (value: string) => value && value.length > 0,
|
|
916
1042
|
},
|
|
917
1043
|
]
|
|
918
1044
|
|
|
@@ -920,7 +1046,10 @@ const addAnotherContract = async (toolbox, { protocolInstance, directory }) => {
|
|
|
920
1046
|
const cwd = process.cwd()
|
|
921
1047
|
|
|
922
1048
|
try {
|
|
923
|
-
let { abi, contract, contractName } = await toolbox.prompt.ask(
|
|
1049
|
+
let { abi, contract, contractName } = await toolbox.prompt.ask(
|
|
1050
|
+
// @ts-expect-error questions do somehow fit
|
|
1051
|
+
questions,
|
|
1052
|
+
)
|
|
924
1053
|
|
|
925
1054
|
if (fs.existsSync(directory)) {
|
|
926
1055
|
process.chdir(directory)
|
package/src/protocols/index.ts
CHANGED
|
@@ -21,6 +21,7 @@ import * as CosmosMappingScaffold from './cosmos/scaffold/mapping'
|
|
|
21
21
|
import debug from '../debug'
|
|
22
22
|
import Subgraph from '../subgraph'
|
|
23
23
|
import { SubgraphOptions } from './subgraph'
|
|
24
|
+
import { ContractCtor } from './contract'
|
|
24
25
|
|
|
25
26
|
let protocolDebug = debug('graph-cli:protocol')
|
|
26
27
|
|
|
@@ -113,7 +114,10 @@ export default class Protocol {
|
|
|
113
114
|
'juno-1',
|
|
114
115
|
'uni-3', // Juno testnet
|
|
115
116
|
],
|
|
116
|
-
}) as immutable.Map<
|
|
117
|
+
}) as immutable.Map<
|
|
118
|
+
'arweave' | 'ethereum' | 'near' | 'cosmos' | 'substreams',
|
|
119
|
+
string[]
|
|
120
|
+
>
|
|
117
121
|
|
|
118
122
|
let allNetworks: string[] = []
|
|
119
123
|
networks.forEach(value => {
|
|
@@ -210,7 +214,7 @@ export type ProtocolName = 'arweave' | 'ethereum' | 'near' | 'cosmos' | 'substre
|
|
|
210
214
|
export interface ProtocolConfig {
|
|
211
215
|
displayName: string
|
|
212
216
|
abi?: any
|
|
213
|
-
contract?:
|
|
217
|
+
contract?: ContractCtor
|
|
214
218
|
getTemplateCodeGen?: (template: any) => any
|
|
215
219
|
getTypeGenerator?: (options: any) => any
|
|
216
220
|
getSubgraph(options: SubgraphOptions): Subgraph
|
|
@@ -1,16 +1,16 @@
|
|
|
1
|
+
import { Contract } from '../contract'
|
|
2
|
+
|
|
1
3
|
const MINIMUM_ACCOUNT_ID_LENGTH = 2 as const
|
|
2
4
|
const MAXIMUM_ACCOUNT_ID_LENGTH = 64 as const
|
|
3
5
|
|
|
4
6
|
const RULES_URL = 'https://docs.near.org/docs/concepts/account#account-id-rules' as const
|
|
5
7
|
|
|
6
|
-
export default class NearContract {
|
|
7
|
-
private account: string
|
|
8
|
-
|
|
8
|
+
export default class NearContract implements Contract {
|
|
9
9
|
static identifierName() {
|
|
10
10
|
return 'account'
|
|
11
11
|
}
|
|
12
12
|
|
|
13
|
-
constructor(account: string) {
|
|
13
|
+
constructor(private account: string) {
|
|
14
14
|
this.account = account
|
|
15
15
|
}
|
|
16
16
|
|
package/src/subgraph.ts
CHANGED
|
@@ -4,7 +4,7 @@ import path from 'path'
|
|
|
4
4
|
import yaml from 'yaml'
|
|
5
5
|
import { strOptions } from 'yaml/types'
|
|
6
6
|
import * as graphql from 'graphql/language'
|
|
7
|
-
import validation from './validation'
|
|
7
|
+
import * as validation from './validation'
|
|
8
8
|
import debug from './debug'
|
|
9
9
|
import { Subgraph as ISubgraph } from './protocols/subgraph'
|
|
10
10
|
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import immutable from 'immutable'
|
|
2
2
|
import Protocol from '../protocols'
|
|
3
|
+
import { ContractCtor } from '../protocols/contract'
|
|
3
4
|
|
|
4
|
-
export const validateContract = (value:
|
|
5
|
+
export const validateContract = (value: string, ProtocolContract: ContractCtor) => {
|
|
5
6
|
const contract = new ProtocolContract(value)
|
|
6
7
|
|
|
7
8
|
const { valid, error } = contract.validate()
|
|
@@ -20,7 +21,7 @@ export const validateContractValues = (
|
|
|
20
21
|
manifest: immutable.Map<any, any>,
|
|
21
22
|
protocol: Protocol,
|
|
22
23
|
) => {
|
|
23
|
-
const ProtocolContract = protocol.getContract()
|
|
24
|
+
const ProtocolContract = protocol.getContract()!
|
|
24
25
|
|
|
25
26
|
const fieldName = ProtocolContract.identifierName()
|
|
26
27
|
|
package/src/validation/index.ts
CHANGED
|
@@ -2,9 +2,4 @@ import { validateSchema } from './schema'
|
|
|
2
2
|
import { validateManifest } from './manifest'
|
|
3
3
|
import { validateContractValues, validateContract } from './contract'
|
|
4
4
|
|
|
5
|
-
export
|
|
6
|
-
validateSchema,
|
|
7
|
-
validateManifest,
|
|
8
|
-
validateContractValues,
|
|
9
|
-
validateContract,
|
|
10
|
-
}
|
|
5
|
+
export { validateSchema, validateManifest, validateContractValues, validateContract }
|