@graphprotocol/graph-cli 0.95.0-alpha-20250127115813-55c1f2bf474a247489f48edfcdcf9ccbb48a00ee → 0.95.0
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 +29 -8
- package/dist/command-helpers/contracts.d.ts +5 -0
- package/dist/command-helpers/contracts.js +39 -0
- package/dist/command-helpers/contracts.test.js +66 -5
- package/dist/command-helpers/network.test.js +2 -1
- package/dist/commands/add.js +8 -1
- package/dist/commands/init.js +31 -47
- package/dist/commands/local.js +2 -1
- package/dist/commands/test.js +38 -19
- package/dist/compiler/index.js +7 -20
- package/dist/protocols/subgraph/manifest.graphql +0 -1
- package/dist/scaffold/index.d.ts +1 -1
- package/dist/scaffold/index.js +13 -30
- package/dist/subgraph.js +2 -1
- package/dist/tsconfig.build.tsbuildinfo +1 -1
- package/dist/utils.d.ts +0 -12
- package/dist/utils.js +0 -56
- package/dist/version.js +2 -1
- package/oclif.manifest.json +1 -1
- package/package.json +9 -4
package/CHANGELOG.md
CHANGED
|
@@ -1,23 +1,44 @@
|
|
|
1
1
|
# @graphprotocol/graph-cli
|
|
2
2
|
|
|
3
|
-
## 0.95.0
|
|
3
|
+
## 0.95.0
|
|
4
4
|
|
|
5
5
|
### Minor Changes
|
|
6
6
|
|
|
7
|
-
- [#
|
|
8
|
-
[`
|
|
9
|
-
Thanks [@
|
|
10
|
-
`graph init`
|
|
7
|
+
- [#1899](https://github.com/graphprotocol/graph-tooling/pull/1899)
|
|
8
|
+
[`8cdaf31`](https://github.com/graphprotocol/graph-tooling/commit/8cdaf31e78c7fb7bf7ef4f5380d0c72b2a05b08d)
|
|
9
|
+
Thanks [@0237h](https://github.com/0237h)! - Add support for Sourcify contract information lookup
|
|
11
10
|
|
|
12
11
|
### Patch Changes
|
|
13
12
|
|
|
14
|
-
- [#
|
|
15
|
-
[`
|
|
16
|
-
Thanks [@
|
|
13
|
+
- [#1910](https://github.com/graphprotocol/graph-tooling/pull/1910)
|
|
14
|
+
[`15384e6`](https://github.com/graphprotocol/graph-tooling/commit/15384e6bd8af6ba2ad07e9eb5a637d148fb39867)
|
|
15
|
+
Thanks [@renovate](https://github.com/apps/renovate)! - dependencies updates:
|
|
16
|
+
|
|
17
|
+
- Updated dependency [`undici@7.2.3` ↗︎](https://www.npmjs.com/package/undici/v/7.2.3) (from
|
|
18
|
+
`7.1.1`, in `dependencies`)
|
|
19
|
+
|
|
20
|
+
- [#1914](https://github.com/graphprotocol/graph-tooling/pull/1914)
|
|
21
|
+
[`e63b483`](https://github.com/graphprotocol/graph-tooling/commit/e63b483612e74587b3d33b7ce6d5f3264096820f)
|
|
22
|
+
Thanks [@YaroShkvorets](https://github.com/YaroShkvorets)! - dependencies updates:
|
|
23
|
+
|
|
17
24
|
- Removed dependency
|
|
18
25
|
[`binary-install@^1.1.0` ↗︎](https://www.npmjs.com/package/binary-install/v/1.1.0) (from
|
|
19
26
|
`dependencies`)
|
|
20
27
|
|
|
28
|
+
- [#1914](https://github.com/graphprotocol/graph-tooling/pull/1914)
|
|
29
|
+
[`e63b483`](https://github.com/graphprotocol/graph-tooling/commit/e63b483612e74587b3d33b7ce6d5f3264096820f)
|
|
30
|
+
Thanks [@YaroShkvorets](https://github.com/YaroShkvorets)! - fix bug with graph test #1904
|
|
31
|
+
|
|
32
|
+
- [#1903](https://github.com/graphprotocol/graph-tooling/pull/1903)
|
|
33
|
+
[`bcaad5e`](https://github.com/graphprotocol/graph-tooling/commit/bcaad5e077e485224c06842491145d05215f4c0e)
|
|
34
|
+
Thanks [@0237h](https://github.com/0237h)! - Fix `import.meta.url` not being parsed as path
|
|
35
|
+
properly
|
|
36
|
+
|
|
37
|
+
- [#1918](https://github.com/graphprotocol/graph-tooling/pull/1918)
|
|
38
|
+
[`14ac25c`](https://github.com/graphprotocol/graph-tooling/commit/14ac25c1f08134d15410dad215cad8a9e941a105)
|
|
39
|
+
Thanks [@YaroShkvorets](https://github.com/YaroShkvorets)! - fix bug with loud errors in
|
|
40
|
+
`graph test`
|
|
41
|
+
|
|
21
42
|
## 0.94.0
|
|
22
43
|
|
|
23
44
|
### Minor Changes
|
|
@@ -10,5 +10,10 @@ export declare class ContractService {
|
|
|
10
10
|
getABI(ABICtor: typeof ABI, networkId: string, address: string): Promise<ABI>;
|
|
11
11
|
getStartBlock(networkId: string, address: string): Promise<string>;
|
|
12
12
|
getContractName(networkId: string, address: string): Promise<string>;
|
|
13
|
+
getFromSourcify(ABICtor: typeof ABI, networkId: string, address: string): Promise<{
|
|
14
|
+
abi: ABI;
|
|
15
|
+
startBlock: string;
|
|
16
|
+
name: string;
|
|
17
|
+
} | null>;
|
|
13
18
|
private fetchTransactionByHash;
|
|
14
19
|
}
|
|
@@ -122,6 +122,45 @@ export class ContractService {
|
|
|
122
122
|
}
|
|
123
123
|
throw new Error(`Failed to fetch contract name for ${address}`);
|
|
124
124
|
}
|
|
125
|
+
async getFromSourcify(ABICtor, networkId, address) {
|
|
126
|
+
try {
|
|
127
|
+
const network = this.registry.getNetworkById(networkId);
|
|
128
|
+
if (!network)
|
|
129
|
+
throw new Error(`Invalid network ${networkId}`);
|
|
130
|
+
if (!network.caip2Id.startsWith('eip155'))
|
|
131
|
+
throw new Error(`Invalid chainId, Sourcify API only supports EVM chains`);
|
|
132
|
+
const chainId = network.caip2Id.split(':')[1];
|
|
133
|
+
const url = `https://sourcify.dev/server/files/any/${chainId}/${address}`;
|
|
134
|
+
const json = await (await fetch(url).catch(error => {
|
|
135
|
+
throw new Error(`Sourcify API is unreachable: ${error}`);
|
|
136
|
+
})).json();
|
|
137
|
+
if (json) {
|
|
138
|
+
if ('error' in json)
|
|
139
|
+
throw new Error(`Sourcify API error: ${json.error}`);
|
|
140
|
+
let metadata = json.files.find(e => e.name === 'metadata.json')?.content;
|
|
141
|
+
if (!metadata)
|
|
142
|
+
throw new Error('Contract is missing metadata');
|
|
143
|
+
const tx_hash = json.files.find(e => e.name === 'creator-tx-hash.txt')?.content;
|
|
144
|
+
if (!tx_hash)
|
|
145
|
+
throw new Error('Contract is missing tx creation hash');
|
|
146
|
+
const tx = await this.fetchTransactionByHash(networkId, tx_hash);
|
|
147
|
+
if (!tx?.blockNumber)
|
|
148
|
+
throw new Error(`Can't fetch blockNumber from tx: ${JSON.stringify(tx)}`);
|
|
149
|
+
metadata = JSON.parse(metadata);
|
|
150
|
+
const contractName = Object.values(metadata.settings.compilationTarget)[0];
|
|
151
|
+
return {
|
|
152
|
+
abi: new ABICtor(contractName, undefined, immutable.fromJS(metadata.output.abi)),
|
|
153
|
+
startBlock: Number(tx.blockNumber).toString(),
|
|
154
|
+
name: contractName,
|
|
155
|
+
};
|
|
156
|
+
}
|
|
157
|
+
throw new Error(`No result: ${JSON.stringify(json)}`);
|
|
158
|
+
}
|
|
159
|
+
catch (error) {
|
|
160
|
+
logger(`Failed to fetch from Sourcify: ${error}`);
|
|
161
|
+
}
|
|
162
|
+
return null;
|
|
163
|
+
}
|
|
125
164
|
async fetchTransactionByHash(networkId, txHash) {
|
|
126
165
|
const urls = this.getRpcUrls(networkId);
|
|
127
166
|
if (!urls.length) {
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { describe, expect, test } from 'vitest';
|
|
2
|
+
import EthereumABI from '../protocols/ethereum/abi.js';
|
|
2
3
|
import { ContractService } from './contracts.js';
|
|
3
4
|
import { loadRegistry } from './registry.js';
|
|
4
5
|
// An object with some test cases for contract deployment block numbers
|
|
@@ -79,16 +80,76 @@ const TEST_CONTRACT_START_BLOCKS = {
|
|
|
79
80
|
// clover: {
|
|
80
81
|
// },
|
|
81
82
|
};
|
|
82
|
-
|
|
83
|
+
const TEST_SOURCIFY_CONTRACT_INFO = {
|
|
84
|
+
mainnet: {
|
|
85
|
+
'0xc2EdaD668740f1aA35E4D8f227fB8E17dcA888Cd': {
|
|
86
|
+
name: 'MasterChef',
|
|
87
|
+
startBlock: 10_736_242,
|
|
88
|
+
},
|
|
89
|
+
},
|
|
90
|
+
optimism: {
|
|
91
|
+
'0xc35DADB65012eC5796536bD9864eD8773aBc74C4': {
|
|
92
|
+
name: 'BentoBoxV1',
|
|
93
|
+
startBlock: 7_019_815,
|
|
94
|
+
},
|
|
95
|
+
},
|
|
96
|
+
wax: {
|
|
97
|
+
account: {
|
|
98
|
+
name: null,
|
|
99
|
+
startBlock: null,
|
|
100
|
+
},
|
|
101
|
+
},
|
|
102
|
+
'non-existing chain': {
|
|
103
|
+
'0x0000000000000000000000000000000000000000': {
|
|
104
|
+
name: null,
|
|
105
|
+
startBlock: null,
|
|
106
|
+
},
|
|
107
|
+
},
|
|
108
|
+
};
|
|
109
|
+
// Retry helper with configurable number of retries
|
|
110
|
+
async function retry(operation, maxRetries = 3, sleepMs = 5000) {
|
|
111
|
+
let lastError;
|
|
112
|
+
for (let attempt = 0; attempt < maxRetries; attempt++) {
|
|
113
|
+
try {
|
|
114
|
+
return await operation();
|
|
115
|
+
}
|
|
116
|
+
catch (error) {
|
|
117
|
+
lastError = error;
|
|
118
|
+
if (attempt < maxRetries - 1) {
|
|
119
|
+
await new Promise(resolve => setTimeout(resolve, sleepMs));
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
throw lastError;
|
|
124
|
+
}
|
|
125
|
+
describe('getStartBlockForContract', { concurrent: true }, async () => {
|
|
83
126
|
const registry = await loadRegistry();
|
|
84
127
|
const contractService = new ContractService(registry);
|
|
85
128
|
for (const [network, contracts] of Object.entries(TEST_CONTRACT_START_BLOCKS)) {
|
|
86
129
|
for (const [contract, startBlockExp] of Object.entries(contracts)) {
|
|
87
|
-
test(`Returns the start block ${network} ${contract} ${startBlockExp}`, async () => {
|
|
88
|
-
|
|
89
|
-
const startBlock = await contractService.getStartBlock(network, contract);
|
|
130
|
+
test(`Returns the start block ${network} ${contract} ${startBlockExp}`, { timeout: 50_000 }, async ({ expect }) => {
|
|
131
|
+
const startBlock = await retry(() => contractService.getStartBlock(network, contract), 10);
|
|
90
132
|
expect(parseInt(startBlock)).toBe(startBlockExp);
|
|
91
|
-
}
|
|
133
|
+
});
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
});
|
|
137
|
+
describe('getFromSourcifyForContract', { concurrent: true }, async () => {
|
|
138
|
+
const registry = await loadRegistry();
|
|
139
|
+
const contractService = new ContractService(registry);
|
|
140
|
+
for (const [networkId, contractInfo] of Object.entries(TEST_SOURCIFY_CONTRACT_INFO)) {
|
|
141
|
+
for (const [contract, t] of Object.entries(contractInfo)) {
|
|
142
|
+
test(`Returns contract information ${networkId} ${contract} ${t.name} ${t.startBlock}`, { timeout: 50_000 }, async () => {
|
|
143
|
+
const result = await retry(() => contractService.getFromSourcify(EthereumABI, networkId, contract));
|
|
144
|
+
if (t.name === null && t.startBlock === null) {
|
|
145
|
+
expect(result).toBeNull();
|
|
146
|
+
}
|
|
147
|
+
else {
|
|
148
|
+
// Only check name and startBlock, omit API property from Sourcify results
|
|
149
|
+
const { name, startBlock } = result;
|
|
150
|
+
expect(t).toEqual({ name, startBlock: parseInt(startBlock) });
|
|
151
|
+
}
|
|
152
|
+
});
|
|
92
153
|
}
|
|
93
154
|
}
|
|
94
155
|
});
|
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
import path from 'node:path';
|
|
2
|
+
import { fileURLToPath } from 'node:url';
|
|
2
3
|
import * as toolbox from 'gluegun';
|
|
3
4
|
import { afterAll, beforeAll, describe, expect, test } from 'vitest';
|
|
4
5
|
import yaml from 'yaml';
|
|
5
6
|
import { initNetworksConfig, updateSubgraphNetwork } from './network.js';
|
|
6
|
-
const SUBGRAPH_PATH_BASE = path.join(
|
|
7
|
+
const SUBGRAPH_PATH_BASE = path.join(fileURLToPath(import.meta.url), '..', '..', '..', '..', '..', 'examples', 'example-subgraph');
|
|
7
8
|
describe('initNetworksConfig', () => {
|
|
8
9
|
beforeAll(async () => {
|
|
9
10
|
await initNetworksConfig(SUBGRAPH_PATH_BASE, 'address');
|
package/dist/commands/add.js
CHANGED
|
@@ -58,10 +58,17 @@ export default class AddCommand extends Command {
|
|
|
58
58
|
this.warn('`localhost` network detected, prompting user for inputs');
|
|
59
59
|
const registry = await loadRegistry();
|
|
60
60
|
const contractService = new ContractService(registry);
|
|
61
|
+
const sourcifyContractInfo = await contractService.getFromSourcify(EthereumABI, network, address);
|
|
61
62
|
let startBlock = startBlockFlag ? parseInt(startBlockFlag).toString() : startBlockFlag;
|
|
62
63
|
let contractName = contractNameFlag || DEFAULT_CONTRACT_NAME;
|
|
63
64
|
let ethabi = null;
|
|
64
|
-
if (
|
|
65
|
+
if (sourcifyContractInfo) {
|
|
66
|
+
startBlock ??= sourcifyContractInfo.startBlock;
|
|
67
|
+
contractName =
|
|
68
|
+
contractName == DEFAULT_CONTRACT_NAME ? sourcifyContractInfo.name : contractName;
|
|
69
|
+
ethabi ??= sourcifyContractInfo.abi;
|
|
70
|
+
}
|
|
71
|
+
if (!ethabi && abi) {
|
|
65
72
|
ethabi = EthereumABI.load(contractName, abi);
|
|
66
73
|
}
|
|
67
74
|
else {
|
package/dist/commands/init.js
CHANGED
|
@@ -18,10 +18,11 @@ import { withSpinner } from '../command-helpers/spinner.js';
|
|
|
18
18
|
import { getSubgraphBasename } from '../command-helpers/subgraph.js';
|
|
19
19
|
import { GRAPH_CLI_SHARED_HEADERS } from '../constants.js';
|
|
20
20
|
import debugFactory from '../debug.js';
|
|
21
|
+
import EthereumABI from '../protocols/ethereum/abi.js';
|
|
21
22
|
import Protocol from '../protocols/index.js';
|
|
22
23
|
import { abiEvents } from '../scaffold/schema.js';
|
|
23
24
|
import Schema from '../schema.js';
|
|
24
|
-
import { createIpfsClient, loadSubgraphSchemaFromIPFS
|
|
25
|
+
import { createIpfsClient, loadSubgraphSchemaFromIPFS } from '../utils.js';
|
|
25
26
|
import { validateContract } from '../validation/index.js';
|
|
26
27
|
import AddCommand from './add.js';
|
|
27
28
|
const protocolChoices = Array.from(Protocol.availableProtocols().keys());
|
|
@@ -154,6 +155,7 @@ export default class InitCommand extends Command {
|
|
|
154
155
|
if ((fromContract || spkgPath) && protocol && subgraphName && directory && network && node) {
|
|
155
156
|
const registry = await loadRegistry();
|
|
156
157
|
const contractService = new ContractService(registry);
|
|
158
|
+
const sourcifyContractInfo = await contractService.getFromSourcify(EthereumABI, network, fromContract);
|
|
157
159
|
if (!protocolChoices.includes(protocol)) {
|
|
158
160
|
this.error(`Protocol '${protocol}' is not supported, choose from these options: ${protocolChoices.join(', ')}`, { exit: 1 });
|
|
159
161
|
}
|
|
@@ -170,7 +172,9 @@ export default class InitCommand extends Command {
|
|
|
170
172
|
}
|
|
171
173
|
else {
|
|
172
174
|
try {
|
|
173
|
-
abi =
|
|
175
|
+
abi = sourcifyContractInfo
|
|
176
|
+
? sourcifyContractInfo.abi
|
|
177
|
+
: await contractService.getABI(ABI, network, fromContract);
|
|
174
178
|
}
|
|
175
179
|
catch (e) {
|
|
176
180
|
this.exit(1);
|
|
@@ -369,7 +373,7 @@ async function processInitForm({ abi: initAbi, abiPath: initAbiPath, directory:
|
|
|
369
373
|
value: 'contract',
|
|
370
374
|
},
|
|
371
375
|
{ message: 'Substreams', name: 'substreams', value: 'substreams' },
|
|
372
|
-
{ message: 'Subgraph', name: 'subgraph', value: 'subgraph' },
|
|
376
|
+
// { message: 'Subgraph', name: 'subgraph', value: 'subgraph' },
|
|
373
377
|
].filter(({ name }) => name),
|
|
374
378
|
});
|
|
375
379
|
return value;
|
|
@@ -433,18 +437,6 @@ async function processInitForm({ abi: initAbi, abiPath: initAbiPath, directory:
|
|
|
433
437
|
return value;
|
|
434
438
|
},
|
|
435
439
|
});
|
|
436
|
-
promptManager.addStep({
|
|
437
|
-
type: 'input',
|
|
438
|
-
name: 'ipfs',
|
|
439
|
-
message: `IPFS node to use for fetching subgraph manifest`,
|
|
440
|
-
initial: ipfsUrl,
|
|
441
|
-
skip: () => !isComposedSubgraph,
|
|
442
|
-
result: value => {
|
|
443
|
-
ipfsNode = value;
|
|
444
|
-
initDebugger.extend('processInitForm')('ipfs: %O', value);
|
|
445
|
-
return value;
|
|
446
|
-
},
|
|
447
|
-
});
|
|
448
440
|
promptManager.addStep({
|
|
449
441
|
type: 'input',
|
|
450
442
|
name: 'source',
|
|
@@ -457,15 +449,7 @@ async function processInitForm({ abi: initAbi, abiPath: initAbiPath, directory:
|
|
|
457
449
|
initial: initContract,
|
|
458
450
|
validate: async (value) => {
|
|
459
451
|
if (isComposedSubgraph) {
|
|
460
|
-
|
|
461
|
-
return true;
|
|
462
|
-
}
|
|
463
|
-
const ipfs = createIpfsClient(ipfsNode);
|
|
464
|
-
const { valid, error } = await validateSubgraphNetworkMatch(ipfs, value, network.id);
|
|
465
|
-
if (!valid) {
|
|
466
|
-
return error || 'Invalid subgraph network match';
|
|
467
|
-
}
|
|
468
|
-
return true;
|
|
452
|
+
return value.startsWith('Qm') ? true : 'Subgraph deployment ID must start with Qm';
|
|
469
453
|
}
|
|
470
454
|
if (initFromExample !== undefined || !protocolInstance.hasContract()) {
|
|
471
455
|
return true;
|
|
@@ -482,11 +466,21 @@ async function processInitForm({ abi: initAbi, abiPath: initAbiPath, directory:
|
|
|
482
466
|
source = address;
|
|
483
467
|
return address;
|
|
484
468
|
}
|
|
469
|
+
const sourcifyContractInfo = await contractService.getFromSourcify(EthereumABI, network.id, address);
|
|
470
|
+
if (sourcifyContractInfo) {
|
|
471
|
+
initStartBlock ??= sourcifyContractInfo.startBlock;
|
|
472
|
+
initContractName ??= sourcifyContractInfo.name;
|
|
473
|
+
initAbi ??= sourcifyContractInfo.abi;
|
|
474
|
+
initDebugger.extend('processInitForm')("infoFromSourcify: '%s'/'%s'", initStartBlock, initContractName);
|
|
475
|
+
}
|
|
485
476
|
// If ABI is not provided, try to fetch it from Etherscan API
|
|
486
477
|
if (protocolInstance.hasABIs() && !initAbi) {
|
|
487
478
|
abiFromApi = await retryWithPrompt(() => withSpinner('Fetching ABI from contract API...', 'Failed to fetch ABI', 'Warning fetching ABI', () => contractService.getABI(protocolInstance.getABI(), network.id, address)));
|
|
488
479
|
initDebugger.extend('processInitForm')("abiFromEtherscan len: '%s'", abiFromApi?.name);
|
|
489
480
|
}
|
|
481
|
+
else {
|
|
482
|
+
abiFromApi = initAbi;
|
|
483
|
+
}
|
|
490
484
|
// If startBlock is not provided, try to fetch it from Etherscan API
|
|
491
485
|
if (!initStartBlock) {
|
|
492
486
|
startBlock = await retryWithPrompt(() => withSpinner('Fetching start block from contract API...', 'Failed to fetch start block', 'Warning fetching start block', () => contractService.getStartBlock(network.id, address)));
|
|
@@ -501,6 +495,18 @@ async function processInitForm({ abi: initAbi, abiPath: initAbiPath, directory:
|
|
|
501
495
|
return address;
|
|
502
496
|
},
|
|
503
497
|
});
|
|
498
|
+
promptManager.addStep({
|
|
499
|
+
type: 'input',
|
|
500
|
+
name: 'ipfs',
|
|
501
|
+
message: `IPFS node to use for fetching subgraph manifest`,
|
|
502
|
+
initial: ipfsUrl,
|
|
503
|
+
skip: () => !isComposedSubgraph,
|
|
504
|
+
result: value => {
|
|
505
|
+
ipfsNode = value;
|
|
506
|
+
initDebugger.extend('processInitForm')('ipfs: %O', value);
|
|
507
|
+
return value;
|
|
508
|
+
},
|
|
509
|
+
});
|
|
504
510
|
promptManager.addStep({
|
|
505
511
|
type: 'input',
|
|
506
512
|
name: 'spkg',
|
|
@@ -617,22 +623,6 @@ async function processInitForm({ abi: initAbi, abiPath: initAbiPath, directory:
|
|
|
617
623
|
},
|
|
618
624
|
});
|
|
619
625
|
await promptManager.executeInteractive();
|
|
620
|
-
// Validate network matches if loading from IPFS
|
|
621
|
-
if (ipfsNode && source && source.startsWith('Qm')) {
|
|
622
|
-
const ipfs = createIpfsClient(ipfsNode);
|
|
623
|
-
try {
|
|
624
|
-
const { valid, error } = await validateSubgraphNetworkMatch(ipfs, source, network.id);
|
|
625
|
-
if (!valid) {
|
|
626
|
-
throw new Error(error || 'Invalid subgraph network match');
|
|
627
|
-
}
|
|
628
|
-
}
|
|
629
|
-
catch (e) {
|
|
630
|
-
if (e instanceof Error) {
|
|
631
|
-
print.error(`Failed to validate subgraph network: ${e.message}`);
|
|
632
|
-
}
|
|
633
|
-
throw e;
|
|
634
|
-
}
|
|
635
|
-
}
|
|
636
626
|
return {
|
|
637
627
|
abi: (abiFromApi || abiFromFile),
|
|
638
628
|
protocolInstance,
|
|
@@ -851,9 +841,8 @@ async function initSubgraphFromContract({ protocolInstance, subgraphName, direct
|
|
|
851
841
|
this.error(`Failed to load and parse subgraph schema: ${e.message}`, { exit: 1 });
|
|
852
842
|
}
|
|
853
843
|
}
|
|
854
|
-
if (!isComposedSubgraph &&
|
|
844
|
+
if (!protocolInstance.isComposedSubgraph() &&
|
|
855
845
|
protocolInstance.hasABIs() &&
|
|
856
|
-
abi && // Add check for abi existence
|
|
857
846
|
(abiEvents(abi).size === 0 ||
|
|
858
847
|
// @ts-expect-error TODO: the abiEvents result is expected to be a List, how's it an array?
|
|
859
848
|
abiEvents(abi).length === 0)) {
|
|
@@ -862,11 +851,6 @@ async function initSubgraphFromContract({ protocolInstance, subgraphName, direct
|
|
|
862
851
|
}
|
|
863
852
|
// Scaffold subgraph
|
|
864
853
|
const scaffold = await withSpinner(`Create subgraph scaffold`, `Failed to create subgraph scaffold`, `Warnings while creating subgraph scaffold`, async (spinner) => {
|
|
865
|
-
initDebugger('Generating scaffold with ABI:', abi);
|
|
866
|
-
initDebugger('ABI data:', abi?.data);
|
|
867
|
-
if (abi) {
|
|
868
|
-
initDebugger('ABI events:', abiEvents(abi));
|
|
869
|
-
}
|
|
870
854
|
const scaffold = await generateScaffold({
|
|
871
855
|
protocolInstance,
|
|
872
856
|
subgraphName,
|
package/dist/commands/local.js
CHANGED
|
@@ -2,6 +2,7 @@ import { spawn } from 'node:child_process';
|
|
|
2
2
|
import http from 'node:http';
|
|
3
3
|
import net from 'node:net';
|
|
4
4
|
import path from 'node:path';
|
|
5
|
+
import { fileURLToPath } from 'node:url';
|
|
5
6
|
import compose from 'docker-compose';
|
|
6
7
|
import { filesystem, patching } from 'gluegun';
|
|
7
8
|
import stripAnsi from 'strip-ansi';
|
|
@@ -67,7 +68,7 @@ export default class LocalCommand extends Command {
|
|
|
67
68
|
const skipWaitForEthereum = skipWaitForEthereumTypo || skipWaitForEthereumGood;
|
|
68
69
|
// Obtain the Docker Compose file for services that the tests run against
|
|
69
70
|
const composeFile = composeFileFlag ||
|
|
70
|
-
path.join(
|
|
71
|
+
path.join(fileURLToPath(import.meta.url), '..', '..', '..', 'resources', 'test', standaloneNode ? 'docker-compose-standalone-node.yml' : 'docker-compose.yml');
|
|
71
72
|
if (!filesystem.exists(composeFile)) {
|
|
72
73
|
this.error(`Docker Compose file "${composeFile}" not found`, { exit: 1 });
|
|
73
74
|
}
|
package/dist/commands/test.js
CHANGED
|
@@ -1,13 +1,15 @@
|
|
|
1
1
|
import { exec, spawn } from 'node:child_process';
|
|
2
|
+
import events from 'node:events';
|
|
3
|
+
import fs from 'node:fs';
|
|
2
4
|
import os from 'node:os';
|
|
3
5
|
import path from 'node:path';
|
|
4
|
-
import {
|
|
6
|
+
import { pipeline } from 'node:stream/promises';
|
|
7
|
+
import { fileURLToPath } from 'node:url';
|
|
5
8
|
import { filesystem, patching, print, system } from 'gluegun';
|
|
6
9
|
import yaml from 'js-yaml';
|
|
7
10
|
import semver from 'semver';
|
|
8
11
|
import { Args, Command, Flags } from '@oclif/core';
|
|
9
12
|
import { GRAPH_CLI_SHARED_HEADERS } from '../constants.js';
|
|
10
|
-
import fetch from '../fetch.js';
|
|
11
13
|
export default class TestCommand extends Command {
|
|
12
14
|
static description = 'Runs rust binary for subgraph testing.';
|
|
13
15
|
static args = {
|
|
@@ -92,10 +94,10 @@ export default class TestCommand extends Command {
|
|
|
92
94
|
});
|
|
93
95
|
}
|
|
94
96
|
if (opts.docker) {
|
|
95
|
-
runDocker.bind(this)(datasource, opts);
|
|
97
|
+
await runDocker.bind(this)(datasource, opts);
|
|
96
98
|
}
|
|
97
99
|
else {
|
|
98
|
-
runBinary.bind(this)(datasource, opts);
|
|
100
|
+
await runBinary.bind(this)(datasource, opts);
|
|
99
101
|
}
|
|
100
102
|
}
|
|
101
103
|
}
|
|
@@ -113,19 +115,36 @@ function getLatestVersionFromCache(cachePath) {
|
|
|
113
115
|
}
|
|
114
116
|
async function runBinary(datasource, opts) {
|
|
115
117
|
const coverageOpt = opts.coverage;
|
|
116
|
-
const forceOpt = opts.force;
|
|
117
118
|
const logsOpt = opts.logs;
|
|
118
119
|
const versionOpt = opts.version;
|
|
119
120
|
const latestVersion = opts.latestVersion;
|
|
120
121
|
const recompileOpt = opts.recompile;
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
122
|
+
let binPath = '';
|
|
123
|
+
try {
|
|
124
|
+
const platform = await getPlatform.bind(this)(versionOpt || latestVersion, logsOpt);
|
|
125
|
+
const url = `https://github.com/LimeChain/matchstick/releases/download/${versionOpt || latestVersion}/${platform}`;
|
|
126
|
+
const binDir = path.join(path.dirname(fileURLToPath(import.meta.url)), 'node_modules', '.bin');
|
|
127
|
+
binPath = path.join(binDir, `matchstick-${platform}`);
|
|
128
|
+
if (logsOpt) {
|
|
129
|
+
this.log(`Download link: ${url}`);
|
|
130
|
+
this.log(`Binary path: ${binPath}`);
|
|
131
|
+
}
|
|
132
|
+
if (!fs.existsSync(binPath)) {
|
|
133
|
+
this.log(`Downloading matchstick binary: ${url}`);
|
|
134
|
+
await fs.promises.mkdir(binDir, { recursive: true });
|
|
135
|
+
const response = await fetch(url);
|
|
136
|
+
if (!response.ok)
|
|
137
|
+
throw new Error(`Status: ${response.statusText}`);
|
|
138
|
+
if (!response.body)
|
|
139
|
+
throw new Error('No response body received');
|
|
140
|
+
const fileStream = fs.createWriteStream(binPath);
|
|
141
|
+
await pipeline(response.body, fileStream);
|
|
142
|
+
await fs.promises.chmod(binPath, '755');
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
catch (e) {
|
|
146
|
+
this.error(`Failed to get matchstick binary: ${e.message}\nConsider using -d flag to run it in Docker instead:\n graph test -d`, { exit: 1 });
|
|
125
147
|
}
|
|
126
|
-
const binary = new Binary(platform, url, versionOpt || latestVersion);
|
|
127
|
-
// eslint-disable-next-line @typescript-eslint/no-unused-expressions
|
|
128
|
-
forceOpt ? await binary.install(true) : await binary.install(false);
|
|
129
148
|
const args = [];
|
|
130
149
|
if (coverageOpt)
|
|
131
150
|
args.push('-c');
|
|
@@ -133,14 +152,17 @@ async function runBinary(datasource, opts) {
|
|
|
133
152
|
args.push('-r');
|
|
134
153
|
if (datasource)
|
|
135
154
|
args.push(datasource);
|
|
136
|
-
|
|
137
|
-
|
|
155
|
+
const child = spawn(binPath, args, { stdio: 'inherit' });
|
|
156
|
+
const [code] = await events.once(child, 'exit');
|
|
157
|
+
if (code !== 0) {
|
|
158
|
+
this.error('Matchstick exited with an error', { exit: 1 });
|
|
159
|
+
}
|
|
138
160
|
}
|
|
139
161
|
async function getPlatform(matchstickVersion, logsOpt) {
|
|
140
162
|
const type = os.type();
|
|
141
163
|
const arch = os.arch();
|
|
142
164
|
const cpuCore = os.cpus()[0];
|
|
143
|
-
const isAppleSilicon = arch === 'arm64' && /Apple (
|
|
165
|
+
const isAppleSilicon = arch === 'arm64' && /Apple (M[0-9]|processor)/.test(cpuCore.model);
|
|
144
166
|
const linuxInfo = type === 'Linux' ? await getLinuxInfo.bind(this)() : {};
|
|
145
167
|
const linuxDistro = linuxInfo.name;
|
|
146
168
|
const release = linuxInfo.version || os.release();
|
|
@@ -156,7 +178,7 @@ async function getPlatform(matchstickVersion, logsOpt) {
|
|
|
156
178
|
}
|
|
157
179
|
return 'binary-macos-12';
|
|
158
180
|
}
|
|
159
|
-
if (type === 'Linux' && majorVersion === 22) {
|
|
181
|
+
if (type === 'Linux' && (majorVersion === 22 || majorVersion === 24)) {
|
|
160
182
|
return 'binary-linux-22';
|
|
161
183
|
}
|
|
162
184
|
}
|
|
@@ -206,9 +228,6 @@ async function runDocker(datasource, opts) {
|
|
|
206
228
|
const versionOpt = opts.version;
|
|
207
229
|
const latestVersion = opts.latestVersion;
|
|
208
230
|
const recompileOpt = opts.recompile;
|
|
209
|
-
// Remove binary-install binaries, because docker has permission issues
|
|
210
|
-
// when building the docker images
|
|
211
|
-
filesystem.remove('./node_modules/binary-install/bin');
|
|
212
231
|
// Get current working directory
|
|
213
232
|
const current_folder = filesystem.cwd();
|
|
214
233
|
// Declate dockerfilePath with default location
|
package/dist/compiler/index.js
CHANGED
|
@@ -336,8 +336,6 @@ export default class Compiler {
|
|
|
336
336
|
// ensure that the output directory exists
|
|
337
337
|
fs.mkdirsSync(this.options.outputDir);
|
|
338
338
|
return await withSpinner(`Write compiled subgraph to ${displayDir}`, `Failed to write compiled subgraph to ${displayDir}`, `Warnings while writing compiled subgraph to ${displayDir}`, async (spinner) => {
|
|
339
|
-
// Add debug log for initial subgraph state
|
|
340
|
-
compilerDebug('Initial subgraph state:', subgraph.toJS());
|
|
341
339
|
// Copy schema and update its path
|
|
342
340
|
subgraph = subgraph.updateIn(['schema', 'file'], schemaFile => {
|
|
343
341
|
const schemaFilePath = path.resolve(this.sourceDir, schemaFile);
|
|
@@ -347,28 +345,17 @@ export default class Compiler {
|
|
|
347
345
|
fs.copyFileSync(schemaFilePath, targetFile);
|
|
348
346
|
return path.relative(this.options.outputDir, targetFile);
|
|
349
347
|
});
|
|
350
|
-
// Add debug log before processing data sources
|
|
351
|
-
compilerDebug('Processing dataSources:', subgraph.get('dataSources').toJS());
|
|
352
348
|
// Copy data source files and update their paths
|
|
353
349
|
subgraph = subgraph.update('dataSources', (dataSources) => dataSources.map(dataSource => {
|
|
354
|
-
// Add debug log for each data source
|
|
355
|
-
compilerDebug('Processing dataSource:', dataSource.toJS());
|
|
356
350
|
let updatedDataSource = dataSource;
|
|
357
351
|
if (this.protocol.hasABIs()) {
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
}
|
|
366
|
-
return abis.map((abi) => abi.update('file', (abiFile) => {
|
|
367
|
-
abiFile = path.resolve(this.sourceDir, abiFile);
|
|
368
|
-
const abiData = this.ABI.load(abi.get('name'), abiFile);
|
|
369
|
-
return path.relative(this.options.outputDir, this._writeSubgraphFile(abiFile, JSON.stringify(abiData.data.toJS(), null, 2), this.sourceDir, this.subgraphDir(this.options.outputDir, dataSource), spinner));
|
|
370
|
-
}));
|
|
371
|
-
});
|
|
352
|
+
updatedDataSource = updatedDataSource
|
|
353
|
+
// Write data source ABIs to the output directory
|
|
354
|
+
.updateIn(['mapping', 'abis'], (abis) => abis.map((abi) => abi.update('file', (abiFile) => {
|
|
355
|
+
abiFile = path.resolve(this.sourceDir, abiFile);
|
|
356
|
+
const abiData = this.ABI.load(abi.get('name'), abiFile);
|
|
357
|
+
return path.relative(this.options.outputDir, this._writeSubgraphFile(abiFile, JSON.stringify(abiData.data.toJS(), null, 2), this.sourceDir, this.subgraphDir(this.options.outputDir, dataSource), spinner));
|
|
358
|
+
})));
|
|
372
359
|
}
|
|
373
360
|
if (protocol.name == 'substreams' || protocol.name == 'substreams/triggers') {
|
|
374
361
|
updatedDataSource = updatedDataSource
|
package/dist/scaffold/index.d.ts
CHANGED
|
@@ -25,7 +25,7 @@ export default class Scaffold {
|
|
|
25
25
|
startBlock?: string;
|
|
26
26
|
spkgPath?: string;
|
|
27
27
|
entities?: string[];
|
|
28
|
-
constructor(
|
|
28
|
+
constructor(options: ScaffoldOptions);
|
|
29
29
|
generatePackageJson(): Promise<string>;
|
|
30
30
|
generatePackageJsonForSubstreams(): Promise<string>;
|
|
31
31
|
generateManifest(): Promise<string>;
|
package/dist/scaffold/index.js
CHANGED
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import debugFactory from 'debug';
|
|
2
1
|
import fs from 'fs-extra';
|
|
3
2
|
import { strings } from 'gluegun';
|
|
4
3
|
import prettier from 'prettier';
|
|
@@ -9,7 +8,6 @@ import { getGitIgnore } from './get-git-ignore.js';
|
|
|
9
8
|
import { generateEventIndexingHandlers } from './mapping.js';
|
|
10
9
|
import { abiEvents, generateEventType, generateExampleEntityType } from './schema.js';
|
|
11
10
|
import { generateTestsFiles } from './tests.js';
|
|
12
|
-
const scaffoldDebugger = debugFactory('graph-cli:scaffold');
|
|
13
11
|
const GRAPH_CLI_VERSION = process.env.GRAPH_CLI_TESTS
|
|
14
12
|
? // JSON.stringify should remove this key, we will install the local
|
|
15
13
|
// graph-cli for the tests using `npm link` instead of fetching from npm.
|
|
@@ -30,21 +28,18 @@ export default class Scaffold {
|
|
|
30
28
|
startBlock;
|
|
31
29
|
spkgPath;
|
|
32
30
|
entities;
|
|
33
|
-
constructor(
|
|
34
|
-
this.protocol = protocol;
|
|
35
|
-
this.abi = abi;
|
|
36
|
-
this.
|
|
37
|
-
this.
|
|
38
|
-
this.
|
|
39
|
-
this.
|
|
40
|
-
this.subgraphName = subgraphName;
|
|
41
|
-
this.
|
|
42
|
-
this.
|
|
43
|
-
this.
|
|
44
|
-
this.entities = entities;
|
|
45
|
-
scaffoldDebugger('Scaffold constructor called with ABI:', abi);
|
|
46
|
-
scaffoldDebugger('ABI data:', abi?.data);
|
|
47
|
-
scaffoldDebugger('ABI file:', abi?.file);
|
|
31
|
+
constructor(options) {
|
|
32
|
+
this.protocol = options.protocol;
|
|
33
|
+
this.abi = options.abi;
|
|
34
|
+
this.indexEvents = options.indexEvents;
|
|
35
|
+
this.contract = options.contract;
|
|
36
|
+
this.network = options.network;
|
|
37
|
+
this.contractName = options.contractName;
|
|
38
|
+
this.subgraphName = options.subgraphName;
|
|
39
|
+
this.startBlock = options.startBlock;
|
|
40
|
+
this.node = options.node;
|
|
41
|
+
this.spkgPath = options.spkgPath;
|
|
42
|
+
this.entities = options.entities;
|
|
48
43
|
}
|
|
49
44
|
async generatePackageJson() {
|
|
50
45
|
return await prettier.format(JSON.stringify({
|
|
@@ -155,21 +150,9 @@ dataSources:
|
|
|
155
150
|
}), { parser: 'typescript', semi: false, trailingComma: 'none' });
|
|
156
151
|
}
|
|
157
152
|
async generateABIs() {
|
|
158
|
-
scaffoldDebugger('Generating ABIs...');
|
|
159
|
-
scaffoldDebugger('Protocol has ABIs:', this.protocol.hasABIs());
|
|
160
|
-
scaffoldDebugger('ABI data:', this.abi?.data);
|
|
161
|
-
scaffoldDebugger('ABI file:', this.abi?.file);
|
|
162
|
-
if (!this.protocol.hasABIs()) {
|
|
163
|
-
scaffoldDebugger('Protocol does not have ABIs, skipping ABI generation');
|
|
164
|
-
return;
|
|
165
|
-
}
|
|
166
|
-
if (!this.abi?.data) {
|
|
167
|
-
scaffoldDebugger('ABI data is undefined, skipping ABI generation');
|
|
168
|
-
return;
|
|
169
|
-
}
|
|
170
153
|
return this.protocol.hasABIs()
|
|
171
154
|
? {
|
|
172
|
-
[`${this.contractName}.json`]: await prettier.format(JSON.stringify(this.abi
|
|
155
|
+
[`${this.contractName}.json`]: await prettier.format(JSON.stringify(this.abi?.data), {
|
|
173
156
|
parser: 'json',
|
|
174
157
|
}),
|
|
175
158
|
}
|
package/dist/subgraph.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import path from 'node:path';
|
|
2
|
+
import { fileURLToPath } from 'node:url';
|
|
2
3
|
import fs from 'fs-extra';
|
|
3
4
|
import * as graphql from 'graphql/language/index.js';
|
|
4
5
|
import immutable from 'immutable';
|
|
@@ -31,7 +32,7 @@ export default class Subgraph {
|
|
|
31
32
|
]);
|
|
32
33
|
}
|
|
33
34
|
// Parse the default subgraph schema
|
|
34
|
-
const schema = graphql.parse(await fs.readFile(path.join(
|
|
35
|
+
const schema = graphql.parse(await fs.readFile(path.join(fileURLToPath(import.meta.url), '..', 'protocols',
|
|
35
36
|
// TODO: substreams/triggers is a special case, should be handled better
|
|
36
37
|
protocol.name === 'substreams/triggers' ? 'substreams' : protocol.name, `manifest.graphql`), 'utf-8'));
|
|
37
38
|
// Obtain the root `SubgraphManifest` type from the schema
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"root":["../src/constants.ts","../src/debug.ts","../src/fetch.ts","../src/index.ts","../src/migrations.ts","../src/schema.ts","../src/subgraph.ts","../src/type-generator.ts","../src/utils.ts","../src/version.ts","../src/watcher.ts","../src/codegen/schema.test.ts","../src/codegen/schema.ts","../src/codegen/template.ts","../src/codegen/typescript.ts","../src/codegen/util.test.ts","../src/codegen/util.ts","../src/codegen/types/conversions.ts","../src/codegen/types/index.test.ts","../src/codegen/types/index.ts","../src/command-helpers/auth.ts","../src/command-helpers/compiler.test.ts","../src/command-helpers/compiler.ts","../src/command-helpers/contracts.test.ts","../src/command-helpers/contracts.ts","../src/command-helpers/data-sources.ts","../src/command-helpers/file-resolver.test.ts","../src/command-helpers/file-resolver.ts","../src/command-helpers/fs.ts","../src/command-helpers/ipfs.ts","../src/command-helpers/jsonrpc.ts","../src/command-helpers/network.test.ts","../src/command-helpers/network.ts","../src/command-helpers/node.ts","../src/command-helpers/prompt-manager.ts","../src/command-helpers/registry.ts","../src/command-helpers/retry.ts","../src/command-helpers/scaffold.ts","../src/command-helpers/sort.test.ts","../src/command-helpers/sort.ts","../src/command-helpers/spinner.ts","../src/command-helpers/subgraph.ts","../src/command-helpers/version.test.ts","../src/command-helpers/version.ts","../src/commands/add.ts","../src/commands/auth.ts","../src/commands/
|
|
1
|
+
{"root":["../src/constants.ts","../src/debug.ts","../src/fetch.ts","../src/index.ts","../src/migrations.ts","../src/schema.ts","../src/subgraph.ts","../src/type-generator.ts","../src/utils.ts","../src/version.ts","../src/watcher.ts","../src/codegen/schema.test.ts","../src/codegen/schema.ts","../src/codegen/template.ts","../src/codegen/typescript.ts","../src/codegen/util.test.ts","../src/codegen/util.ts","../src/codegen/types/conversions.ts","../src/codegen/types/index.test.ts","../src/codegen/types/index.ts","../src/command-helpers/auth.ts","../src/command-helpers/compiler.test.ts","../src/command-helpers/compiler.ts","../src/command-helpers/contracts.test.ts","../src/command-helpers/contracts.ts","../src/command-helpers/data-sources.ts","../src/command-helpers/file-resolver.test.ts","../src/command-helpers/file-resolver.ts","../src/command-helpers/fs.ts","../src/command-helpers/ipfs.ts","../src/command-helpers/jsonrpc.ts","../src/command-helpers/network.test.ts","../src/command-helpers/network.ts","../src/command-helpers/node.ts","../src/command-helpers/prompt-manager.ts","../src/command-helpers/registry.ts","../src/command-helpers/retry.ts","../src/command-helpers/scaffold.ts","../src/command-helpers/sort.test.ts","../src/command-helpers/sort.ts","../src/command-helpers/spinner.ts","../src/command-helpers/subgraph.ts","../src/command-helpers/version.test.ts","../src/command-helpers/version.ts","../src/commands/add.ts","../src/commands/auth.ts","../src/commands/build.ts","../src/commands/clean.ts","../src/commands/codegen.ts","../src/commands/create.ts","../src/commands/deploy.ts","../src/commands/init.ts","../src/commands/local.ts","../src/commands/publish.ts","../src/commands/remove.ts","../src/commands/test.ts","../src/compiler/asc.ts","../src/compiler/index.ts","../src/migrations/mapping_api_version_0_0_1.ts","../src/migrations/mapping_api_version_0_0_2.ts","../src/migrations/mapping_api_version_0_0_3.ts","../src/migrations/mapping_api_version_0_0_4.ts","../src/migrations/mapping_api_version_0_0_5.ts","../src/migrations/spec_version_0_0_2.ts","../src/migrations/spec_version_0_0_3.ts","../src/migrations/util/load-manifest.ts","../src/migrations/util/versions.ts","../src/protocols/contract.ts","../src/protocols/file_template.ts","../src/protocols/index.ts","../src/protocols/subgraph.ts","../src/protocols/arweave/subgraph.ts","../src/protocols/arweave/scaffold/manifest.ts","../src/protocols/arweave/scaffold/mapping.ts","../src/protocols/cosmos/subgraph.ts","../src/protocols/cosmos/scaffold/manifest.ts","../src/protocols/cosmos/scaffold/mapping.ts","../src/protocols/ethereum/abi.ts","../src/protocols/ethereum/contract.ts","../src/protocols/ethereum/subgraph.ts","../src/protocols/ethereum/type-generator.ts","../src/protocols/ethereum/codegen/abi.test.ts","../src/protocols/ethereum/codegen/abi.ts","../src/protocols/ethereum/codegen/template.ts","../src/protocols/ethereum/scaffold/manifest.ts","../src/protocols/ethereum/scaffold/mapping.ts","../src/protocols/near/contract.ts","../src/protocols/near/subgraph.ts","../src/protocols/near/scaffold/manifest.ts","../src/protocols/near/scaffold/mapping.ts","../src/protocols/subgraph/subgraph.ts","../src/protocols/subgraph/scaffold/manifest.ts","../src/protocols/subgraph/scaffold/mapping.ts","../src/protocols/substreams/subgraph.ts","../src/protocols/substreams/scaffold/manifest.ts","../src/scaffold/cosmos.test.ts","../src/scaffold/ethereum.test.ts","../src/scaffold/get-docker-file.ts","../src/scaffold/get-git-ignore.ts","../src/scaffold/index.ts","../src/scaffold/mapping.ts","../src/scaffold/near.test.ts","../src/scaffold/schema.ts","../src/scaffold/tests.ts","../src/validation/contract.ts","../src/validation/index.ts","../src/validation/manifest.ts","../src/validation/schema.test.ts","../src/validation/schema.ts"],"version":"5.7.2"}
|
package/dist/utils.d.ts
CHANGED
|
@@ -1,14 +1,2 @@
|
|
|
1
1
|
export declare const createIpfsClient: typeof import("kubo-rpc-client").create;
|
|
2
2
|
export declare function loadSubgraphSchemaFromIPFS(ipfsClient: any, manifest: string): Promise<string>;
|
|
3
|
-
export declare function loadManifestFromIPFS(ipfsClient: any, manifest: string): Promise<string>;
|
|
4
|
-
/**
|
|
5
|
-
* Validates that the network of a source subgraph matches the target network
|
|
6
|
-
* @param ipfsClient IPFS client instance
|
|
7
|
-
* @param sourceSubgraphId IPFS hash of the source subgraph
|
|
8
|
-
* @param targetNetwork Network of the target subgraph being created
|
|
9
|
-
* @returns Object containing validation result and error message if any
|
|
10
|
-
*/
|
|
11
|
-
export declare function validateSubgraphNetworkMatch(ipfsClient: any, sourceSubgraphId: string, targetNetwork: string): Promise<{
|
|
12
|
-
valid: boolean;
|
|
13
|
-
error?: string;
|
|
14
|
-
}>;
|
package/dist/utils.js
CHANGED
|
@@ -27,59 +27,3 @@ export async function loadSubgraphSchemaFromIPFS(ipfsClient, manifest) {
|
|
|
27
27
|
throw Error(`Failed to load schema from IPFS ${manifest}`);
|
|
28
28
|
}
|
|
29
29
|
}
|
|
30
|
-
export async function loadManifestFromIPFS(ipfsClient, manifest) {
|
|
31
|
-
try {
|
|
32
|
-
const manifestBuffer = ipfsClient.cat(manifest);
|
|
33
|
-
let manifestFile = '';
|
|
34
|
-
for await (const chunk of manifestBuffer) {
|
|
35
|
-
manifestFile += Buffer.from(chunk).toString('utf8');
|
|
36
|
-
}
|
|
37
|
-
return manifestFile;
|
|
38
|
-
}
|
|
39
|
-
catch (e) {
|
|
40
|
-
utilsDebug.extend('loadManifestFromIPFS')(`Failed to load manifest from IPFS ${manifest}`);
|
|
41
|
-
utilsDebug.extend('loadManifestFromIPFS')(e);
|
|
42
|
-
throw Error(`Failed to load manifest from IPFS ${manifest}`);
|
|
43
|
-
}
|
|
44
|
-
}
|
|
45
|
-
/**
|
|
46
|
-
* Validates that the network of a source subgraph matches the target network
|
|
47
|
-
* @param ipfsClient IPFS client instance
|
|
48
|
-
* @param sourceSubgraphId IPFS hash of the source subgraph
|
|
49
|
-
* @param targetNetwork Network of the target subgraph being created
|
|
50
|
-
* @returns Object containing validation result and error message if any
|
|
51
|
-
*/
|
|
52
|
-
export async function validateSubgraphNetworkMatch(ipfsClient, sourceSubgraphId, targetNetwork) {
|
|
53
|
-
try {
|
|
54
|
-
const manifestFile = await loadManifestFromIPFS(ipfsClient, sourceSubgraphId);
|
|
55
|
-
const manifestYaml = yaml.load(manifestFile);
|
|
56
|
-
// Extract network from data sources
|
|
57
|
-
const dataSources = manifestYaml.dataSources || [];
|
|
58
|
-
const templates = manifestYaml.templates || [];
|
|
59
|
-
const allSources = [...dataSources, ...templates];
|
|
60
|
-
if (allSources.length === 0) {
|
|
61
|
-
return { valid: true }; // No data sources to validate
|
|
62
|
-
}
|
|
63
|
-
// Get network from first data source
|
|
64
|
-
const sourceNetwork = allSources[0].network;
|
|
65
|
-
if (!sourceNetwork) {
|
|
66
|
-
return { valid: true }; // Network not specified in source, skip validation
|
|
67
|
-
}
|
|
68
|
-
const normalizedSourceNetwork = sourceNetwork.toLowerCase();
|
|
69
|
-
const normalizedTargetNetwork = targetNetwork.toLowerCase();
|
|
70
|
-
if (normalizedSourceNetwork !== normalizedTargetNetwork) {
|
|
71
|
-
return {
|
|
72
|
-
valid: false,
|
|
73
|
-
error: `Network mismatch: The source subgraph is indexing the '${sourceNetwork}' network, but you're creating a subgraph for '${targetNetwork}' network. When composing subgraphs, they must index the same network.`,
|
|
74
|
-
};
|
|
75
|
-
}
|
|
76
|
-
return { valid: true };
|
|
77
|
-
}
|
|
78
|
-
catch (e) {
|
|
79
|
-
utilsDebug.extend('validateSubgraphNetworkMatch')(`Failed to validate network match: ${e}`);
|
|
80
|
-
return {
|
|
81
|
-
valid: false,
|
|
82
|
-
error: e instanceof Error ? e.message : 'Failed to validate subgraph network',
|
|
83
|
-
};
|
|
84
|
-
}
|
|
85
|
-
}
|
package/dist/version.js
CHANGED
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
import fs from 'node:fs';
|
|
2
2
|
import path from 'node:path';
|
|
3
|
+
import { fileURLToPath } from 'node:url';
|
|
3
4
|
const packageJson = JSON.parse(fs
|
|
4
5
|
.readFileSync(
|
|
5
6
|
// works even when bundled/built because the path to package.json is the same
|
|
6
|
-
path.join(
|
|
7
|
+
path.join(fileURLToPath(import.meta.url), '..', '..', 'package.json'))
|
|
7
8
|
.toString());
|
|
8
9
|
export const version = packageJson.version;
|
|
9
10
|
export const nodeVersion = (packageJson.engines?.node ?? '');
|
package/oclif.manifest.json
CHANGED
package/package.json
CHANGED
|
@@ -1,8 +1,13 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@graphprotocol/graph-cli",
|
|
3
|
-
"version": "0.95.0
|
|
3
|
+
"version": "0.95.0",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "CLI for building for and deploying to The Graph",
|
|
6
|
+
"repository": {
|
|
7
|
+
"type": "git",
|
|
8
|
+
"url": "https://github.com/graphprotocol/graph-tooling.git",
|
|
9
|
+
"directory": "packages/cli"
|
|
10
|
+
},
|
|
6
11
|
"license": "(Apache-2.0 OR MIT)",
|
|
7
12
|
"engines": {
|
|
8
13
|
"node": ">=20.18.1"
|
|
@@ -29,7 +34,6 @@
|
|
|
29
34
|
"@pinax/graph-networks-registry": "^0.6.5",
|
|
30
35
|
"@whatwg-node/fetch": "^0.10.1",
|
|
31
36
|
"assemblyscript": "0.19.23",
|
|
32
|
-
"binary-install": "^1.1.0",
|
|
33
37
|
"chokidar": "4.0.1",
|
|
34
38
|
"debug": "4.3.7",
|
|
35
39
|
"docker-compose": "1.1.0",
|
|
@@ -45,7 +49,7 @@
|
|
|
45
49
|
"prettier": "3.4.2",
|
|
46
50
|
"semver": "7.6.3",
|
|
47
51
|
"tmp-promise": "3.0.3",
|
|
48
|
-
"undici": "7.
|
|
52
|
+
"undici": "7.2.3",
|
|
49
53
|
"web3-eth-abi": "4.4.1",
|
|
50
54
|
"yaml": "2.6.1"
|
|
51
55
|
},
|
|
@@ -63,7 +67,8 @@
|
|
|
63
67
|
"vitest": "^2.1.8"
|
|
64
68
|
},
|
|
65
69
|
"publishConfig": {
|
|
66
|
-
"access": "public"
|
|
70
|
+
"access": "public",
|
|
71
|
+
"provenance": true
|
|
67
72
|
},
|
|
68
73
|
"oclif": {
|
|
69
74
|
"bin": "graph",
|