@graphprotocol/graph-cli 0.30.0-alpha.1 → 0.30.2
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/examples/basic-event-handlers/node_modules/@graphprotocol/graph-ts/chain/arweave.ts +76 -0
- package/examples/basic-event-handlers/node_modules/@graphprotocol/graph-ts/chain/cosmos.ts +341 -0
- package/examples/basic-event-handlers/node_modules/@graphprotocol/graph-ts/chain/ethereum.ts +39 -0
- package/examples/basic-event-handlers/node_modules/@graphprotocol/graph-ts/global/global.ts +286 -142
- package/examples/basic-event-handlers/node_modules/@graphprotocol/graph-ts/index.ts +4 -2
- package/examples/basic-event-handlers/node_modules/@graphprotocol/graph-ts/package.json +2 -1
- package/examples/basic-event-handlers/node_modules/@graphprotocol/graph-ts/test/test.js +4 -2
- package/examples/basic-event-handlers/node_modules/keccak/build/config.gypi +300 -125
- package/examples/basic-event-handlers/node_modules/websocket/build/config.gypi +292 -15
- package/examples/basic-event-handlers/package.json +1 -1
- package/examples/basic-event-handlers/yarn.lock +4 -4
- package/examples/example-subgraph/package.json +1 -1
- package/examples/example-subgraph/yarn.lock +4 -4
- package/package.json +1 -1
- package/src/codegen/schema.js +5 -1
- package/src/codegen/schema.test.js +102 -0
- package/src/command-helpers/abi.js +69 -0
- package/src/command-helpers/scaffold.js +65 -0
- package/src/commands/add.js +198 -0
- package/src/commands/init.js +23 -72
- package/src/migrations.js +0 -2
- package/src/protocols/arweave/manifest.graphql +57 -0
- package/src/protocols/arweave/scaffold/manifest.js +19 -0
- package/src/protocols/arweave/scaffold/mapping.js +53 -0
- package/src/protocols/arweave/subgraph.js +20 -0
- package/src/protocols/{tendermint → cosmos}/manifest.graphql +6 -0
- package/src/protocols/cosmos/scaffold/manifest.js +16 -0
- package/src/protocols/cosmos/scaffold/mapping.js +39 -0
- package/src/protocols/{tendermint → cosmos}/subgraph.js +2 -1
- package/src/protocols/ethereum/codegen/abi.js +21 -4
- package/src/protocols/ethereum/scaffold/manifest.js +2 -1
- package/src/protocols/index.js +51 -18
- package/src/protocols/near/manifest.graphql +1 -0
- package/src/protocols/near/scaffold/manifest.js +4 -2
- package/src/scaffold/cosmos.test.js +86 -0
- package/src/scaffold/ethereum.test.js +2 -2
- package/src/scaffold/index.js +3 -2
- package/src/scaffold/near.test.js +2 -2
- package/src/validation/schema.js +2 -0
- package/examples/basic-event-handlers/node_modules/@graphprotocol/graph-ts/chain/tendermint.ts +0 -554
- package/examples/basic-event-handlers/node_modules/keccak/build/Makefile +0 -342
- package/examples/basic-event-handlers/node_modules/keccak/build/Release/.deps/Release/obj.target/keccak/src/addon.o.d.raw +0 -27
- package/examples/basic-event-handlers/node_modules/keccak/build/binding.Makefile +0 -6
- package/examples/basic-event-handlers/node_modules/keccak/build/gyp-mac-tool +0 -615
- package/examples/basic-event-handlers/node_modules/keccak/build/keccak.target.mk +0 -209
- package/examples/basic-event-handlers/node_modules/websocket/build/Makefile +0 -347
- package/examples/basic-event-handlers/node_modules/websocket/build/Release/.deps/Release/obj.target/bufferutil/src/bufferutil.o.d.raw +0 -25
- package/examples/basic-event-handlers/node_modules/websocket/build/binding.Makefile +0 -6
- package/examples/basic-event-handlers/node_modules/websocket/build/bufferutil.target.mk +0 -192
- package/examples/basic-event-handlers/node_modules/websocket/build/gyp-mac-tool +0 -615
- package/examples/basic-event-handlers/node_modules/websocket/build/validation.target.mk +0 -192
- package/src/codegen/types/defaults.js +0 -34
- package/src/migrations/mapping_api_version_0_0_6.js +0 -74
- package/src/migrations/spec_version_0_0_4.js +0 -25
- package/tests/cli/init/ethereum/from-example/.gitattributes +0 -1
- package/tests/cli/init/ethereum/from-example/LICENSE +0 -21
- package/tests/cli/init/ethereum/from-example/README.md +0 -3
- package/tests/cli/init/ethereum/from-example/abis/Gravity.json +0 -1
- package/tests/cli/init/ethereum/from-example/bin/Counter.bin +0 -1
- package/tests/cli/init/ethereum/from-example/contracts/Gravity.sol +0 -63
- package/tests/cli/init/ethereum/from-example/contracts/Migrations.sol +0 -23
- package/tests/cli/init/ethereum/from-example/docker-compose.yml +0 -39
- package/tests/cli/init/ethereum/from-example/migrations/1_initial_migration.js +0 -5
- package/tests/cli/init/ethereum/from-example/migrations/2_deploy_contract.js +0 -5
- package/tests/cli/init/ethereum/from-example/migrations/3_create_gravatars.js +0 -15
- package/tests/cli/init/ethereum/from-example/networks.json +0 -7
- package/tests/cli/init/ethereum/from-example/package.json +0 -23
- package/tests/cli/init/ethereum/from-example/schema.graphql +0 -6
- package/tests/cli/init/ethereum/from-example/src/mapping.ts +0 -22
- package/tests/cli/init/ethereum/from-example/subgraph.yaml +0 -27
- package/tests/cli/init/ethereum/from-example/truffle.js +0 -27
- package/tests/cli/init/ethereum/from-example/yarn.lock +0 -5977
|
@@ -1,8 +1,28 @@
|
|
|
1
1
|
const fs = require('fs-extra')
|
|
2
2
|
const path = require('path')
|
|
3
|
+
const prettier = require('prettier')
|
|
4
|
+
const yaml = require('yaml')
|
|
3
5
|
|
|
4
6
|
const { step } = require('./spinner')
|
|
5
7
|
const Scaffold = require('../scaffold')
|
|
8
|
+
const { generateEventIndexingHandlers } = require('../scaffold/mapping')
|
|
9
|
+
const { generateEventType, abiEvents } = require('../scaffold/schema')
|
|
10
|
+
const { strings } = require('gluegun')
|
|
11
|
+
const { Map } = require('immutable')
|
|
12
|
+
|
|
13
|
+
const generateDataSource = async (protocol, contractName, network, contractAddress, abi) => {
|
|
14
|
+
const protocolManifest = protocol.getManifestScaffold()
|
|
15
|
+
|
|
16
|
+
return Map.of(
|
|
17
|
+
'kind', protocol.name,
|
|
18
|
+
'name', contractName,
|
|
19
|
+
'network', network,
|
|
20
|
+
'source', yaml.parse(prettier.format(protocolManifest.source({contract: contractAddress, contractName}),
|
|
21
|
+
{parser: 'yaml'})),
|
|
22
|
+
'mapping', yaml.parse(prettier.format(protocolManifest.mapping({abi, contractName}),
|
|
23
|
+
{parser: 'yaml'}))
|
|
24
|
+
).asMutable()
|
|
25
|
+
}
|
|
6
26
|
|
|
7
27
|
const generateScaffold = async (
|
|
8
28
|
{
|
|
@@ -59,8 +79,53 @@ const writeScaffold = async (scaffold, directory, spinner) => {
|
|
|
59
79
|
await writeScaffoldDirectory(scaffold, directory, spinner)
|
|
60
80
|
}
|
|
61
81
|
|
|
82
|
+
const writeABI = async (abi, contractName, abiPath = `./abis/${contractName}.json`) => {
|
|
83
|
+
let data = prettier.format(JSON.stringify(abi.data), {
|
|
84
|
+
parser: 'json',
|
|
85
|
+
})
|
|
86
|
+
|
|
87
|
+
await fs.writeFile(abiPath, data, { encoding: 'utf-8' })
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
const writeSchema = async (abi, protocol, schemaPath, entities) => {
|
|
91
|
+
const events = protocol.hasEvents()
|
|
92
|
+
? abiEvents(abi).filter(event => entities.indexOf(event.get('name')) === -1).toJS()
|
|
93
|
+
: []
|
|
94
|
+
|
|
95
|
+
let data = prettier.format(
|
|
96
|
+
events.map(
|
|
97
|
+
event => generateEventType(event, protocol.name)
|
|
98
|
+
).join('\n\n'),
|
|
99
|
+
{
|
|
100
|
+
parser: 'graphql',
|
|
101
|
+
},
|
|
102
|
+
)
|
|
103
|
+
|
|
104
|
+
await fs.appendFile(schemaPath, data, { encoding: 'utf-8' })
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
const writeMapping = async (abi, protocol, contractName, entities) => {
|
|
108
|
+
const events = protocol.hasEvents()
|
|
109
|
+
? abiEvents(abi).filter(event => entities.indexOf(event.get('name')) === -1).toJS()
|
|
110
|
+
: []
|
|
111
|
+
|
|
112
|
+
let mapping = prettier.format(
|
|
113
|
+
generateEventIndexingHandlers(
|
|
114
|
+
events,
|
|
115
|
+
contractName,
|
|
116
|
+
),
|
|
117
|
+
{ parser: 'typescript', semi: false },
|
|
118
|
+
)
|
|
119
|
+
|
|
120
|
+
await fs.writeFile(`./src/${strings.kebabCase(contractName)}.ts`, mapping, { encoding: 'utf-8' })
|
|
121
|
+
}
|
|
122
|
+
|
|
62
123
|
module.exports = {
|
|
63
124
|
...module.exports,
|
|
64
125
|
generateScaffold,
|
|
65
126
|
writeScaffold,
|
|
127
|
+
generateDataSource,
|
|
128
|
+
writeABI,
|
|
129
|
+
writeSchema,
|
|
130
|
+
writeMapping,
|
|
66
131
|
}
|
|
@@ -0,0 +1,198 @@
|
|
|
1
|
+
const chalk = require('chalk')
|
|
2
|
+
const toolbox = require('gluegun/toolbox')
|
|
3
|
+
const immutable = require('immutable')
|
|
4
|
+
const { withSpinner } = require('../command-helpers/spinner')
|
|
5
|
+
const Subgraph = require('../subgraph')
|
|
6
|
+
const Protocol = require('../protocols')
|
|
7
|
+
const DataSourcesExtractor = require('../command-helpers/data-sources')
|
|
8
|
+
const { generateDataSource, writeABI, writeSchema, writeMapping } = require('../command-helpers/scaffold')
|
|
9
|
+
const { loadAbiFromEtherscan, loadAbiFromBlockScout } = require('../command-helpers/abi')
|
|
10
|
+
const EthereumABI = require('../protocols/ethereum/abi')
|
|
11
|
+
const { fixParameters } = require('../command-helpers/gluegun')
|
|
12
|
+
|
|
13
|
+
const HELP = `
|
|
14
|
+
${chalk.bold('graph add')} <address> [<subgraph-manifest default: "./subgraph.yaml">]
|
|
15
|
+
|
|
16
|
+
${chalk.dim('Options:')}
|
|
17
|
+
|
|
18
|
+
--abi <path> Path to the contract ABI (default: download from Etherscan)
|
|
19
|
+
--contract-name Name of the contract (default: Contract)
|
|
20
|
+
--merge-entities Whether to merge entities with the same name (default: false)
|
|
21
|
+
-h, --help Show usage information
|
|
22
|
+
`
|
|
23
|
+
|
|
24
|
+
module.exports = {
|
|
25
|
+
description: 'Creates a new subgraph with basic scaffolding',
|
|
26
|
+
run: async toolbox => {
|
|
27
|
+
// Obtain tools
|
|
28
|
+
let { print, system } = toolbox
|
|
29
|
+
|
|
30
|
+
// Read CLI parameters
|
|
31
|
+
let {
|
|
32
|
+
abi,
|
|
33
|
+
contractName,
|
|
34
|
+
h,
|
|
35
|
+
help,
|
|
36
|
+
mergeEntities
|
|
37
|
+
} = toolbox.parameters.options
|
|
38
|
+
|
|
39
|
+
let address = toolbox.parameters.first
|
|
40
|
+
let manifestPath = toolbox.parameters.second || './subgraph.yaml'
|
|
41
|
+
contractName = contractName || 'Contract'
|
|
42
|
+
|
|
43
|
+
// Validate the address
|
|
44
|
+
if (!address) {
|
|
45
|
+
print.error('No contract address provided')
|
|
46
|
+
process.exitCode = 1
|
|
47
|
+
return
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
try {
|
|
51
|
+
fixParameters(toolbox.parameters, {
|
|
52
|
+
h,
|
|
53
|
+
help,
|
|
54
|
+
mergeEntities,
|
|
55
|
+
})
|
|
56
|
+
} catch (e) {
|
|
57
|
+
print.error(e.message)
|
|
58
|
+
process.exitCode = 1
|
|
59
|
+
return
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
// Show help text if requested
|
|
63
|
+
if (help || h) {
|
|
64
|
+
print.info(HELP)
|
|
65
|
+
return
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
const dataSourcesAndTemplates = await DataSourcesExtractor.fromFilePath(manifestPath)
|
|
69
|
+
let protocol = Protocol.fromDataSources(dataSourcesAndTemplates)
|
|
70
|
+
let manifest = await Subgraph.load(manifestPath, { protocol })
|
|
71
|
+
let network = manifest.result.get('dataSources').get(0).get('network')
|
|
72
|
+
let result = manifest.result.asMutable()
|
|
73
|
+
|
|
74
|
+
let entities = getEntities(manifest)
|
|
75
|
+
let contractNames = getContractNames(manifest)
|
|
76
|
+
if (contractNames.indexOf(contractName) !== -1) {
|
|
77
|
+
print.error(
|
|
78
|
+
`Datasource or template with name ${contractName} already exists, please choose a different name`,
|
|
79
|
+
)
|
|
80
|
+
process.exitCode = 1
|
|
81
|
+
return
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
let ethabi = null
|
|
85
|
+
if (abi) {
|
|
86
|
+
ethabi = EthereumABI.load(contractName, abi)
|
|
87
|
+
} else {
|
|
88
|
+
if (network === 'poa-core') {
|
|
89
|
+
ethabi = await loadAbiFromBlockScout(EthereumABI, network, address)
|
|
90
|
+
} else {
|
|
91
|
+
ethabi = await loadAbiFromEtherscan(EthereumABI, network, address)
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
let { collisionEntities, onlyCollisions, abiData } = updateEventNamesOnCollision(ethabi, entities, contractName, mergeEntities)
|
|
96
|
+
ethabi.data = abiData
|
|
97
|
+
|
|
98
|
+
await writeABI(ethabi, contractName, abi)
|
|
99
|
+
await writeSchema(ethabi, protocol, result.getIn(['schema', 'file']), collisionEntities)
|
|
100
|
+
await writeMapping(ethabi, protocol, contractName, collisionEntities)
|
|
101
|
+
|
|
102
|
+
let dataSources = result.get('dataSources')
|
|
103
|
+
let dataSource = await generateDataSource(protocol,
|
|
104
|
+
contractName, network, address, ethabi)
|
|
105
|
+
|
|
106
|
+
// Handle the collisions edge case by copying another data source yaml data
|
|
107
|
+
if (mergeEntities && onlyCollisions) {
|
|
108
|
+
let firstDataSource = dataSources.get(0)
|
|
109
|
+
let source = dataSource.get('source')
|
|
110
|
+
let mapping = firstDataSource.get('mapping').asMutable()
|
|
111
|
+
|
|
112
|
+
// Save the address of the new data source
|
|
113
|
+
source.abi = firstDataSource.get('source').get('abi')
|
|
114
|
+
|
|
115
|
+
dataSource.set('mapping', mapping)
|
|
116
|
+
dataSource.set('source', source)
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
result.set('dataSources', dataSources.push(dataSource))
|
|
120
|
+
|
|
121
|
+
await Subgraph.write(result, manifestPath)
|
|
122
|
+
|
|
123
|
+
// Detect Yarn and/or NPM
|
|
124
|
+
let yarn = await system.which('yarn')
|
|
125
|
+
let npm = await system.which('npm')
|
|
126
|
+
if (!yarn && !npm) {
|
|
127
|
+
print.error(
|
|
128
|
+
`Neither Yarn nor NPM were found on your system. Please install one of them.`,
|
|
129
|
+
)
|
|
130
|
+
process.exitCode = 1
|
|
131
|
+
return
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
await withSpinner(
|
|
135
|
+
'Running codegen',
|
|
136
|
+
'Failed to run codegen',
|
|
137
|
+
'Warning during codegen',
|
|
138
|
+
async spinner => {
|
|
139
|
+
await system.run(yarn ? 'yarn codegen' : 'npm run codegen')
|
|
140
|
+
}
|
|
141
|
+
)
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
const getEntities = (manifest) => {
|
|
146
|
+
let dataSources = manifest.result.get('dataSources', immutable.List())
|
|
147
|
+
let templates = manifest.result.get('templates', immutable.List())
|
|
148
|
+
|
|
149
|
+
return dataSources
|
|
150
|
+
.concat(templates)
|
|
151
|
+
.map(dataSource => dataSource.getIn(['mapping', 'entities']))
|
|
152
|
+
.flatten()
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
const getContractNames = (manifest) => {
|
|
156
|
+
let dataSources = manifest.result.get('dataSources', immutable.List())
|
|
157
|
+
let templates = manifest.result.get('templates', immutable.List())
|
|
158
|
+
|
|
159
|
+
return dataSources
|
|
160
|
+
.concat(templates)
|
|
161
|
+
.map(dataSource => dataSource.get('name'))
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
const updateEventNamesOnCollision = (ethabi, entities, contractName, mergeEntities) => {
|
|
165
|
+
let abiData = ethabi.data
|
|
166
|
+
let { print } = toolbox
|
|
167
|
+
let collisionEntities = []
|
|
168
|
+
let onlyCollisions = true
|
|
169
|
+
|
|
170
|
+
for (let i = 0; i < abiData.size; i++) {
|
|
171
|
+
let dataRow = abiData.get(i).asMutable()
|
|
172
|
+
|
|
173
|
+
if (dataRow.get('type') === 'event'){
|
|
174
|
+
if (entities.indexOf(dataRow.get('name')) !== -1) {
|
|
175
|
+
if (entities.indexOf(`${contractName}${dataRow.get('name')}`) !== -1) {
|
|
176
|
+
print.error(`Contract name ('${contractName}')
|
|
177
|
+
+ event name ('${dataRow.get('name')}') entity already exists.`)
|
|
178
|
+
process.exitCode = 1
|
|
179
|
+
return
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
if (mergeEntities) {
|
|
183
|
+
collisionEntities.push(dataRow.get('name'))
|
|
184
|
+
abiData = abiData.asImmutable().delete(i) // needs to be immutable when deleting, yes you read that right - https://github.com/immutable-js/immutable-js/issues/1901
|
|
185
|
+
i-- // deletion also shifts values to the left
|
|
186
|
+
continue
|
|
187
|
+
} else {
|
|
188
|
+
dataRow.set('name', `${contractName}${dataRow.get('name')}`)
|
|
189
|
+
}
|
|
190
|
+
} else {
|
|
191
|
+
onlyCollisions = false
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
abiData = abiData.asMutable().set(i, dataRow)
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
return { abiData, collisionEntities, onlyCollisions }
|
|
198
|
+
}
|
package/src/commands/init.js
CHANGED
|
@@ -16,6 +16,7 @@ const { initNetworksConfig } = require('../command-helpers/network')
|
|
|
16
16
|
const { withSpinner, step } = require('../command-helpers/spinner')
|
|
17
17
|
const { fixParameters } = require('../command-helpers/gluegun')
|
|
18
18
|
const { chooseNodeUrl } = require('../command-helpers/node')
|
|
19
|
+
const { loadAbiFromEtherscan, loadAbiFromBlockScout } = require('../command-helpers/abi')
|
|
19
20
|
const { generateScaffold, writeScaffold } = require('../command-helpers/scaffold')
|
|
20
21
|
const { abiEvents } = require('../scaffold/schema')
|
|
21
22
|
const { validateContract } = require('../validation')
|
|
@@ -57,6 +58,11 @@ ${chalk.dim.underline('NEAR:')}
|
|
|
57
58
|
|
|
58
59
|
--network <${availableNetworks.get('near').join('|')}>
|
|
59
60
|
Selects the network the contract is deployed to
|
|
61
|
+
|
|
62
|
+
${chalk.dim.underline('Cosmos:')}
|
|
63
|
+
|
|
64
|
+
--network <${availableNetworks.get('cosmos').join('|')}>
|
|
65
|
+
Selects the network the contract is deployed to
|
|
60
66
|
`
|
|
61
67
|
|
|
62
68
|
const processInitForm = async (
|
|
@@ -169,6 +175,11 @@ const processInitForm = async (
|
|
|
169
175
|
return value
|
|
170
176
|
},
|
|
171
177
|
},
|
|
178
|
+
// TODO:
|
|
179
|
+
//
|
|
180
|
+
// protocols that don't support contract
|
|
181
|
+
// - arweave
|
|
182
|
+
// - cosmos
|
|
172
183
|
{
|
|
173
184
|
type: 'input',
|
|
174
185
|
name: 'contract',
|
|
@@ -176,10 +187,10 @@ const processInitForm = async (
|
|
|
176
187
|
ProtocolContract = protocolInstance.getContract()
|
|
177
188
|
return `Contract ${ProtocolContract.identifierName()}`
|
|
178
189
|
},
|
|
179
|
-
skip: fromExample !== undefined,
|
|
190
|
+
skip: () => fromExample !== undefined || !protocolInstance.hasContract(),
|
|
180
191
|
initial: contract,
|
|
181
192
|
validate: async value => {
|
|
182
|
-
if (fromExample !== undefined) {
|
|
193
|
+
if (fromExample !== undefined || !protocolInstance.hasContract()) {
|
|
183
194
|
return true
|
|
184
195
|
}
|
|
185
196
|
|
|
@@ -237,11 +248,11 @@ const processInitForm = async (
|
|
|
237
248
|
name: 'contractName',
|
|
238
249
|
message: 'Contract Name',
|
|
239
250
|
initial: contractName || 'Contract',
|
|
240
|
-
skip: () => fromExample !== undefined,
|
|
251
|
+
skip: () => fromExample !== undefined || !protocolInstance.hasContract(),
|
|
241
252
|
validate: value => value && value.length > 0,
|
|
242
253
|
result: value => {
|
|
243
|
-
contractName = value
|
|
244
|
-
return value
|
|
254
|
+
contractName = value
|
|
255
|
+
return value
|
|
245
256
|
}
|
|
246
257
|
},
|
|
247
258
|
]
|
|
@@ -254,68 +265,6 @@ const processInitForm = async (
|
|
|
254
265
|
}
|
|
255
266
|
}
|
|
256
267
|
|
|
257
|
-
const loadAbiFromBlockScout = async (ABI, network, address) =>
|
|
258
|
-
await withSpinner(
|
|
259
|
-
`Fetching ABI from BlockScout`,
|
|
260
|
-
`Failed to fetch ABI from BlockScout`,
|
|
261
|
-
`Warnings while fetching ABI from BlockScout`,
|
|
262
|
-
async spinner => {
|
|
263
|
-
let result = await fetch(
|
|
264
|
-
`https://blockscout.com/${
|
|
265
|
-
network.replace('-', '/')
|
|
266
|
-
}/api?module=contract&action=getabi&address=${address}`,
|
|
267
|
-
)
|
|
268
|
-
let json = await result.json()
|
|
269
|
-
|
|
270
|
-
// BlockScout returns a JSON object that has a `status`, a `message` and
|
|
271
|
-
// a `result` field. The `status` is '0' in case of errors and '1' in
|
|
272
|
-
// case of success
|
|
273
|
-
if (json.status === '1') {
|
|
274
|
-
return new ABI('Contract', undefined, immutable.fromJS(JSON.parse(json.result)))
|
|
275
|
-
} else {
|
|
276
|
-
throw new Error('ABI not found, try loading it from a local file')
|
|
277
|
-
}
|
|
278
|
-
},
|
|
279
|
-
)
|
|
280
|
-
|
|
281
|
-
const getEtherscanLikeAPIUrl = (network) => {
|
|
282
|
-
switch(network){
|
|
283
|
-
case "mainnet": return `https://api.etherscan.io/api`;
|
|
284
|
-
case "arbitrum-one": return `https://api.arbiscan.io/api`;
|
|
285
|
-
case "bsc": return `https://api.bscscan.com/api`;
|
|
286
|
-
case "matic": return `https://api.polygonscan.com/api`;
|
|
287
|
-
case "mumbai": return `https://api-testnet.polygonscan.com/api`;
|
|
288
|
-
case "aurora": return `https://api.aurorascan.dev/api`;
|
|
289
|
-
case "aurora-testnet": return `https://api-testnet.aurorascan.dev/api`;
|
|
290
|
-
case "optimism-kovan": return `https://api-kovan-optimistic.etherscan.io/api`;
|
|
291
|
-
case "avalanche": return `https://api.snowtrace.io/api`;
|
|
292
|
-
default: return `https://api-${network}.etherscan.io/api`;
|
|
293
|
-
}
|
|
294
|
-
}
|
|
295
|
-
|
|
296
|
-
const loadAbiFromEtherscan = async (ABI, network, address) =>
|
|
297
|
-
await withSpinner(
|
|
298
|
-
`Fetching ABI from Etherscan`,
|
|
299
|
-
`Failed to fetch ABI from Etherscan`,
|
|
300
|
-
`Warnings while fetching ABI from Etherscan`,
|
|
301
|
-
async spinner => {
|
|
302
|
-
const scanApiUrl = getEtherscanLikeAPIUrl(network);
|
|
303
|
-
let result = await fetch(
|
|
304
|
-
`${scanApiUrl}?module=contract&action=getabi&address=${address}`,
|
|
305
|
-
)
|
|
306
|
-
let json = await result.json()
|
|
307
|
-
|
|
308
|
-
// Etherscan returns a JSON object that has a `status`, a `message` and
|
|
309
|
-
// a `result` field. The `status` is '0' in case of errors and '1' in
|
|
310
|
-
// case of success
|
|
311
|
-
if (json.status === '1') {
|
|
312
|
-
return new ABI('Contract', undefined, immutable.fromJS(JSON.parse(json.result)))
|
|
313
|
-
} else {
|
|
314
|
-
throw new Error('ABI not found, try loading it from a local file')
|
|
315
|
-
}
|
|
316
|
-
},
|
|
317
|
-
)
|
|
318
|
-
|
|
319
268
|
const loadAbiFromFile = async (ABI, filename) => {
|
|
320
269
|
let exists = await toolbox.filesystem.exists(filename)
|
|
321
270
|
|
|
@@ -836,11 +785,13 @@ const initSubgraphFromContract = async (
|
|
|
836
785
|
return
|
|
837
786
|
}
|
|
838
787
|
|
|
839
|
-
|
|
840
|
-
|
|
841
|
-
|
|
842
|
-
|
|
843
|
-
|
|
788
|
+
if (protocolInstance.hasContract()) {
|
|
789
|
+
let identifierName = protocolInstance.getContract().identifierName()
|
|
790
|
+
let networkConf = await initNetworksConfig(toolbox, directory, identifierName)
|
|
791
|
+
if (networkConf !== true) {
|
|
792
|
+
process.exitCode = 1
|
|
793
|
+
return
|
|
794
|
+
}
|
|
844
795
|
}
|
|
845
796
|
|
|
846
797
|
// Initialize a fresh Git repository
|
package/src/migrations.js
CHANGED
|
@@ -6,10 +6,8 @@ const MIGRATIONS = [
|
|
|
6
6
|
require('./migrations/mapping_api_version_0_0_3'),
|
|
7
7
|
require('./migrations/mapping_api_version_0_0_4'),
|
|
8
8
|
require('./migrations/mapping_api_version_0_0_5'),
|
|
9
|
-
require('./migrations/mapping_api_version_0_0_6'),
|
|
10
9
|
require('./migrations/spec_version_0_0_2'),
|
|
11
10
|
require('./migrations/spec_version_0_0_3'),
|
|
12
|
-
require('./migrations/spec_version_0_0_4'),
|
|
13
11
|
]
|
|
14
12
|
|
|
15
13
|
const applyMigrations = async options =>
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
# Each referenced type's in any of the types below must be listed
|
|
2
|
+
# here either as `scalar` or `type` for the validation code to work
|
|
3
|
+
# properly.
|
|
4
|
+
#
|
|
5
|
+
# That's why `String` is listed as a scalar even though it's built-in
|
|
6
|
+
# GraphQL basic types.
|
|
7
|
+
scalar String
|
|
8
|
+
scalar File
|
|
9
|
+
scalar BigInt
|
|
10
|
+
|
|
11
|
+
type SubgraphManifest {
|
|
12
|
+
specVersion: String!
|
|
13
|
+
schema: Schema!
|
|
14
|
+
description: String
|
|
15
|
+
repository: String
|
|
16
|
+
graft: Graft
|
|
17
|
+
dataSources: [DataSource!]!
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
type Schema {
|
|
21
|
+
file: File!
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
type DataSource {
|
|
25
|
+
kind: String!
|
|
26
|
+
name: String!
|
|
27
|
+
network: String
|
|
28
|
+
source: ContractSource!
|
|
29
|
+
mapping: ContractMapping!
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
type ContractSource {
|
|
33
|
+
owner: String
|
|
34
|
+
startBlock: BigInt
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
type ContractMapping {
|
|
38
|
+
apiVersion: String!
|
|
39
|
+
language: String!
|
|
40
|
+
file: File!
|
|
41
|
+
entities: [String!]!
|
|
42
|
+
blockHandlers: [BlockHandler!]
|
|
43
|
+
transactionHandlers: [TransactionHandler!]
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
type BlockHandler {
|
|
47
|
+
handler: String!
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
type TransactionHandler {
|
|
51
|
+
handler: String!
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
type Graft {
|
|
55
|
+
base: String!
|
|
56
|
+
block: BigInt!
|
|
57
|
+
}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
const source = ({ contract }) => `
|
|
2
|
+
owner: '${contract}'`
|
|
3
|
+
|
|
4
|
+
const mapping = () => `
|
|
5
|
+
apiVersion: 0.0.5
|
|
6
|
+
language: wasm/assemblyscript
|
|
7
|
+
entities:
|
|
8
|
+
- Block
|
|
9
|
+
- Transaction
|
|
10
|
+
blockHandlers:
|
|
11
|
+
- handler: handleBlock
|
|
12
|
+
transactionHandlers:
|
|
13
|
+
- handler: handleTx
|
|
14
|
+
file: ./src/mapping.ts`
|
|
15
|
+
|
|
16
|
+
module.exports = {
|
|
17
|
+
source,
|
|
18
|
+
mapping,
|
|
19
|
+
}
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
const generatePlaceholderHandlers = () =>
|
|
2
|
+
`
|
|
3
|
+
import { arweave, BigInt } from '@graphprotocol/graph-ts'
|
|
4
|
+
import { Block, Transaction } from '../generated/schema'
|
|
5
|
+
|
|
6
|
+
export function handleBlock(block: arweave.Block): void {
|
|
7
|
+
// Entities can be loaded from the store using a indepHash; this indepHash
|
|
8
|
+
// needs to be unique across all entities of the same type
|
|
9
|
+
let entity = Block.load(block.indepHash.toHexString())
|
|
10
|
+
|
|
11
|
+
// Entities only exist after they have been saved to the store;
|
|
12
|
+
// \`null\` checks allow to create entities on demand
|
|
13
|
+
if (!entity) {
|
|
14
|
+
entity = new Block(block.indepHash.toHexString());
|
|
15
|
+
|
|
16
|
+
// Entity fields can be set using simple assignments
|
|
17
|
+
entity.height = BigInt.fromU64(block.height)
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
// Entities can be written to the store with \`.save()\`
|
|
21
|
+
entity.save()
|
|
22
|
+
|
|
23
|
+
// Note: If a handler doesn't require existing field values, it is faster
|
|
24
|
+
// _not_ to load the entity from the store. Instead, create it fresh with
|
|
25
|
+
// \`new Entity(...)\`, set the fields that should be updated and save the
|
|
26
|
+
// entity back to the store. Fields that were not set or unset remain
|
|
27
|
+
// unchanged, allowing for partial updates to be applied.
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
export function handleTx(tb: arweave.TransactionWithBlockPtr): void {
|
|
31
|
+
const tx = tb.tx;
|
|
32
|
+
const entity = new Transaction(tx.id.toHexString());
|
|
33
|
+
|
|
34
|
+
entity.block = tb.block.indepHash;
|
|
35
|
+
entity.tx_id = tx.id;
|
|
36
|
+
entity.last_tx = tx.lastTx;
|
|
37
|
+
entity.owner = tx.owner;
|
|
38
|
+
entity.tags = saveTags(tx.id.toHexString(), tx.tags);
|
|
39
|
+
entity.data = tx.data;
|
|
40
|
+
entity.data_root = tx.dataRoot;
|
|
41
|
+
entity.data_size = tx.dataSize;
|
|
42
|
+
entity.target = tx.target;
|
|
43
|
+
entity.quantity = tx.quantity;
|
|
44
|
+
entity.signature = tx.signature;
|
|
45
|
+
entity.reward = tx.reward;
|
|
46
|
+
|
|
47
|
+
entity.save();
|
|
48
|
+
}
|
|
49
|
+
`
|
|
50
|
+
|
|
51
|
+
module.exports = {
|
|
52
|
+
generatePlaceholderHandlers,
|
|
53
|
+
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
const immutable = require('immutable')
|
|
2
|
+
|
|
3
|
+
module.exports = class ArweaveSubgraph {
|
|
4
|
+
constructor(options = {}) {
|
|
5
|
+
this.manifest = options.manifest
|
|
6
|
+
this.resolveFile = options.resolveFile
|
|
7
|
+
this.protocol = options.protocol
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
validateManifest() {
|
|
11
|
+
return immutable.List()
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
handlerTypes() {
|
|
15
|
+
return immutable.List([
|
|
16
|
+
'blockHandlers',
|
|
17
|
+
'transactionHandlers',
|
|
18
|
+
])
|
|
19
|
+
}
|
|
20
|
+
}
|
|
@@ -10,6 +10,7 @@ scalar BigInt
|
|
|
10
10
|
|
|
11
11
|
type SubgraphManifest {
|
|
12
12
|
specVersion: String!
|
|
13
|
+
features: [String!]
|
|
13
14
|
schema: Schema!
|
|
14
15
|
description: String
|
|
15
16
|
repository: String
|
|
@@ -40,6 +41,11 @@ type ContractMapping {
|
|
|
40
41
|
entities: [String!]!
|
|
41
42
|
blockHandlers: [BlockHandler!]
|
|
42
43
|
eventHandlers: [EventHandler!]
|
|
44
|
+
transactionHandlers: [TransactionHandler!]
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
type TransactionHandler {
|
|
48
|
+
handler: String!
|
|
43
49
|
}
|
|
44
50
|
|
|
45
51
|
type BlockHandler {
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
const source = () => `
|
|
2
|
+
startBlock: 0`
|
|
3
|
+
|
|
4
|
+
const mapping = () => `
|
|
5
|
+
apiVersion: 0.0.5
|
|
6
|
+
language: wasm/assemblyscript
|
|
7
|
+
entities:
|
|
8
|
+
- ExampleEntity
|
|
9
|
+
blockHandlers:
|
|
10
|
+
- handler: handleBlock
|
|
11
|
+
file: ./src/contract.ts`
|
|
12
|
+
|
|
13
|
+
module.exports = {
|
|
14
|
+
source,
|
|
15
|
+
mapping,
|
|
16
|
+
}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
const generatePlaceholderHandlers = () =>
|
|
2
|
+
`
|
|
3
|
+
import { cosmos, BigInt } from '@graphprotocol/graph-ts'
|
|
4
|
+
import { ExampleEntity } from '../generated/schema'
|
|
5
|
+
|
|
6
|
+
export function handleBlock(block: cosmos.Block): void {
|
|
7
|
+
// Entities can be loaded from the store using a string ID; this ID
|
|
8
|
+
// needs to be unique across all entities of the same type
|
|
9
|
+
let entity = ExampleEntity.load(block.header.hash.toHex())
|
|
10
|
+
|
|
11
|
+
// Entities only exist after they have been saved to the store;
|
|
12
|
+
// \`null\` checks allow to create entities on demand
|
|
13
|
+
if (!entity) {
|
|
14
|
+
entity = new ExampleEntity(block.header.hash.toHex())
|
|
15
|
+
|
|
16
|
+
// Entity fields can be set using simple assignments
|
|
17
|
+
entity.count = BigInt.fromI32(0)
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
// BigInt and BigDecimal math are supported
|
|
21
|
+
entity.count = entity.count + BigInt.fromI32(1)
|
|
22
|
+
|
|
23
|
+
// Entity fields can be set based on receipt information
|
|
24
|
+
entity.height = block.header.height
|
|
25
|
+
|
|
26
|
+
// Entities can be written to the store with \`.save()\`
|
|
27
|
+
entity.save()
|
|
28
|
+
|
|
29
|
+
// Note: If a handler doesn't require existing field values, it is faster
|
|
30
|
+
// _not_ to load the entity from the store. Instead, create it fresh with
|
|
31
|
+
// \`new Entity(...)\`, set the fields that should be updated and save the
|
|
32
|
+
// entity back to the store. Fields that were not set or unset remain
|
|
33
|
+
// unchanged, allowing for partial updates to be applied.
|
|
34
|
+
}
|
|
35
|
+
`
|
|
36
|
+
|
|
37
|
+
module.exports = {
|
|
38
|
+
generatePlaceholderHandlers,
|
|
39
|
+
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
const immutable = require('immutable')
|
|
2
2
|
|
|
3
|
-
module.exports = class
|
|
3
|
+
module.exports = class CosmosSubgraph {
|
|
4
4
|
constructor(options = {}) {
|
|
5
5
|
this.manifest = options.manifest
|
|
6
6
|
this.resolveFile = options.resolveFile
|
|
@@ -15,6 +15,7 @@ module.exports = class TendermintSubgraph {
|
|
|
15
15
|
return immutable.List([
|
|
16
16
|
'blockHandlers',
|
|
17
17
|
'eventHandlers',
|
|
18
|
+
'transactionHandlers',
|
|
18
19
|
])
|
|
19
20
|
}
|
|
20
21
|
}
|